/** * Given the given fragmentation threshold, determine whether the given bundle should be split * into several smaller bundles. If so, this returns true and generates a bunch of bundle received * events for the individual fragments. * * @param bundle Bundle to split into fragments * @param link Bundle to send on the given link * @param max_length Maximum length of the fragment * @return FragmentState that has the list of created fragments for the given bundle. */ public FragmentState proactively_fragment(Bundle bundle, final Link link, int max_length) { int payload_len = bundle.payload().length(); Bundle fragment; FragmentState state = new FragmentState(bundle); int todo = payload_len; int offset = 0; int count = 0; BlockInfoVec first_frag_blocks = new BlockInfoVec(); BlockInfoVec all_frag_blocks = new BlockInfoVec(); BlockInfoVec this_frag_blocks = first_frag_blocks; ListIterator<BlockInfo> entry = bundle.xmit_link_block_set().find_blocks(link).listIterator(); while (entry.hasNext()) { BlockInfo block_info = entry.next(); if ((block_info.type() == bundle_block_type_t.PRIMARY_BLOCK) || (block_info.type() == bundle_block_type_t.PAYLOAD_BLOCK)) { all_frag_blocks.add(block_info); first_frag_blocks.add(block_info); } else if ((block_info.flags() & block_flag_t.BLOCK_FLAG_REPLICATE.getCode()) > 0) { all_frag_blocks.add(block_info); } else { first_frag_blocks.add(block_info); } } do { fragment = create_fragment(bundle, link, this_frag_blocks, offset, max_length); assert (fragment != null) : TAG + ": proactively_fragment() fragment not valid"; state.add_fragment(fragment); offset += fragment.payload().length(); todo -= fragment.payload().length(); this_frag_blocks = all_frag_blocks; ++count; } while (todo > 0); Logger.getInstance() .debug( TAG, String.format( "proactively fragmenting " + "%s byte payload into %s %s byte fragments", payload_len, count, max_length)); String[] hash_key = new String[1]; get_hash_key(fragment, hash_key); fragment_table_.put(hash_key[0], state); return state; }
/** * "Search the list for a bundle with the given GBOF IDthe found bundle otherwise, null * * @return the found bundle otherwise, null. */ public Bundle find(GbofId gbof_id) { lock_.lock(); try { Iterator<Bundle> iter = list_.iterator(); while (iter.hasNext()) { Bundle bundle = iter.next(); if (gbof_id.equals( bundle.source(), bundle.creation_ts(), bundle.is_fragment(), bundle.payload().length(), bundle.frag_offset())) return bundle; } return null; } finally { lock_.unlock(); } }
/** * "Assuming the given bundle is an administrative bundle, extract the admin bundle type code from * the bundle's payload." [DTN2] * * @return true if successful */ public static boolean get_admin_type(final Bundle bundle, admin_record_type_t[] type) { if (!bundle.is_admin()) { return false; } IByteBuffer buf = new SerializableByteBuffer(16); bundle.payload().read_data(0, 1, buf); admin_record_type_t admin_record_type = admin_record_type_t.get((byte) (buf.get(0) >> 4)); switch (admin_record_type) { case ADMIN_STATUS_REPORT: case ADMIN_CUSTODY_SIGNAL: case ADMIN_ANNOUNCE: type[0] = admin_record_type; return true; default: return false; // unknown type } }
/** * Create a bundle fragment from another bundle. * * @param bundle the source bundle from which we create the fragment. Note: the bundle may itself * be a fragment * @param offset the offset relative to this bundle (not the original) for the for the new * fragment. note that if this bundle is already a fragment, the offset into the original * bundle will be this bundle's frag_offset + offset * @param length the length of the fragment we want * @return Newly created bundle */ public Bundle create_fragment(Bundle bundle, BlockInfoVec blocks, int offset, int length) { Bundle fragment = new Bundle(location_t.MEMORY); bundle.copy_metadata(fragment); fragment.set_is_fragment(true); fragment.set_do_not_fragment(false); // initialize the fragment's orig_length and figure out the offset // into the payload if (!bundle.is_fragment()) { fragment.set_orig_length(bundle.payload().length()); fragment.set_frag_offset(offset); } else { fragment.set_orig_length(bundle.orig_length()); fragment.set_frag_offset(bundle.frag_offset() + offset); } // check for overallocated length if ((offset + length) > fragment.orig_length()) { Logger.getInstance() .error( TAG, String.format( "fragment length overrun: " + "orig_length %d frag_offset %d requested offset %d length %d", fragment.orig_length(), fragment.frag_offset(), offset, length)); // Panic; return null; } // initialize payload fragment.payload().write_data(bundle.payload(), offset, length, 0); // copy all blocks that follow the payload, and all those before // the payload that are marked with the "must be replicated in every // fragment" bit ListIterator<BlockInfo> iter = blocks.listIterator(); // BlockInfoVec vec; boolean found_payload = false; while (iter.hasNext()) { BlockInfo entry = iter.next(); int type = entry.type().getCode(); if ((type == bundle_block_type_t.PRIMARY_BLOCK.getCode()) || (bundle_block_type_t.PAYLOAD_BLOCK.getCode() > 0) || found_payload || ((entry.flags() & block_flag_t.BLOCK_FLAG_REPLICATE.getCode()) > 0)) { // we need to include this block; copy the BlockInfo into the // fragment fragment.recv_blocks().add(entry); if (type == bundle_block_type_t.PAYLOAD_BLOCK.getCode()) { found_payload = true; } } } return fragment; }
/** * Given a newly arrived bundle fragment, append it to the table of fragments and see if it allows * us to reassemble the bundle. If it does, a ReassemblyCompletedEvent will be posted. * * @param fragment Newly received fragment */ public void process_for_reassembly(Bundle fragment) { FragmentState state; assert (fragment.is_fragment()) : TAG + ": process_for_reassembly() not a fragment"; String[] hash_key = new String[1]; get_hash_key(fragment, hash_key); FragmentState iter = fragment_table_.get(hash_key); Logger.getInstance() .debug( TAG, String.format( "processing bundle fragment id=%s hash=%s %s", fragment.bundleid(), hash_key, fragment.is_fragment())); if (iter == null) { state = new FragmentState(); fragment.copy_metadata(state.bundle()); state.bundle().set_is_fragment(false); state.bundle().payload().set_length(fragment.orig_length()); fragment_table_.put(hash_key[0], state); } else { state = iter; Logger.getInstance() .debug( TAG, String.format( "found reassembly state for key %s (%s fragments)", hash_key, state.fragment_list().size())); } // stick the fragment on the reassembly list state.add_fragment(fragment); // store the fragment data in the partially reassembled bundle file int fraglen = fragment.payload().length(); Logger.getInstance() .debug( TAG, String.format( "write_data: length_=%s src_offset=%s dst_offset=%s len %s", state.bundle().payload().length(), 0, fragment.frag_offset(), fraglen)); state.bundle().payload().write_data(fragment.payload(), 0, fraglen, fragment.frag_offset()); // reassembled bundle, but eventually reassembly will have to do much // more if (fragment.frag_offset() == 0 && state.bundle().recv_blocks().size() > 0) { BlockInfo block_i; ListIterator<BlockInfo> entry = fragment.recv_blocks().listIterator(); while (entry.hasNext()) { block_i = entry.next(); state.bundle().recv_blocks().add(block_i); } } // check see if we're done if (state.check_completed()) { return; } BundleDaemon.getInstance() .post_at_head(new ReassemblyCompletedEvent(state.bundle(), state.fragment_list())); assert (state.fragment_list().size() == 0) : TAG + ": process_for_reassembly size not 0"; // moved into the event fragment_table_.remove(hash_key); }
/** * Create a fragment to be sent out on a particular link. * * @param bundle Source Bundle from which we create a fragment. * @param link Link on which we will send the fragment * @param blocks_to_copy Blocks to copy on this fragment. * @param offset The offset relative to this bundle for the for the new fragment * @param max_length Maximum length of the newly created fragment * @return Newly created fragment. */ public Bundle create_fragment( Bundle bundle, final Link link, final BlockInfoVec blocks_to_copy, int offset, int max_length) { int block_length = 0; ListIterator<BlockInfo> entry = blocks_to_copy.listIterator(); BlockInfo block_i; while (entry.hasNext()) { block_i = entry.next(); if (block_i.type() == bundle_block_type_t.PRIMARY_BLOCK) { block_length += block_i.data_length(); } else { block_length += block_i.data_offset(); // data offset is the // starting point of } } if (block_length > max_length) { Logger.getInstance() .error( TAG, String.format( "unable to create a fragment of length %s; minimum length " + "required is %s", max_length, block_length)); return null; } Bundle fragment = new Bundle(location_t.DISK); // copy the metadata into the new fragment (which can be further // fragmented) bundle.copy_metadata(fragment); fragment.set_is_fragment(true); fragment.set_do_not_fragment(false); // initialize the fragment's orig_length and figure out the offset // into the payload if (!bundle.is_fragment()) { fragment.set_orig_length(bundle.payload().length()); fragment.set_frag_offset(offset); } else { fragment.set_orig_length(bundle.orig_length()); fragment.set_frag_offset(bundle.frag_offset() + offset); } // initialize payload int to_copy = Math.min(max_length - block_length, bundle.payload().length() - offset); fragment.payload().set_length(to_copy); fragment.payload().write_data(bundle.payload(), offset, to_copy, 0); BlockInfoVec xmit_blocks = fragment.xmit_link_block_set().create_blocks(link); entry = blocks_to_copy.listIterator(); // reset Iterator while (entry.hasNext()) { block_i = entry.next(); xmit_blocks.add(block_i); } Logger.getInstance() .debug( TAG, String.format( "created %s byte fragment bundle with %s bytes of payload", to_copy + block_length, to_copy)); return fragment; }
/** "Constructor-like function to create a new custody signal bundle." [DTN2] */ public static Bundle create_custody_signal( final Bundle orig_bundle, final EndpointID source_eid, boolean succeeded, BundleProtocol.custody_signal_reason_t reason) { Bundle bundle = new Bundle(location_t.MEMORY); bundle.source().assign(source_eid); if (orig_bundle.custodian().equals(EndpointID.NULL_EID())) { Logger.getInstance() .error( TAG, String.format( "create_custody_signal(for bundle id %d): " + "custody signal cannot be generated due to custodian is null eid", orig_bundle.bundleid())); } bundle.dest().assign(orig_bundle.custodian()); bundle.replyto().assign(EndpointID.NULL_EID()); bundle.custodian().assign(EndpointID.NULL_EID()); bundle.set_is_admin(true); bundle.set_expiration(orig_bundle.expiration()); int sdnv_encoding_len = 0; int signal_len = 0; // "format of custody signals: // // 1 byte admin payload type and flags // 1 byte status code // SDNV [Fragment Offset (if present)] // SDNV [Fragment Length (if present)] // SDNVx2 Time of custody signal // SDNVx2 Copy of bundle X's Creation Timestamp // SDNV Length of X's source endpoint ID // vari Source endpoint ID of bundle X // // first calculate the length // // the non-optional, fixed-length fields above:" [DTN2] signal_len = 1 + 1; // "the 2 SDNV fragment fields:" [DTN2] if (orig_bundle.is_fragment()) { signal_len += SDNV.encoding_len(orig_bundle.frag_offset()); signal_len += SDNV.encoding_len(orig_bundle.orig_length()); } // "Time field, set to the current time:" [DTN2] DTNTime now = new DTNTime(); signal_len += DTNTime.SDNV_encoding_len(now); // "The bundle's creation timestamp:" [DTN2] signal_len += BundleTimestamp.SDNV_encoding_len(orig_bundle.creation_ts()); // the Source Endpoint ID length and value signal_len += SDNV.encoding_len(orig_bundle.source().length()) + orig_bundle.source().length(); // // "We got all the data ready, now format the buffer" [DTN2] // IByteBuffer bp = new SerializableByteBuffer(signal_len); int len = signal_len; bp.rewind(); // "Admin Payload Type and flags" [DTN2] byte type_and_flags_byte = (byte) (BundleProtocol.admin_record_type_t.ADMIN_CUSTODY_SIGNAL.getCode() << 4); if (orig_bundle.is_fragment()) { type_and_flags_byte |= BundleProtocol.admin_record_flags_t.ADMIN_IS_FRAGMENT.getCode(); } bp.put(type_and_flags_byte); len--; // Status_Flag_Byte consists of Success flag and reason code byte status_flag_byte = (byte) ((succeeded ? 1 : 0) << 7 | (reason.getCode() & 0x7f)); bp.put(status_flag_byte); len--; // "The 2 Fragment Fields" [DTN2] if (orig_bundle.is_fragment()) { sdnv_encoding_len = SDNV.encode(orig_bundle.frag_offset(), bp, len); assert (sdnv_encoding_len > 0); len -= sdnv_encoding_len; sdnv_encoding_len = SDNV.encode(orig_bundle.orig_length(), bp, len); assert (sdnv_encoding_len > 0); len -= sdnv_encoding_len; } // DTNTime which is a time of signal field sdnv_encoding_len = DTNTime.SDNV_encoding_len(now); assert (sdnv_encoding_len > 0); DTNTime.encodeSDNV(now, bp); len -= sdnv_encoding_len; // "Copy of bundle X's Creation Timestamp" [DTN2] sdnv_encoding_len = BundleTimestamp.SDNV_encoding_len(orig_bundle.creation_ts()); assert (sdnv_encoding_len > 0); BundleTimestamp.encodeSDNV(orig_bundle.creation_ts(), bp); len -= sdnv_encoding_len; // "The Endpoint ID length and data" [DTN2] sdnv_encoding_len = SDNV.encode(orig_bundle.source().length(), bp, len); assert (sdnv_encoding_len > 0); len -= sdnv_encoding_len; assert (len == orig_bundle.source().length()); bp.put(orig_bundle.source().byte_array()); // // "Finished generating the payload" [DTN2] // bp.rewind(); bundle.payload().set_data(bp, signal_len); return bundle; }