<?php
/**
* A PackageFragmenter class to fragment package data into smaller chunks for
- * delivery. This class does add a serial number to it and in the first data
- * submission chunk it will add a sumerization of all fragements and their
- * serial numbers.
+ * delivery. This class calculates a final hash on the raw input data and
+ * fragments the data into smaller chunks after it has been encoded by a
+ * "outgoing encoding stream".
+ *
+ * All chunks are extended with a hash and a serial number to make it later
+ * easier to verify them and put them back in the right order and to, if
+ * required, request a re-delivery of an invalid chunk (e.g. hash didn't match).
+ * Also an "end-of-package" marker is being added as the last chunk to mark the
+ * end of of the whole package submission.
*
* @author Roland Haeder <webmaster@ship-simu.org>
* @version 0.0.0
* Maximum possible serial number
*/
private $maxSerialNumber = 0;
+
/**
* Seperator between chunk data, serial number and chunk hash
*/
*/
const CHUNK_HASH_SEPERATOR = ';';
+ /**
+ * Seperator between two chunks
+ */
+ const CHUNK_SEPERATOR = '|';
+
/**
* Identifier for hash chunk
*/
const HASH_CHUNK_IDENTIFIER = 'HASH-CHUNK:';
+ /**
+ * Identifier for end-of-package marker
+ */
+ const END_OF_PACKAGE_IDENTIFIER = 'EOP:';
+
/**
* Protected constructor
*
// Get new instance
$fragmenterInstance = new PackageFragmenter();
- // Get an output stream for all out-going packages
- $streamInstance = ObjectFactory::createObjectByConfiguredName('node_raw_package_output_stream');
-
- // And set it in this fragmenter
- $fragmenterInstance->setOutputStreamInstance($streamInstance);
-
// And also a crypto instance (for our encrypted messages)
$cryptoInstance = ObjectFactory::createObjectByConfiguredName('crypto_class');
$fragmenterInstance->setCryptoInstance($cryptoInstance);
return $encodedSerialNumber;
}
+ /**
+ * Appends an end-of-package chunk to the chunk list for given chunk and
+ * final hash.
+ *
+ * @param $chunkHash Last chunk's hash
+ * @param $finalHash Final hash for raw (unencoded) data
+ * @return void
+ */
+ private function appendEndOfPackageChunk ($chunkHash, $finalHash) {
+ // Generate end-of-package marker
+ $rawData =
+ self::END_OF_PACKAGE_IDENTIFIER .
+ $finalHash . self::CHUNK_HASH_SEPERATOR .
+ $chunkHash . self::CHUNK_SEPERATOR;
+
+ // Also get a hash from it
+ $chunkHash = $this->generateHashFromRawData($rawData);
+
+ // Append it to the chunk's data and hash array
+ $this->chunkHashes[$finalHash][] = $chunkHash;
+ $this->chunks[$finalHash][] = $rawData;
+ }
+
/**
* Splits the given encoded data into smaller chunks, the size of the final
* and the seperator is being subtracted from chunk size to fit it into a
* TCP package (512 bytes).
*
- * @param $encodedData Encoded data string
- * @param $finalHash Final hash from the raw data
+ * @param $rawData Raw data string
+ * @param $finalHash Final hash from the raw data
* @return void
*/
- private function splitEncodedDataIntoChunks ($encodedData, $finalHash) {
+ private function splitEncodedDataIntoChunks ($rawData, $finalHash) {
// Make sure final hashes with at least 32 bytes can pass
assert(strlen($finalHash) >= 32);
$dataChunkSize = $this->getDataChunkSizeFromHash($finalHash);
//* NOISY-DEBUG: */ $this->debugOutput('FRAGMENTER: dataChunkSize=' . $dataChunkSize);
+ // Init variables
+ $chunkHash = '';
+
// Now split it up
- for ($idx = 0; $idx < strlen($encodedData); $idx += $dataChunkSize) {
+ for ($idx = 0; $idx < strlen($rawData); $idx += $dataChunkSize) {
// Get the next chunk
- $chunk = substr($encodedData, $idx, $dataChunkSize);
+ $chunk = substr($rawData, $idx, $dataChunkSize);
// Hash it and remember it in seperate array
$chunkHash = $this->getCryptoInstance()->hashString($chunk);
$this->chunkHashes[$finalHash][] = $chunkHash;
// Prepend the hash to the chunk
- $chunk = $chunkHash . self::CHUNK_DATA_HASH_SEPERATOR . $this->getNextHexSerialNumber() . self::CHUNK_DATA_HASH_SEPERATOR . $chunk;
+ $chunk =
+ $chunkHash . self::CHUNK_DATA_HASH_SEPERATOR .
+ $this->getNextHexSerialNumber() . self::CHUNK_DATA_HASH_SEPERATOR .
+ $chunk . self::CHUNK_SEPERATOR
+ ;
// Make sure the chunk is not larger than a TCP package can hold
assert(strlen($chunk) <= NetworkPackage::TCP_PACKAGE_SIZE);
} // END - for
// Debug output
- $this->debugOutput('FRAGMENTER: Encoded data of ' . strlen($encodedData) . ' bytes has been fragmented into ' . count($this->chunks[$finalHash]) . ' chunk(s).');
+ //* NOISY-DEBUG: */ $this->debugOutput('FRAGMENTER: Raw data of ' . strlen($rawData) . ' bytes has been fragmented into ' . count($this->chunks[$finalHash]) . ' chunk(s).');
+
+ // Add end-of-package chunk
+ $this->appendEndOfPackageChunk($chunkHash, $finalHash);
}
/**
* Prepends a chunk (or more) with all hashes from all chunks + final chunk.
*
- * @param $encodedData Encoded data string
- * @param $finalHash Final hash from the raw data
+ * @param $rawData Raw data string
+ * @param $finalHash Final hash from the raw data
* @return void
*/
- private function prependHashChunk ($encodedData, $finalHash) {
+ private function prependHashChunk ($rawData, $finalHash) {
// "Implode" the whole array of hashes into one string
$rawData = self::HASH_CHUNK_IDENTIFIER . implode(self::CHUNK_HASH_SEPERATOR, $this->chunkHashes[$finalHash]);
// Also get a hash from it
$chunkHash = $this->generateHashFromRawData($rawData);
- // Also encode this one
- $encodedData = $this->getOutputStreamInstance()->streamData($rawData);
-
// Calulcate chunk size
$dataChunkSize = $this->getDataChunkSizeFromHash($chunkHash);
// Now array_unshift() it to the two chunk arrays
- for ($idx = 0; $idx < strlen($encodedData); $idx += $dataChunkSize) {
+ for ($idx = 0; $idx < strlen($rawData); $idx += $dataChunkSize) {
// Get the next chunk
- $chunk = substr($encodedData, $idx, $dataChunkSize);
+ $chunk = substr($rawData, $idx, $dataChunkSize);
// Hash it and remember it in seperate array
$chunkHash = $this->getCryptoInstance()->hashString($chunk);
array_unshift($this->chunkHashes[$finalHash], $chunkHash);
// Prepend the hash to the chunk
- $chunk = $chunkHash . self::CHUNK_DATA_HASH_SEPERATOR . $this->getNextHexSerialNumber() . self::CHUNK_DATA_HASH_SEPERATOR . $chunk;
+ $chunk =
+ $chunkHash . self::CHUNK_DATA_HASH_SEPERATOR .
+ $this->getNextHexSerialNumber() . self::CHUNK_DATA_HASH_SEPERATOR .
+ $chunk . self::CHUNK_SEPERATOR
+ ;
// Make sure the chunk is not larger than a TCP package can hold
assert(strlen($chunk) <= NetworkPackage::TCP_PACKAGE_SIZE);
// Init pointer
$this->initPointer($finalHash);
- // Encode the package for delivery
- $encodedData = $this->getOutputStreamInstance()->streamData($rawData);
-
// Split the encoded data into smaller chunks
- $this->splitEncodedDataIntoChunks($encodedData, $finalHash);
+ $this->splitEncodedDataIntoChunks($rawData, $finalHash);
// Prepend a chunk with all hashes together
- $this->prependHashChunk($encodedData, $finalHash);
+ $this->prependHashChunk($rawData, $finalHash);
// Mark the package as fragmented
$this->markPackageDataProcessed($packageData);