/* * Part of the CCNx Java Library. * * Copyright (C) 2008, 2009 Palo Alto Research Center, Inc. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 2.1 * as published by the Free Software Foundation. * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. You should have received * a copy of the GNU Lesser General Public License along with this library; * if not, write to the Free Software Foundation, Inc., 51 Franklin Street, * Fifth Floor, Boston, MA 02110-1301 USA. */ package org.ccnx.ccn.io; import java.io.IOException; import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.security.SignatureException; import org.ccnx.ccn.CCNHandle; import org.ccnx.ccn.impl.CCNFlowControl; import org.ccnx.ccn.impl.CCNSegmenter; import org.ccnx.ccn.impl.security.crypto.CCNBlockSigner; import org.ccnx.ccn.impl.security.crypto.ContentKeys; import org.ccnx.ccn.profiles.SegmentationProfile; import org.ccnx.ccn.profiles.SegmentationProfile.SegmentNumberType; import org.ccnx.ccn.protocol.ContentName; import org.ccnx.ccn.protocol.KeyLocator; import org.ccnx.ccn.protocol.PublisherPublicKeyDigest; import org.ccnx.ccn.protocol.SignedInfo; /** * This class acts as a packet-oriented stream of data. It might be * better implemented as a subclass of DatagramSocket. Given a base name * and signing information, it writes content blocks under that base name, * where each block is named according to the base name concatenated with a * sequence number identifying the specific block. * * Each call to write writes one or more individual ContentObjects. The * maximum size is given by parameters of the segmenter used; if buffers * are larger than that size they are output as multiple fragments. * * It does offer flexible content name increment options. The creator * can specify an initial block id (default is 0), and an increment (default 1) * for fixed-width blocks, or blocks can be identified by byte offset * in the running stream, or by another integer metric (e.g. time offset), * by supplying a multiplier to convert the byte offset into a metric value. * Finally, writers can specify the block identifier with a write. * Currently, however, the corresponding reader org.ccnx.ccn.io.CCNBlockInputStream expects * sequential segment numbering (and constraints based on the low-level CCN * Interest specification may make this difficult to overcome). */ public class CCNBlockOutputStream extends CCNAbstractOutputStream { public CCNBlockOutputStream(ContentName baseName, SignedInfo.ContentType type) throws IOException { this(baseName, type, null, null); } public CCNBlockOutputStream(ContentName baseName, SignedInfo.ContentType type, PublisherPublicKeyDigest publisher, CCNHandle handle) throws IOException { this(baseName, type, null, publisher, null, new CCNFlowControl((null == handle) ? CCNHandle.getHandle() : handle)); } public CCNBlockOutputStream(ContentName baseName, SignedInfo.ContentType type, KeyLocator locator, PublisherPublicKeyDigest publisher, ContentKeys keys, CCNFlowControl flowControl) throws IOException { super((SegmentationProfile.isSegment(baseName) ? SegmentationProfile.segmentRoot(baseName) : baseName), locator, publisher, type, keys, new CCNSegmenter(flowControl, new CCNBlockSigner())); startWrite(); // set up flow controller to write } public void useByteCountSequenceNumbers() { getSegmenter().setSequenceType(SegmentNumberType.SEGMENT_BYTE_COUNT); getSegmenter().setByteScale(1); } public void useFixedIncrementSequenceNumbers(int increment) { getSegmenter().setSequenceType(SegmentNumberType.SEGMENT_FIXED_INCREMENT); getSegmenter().setBlockIncrement(increment); } public void useScaledByteCountSequenceNumbers(int scale) { getSegmenter().setSequenceType(SegmentNumberType.SEGMENT_BYTE_COUNT); getSegmenter().setByteScale(scale); } @Override public void write(byte[] b, int off, int len) throws IOException { try { getSegmenter().put(_baseName, b, off, len, false, getType(), null, null, null, _keys); } catch (InvalidKeyException e) { throw new IOException("Cannot sign content -- invalid key!: " + e.getMessage()); } catch (SignatureException e) { throw new IOException("Cannot sign content -- signature failure!: " + e.getMessage()); } catch (NoSuchAlgorithmException e) { throw new IOException("Cannot sign content -- unknown algorithm!: " + e.getMessage()); } catch (InvalidAlgorithmParameterException e) { throw new IOException("Cannot encrypt content -- bad algorithm parameter!: " + e.getMessage()); } } }