Example #1
0
  /** "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);
    }
  }
Example #2
0
  /**
   * "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;
  }
  /**
   * 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);
  }
Example #5
0
  /**
   * "Loop through the bundle's received block list to validate each entry." [DTN2]
   *
   * @return "true if the bundle is valid, false if it should be deleted." [DTN2]
   */
  public static boolean validate(
      Bundle bundle,
      status_report_reason_t[] reception_reason,
      status_report_reason_t[] deletion_reason) {
    int primary_blocks = 0, payload_blocks = 0;
    BlockInfoVec recv_blocks = bundle.recv_blocks();

    // "a bundle must include at least two blocks (primary and payload)"
    // [DTN2]
    if (recv_blocks.size() < 2) {
      BPF.getInstance().getBPFLogger().error(TAG, "bundle fails to contain at least two blocks");
      deletion_reason[0] = BundleProtocol.status_report_reason_t.REASON_BLOCK_UNINTELLIGIBLE;
      return false;
    }

    // "the first block of a bundle must be a primary block" [DTN2]
    if (recv_blocks.front().type() != BundleProtocol.bundle_block_type_t.PRIMARY_BLOCK) {
      BPF.getInstance().getBPFLogger().error(TAG, "bundle fails to contain a primary block");
      deletion_reason[0] = BundleProtocol.status_report_reason_t.REASON_BLOCK_UNINTELLIGIBLE;
      return false;
    }

    // "validate each individual block" [DTN2]

    int last_block_index = recv_blocks.size() - 1;
    for (int i = 0; i < recv_blocks.size(); i++) {
      BlockInfo current_block = recv_blocks.get(i);

      // "a block may not have enough data for the preamble" [DTN2]
      if (current_block.data_offset() == 0) {
        // "either the block is not the last one and something went
        // badly wrong, or it is the last block present" [DTN2]
        if (i != last_block_index) {
          BPF.getInstance().getBPFLogger().error(TAG, "bundle block too short for the preamble");
          deletion_reason[0] = BundleProtocol.status_report_reason_t.REASON_BLOCK_UNINTELLIGIBLE;
          return false;
        }
        // "this is the last block, so drop it" [DTN2]
        BPF.getInstance().getBPFLogger().debug(TAG, "forgetting preamble-starved last block");
        recv_blocks.remove(current_block);
        if (recv_blocks.size() < 2) {
          BPF.getInstance()
              .getBPFLogger()
              .error(TAG, "bundle fails to contain at least two blocks");
          deletion_reason[0] = BundleProtocol.status_report_reason_t.REASON_BLOCK_UNINTELLIGIBLE;
          return false;
        }
        // "continue with the tests; results may have changed now that
        // a different block is last" [DTN2]
        return false;
      } else {
        if (current_block.type() == BundleProtocol.bundle_block_type_t.PRIMARY_BLOCK) {
          primary_blocks++;
        }

        if (current_block.type() == BundleProtocol.bundle_block_type_t.PAYLOAD_BLOCK) {
          payload_blocks++;
        }
      }

      if (!current_block
          .owner()
          .validate(bundle, recv_blocks, current_block, reception_reason, deletion_reason)) {
        return false;
      }

      // "a bundle's last block must be flagged as such,
      // and all other blocks should not be flagged" [DTN2]
      if (i == last_block_index) {
        if (!current_block.last_block()) {
          if (!bundle.fragmented_incoming()) {
            BPF.getInstance().getBPFLogger().error(TAG, "bundle's last block not flagged");
            deletion_reason[0] = BundleProtocol.status_report_reason_t.REASON_BLOCK_UNINTELLIGIBLE;
            return false;
          } else {
            BPF.getInstance()
                .getBPFLogger()
                .debug(TAG, "bundle's last block not flagged, but " + "it is a reactive fragment");
          }
        }
      } else {
        if (current_block.last_block()) {
          BPF.getInstance().getBPFLogger().error(TAG, "bundle block incorrectly flagged as last");
          deletion_reason[0] = BundleProtocol.status_report_reason_t.REASON_BLOCK_UNINTELLIGIBLE;
          return false;
        }
      }
    }

    // "a bundle must contain one, and only one, primary block" [DTN2]
    if (primary_blocks != 1) {
      BPF.getInstance()
          .getBPFLogger()
          .error(TAG, String.format("bundle contains %d primary blocks", primary_blocks));
      deletion_reason[0] = BundleProtocol.status_report_reason_t.REASON_BLOCK_UNINTELLIGIBLE;
      return false;
    }

    // "a bundle must not contain more than one payload block" [DTN2]
    if (payload_blocks > 1) {
      BPF.getInstance()
          .getBPFLogger()
          .error(TAG, String.format("bundle contains %d payload blocks", payload_blocks));
      deletion_reason[0] = BundleProtocol.status_report_reason_t.REASON_BLOCK_UNINTELLIGIBLE;
      return false;
    }

    return true;
  }
Example #6
0
  /**
   * "Parse the supplied chunk of arriving data and append it to the rcvd_blocks_ list in the given
   * bundle, finding the appropriate BlockProcessor element and calling its receive() handler.
   *
   * <p>When called repeatedly for arriving chunks of data, this properly fills in the entire
   * bundle, including the in_blocks_ record of the arriving blocks and the payload (which is stored
   * externally)." [DTN2]
   *
   * @return "the length of data consumed or -1 on protocol error, plus sets last to true if the
   *     bundle is complete." [DTN2]
   */
  public static int consume(Bundle bundle, IByteBuffer data, int len, boolean[] last) {

    int old_position = data.position();
    int origlen = len;
    last[0] = false;

    BlockInfoVec recv_blocks = bundle.recv_blocks();

    // "special case for first time we get called, since we need to
    // create a BlockInfo struct for the primary block without knowing
    // the typecode or the length" [DTN2]
    if (recv_blocks.isEmpty()) {
      BPF.getInstance()
          .getBPFLogger()
          .debug(TAG, "consume: got first block... " + "creating primary block info");
      recv_blocks.append_block(find_processor(bundle_block_type_t.PRIMARY_BLOCK), null);
    }

    // "loop as long as there is data left to process" [DTN2]
    while (len != 0) {
      BPF.getInstance()
          .getBPFLogger()
          .debug(TAG, String.format("consume: %d bytes left to process", len));
      BlockInfo info = recv_blocks.back();

      // "if the last received block is complete, create a new one
      // and push it onto the vector. at this stage we consume all
      // blocks, even if there's no BlockProcessor that understands
      // how to parse it" [DTN2]
      if (info.complete()) {
        data.mark();
        byte bundle_block_type_byte = data.get();
        bundle_block_type_t type = bundle_block_type_t.get(bundle_block_type_byte);
        data.reset();
        info = recv_blocks.append_block(find_processor(type), null);
        BPF.getInstance()
            .getBPFLogger()
            .debug(
                TAG,
                String.format(
                    "consume: previous block complete, " + "created new BlockInfo type %s",
                    info.owner().block_type()));
      }

      // "now we know that the block isn't complete, so we tell it to
      // consume a chunk of data" [DTN2]
      BPF.getInstance()
          .getBPFLogger()
          .debug(
              TAG,
              String.format(
                  "consume: block processor %s type %s incomplete, "
                      + "calling consume (%d bytes already buffered)",
                  info.owner().block_type(), info.type(), info.contents().position()));

      int cc = info.owner().consume(bundle, info, data, len);
      if (cc < 0) {
        BPF.getInstance()
            .getBPFLogger()
            .error(TAG, String.format("consume: protocol error handling block %s", info.type()));
        return -1;
      }

      // "decrement the amount that was just handled from the overall
      // total. verify that the block was either completed or
      // consumed all the data that was passed in." [DTN2]
      len -= cc;
      data.position(data.position() + cc);

      BPF.getInstance()
          .getBPFLogger()
          .debug(
              TAG,
              String.format(
                  "consume: consumed %d bytes of block type %s (%s)",
                  cc, info.type(), info.complete() ? "complete" : "not complete"));

      if (info.complete()) {
        // check if we're done with the bundle
        if ((info.flags() & block_flag_t.BLOCK_FLAG_LAST_BLOCK.getCode()) > 0) {
          last[0] = true;
          break;
        }

      } else {
        assert (len == 0);
      }
    }

    BPF.getInstance()
        .getBPFLogger()
        .debug(
            TAG,
            String.format(
                "bundle id %d consume completed, %d/%d bytes consumed %s",
                bundle.bundleid(), origlen - len, origlen, last[0] ? "(completed bundle)" : ""));

    data.position(old_position);
    return origlen - len;
  }