]> git.mxchange.org Git - hub.git/blobdiff - application/hub/main/package/fragmenter/class_PackageFragmenter.php
Updated 'core' + renamed 'main' -> 'classes'.
[hub.git] / application / hub / main / package / fragmenter / class_PackageFragmenter.php
diff --git a/application/hub/main/package/fragmenter/class_PackageFragmenter.php b/application/hub/main/package/fragmenter/class_PackageFragmenter.php
deleted file mode 100644 (file)
index a816686..0000000
+++ /dev/null
@@ -1,542 +0,0 @@
-<?php
-/**
- * A PackageFragmenter class to fragment package data into smaller chunks for
- * 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@shipsimu.org>
- * @version            0.0.0
- * @copyright  Copyright (c) 2007, 2008 Roland Haeder, 2009 - 2015 Hub Developer Team
- * @license            GNU GPL 3.0 or any newer version
- * @link               http://www.shipsimu.org
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-class PackageFragmenter extends BaseHubSystem implements Fragmentable, Registerable {
-       /**
-        * Cached chunk size in bits
-        */
-       private $chunkSize = 0;
-
-       /**
-        * Array for chunks
-        */
-       private $chunks = array();
-
-       /**
-        * Array for chunk hashes
-        */
-       private $chunkHashes = array();
-
-       /**
-        * Array for chunk pointers
-        */
-       private $chunkPointers = array();
-
-       /**
-        * Array for processed packages
-        */
-       private $processedPackages = array();
-
-       /**
-        * Serial numbers (array key is final hash)
-        */
-       private $serialNumber = array();
-
-       /**
-        * Maximum possible serial number, "cache" for speeding up things
-        */
-       private $maxSerialNumber  = 0;
-
-       /**
-        * Length of largest possible serial number
-        */
-       const MAX_SERIAL_LENGTH = 8;
-
-       /**
-        * Separator between chunk data, serial number and chunk hash
-        */
-       const CHUNK_DATA_HASH_SEPARATOR = '@';
-
-       /**
-        * SEPARATOR for all chunk hashes
-        */
-       const CHUNK_HASH_SEPARATOR = ';';
-
-       /**
-        * SEPARATOR between two chunks
-        */
-       const CHUNK_SEPARATOR = '|';
-
-       /**
-        * Identifier for hash chunk
-        */
-       const HASH_CHUNK_IDENTIFIER = 'HASH-CHUNK:';
-
-       /**
-        * Identifier for end-of-package marker
-        */
-       const END_OF_PACKAGE_IDENTIFIER = 'EOP:';
-
-       /**
-        * Protected constructor
-        *
-        * @return      void
-        */
-       protected function __construct () {
-               // Call parent constructor
-               parent::__construct(__CLASS__);
-
-               // Init this fragmenter
-               $this->initFragmenter();
-       }
-
-       /**
-        * Creates an instance of this class
-        *
-        * @return      $fragmenterInstance             An instance of a Fragmentable class
-        */
-       public static final function createPackageFragmenter () {
-               // Get new instance
-               $fragmenterInstance = new PackageFragmenter();
-
-               // Get a crypto instance and set it here
-               $cryptoInstance = ObjectFactory::createObjectByConfiguredName('crypto_class');
-               $fragmenterInstance->setCryptoInstance($cryptoInstance);
-
-               // Return the prepared instance
-               return $fragmenterInstance;
-       }
-
-       /**
-        * Initializes this fragmenter
-        *
-        * @return      void
-        */
-       private function initFragmenter () {
-               // Load some configuration entries and "cache" them:
-               // - Chunk size in bits
-               $this->chunkSize = $this->getConfigInstance()->getConfigEntry('package_chunk_size');
-
-               // - Maximum serial number
-               $this->maxSerialNumber = $this->hex2dec(str_repeat('f', self::MAX_SERIAL_LENGTH));
-       }
-
-       /**
-        * Initializes the pointer for given final hash
-        *
-        * @param       $finalHash      Final hash to initialize pointer for
-        * @return      void
-        */
-       private function initPointer ($finalHash) {
-               $this->chunkPointers[$finalHash] = 0;
-       }
-
-       /**
-        * "Getter" for processedPackages array index
-        *
-        * @param       $packageData    Raw package data array
-        * @return      $index                  Array index for processedPackages
-        */
-       private function getProcessedPackagesIndex (array $packageData) {
-               return (
-                       $packageData[NetworkPackage::PACKAGE_DATA_SENDER]    . NetworkPackage::PACKAGE_DATA_SEPARATOR .
-                       $packageData[NetworkPackage::PACKAGE_DATA_RECIPIENT] . NetworkPackage::PACKAGE_DATA_SEPARATOR .
-                       $packageData[NetworkPackage::PACKAGE_DATA_CONTENT]   . NetworkPackage::PACKAGE_DATA_SEPARATOR
-               );
-       }
-
-       /**
-        * Checks whether the given package data is already processed by this fragmenter
-        *
-        * @param       $packageData    Raw package data array
-        * @return      $isProcessed    Whether the package has been fragmented
-        */
-       private function isPackageProcessed (array $packageData) {
-               // Get array index
-               $index = $this->getProcessedPackagesIndex($packageData);
-
-               // Is the array index there?
-               $isProcessed = (
-                       (isset($this->processedPackages[$index]))
-                               &&
-                       ($this->processedPackages[$index] === TRUE)
-               );
-
-               // Return it
-               return $isProcessed;
-       }
-
-       /**
-        * Marks the given package data as processed by this fragmenter
-        *
-        * @param       $packageData    Raw package data array
-        * @return      void
-        */
-       private function markPackageDataProcessed (array $packageData) {
-               // Remember it (until we may remove it)
-               $this->processedPackages[$this->getProcessedPackagesIndex($packageData)] = TRUE;
-       }
-
-       /**
-        * Getter for final hash from given package data
-        *
-        * @param       $packageData    Raw package data array
-        * @return      $finalHash              Final hash for package data
-        */
-       private function getFinalHashFromPackageData (array $packageData) {
-               // Make sure it is there
-               assert(isset($this->processedPackages[$this->getProcessedPackagesIndex($packageData)]));
-
-               // Return it
-               return $this->processedPackages[$this->getProcessedPackagesIndex($packageData)];
-       }
-
-       /**
-        * Get next chunk pointer for given final hash
-        *
-        * @param       $finalHash      Final hash to get current pointer for
-        */
-       private function getCurrentChunkPointer ($finalHash) {
-               // Is the final hash valid?
-               assert(strlen($finalHash) > 0);
-
-               // Is the pointer already initialized?
-               //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('PACKAGE-FRAGMENTER[' . __METHOD__ . ':' . __LINE__ . ']: finalHash[' . gettype($finalHash) . ']=' . $finalHash);
-               assert(isset($this->chunkPointers[$finalHash]));
-
-               // Return it
-               return $this->chunkPointers[$finalHash];
-       }
-
-       /**
-        * Advance the chunk pointer for given final hash
-        *
-        * @param       $finalHash      Final hash to advance the pointer for
-        */
-       private function nextChunkPointer ($finalHash) {
-               // Is the pointer already initialized?
-               assert(isset($this->chunkPointers[$finalHash]));
-
-               // Count one up
-               //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('PACKAGE-FRAGMENTER[' . __METHOD__ . ':' . __LINE__ . ']: finalHash[' . gettype($finalHash) . ']=' . $finalHash);
-               $this->chunkPointers[$finalHash]++;
-       }
-
-       /**
-        * "Getter" for data chunk size of given hash.
-        *
-        * @param       $hash                   Hash to substract it's length
-        * @return      $dataChunkSize  The chunk size
-        */
-       private function getDataChunkSizeFromHash ($hash) {
-               // Calculate real (data) chunk size
-               $dataChunkSize = (
-                       // Real chunk size
-                       ($this->chunkSize / 8) -
-                       // Hash size
-                       strlen($hash) -
-                       // Length of sperators
-                       (strlen(self::CHUNK_DATA_HASH_SEPARATOR) * 2) -
-                       // Length of max serial number
-                       self::MAX_SERIAL_LENGTH
-               );
-
-               // This should be larger than zero bytes
-               assert($dataChunkSize > 0);
-
-               // Return it
-               return $dataChunkSize;
-       }
-
-       /**
-        * Generates a hash from raw data
-        *
-        * @param       $rawData        Raw data bytes to hash
-        * @return      $hash           Hash from the raw data
-        * @todo        Implement a way to send non-announcement packages with extra-salt
-        */
-       private function generateHashFromRawData ($rawData) {
-               /*
-                * Get the crypto instance and hash the data with no extra salt because
-                * the other peer doesn't have *this* peer's salt.
-                */
-               $hash = $this->getCryptoInstance()->hashString($rawData, '', FALSE);
-
-               // Return it
-               return $hash;
-       }
-
-       /**
-        * Appends an end-of-package chunk to the chunk list for given chunk and
-        * final hash. As of 23-March-2012 the format of this chunk will be as any
-        * regular one to keep things easy (KISS) in ChunkHandler class.
-        *
-        * @param       $lastChunk      Last chunk raw data
-        * @param       $finalHash      Final hash for raw (unencoded) data
-        * @return      void
-        */
-       private function appendEndOfPackageChunk ($lastChunk, $finalHash) {
-               // Generate end-of-package marker
-               $chunkData =
-                       self::END_OF_PACKAGE_IDENTIFIER .
-                       $finalHash . self::CHUNK_HASH_SEPARATOR .
-                       $this->generateHashFromRawData($lastChunk);
-
-               // Debug message
-               //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('PACKAGE-FRAGMENTER[' . __METHOD__ . ':' . __LINE__ . ']: Adding EOP chunk with size of ' . strlen($chunkData) . ',finalHash=' . $finalHash . ' ...');
-
-               // Add it as regular chunk
-               $this->addChunkData($finalHash, $chunkData);
-       }
-
-       /**
-        * Splits the given encoded data into smaller chunks, the size of the final
-        * and the SEPARATOR is being subtracted from chunk size to fit it into a
-        * TCP package (512 bytes).
-        *
-        * @param       $rawData        Raw data string
-        * @param       $finalHash      Final hash from the raw data
-        * @return      void
-        */
-       private function splitEncodedDataIntoChunks ($rawData, $finalHash) {
-               // Make sure final hashes with at least 32 bytes can pass
-               assert(strlen($finalHash) >= 32);
-
-               // Calculate real (data) chunk size
-               $dataChunkSize = $this->getDataChunkSizeFromHash($finalHash);
-               //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('PACKAGE-FRAGMENTER[' . __METHOD__ . ':' . __LINE__ . ']: dataChunkSize=' . $dataChunkSize);
-
-               // Init variables
-               $chunkHash = '';
-               $chunkData = '';
-
-               // Now split it up
-               for ($idx = 0; $idx < strlen($rawData); $idx += $dataChunkSize) {
-                       // Get the next chunk
-                       $chunkData = substr($rawData, $idx, $dataChunkSize);
-
-                       // Add the chunk to the propper array and do all the stuff there
-                       $this->addChunkData($finalHash, $chunkData);
-               } // END - for
-
-               // Debug output
-               //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('PACKAGE-FRAGMENTER[' . __METHOD__ . ':' . __LINE__ . ']: Raw data of ' . strlen($rawData) . ' bytes has been fragmented into ' . count($this->chunks[$finalHash]) . ' chunk(s).');
-
-               // Add end-of-package chunk
-               $this->appendEndOfPackageChunk($chunkData, $finalHash);
-       }
-
-       /**
-        * Adds the given chunk (raw data) to the proper array and hashes it for
-        * later verfication.
-        *
-        * @param       $finalHash      Final hash for faster processing
-        * @param       $chunkData      Raw chunk data
-        * @param       $prepend        Whether append (default) or prepend the chunk
-        * @return      void
-        */
-       private function addChunkData ($finalHash, $chunkData, $prepend = FALSE) {
-               // Hash it
-               $rawDataHash = $this->getCryptoInstance()->hashString($chunkData, '', FALSE);
-
-               // Prepend the hash to the chunk
-               $rawData = (
-                       $rawDataHash . self::CHUNK_DATA_HASH_SEPARATOR .
-                       $this->getNextHexSerialNumber($finalHash) . self::CHUNK_DATA_HASH_SEPARATOR .
-                       $chunkData . self::CHUNK_SEPARATOR
-               );
-
-               // Make sure the chunk is not larger than a TCP package can hold
-               //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('PACKAGE-FRAGMENTER[' . __METHOD__ . ':' . __LINE__ . ']: assert: ' . strlen($rawData) . '/' . NetworkPackage::TCP_PACKAGE_SIZE . ' ...');
-               // @TODO This assert broke packages where the hash chunk was very large: assert(strlen($rawData) <= NetworkPackage::TCP_PACKAGE_SIZE);
-
-               // Add it to the array
-               if ($prepend === TRUE) {
-                       // Debug message
-                       //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('PACKAGE-FRAGMENTER[' . __METHOD__ . ':' . __LINE__ . ']: Prepending ' . strlen($rawData) . ' bytes of a chunk, finalHash=' . $finalHash . ' ...');
-                       array_unshift($this->chunkHashes[$finalHash], $rawDataHash);
-                       array_unshift($this->chunks[$finalHash]     , $rawData);
-               } else {
-                       // Debug message
-                       //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('PACKAGE-FRAGMENTER[' . __METHOD__ . ':' . __LINE__ . ']: Appending ' . strlen($rawData) . ' bytes of a chunk, finalHash=' . $finalHash . ' ...');
-
-                       // Is the array there?
-                       if (!isset($this->chunks[$finalHash])) {
-                               // Then initialize it
-                               $this->chunks[$finalHash]      = array();
-                               $this->chunkHashes[$finalHash] = array();
-                       } // END - if
-
-                       // Add both
-                       array_push($this->chunks[$finalHash]     , $rawData);
-                       array_push($this->chunkHashes[$finalHash], $rawDataHash);
-               }
-       }
-
-       /**
-        * Prepends a chunk (or more) with all hashes from all chunks + final chunk.
-        *
-        * @param       $finalHash      Final hash from the raw data
-        * @return      void
-        */
-       private function prependHashChunk ($finalHash) {
-               // "Implode" the whole array of hashes into one string
-               $rawData = self::HASH_CHUNK_IDENTIFIER . implode(self::CHUNK_HASH_SEPARATOR, $this->chunkHashes[$finalHash]);
-
-               // Prepend chunk
-               $this->addChunkData($finalHash, $rawData, TRUE);
-       }
-
-       /**
-        * "Getter" for the next hexadecimal-encoded serial number
-        *
-        * @param       $finalHash                              Final hash
-        * @return      $encodedSerialNumber    The next hexadecimal-encoded serial number
-        */
-       public function getNextHexSerialNumber ($finalHash) {
-               // Assert on maximum serial number length
-               assert(isset($this->serialNumber[$finalHash]));
-               assert($this->serialNumber[$finalHash] <= $this->maxSerialNumber);
-
-               // Encode the current serial number
-               //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('PACKAGE-FRAGMENTER[' . __METHOD__ . ':' . __LINE__ . ']: serialNumber[' . $finalHash . ']=' . $this->serialNumber[$finalHash]);
-               $encodedSerialNumber = $this->dec2Hex($this->serialNumber[$finalHash], self::MAX_SERIAL_LENGTH);
-
-               // Count one up
-               $this->serialNumber[$finalHash]++;
-
-               // Return the encoded serial number
-               //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('PACKAGE-FRAGMENTER[' . __METHOD__ . ':' . __LINE__ . ']: encodedSerialNumber=' . $encodedSerialNumber);
-               return $encodedSerialNumber;
-       }
-
-       /**
-        * This method does "implode" the given package data array into one long
-        * string, splits it into small chunks, adds a serial number and checksum
-        * to all chunks and prepends a chunk with all hashes only in it. It will
-        * return the final hash for faster processing of packages.
-        *
-        * @param       $packageData            Raw package data array
-        * @param       $helperInstance         An instance of a ConnectionHelper class
-        * @return      $finalHash                      Final hash for faster processing
-        * @todo        $helperInstance is unused
-        */
-       public function fragmentPackageArray (array $packageData, ConnectionHelper $helperInstance) {
-               // Is this package already fragmented?
-               if (!$this->isPackageProcessed($packageData)) {
-                       // First we need to "implode" the array
-                       $rawData = implode(NetworkPackage::PACKAGE_DATA_SEPARATOR, $packageData);
-
-                       // Generate the final hash from the raw data (not encoded!)
-                       $finalHash = $this->generateHashFromRawData($rawData);
-
-                       // Remember it
-                       $this->processedPackages[$this->getProcessedPackagesIndex($packageData)] = $finalHash;
-
-                       // Init pointer and reset serial number
-                       $this->initPointer($finalHash);
-                       $this->resetSerialNumber($finalHash);
-
-                       // Split the encoded data into smaller chunks
-                       $this->splitEncodedDataIntoChunks($rawData, $finalHash);
-
-                       // Prepend a chunk with all hashes together
-                       $this->prependHashChunk($finalHash);
-
-                       // Mark the package as fragmented
-                       $this->markPackageDataProcessed($packageData);
-               } else {
-                       // Get the final hash from the package data
-                       $finalHash = $this->getFinalHashFromPackageData($packageData);
-               }
-
-               // Return final hash
-               //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('PACKAGE-FRAGMENTER[' . __METHOD__ . ':' . __LINE__ . ']: finalHash[' . gettype($finalHash) . ']=' . $finalHash);
-               return $finalHash;
-       }
-
-       /**
-        * This method gets the next chunk from the internal FIFO which should be
-        * sent to the given recipient. It will return an associative array where
-        * the key is the chunk hash and value the raw chunk data.
-        *
-        * @param       $finalHash              Final hash for faster lookup
-        * @return      $rawDataChunk   Raw package data chunk
-        * @throws      AssertionException      If $finalHash was not 'TRUE'
-        */
-       public function getNextRawDataChunk ($finalHash) {
-               // Debug message
-               //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('PACKAGE-FRAGMENTER[' . __METHOD__ . ':' . __LINE__ . ']: finalHash[' . gettype($finalHash) . ']=' . $finalHash);
-
-               try {
-                       // Get current chunk index
-                       $current = $this->getCurrentChunkPointer($finalHash);
-               } catch (AssertionException $e) {
-                       // This may happen when the final hash is TRUE
-                       if ($finalHash === TRUE) {
-                               // Set current to null
-                               $current = NULL;
-                       } else {
-                               // Throw the exception
-                               throw $e;
-                       }
-               }
-
-               // If there is no entry left, return an empty array
-               if ((!isset($this->chunkHashes[$finalHash][$current])) || (!isset($this->chunks[$finalHash][$current]))) {
-                       // No more entries found
-                       //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(__METHOD__. ': finalHash=' . $finalHash . ',current=' . $current . ' - No more entries found!');
-                       return array();
-               } // END - if
-
-               // Debug message
-               //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(__METHOD__. ': finalHash=' . $finalHash . ',current=' . $current . ',chunkHashes()=' . count($this->chunkHashes[$finalHash]) .' - Entry choosen ...');
-
-               // Generate the array
-               $rawDataChunk = array(
-                       $this->chunkHashes[$finalHash][$current] => $this->chunks[$finalHash][$current]
-               );
-
-               // Count one index up
-               $this->nextChunkPointer($finalHash);
-
-               // Return the chunk array
-               return $rawDataChunk;
-       }
-
-       /**
-        * Resets the serial number to zero for given final hash
-        *
-        * @param       $finalHash      Final hash to reset counter for
-        * @return      void
-        */
-       public function resetSerialNumber ($finalHash) {
-               // Final hash must be set
-               assert((is_string($finalHash)) && (!empty($finalHash)));
-
-               // Reset/set serial number
-               $this->serialNumber[$finalHash] = 0;
-       }
-}
-
-// [EOF]
-?>