/** "Return the total length of the formatted bundle block data." [DTN2] */ public static int total_length(final BlockInfoVec blocks) { int ret = 0; Iterator<BlockInfo> itr = blocks.iterator(); while (itr.hasNext()) { BlockInfo block = itr.next(); ret += block.full_length(); } return ret; }
/** "Give the processors a chance to chew on the bundle after reloading from disk." [DTN2] */ public static void reload_post_process(Bundle bundle) { BlockInfoVec recv_blocks = bundle.recv_blocks(); Iterator<BlockInfo> iter = recv_blocks.iterator(); while (iter.hasNext()) { // "allow BlockProcessors [and Ciphersuites] a chance to re-do // things needed after a load-from-store" [DTN2] BlockInfo block = iter.next(); block.owner().reload_post_process(bundle, recv_blocks, block); } }
/** * "Generate a BlockInfoVec for the outgoing link and put it into xmit_blocks_." [DTN2] * * @return a list of new BLockInfo */ public static BlockInfoVec prepare_blocks(Bundle bundle, final Link link) { // "create a new block list for the outgoing link by first calling // prepare on all the BlockProcessor classes for the blocks that // arrived on the link" [DTN2] BlockInfoVec xmit_blocks = bundle.xmit_link_block_set().create_blocks(link); BlockInfoVec recv_blocks = bundle.recv_blocks(); if (recv_blocks.size() > 0) { // "if there is a received block, the first one better be the primary" // [DTN2] assert (recv_blocks.front().type() == bundle_block_type_t.PRIMARY_BLOCK); Iterator<BlockInfo> iter = recv_blocks.iterator(); while (iter.hasNext()) { BlockInfo block = iter.next(); if (bundle.fragmented_incoming() && xmit_blocks.find_block(BundleProtocol.bundle_block_type_t.PAYLOAD_BLOCK) != null) { continue; } block .owner() .prepare(bundle, xmit_blocks, block, link, BlockInfo.list_owner_t.LIST_RECEIVED); } } else { BPF.getInstance().getBPFLogger().debug(TAG, "adding primary and payload block"); BlockProcessor bp = find_processor(BundleProtocol.bundle_block_type_t.PRIMARY_BLOCK); bp.prepare(bundle, xmit_blocks, null, link, BlockInfo.list_owner_t.LIST_NONE); bp = find_processor(bundle_block_type_t.PAYLOAD_BLOCK); bp.prepare(bundle, xmit_blocks, null, link, BlockInfo.list_owner_t.LIST_NONE); } // "now we also make sure to prepare() on any registered processors // that don't already have a block in the output list. this // handles the case where we have a locally generated block with // nothing in the recv_blocks vector" [DTN2] Iterator<BlockProcessor> itr = processors_.iterator(); while (itr.hasNext()) { BlockProcessor bp = itr.next(); if (!xmit_blocks.has_block(bp.block_type())) { bp.prepare(bundle, xmit_blocks, null, link, BlockInfo.list_owner_t.LIST_NONE); } } // Now prepare security blocks BPF.getInstance().getBPFLogger().debug(TAG, "Now preparing security blocks..."); Security.prepare_out_blocks(bundle, link, xmit_blocks); return xmit_blocks; }
/** * "Temporary helper function to find the offset of the first byte of the payload in a * BlockInfoVec." [DTN2] */ public static int payload_offset(final BlockInfoVec blocks) { int ret = 0; Iterator<BlockInfo> itr = blocks.iterator(); while (itr.hasNext()) { BlockInfo block = itr.next(); if (block.type() == BundleProtocol.bundle_block_type_t.PAYLOAD_BLOCK) { ret += block.data_offset(); return ret; } ret += block.full_length(); } return ret; }
/** * "Copies out a chunk of formatted bundle data at a specified offset from the provided * BlockInfoVec." [DTN2] * * @return "the length of the chunk produced (up to the supplied length) and sets last to true if * the bundle is complete." [DTN2] */ public static int produce( final Bundle bundle, final BlockInfoVec blocks, IByteBuffer data, int offset, int len, boolean[] last) { int old_position = data.position(); int origlen = len; last[0] = false; if (len == 0) return 0; assert (!blocks.isEmpty()); Iterator<BlockInfo> iter = blocks.iterator(); BlockInfo current_block = iter.next(); // "advance past any blocks that are skipped by the given offset."[DTN2] while (offset >= current_block.full_length()) { BPF.getInstance() .getBPFLogger() .debug( TAG, String.format( "BundleProtocol::produce skipping block type %s " + "since offset %d >= block length %d", current_block.type().toString(), offset, current_block.full_length())); offset -= current_block.full_length(); current_block = iter.next(); } // "the offset value now should be within the current block" [DTN2] while (true) { // The first time remainder will be minus from leftover offset above // but later on it will be the full content of the block int remainder = current_block.full_length() - offset; int tocopy = Math.min(len, remainder); BPF.getInstance() .getBPFLogger() .debug( TAG, String.format( "BundleProtocol::produce copying %d/%d bytes from " + "block type %s at offset %d", tocopy, remainder, current_block.type().toString(), offset)); current_block.owner().produce(bundle, current_block, data, offset, tocopy); len -= tocopy; // move the position of IByteBuffer data.position(data.position() + tocopy); // "if we've copied out the full amount the user asked for, // we're done. note that we need to check the corner case // where we completed the block exactly to properly set the // last bit" [DTN2] if (len == 0) { if ((tocopy == remainder) && ((current_block.flags() & BundleProtocol.block_flag_t.BLOCK_FLAG_LAST_BLOCK.getCode()) > 0)) { last[0] = true; } break; } // "we completed the current block, so we're done if this // is the last block, even if there's space in the user buffer" // [DTN2] assert (tocopy == remainder); if ((current_block.flags() & BundleProtocol.block_flag_t.BLOCK_FLAG_LAST_BLOCK.getCode()) > 0) { last[0] = true; break; } // advance to next block current_block = iter.next(); offset = 0; } BPF.getInstance() .getBPFLogger() .debug( TAG, String.format( "BundleProtocol::produce complete: " + "produced %d bytes, bundle id %d, status is %s", origlen - len, bundle.bundleid(), last[0] ? "complete" : "not complete")); data.position(old_position); return origlen - len; }