/** * Produce a bundle by coping all payload and payload block metadata to buffer. * * @param bundle Bundle to produce * @param block Payload block of Bundle * @param buf Copy the data on the current position this buffer * @param offset Offset of the block data. Keep track of how many bytes have been produced before. * @param len Number of bytes to produce */ public void produce( final Bundle bundle, final BlockInfo block, IByteBuffer buf, int offset, int len) { int old_position = buf.position(); // First copy out the specified range of the preamble if (offset < block.data_offset()) { int tocopy = Math.min(len, block.data_offset() - offset); BufferHelper.copy_data(buf, buf.position(), block.contents(), offset, tocopy); buf.position(buf.position() + tocopy); offset += tocopy; len -= tocopy; } if (len == 0) { buf.position(old_position); return; } // Adjust offset to account for the preamble int payload_offset = offset - block.data_offset(); int tocopy = (int) Math.min(len, bundle.payload().length() - payload_offset); bundle.payload().read_data(payload_offset, tocopy, buf); buf.position(old_position); return; }
/** * Check the validity of the Payload block * * @param bundle Bundle to check the generic validity of block * @param block_list List of Blocks * @param block Block to check if it's valid or not * @param reception_reason If block is not valid then reception reason * @param deletion_reason If block is not balid then deletion reason * @return True if the block is valid else false */ public boolean validate( final Bundle bundle, BlockInfoVec block_list, BlockInfo block, status_report_reason_t[] reception_reason, status_report_reason_t[] deletion_reason) { // check for generic block errors if (!super.validate(bundle, block_list, block, reception_reason, deletion_reason)) { return false; } if (!block.complete()) { // We do not need the block to be complete because we may be // able to reactively fragment it, but we must have at least // the full preamble to do so. if (block.data_offset() == 0 // There is not much value in a 0-byte payload fragment so // discard those as well. || (block.data_length() != 0 && bundle.payload().length() == 0) // If the bundle should not be fragmented and the payload // block is not complete, we must discard the bundle. || bundle.do_not_fragment()) { Log.d(TAG, "payload incomplete and cannot be fragmented"); deletion_reason[0] = status_report_reason_t.REASON_BLOCK_UNINTELLIGIBLE; return false; } } return true; }
/** * Generate the preamble for the payload block. * * @param bundle Bundle to generate preamble * @param xmit_blocks xmit_blocks to get the dictionary for generating preamble * @param block Block to write the payload preamble * @param link Link type * @param last If its a last block * @return If successfully generated then return Success message. */ public int generate( final Bundle bundle, BlockInfoVec xmit_blocks, BlockInfo block, final Link link, boolean last) { // in the ::generate pass, we just need to set up the preamble, // since the payload stays on disk super.generate_preamble( xmit_blocks, block, bundle_block_type_t.PAYLOAD_BLOCK, last ? block_flag_t.BLOCK_FLAG_LAST_BLOCK.getCode() : 0, bundle.payload().length()); return BP_SUCCESS; }
/** * "Similar to process() but for potentially mutating processing functions. The function returns * true iff it modified the target_block." [DTN2] * * <p>Function used for security purposes. When a block is going to be encrypted, * ciphersuiteC3.finalize calls this function with the pointer to do_crypt, defined inside * finalize. * * @param func (IN): function to call * @param bundle (): * @param caller_block (IN): security block * @param target_block (OUT): payload block that we are going to change * @param offset (): data offset * @param len (IN): data length * @param r (IN): nu se. * @return Return number of bytes successfully consumed */ public boolean mutate( mutate_func func, Bundle bundle, final BlockInfo caller_block, BlockInfo target_block, int offset, int len, OpaqueContext r) { /* // "convert the offset to a pointer in the target block" [DTN2] IByteBuffer buf = target_block.contents(); buf.position( buf.position()+ offset); */ boolean changed = false; IByteBuffer buf; // char work[1024]; // XXX/pl TODO rework buffer usage // and look at type for the payload data int len_to_do = 0; // re-do these appropriately for the payload // ASSERT(offset < target_block->contents().len()); // ASSERT(target_block->contents().len() >= offset + len); // First work on specified range of the preamble if (offset < target_block.data_offset()) { len_to_do = Math.min(len, target_block.data_offset() - offset); // convert the offset to a pointer in the target block buf = target_block.contents(); buf.position(buf.position() + offset); // call the processing function to do the work // "call the mutating function to do the work" [DTN2] mutate_func_event_data data = new mutate_func_event_data(); data.set_bundle(bundle); data.set_caller_block(caller_block); data.set_target_block(target_block); data.set_buf(buf); data.set_len(len_to_do); data.set_context(r); changed = func.action(data); buf.position(buf.position() + len_to_do); offset += len_to_do; len -= len_to_do; } if (len == 0) return changed; // Adjust offset to account for the preamble int payload_offset = offset - target_block.data_offset(); int remaining = Math.min(len, bundle.payload().length() - payload_offset); int outlen; // buf = new SerializableByteBuffer(5000*1024); // use local buffer, max=10k buf = new SerializableByteBuffer(2100000); // use local buffer, max=10k while (remaining > 0) { Log.d(TAG, "mutate(): We start a pass in the while loop to mutate payload"); outlen = 0; len_to_do = Math.min(remaining, buf.capacity()); bundle.payload().read_data(payload_offset, len_to_do, buf); // call the processing function to do the work // boolean chunk_changed =(*func)(bundle, caller_block, target_block, buf, len_to_do, r); mutate_func_event_data data = new mutate_func_event_data(); data.set_bundle(bundle); data.set_caller_block(caller_block); data.set_target_block(target_block); data.set_buf(buf); data.set_len(len_to_do); data.set_context(r); boolean chunk_changed = func.action(data); // if we need to flush changed content back to disk, do it . // sd. In android, we dont do it yet, because we havent obtained the ciphertext yet!!! // if ( chunk_changed ) // bundle.payload().write_data(buf, payload_offset, len_to_do); assert (chunk_changed == true) : TAG + "mutate(): ERROR. A payload change is not going to happen!"; changed |= chunk_changed; payload_offset += len_to_do; remaining -= len_to_do; } return changed; }
/** * This function consumes the payload block of the bundle. It is a virtual from BlockProcessor. * * @param bundle Bundle to set data after consuming * @param blcok Payload block to set data after consuming * @param buf Populated buffer to read data from for consuming * @param len Number of bytes to consume * @return Return number of bytes successfully consumed */ public int consume(Bundle bundle, BlockInfo block, IByteBuffer buf, int len) { BlockInfoVec recv_blocks = bundle.recv_blocks(); int consumed = 0; int[] flags = new int[1]; if (block.data_offset() == 0) { int cc = super.consume_preamble(recv_blocks, block, buf, len, flags); if (cc == -1) { return -1; } buf.position(buf.position() + cc); len -= cc; consumed += cc; Log.d(TAG, "in len: " + len + " : cc" + cc + " " + bundle.payload().length()); assert (bundle.payload().length() == 0) : TAG + "consume() bundle payload length is not 0"; } Log.d(TAG, "out len: " + len + " : cc" + consumed + " " + bundle.payload().length()); if (block.data_offset() == 0) { assert (len == 0) : TAG + ": consume() len!=0"; return consumed; } // Special case for the simulator -- if the payload location is // NODATA, then we're done. if (bundle.payload().location().getCode() == location_t.NODATA.getCode()) { block.set_complete(true); return consumed; } // If we've consumed the length (because the data_offset is // non-zero) and the length is zero, then we're done. if (block.data_offset() != 0 && block.data_length() == 0) { block.set_complete(true); return consumed; } // Also bail if there's nothing left to do if (len == 0) { return consumed; } // Otherwise, the buffer should always hold just the preamble // since we store the rest in the payload file assert (block.contents().capacity() == block.data_offset()) : TAG + ": consume() data_offset not equal to content capacity"; // Now make sure there's still something left to do for the block, // otherwise it should have been marked as complete assert (block.data_length() > bundle.payload().length()); int rcvd = (int) bundle.payload().length(); int remainder = block.data_length() - rcvd; int tocopy; if (len >= remainder) { block.set_complete(true); tocopy = remainder; } else { tocopy = len; } bundle.payload().set_length(rcvd + tocopy); bundle.payload().write_data(buf, rcvd, tocopy); consumed += tocopy; Log.d( TAG, String.format( "consumed %s/%s (%s)", consumed, block.full_length(), block.complete() ? "complete" : "not complete")); return consumed; }