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