/** Delete reassembly state for a bundle. */ public void delete_fragment(Bundle fragment) { FragmentState state; assert (fragment.is_fragment()) : TAG + "delete_fragment() not a fragment"; // cons up the key to do the table lookup and look for reassembly state String[] hash_key = new String[1]; get_hash_key(fragment, hash_key); state = fragment_table_.get(hash_key); // remove the fragment from the reassembly list boolean erased = state.erase_fragment(fragment); // fragment was not in reassembly list, simply return if (!erased) { return; } // note that the old fragment data is still kept in the // partially-reassembled bundle file, but there won't be metadata // to indicate as such // delete reassembly state if no fragments now exist if (state.num_fragments() == 0) { fragment_table_.remove(hash_key); } }
/** * 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; }
/** Delete any fragments that are no longer needed given the incoming (non-fragment) bundle. */ public void delete_obsoleted_fragments(Bundle bundle) { FragmentState state; // cons up the key to do the table lookup and look for reassembly state String[] hash_key = new String[1]; hash_key[0] = ""; get_hash_key(bundle, hash_key); state = fragment_table_.get(hash_key); Logger.getInstance() .debug( TAG, String.format( "checking for obsolete fragments id=%s hash=%s...", bundle.bundleid(), hash_key[0])); if (state == null) { Logger.getInstance().error(TAG, String.format("no reassembly state for key %s", hash_key[0])); return; } Logger.getInstance() .debug( TAG, String.format( "found reassembly state... deleting %d fragments", state.num_fragments())); state.fragment_list().get_lock().lock(); try { while (state.fragment_list().size() > 0) { BundleDaemon.getInstance() .post( new BundleDeleteRequest( state.fragment_list().pop_back(false), status_report_reason_t.REASON_NO_ADDTL_INFO)); } assert (state.fragment_list().size() == 0) : TAG + ": delete_obsoleted_fragments Size not 0"; // moved into // events } finally { state.fragment_list().get_lock().unlock(); } fragment_table_.remove(hash_key); }
/** * 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); }
/** * Remove Fragment state from the fragment table * * @param fragment FragmentState to remove */ public void erase_fragment_state(FragmentState fragment_state) { String[] hash_key = new String[1]; get_hash_key(fragment_state.bundle(), hash_key); fragment_table_.remove(hash_key); }