/**
   * 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();
    }
  }
Beispiel #3
0
  /**
   * "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;
  }