/** * 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; }
/** * 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); }