From a350963ce5cca9cce90c958a34287cec1743ac55 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Roland=20H=C3=A4der?= Date: Fri, 27 Apr 2012 15:42:00 +0000 Subject: [PATCH] 'hub' project continued: - New package "decoder" class added which has also a new interface Decodeable - Handling of incoming packages almost finished - Loop fixed the second $this->shutdownSocket() call is required - Many objects have extended BaseFrameworkSystem but should be BaseHubSystem - TODOs.txt updated --- .gitattributes | 8 + application/hub/config.php | 21 ++ ...class_UnexpectedPackageStatusException.php | 5 +- application/hub/interfaces/decoder/.htaccess | 1 + .../interfaces/decoder/class_Decodeable.php | 55 ++++ .../discovery/class_DiscoverableRecipient.php | 8 + .../handler/chunks/class_HandleableChunks.php | 17 ++ .../interfaces/package/class_Receivable.php | 9 + application/hub/main/class_BaseHubSystem.php | 59 +++- ...lass_NetworkPackageCompressorDecorator.php | 2 +- application/hub/main/decoder/.htaccess | 1 + application/hub/main/decoder/class_ | 50 ++++ .../hub/main/decoder/class_BaseDecoder.php | 38 +++ .../hub/main/decoder/package/.htaccess | 1 + .../decoder/package/class_PackageDecoder.php | 138 ++++++++++ .../class_PackageRecipientDiscovery.php | 52 +++- .../socket/class_PackageSocketDiscovery.php | 4 +- ...class_NodeTaskHandlerInitializerFilter.php | 6 + .../handler/chunks/class_ChunkHandler.php | 255 +++++++++++++++++- .../connection/class_BaseConnectionHelper.php | 3 + application/hub/main/lists/class_BaseList.php | 2 +- .../hub/main/package/class_NetworkPackage.php | 84 +++++- .../fragmenter/class_PackageFragmenter.php | 58 ++-- .../class_ConnectionStatisticsHelper.php | 3 +- .../chunks/class_HubChunkAssemblerTask.php | 6 + .../hub/main/tasks/hub/decoder/.htaccess | 1 + .../decoder/class_HubPackageDecoderTask.php | 90 +++++++ application/hub/main/tools/class_HubTools.php | 2 +- docs/TODOs.txt | 27 +- 29 files changed, 938 insertions(+), 68 deletions(-) create mode 100644 application/hub/interfaces/decoder/.htaccess create mode 100644 application/hub/interfaces/decoder/class_Decodeable.php create mode 100644 application/hub/main/decoder/.htaccess create mode 100644 application/hub/main/decoder/class_ create mode 100644 application/hub/main/decoder/class_BaseDecoder.php create mode 100644 application/hub/main/decoder/package/.htaccess create mode 100644 application/hub/main/decoder/package/class_PackageDecoder.php create mode 100644 application/hub/main/tasks/hub/decoder/.htaccess create mode 100644 application/hub/main/tasks/hub/decoder/class_HubPackageDecoderTask.php diff --git a/.gitattributes b/.gitattributes index c0c459a69..3f6d8cc60 100644 --- a/.gitattributes +++ b/.gitattributes @@ -40,6 +40,8 @@ application/hub/interfaces/consumer/.htaccess svneol=native#text/plain application/hub/interfaces/consumer/class_Consumer.php svneol=native#text/plain application/hub/interfaces/cruncher/.htaccess svneol=native#text/plain application/hub/interfaces/cruncher/class_CruncherHelper.php svneol=native#text/plain +application/hub/interfaces/decoder/.htaccess -text svneol=unset#text/plain +application/hub/interfaces/decoder/class_Decodeable.php svneol=native#text/plain application/hub/interfaces/discovery/.htaccess -text svneol=unset#text/plain application/hub/interfaces/discovery/class_DiscoverableRecipient.php svneol=native#text/plain application/hub/interfaces/discovery/class_DiscoverableSocket.php svneol=native#text/plain @@ -182,6 +184,10 @@ application/hub/main/database/wrapper/node/class_NodeInformationDatabaseWrapper. application/hub/main/database/wrapper/node/class_NodeListDatabaseWrapper.php svneol=native#text/plain application/hub/main/database/wrapper/states/.htaccess svneol=native#text/plain application/hub/main/database/wrapper/states/class_PeerStateLookupDatabaseWrapper.php svneol=native#text/plain +application/hub/main/decoder/.htaccess -text svneol=unset#text/plain +application/hub/main/decoder/class_ svneol=native#text/plain +application/hub/main/decoder/package/.htaccess -text svneol=unset#text/plain +application/hub/main/decoder/package/class_PackageDecoder.php svneol=native#text/plain application/hub/main/decorators/.htaccess -text svneol=unset#text/plain application/hub/main/discovery/.htaccess -text svneol=unset#text/plain application/hub/main/discovery/class_BaseHubDiscovery.php svneol=native#text/plain @@ -497,6 +503,8 @@ application/hub/main/tasks/hub/chunks/.htaccess -text svneol=unset#text/plain application/hub/main/tasks/hub/chunks/class_HubChunkAssemblerTask.php svneol=native#text/plain application/hub/main/tasks/hub/class_Hub svneol=native#text/plain application/hub/main/tasks/hub/class_HubSelfConnectTask.php svneol=native#text/plain +application/hub/main/tasks/hub/decoder/.htaccess -text svneol=unset#text/plain +application/hub/main/tasks/hub/decoder/class_HubPackageDecoderTask.php svneol=native#text/plain application/hub/main/tasks/hub/ping/.htaccess -text svneol=unset#text/plain application/hub/main/tasks/hub/ping/class_HubPingTask.php svneol=native#text/plain application/hub/main/tasks/hub/update/.htaccess -text svneol=unset#text/plain diff --git a/application/hub/config.php b/application/hub/config.php index fc996d7e3..d1394fb6c 100644 --- a/application/hub/config.php +++ b/application/hub/config.php @@ -303,6 +303,12 @@ $cfg->setConfigEntry('stacker_decoded_data_max_size', 100); // CFG: STACKER-FINAL-CHUNKS-MAX-SIZE $cfg->setConfigEntry('stacker_final_chunks_max_size', 100); +// CFG: STACKER-CHUNK-RAW-DATA-MAX-SIZE +$cfg->setConfigEntry('stacker_chunk_raw_data_max_size', 100); + +// CFG: STACKER-DECODED-PACKAGE-MAX-SIZE +$cfg->setConfigEntry('stacker_decoded_package_max_size', 100); + // CFG: NEWS-MAIN-LIMIT $cfg->setConfigEntry('news_main_limit', 5); @@ -399,6 +405,9 @@ $cfg->setConfigEntry('hub_socket_listener_task_class', 'HubSocketListenerTask'); // CFG: HUB-CHUNK-ASSEMBLER-TASK-CLASS $cfg->setConfigEntry('hub_chunk_assembler_task_class', 'HubChunkAssemblerTask'); +// CFG: HUB-PACKAGE-DECODER-TASK-CLASS +$cfg->setConfigEntry('hub_package_decoder_task_class', 'HubPackageDecoderTask'); + // CFG: TASK-NETWORK-PACKAGE-WRITER-STARTUP-DELAY $cfg->setConfigEntry('task_network_package_writer_startup_delay', 2500); @@ -429,12 +438,21 @@ $cfg->setConfigEntry('task_socket_listener_max_runs', 0); // CFG: TASK-CHUNK-ASSEMBLER-STATUP-DELAY $cfg->setConfigEntry('task_chunk_assembler_startup_delay', 1500); +// CFG: TASK-PACKAGE-DECODER-STATUP-DELAY +$cfg->setConfigEntry('task_package_decoder_startup_delay', 1300); + // CFG: TASK-CHUNK-ASSEMBLER-INTERVAL-DELAY $cfg->setConfigEntry('task_chunk_assembler_interval_delay', 10); +// CFG: TASK-PACKAGE-DECODER-INTERVAL-DELAY +$cfg->setConfigEntry('task_package_decoder_interval_delay', 10); + // CFG: TASK-CHUNK-ASSEMBLER-MAX-RUNS $cfg->setConfigEntry('task_chunk_assembler_max_runs', 0); +// CFG: TASK-PACKAGE-DECODER-MAX-RUNS +$cfg->setConfigEntry('task_package_decoder_max_runs', 0); + // CFG: TASK-LIST-CLASS $cfg->setConfigEntry('task_list_class', 'TaskList'); @@ -555,6 +573,9 @@ $cfg->setConfigEntry('socket_timeout_microseconds', 0); // CFG: CHUNK-HANDLER-CLASS $cfg->setConfigEntry('chunk_handler_class', 'ChunkHandler'); +// CFG: PACKAGE-DECODER-CLASS +$cfg->setConfigEntry('package_decoder_class', 'PackageDecoder'); + /////////////////////////////////////////////////////////////////////////////// // Peer states /////////////////////////////////////////////////////////////////////////////// diff --git a/application/hub/exceptions/package/class_UnexpectedPackageStatusException.php b/application/hub/exceptions/package/class_UnexpectedPackageStatusException.php index a2bd25b08..3b6383377 100644 --- a/application/hub/exceptions/package/class_UnexpectedPackageStatusException.php +++ b/application/hub/exceptions/package/class_UnexpectedPackageStatusException.php @@ -31,13 +31,14 @@ class UnexpectedPackageStatusException extends FrameworkException { */ public function __construct (array $messageArray, $code) { // Construct the message - $message = sprintf("[%s:%d] Unexpected package status %s!=%s detected, recipient=%s, sender=%s.", + $message = sprintf("[%s:%d] Unexpected package status %s!=%s detected, recipient=%s, sender=%s, signature=%s.", $messageArray[0]->__toString(), $this->getLine(), $messageArray[1][NetworkPackage::PACKAGE_DATA_STATUS], $messageArray[2], $messageArray[1][NetworkPackage::PACKAGE_DATA_RECIPIENT], - $messageArray[1][NetworkPackage::PACKAGE_DATA_SENDER] + $messageArray[1][NetworkPackage::PACKAGE_DATA_SENDER], + $messageArray[1][NetworkPackage::PACKAGE_DATA_SIGNATURE] ); // Call parent exception constructor diff --git a/application/hub/interfaces/decoder/.htaccess b/application/hub/interfaces/decoder/.htaccess new file mode 100644 index 000000000..3a4288278 --- /dev/null +++ b/application/hub/interfaces/decoder/.htaccess @@ -0,0 +1 @@ +Deny from all diff --git a/application/hub/interfaces/decoder/class_Decodeable.php b/application/hub/interfaces/decoder/class_Decodeable.php new file mode 100644 index 000000000..72bce82cf --- /dev/null +++ b/application/hub/interfaces/decoder/class_Decodeable.php @@ -0,0 +1,55 @@ + + * @version 0.0.0 + * @copyright Copyright (c) 2007, 2008 Roland Haeder, 2009 - 2011 Hub Developer Team + * @license GNU GPL 3.0 or any newer version + * @link http://www.ship-simu.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 . + */ +interface Decodeable extends FrameworkInterface { + /** + * Checks whether the assoziated stacker for raw package data has some entries left + * + * @return $unhandledDataLeft Whether some unhandled raw package data is left + */ + function ifUnhandledRawPackageDataLeft (); + + /** + * Handles raw package data by decoding it + * + * @return void + */ + function handleRawPackageData (); + + /** + * Checks whether decoded packages have arrived (for this peer) + * + * @return $ifDecodedPackagesLeft Whether decoded packages have arrived + */ + function ifDeocedPackagesLeft (); + + /** + * Handles received decoded packages internally (recipient is this node) + * + * @return void + */ + function handleDecodedPackage (); +} + +// [EOF] +?> diff --git a/application/hub/interfaces/discovery/class_DiscoverableRecipient.php b/application/hub/interfaces/discovery/class_DiscoverableRecipient.php index 20189ad6f..2730741d0 100644 --- a/application/hub/interfaces/discovery/class_DiscoverableRecipient.php +++ b/application/hub/interfaces/discovery/class_DiscoverableRecipient.php @@ -30,6 +30,14 @@ interface DiscoverableRecipient extends FrameworkInterface { */ function discoverRecipients (array $packageData); + /** + * Tries to discover all recipients by given decoded package data. + * + * @param $decodedData Decoded raw package data array + * @return void + */ + function discoverDecodedRecipients (array $decodedData); + /** * "Getter" for recipient iterator * diff --git a/application/hub/interfaces/handler/chunks/class_HandleableChunks.php b/application/hub/interfaces/handler/chunks/class_HandleableChunks.php index 2fcc8c53a..4c3d66ee8 100644 --- a/application/hub/interfaces/handler/chunks/class_HandleableChunks.php +++ b/application/hub/interfaces/handler/chunks/class_HandleableChunks.php @@ -70,6 +70,23 @@ interface HandleableChunks extends Handleable { * @return void */ function assembleChunksFromFinalArray (); + + /** + * Checks whether the raw package data has been assembled back together. + * This can be safely assumed when rawPackageData is not empty and the + * collection of all chunks is false (because initHandler() will reset it). + * + * @return $isRawPackageDataAvailable Whether raw package data is available + */ + function ifRawPackageDataIsAvailable (); + + /** + * Handles the finally assembled raw package data by feeding it into another + * stacker for further decoding/processing. + * + * @return void + */ + function handledAssembledRawPackageData (); } // [EOF] diff --git a/application/hub/interfaces/package/class_Receivable.php b/application/hub/interfaces/package/class_Receivable.php index b6034b048..869a710bf 100644 --- a/application/hub/interfaces/package/class_Receivable.php +++ b/application/hub/interfaces/package/class_Receivable.php @@ -68,6 +68,15 @@ interface Receivable extends FrameworkInterface { * @return void */ function addDecodedDataToIncomingStack (Networkable $handlerInstance); + + /** + * "Decode" the package content. This method does also verify the attached hash + * against the real raw package data (that what the sender has sent). + * + * @param $rawPackageContent The raw package content to be "decoded" + * @return $decodedData The real package data that the sender has sent + */ + function decodeRawContent ($rawPackageContent); } // [EOF] diff --git a/application/hub/main/class_BaseHubSystem.php b/application/hub/main/class_BaseHubSystem.php index 62c578028..18a448d7a 100644 --- a/application/hub/main/class_BaseHubSystem.php +++ b/application/hub/main/class_BaseHubSystem.php @@ -66,6 +66,16 @@ class BaseHubSystem extends BaseFrameworkSystem { */ private $listenerPoolInstance = NULL; + /** + * Fragmenter instance + */ + private $fragmenterInstance = NULL; + + /** + * Decoder instance + */ + private $decoderInstance = NULL; + /** * Protected constructor * @@ -210,6 +220,44 @@ class BaseHubSystem extends BaseFrameworkSystem { return $this->listenerPoolInstance; } + /** + * Setter for fragmenter instance + * + * @param $fragmenterInstance A Fragmentable instance + * @return void + */ + protected final function setFragmenterInstance (Fragmentable $fragmenterInstance) { + $this->fragmenterInstance = $fragmenterInstance; + } + + /** + * Getter for fragmenter instance + * + * @return $fragmenterInstance A Fragmentable instance + */ + protected final function getFragmenterInstance () { + return $this->fragmenterInstance; + } + + /** + * Setter for decoder instance + * + * @param $decoderInstance A Decodeable instance + * @return void + */ + protected final function setDecoderInstance (Decodeable $decoderInstance) { + $this->decoderInstance = $decoderInstance; + } + + /** + * Getter for decoder instance + * + * @return $decoderInstance A Decodeable instance + */ + protected final function getDecoderInstance () { + return $this->decoderInstance; + } + /** * Constructs a callable method name from given socket error code. If the * method is not found, a generic one is used. @@ -219,10 +267,7 @@ class BaseHubSystem extends BaseFrameworkSystem { * @throws UnsupportedSocketErrorHandlerException If the error handler is not implemented */ protected function getSocketErrorHandlerFromCode ($errorCode) { - // Set NULL, so everyone is forced to implement socket error handlers - $handlerName = NULL; - - // Temporary create a possible name from translated error code + // Create a name from translated error code $handlerName = 'socketError' . $this->convertToClassName($this->translateSocketErrorCodeToName($errorCode)) . 'Handler'; // Is the call-back method there? @@ -382,6 +427,9 @@ class BaseHubSystem extends BaseFrameworkSystem { // Get a visitor instance $visitorInstance = ObjectFactory::createObjectByConfiguredName('shutdown_socket_visitor_class'); + // Debug output + $this->debugOutput('HUB-SYSTEM:' . $this->__toString() . ': visitorInstance=' . $visitorInstance->__toString()); + // Call the visitor $this->accept($visitorInstance); } @@ -403,6 +451,9 @@ class BaseHubSystem extends BaseFrameworkSystem { // Get a visitor instance $visitorInstance = ObjectFactory::createObjectByConfiguredName('half_shutdown_socket_visitor_class'); + // Debug output + $this->debugOutput('HUB-SYSTEM:' . $this->__toString() . ': visitorInstance=' . $visitorInstance->__toString()); + // Call the visitor $this->accept($visitorInstance); } diff --git a/application/hub/main/compressor/decorator/class_NetworkPackageCompressorDecorator.php b/application/hub/main/compressor/decorator/class_NetworkPackageCompressorDecorator.php index 04c2a8ab4..60e96ed74 100644 --- a/application/hub/main/compressor/decorator/class_NetworkPackageCompressorDecorator.php +++ b/application/hub/main/compressor/decorator/class_NetworkPackageCompressorDecorator.php @@ -22,7 +22,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -class NetworkPackageCompressorDecorator extends BaseFrameworkSystem implements Compressor { +class NetworkPackageCompressorDecorator extends BaseHubSystem implements Compressor { /** * Protected constructor * diff --git a/application/hub/main/decoder/.htaccess b/application/hub/main/decoder/.htaccess new file mode 100644 index 000000000..3a4288278 --- /dev/null +++ b/application/hub/main/decoder/.htaccess @@ -0,0 +1 @@ +Deny from all diff --git a/application/hub/main/decoder/class_ b/application/hub/main/decoder/class_ new file mode 100644 index 000000000..a597db987 --- /dev/null +++ b/application/hub/main/decoder/class_ @@ -0,0 +1,50 @@ + + * @version 0.0.0 + * @copyright Copyright (c) 2007, 2008 Roland Haeder, 2009 - 2011 Hub Developer Team + * @license GNU GPL 3.0 or any newer version + * @link http://www.ship-simu.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 . + */ +class ???Decoder extends BaseDecoder implements Decodeable { + /** + * Protected constructor + * + * @return void + */ + protected function __construct () { + // Call parent constructor + parent::__construct(__CLASS__); + } + + /** + * Creates an instance of this class + * + * @return $decoderInstance An instance of a Decodeable class + */ + public final static function create???Decoder () { + // Get new instance + $decoderInstance = new ???Decoder(); + + // Return the prepared instance + return $decoderInstance; + } +} + +// [EOF] +?> diff --git a/application/hub/main/decoder/class_BaseDecoder.php b/application/hub/main/decoder/class_BaseDecoder.php new file mode 100644 index 000000000..35fd1294c --- /dev/null +++ b/application/hub/main/decoder/class_BaseDecoder.php @@ -0,0 +1,38 @@ + + * @version 0.0.0 + * @copyright Copyright (c) 2007, 2008 Roland Haeder, 2009 - 2011 Hub Developer Team + * @license GNU GPL 3.0 or any newer version + * @link http://www.ship-simu.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 . + */ +class BaseDecoder extends BaseHubSystem { + /** + * Protected constructor + * + * @param $className Name of the class + * @return void + */ + protected function __construct ($className) { + // Call parent constructor + parent::__construct($className); + } +} + +// [EOF] +?> diff --git a/application/hub/main/decoder/package/.htaccess b/application/hub/main/decoder/package/.htaccess new file mode 100644 index 000000000..3a4288278 --- /dev/null +++ b/application/hub/main/decoder/package/.htaccess @@ -0,0 +1 @@ +Deny from all diff --git a/application/hub/main/decoder/package/class_PackageDecoder.php b/application/hub/main/decoder/package/class_PackageDecoder.php new file mode 100644 index 000000000..4d663454b --- /dev/null +++ b/application/hub/main/decoder/package/class_PackageDecoder.php @@ -0,0 +1,138 @@ + + * @version 0.0.0 + * @copyright Copyright (c) 2007, 2008 Roland Haeder, 2009 - 2011 Hub Developer Team + * @license GNU GPL 3.0 or any newer version + * @link http://www.ship-simu.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 . + */ +class PackageDecoder extends BaseDecoder implements Decodeable { + /** + * Name for stacker for received packages + */ + const STACKER_NAME_DECODED_PACKAGE = 'decoded_package'; + + /** + * Protected constructor + * + * @return void + */ + protected function __construct () { + // Call parent constructor + parent::__construct(__CLASS__); + } + + /** + * Creates an instance of this class + * + * @param $stackerInstance An instance of a Stackable class + * @return $decoderInstance An instance of a Decodeable class + */ + public final static function createPackageDecoder (Stackable $stackerInstance) { + // Get new instance + $decoderInstance = new PackageDecoder(); + + // Init stacker for received packages + $stackerInstance->initStacker(self::STACKER_NAME_DECODED_PACKAGE); + + // Set the stacker instance here + $decoderInstance->setStackerInstance($stackerInstance); + + // Get a singleton network package instance + $packageInstance = NetworkPackageFactory::createNetworkPackageInstance(); + + // And set it in this decoder + $decoderInstance->setPackageInstance($packageInstance); + + // Return the prepared instance + return $decoderInstance; + } + + /** + * Checks whether the assoziated stacker for raw package data has some entries left + * + * @return $unhandledDataLeft Whether some unhandled raw package data is left + */ + public function ifUnhandledRawPackageDataLeft () { + // Check it + $unhandledDataLeft = (!$this->getStackerInstance()->isStackEmpty(ChunkHandler::STACKER_NAME_ASSEMBLED_RAW_DATA)); + + // Return it + return $unhandledDataLeft; + } + + /** + * Handles raw package data by decoding it + * + * @return void + */ + public function handleRawPackageData () { + // Assert on it to make sure the next popNamed() call won't throw an exception + assert($this->ifUnhandledRawPackageDataLeft()); + + // "Pop" the next raw package content + $rawPackageContent = $this->getStackerInstance()->popNamed(ChunkHandler::STACKER_NAME_ASSEMBLED_RAW_DATA); + + // "Decode" the raw package content by using the NetworkPackage instance + $decodedData = $this->getPackageInstance()->decodeRawContent($rawPackageContent); + + // Next get a recipient-discovery instance + $discoveryInstance = PackageDiscoveryFactory::createPackageDiscoveryInstance(); + + // ... then disover all recipient (might be only one), this package may shall be forwarded + $discoveryInstance->discoverDecodedRecipients($decodedData); + + // Check for 'recipient' field (the 'sender' field and others are ignored here) + if ($discoveryInstance->isRecipientListEmpty()) { + // The recipient is this node so next stack it on 'decoded_package' + $this->getStackerInstance()->pushNamed(self::STACKER_NAME_DECODED_PACKAGE, $decodedData); + } else { + // Forward the package to the next node + $this->getPackageInstance()->forwardDecodedPackage($decodedData); + } + } + + /** + * Checks whether decoded packages have arrived (for this peer) + * + * @return $ifDecodedPackagesLeft Whether decoded packages have arrived + */ + public function ifDeocedPackagesLeft () { + // Check it ... + $ifDecodedPackagesLeft = (!$this->getStackerInstance()->isStackEmpty(self::STACKER_NAME_DECODED_PACKAGE)); + + // ... return it + return $ifDecodedPackagesLeft; + } + + /** + * Handles received decoded packages internally (recipient is this node) + * + * @return void + */ + public function handleDecodedPackage () { + // Get the next entry (assoziative array) + $decodedData = $this->getStackerInstance()->popNamed(self::STACKER_NAME_DECODED_PACKAGE); + + // Handle it + die('decodedData='.print_r($decodedData,true)); + } +} + +// [EOF] +?> diff --git a/application/hub/main/discovery/package/class_PackageRecipientDiscovery.php b/application/hub/main/discovery/package/class_PackageRecipientDiscovery.php index d1de14232..6c70284b6 100644 --- a/application/hub/main/discovery/package/class_PackageRecipientDiscovery.php +++ b/application/hub/main/discovery/package/class_PackageRecipientDiscovery.php @@ -41,13 +41,13 @@ class PackageRecipientDiscovery extends BaseHubDiscovery implements Discoverable // Get an instance of this class $discoveryInstance = new PackageRecipientDiscovery(); - // Output debug message - $discoveryInstance->debugOutput('RECIPIENT-DISCOVERY: Initialized.'); - // Get recipients list instance and set it $listInstance = RecipientListFactory::createRecipientListInstance(); $discoveryInstance->setListInstance($listInstance); + // Output debug message + $discoveryInstance->debugOutput('RECIPIENT-DISCOVERY: Initialized.'); + // Return the prepared instance return $discoveryInstance; } @@ -92,6 +92,39 @@ class PackageRecipientDiscovery extends BaseHubDiscovery implements Discoverable } // END - switch } + /** + * Tries to discover all recipients by given decoded package data. + * + * @param $decodedData Decoded raw package data array + * @return void + * @todo Add some validation of recipient field, e.g. ip:port is found + */ + public function discoverDecodedRecipients (array $decodedData) { + // First clear all recipients + $this->clearRecipients(); + + // Explode 'recipient', first element is the IP/hostname + $recipient = explode(':', $decodedData[NetworkPackage::PACKAGE_DATA_RECIPIENT]); + + // Is the 'recipient' field same as this peer's IP? + if ($recipient[0] == HubTools::determineOwnExternalIp()) { + /* + * Is same as own external IP, don't do anything here so other + * classes found an empty recipient list for internal (own) handling + * of the original content. + */ + + // Debug output (may flood) + /* NOISY-DEBUG: */ $this->debugOutput('RECIPIENT-DISCOVERY: Recipient ' . $recipient[0] . ' matches own ip (' . HubTools::determineOwnExternalIp() . ')'); + } else { + // Debug output (may flood) + /* NOISY-DEBUG: */ $this->debugOutput('RECIPIENT-DISCOVERY: Recipient ' . $recipient[0] . ' is different than own ip (' . HubTools::determineOwnExternalIp() . '), need to forward (not yet implemented)!'); + + // This package is to be delivered to someone else, so add it + $this->getListInstance()->addEntry('ip_port', $decodedData[NetworkPackage::PACKAGE_DATA_RECIPIENT]); + } + } + /** * "Getter" for recipient iterator * @@ -105,6 +138,19 @@ class PackageRecipientDiscovery extends BaseHubDiscovery implements Discoverable return $iteratorInstance; } + /** + * Checks whether the recipient list is empty + * + * @return $isEmpty Whether the recipient list is empty + */ + public function isRecipientListEmpty () { + // Check it ... + $isEmpty = ($this->getListInstance()->count() == 0); + + // Return it + return $isEmpty; + } + /** * Clears all recipients for e.g. another package to deliver. This method * simply clears the inner list instance. diff --git a/application/hub/main/discovery/socket/class_PackageSocketDiscovery.php b/application/hub/main/discovery/socket/class_PackageSocketDiscovery.php index d48b5a5e9..1816b51c8 100644 --- a/application/hub/main/discovery/socket/class_PackageSocketDiscovery.php +++ b/application/hub/main/discovery/socket/class_PackageSocketDiscovery.php @@ -121,11 +121,9 @@ class PackageSocketDiscovery extends BaseHubDiscovery implements DiscoverableSoc // Get a socket resource from our factory (if succeeded) $socketResource = SocketFactory::createSocketFromPackageData($packageData, $protocolName); - - // This succeeded, so change the state to 'CONNECTED' } catch (SocketConnectionException $e) { // The connection fails of being established, so log it away - $this->debugOutput('SOCKET-DISCOVERY: ' . $e->__toString() . ',message=' . $e->getMessage()); + $this->debugOutput('SOCKET-DISCOVERY: Caught ' . $e->__toString() . ',message=' . $e->getMessage()); } } // END - if diff --git a/application/hub/main/filter/task/node/class_NodeTaskHandlerInitializerFilter.php b/application/hub/main/filter/task/node/class_NodeTaskHandlerInitializerFilter.php index a64280ca4..47c092631 100644 --- a/application/hub/main/filter/task/node/class_NodeTaskHandlerInitializerFilter.php +++ b/application/hub/main/filter/task/node/class_NodeTaskHandlerInitializerFilter.php @@ -85,6 +85,12 @@ class NodeTaskHandlerInitializerFilter extends BaseFilter implements Filterable // Register it as well $handlerInstance->registerTask('chunk_assembler', $taskInstance); + // Generate package decoder task + $taskInstance = ObjectFactory::createObjectByConfiguredName('hub_package_decoder_task_class'); + + // Register it as well + $handlerInstance->registerTask('package_decoder', $taskInstance); + // Query handler instance $handlerInstance->registerTask('query_handler', $nodeInstance->getQueryConnectorInstance()); diff --git a/application/hub/main/handler/chunks/class_ChunkHandler.php b/application/hub/main/handler/chunks/class_ChunkHandler.php index 5de34ac11..04db917df 100644 --- a/application/hub/main/handler/chunks/class_ChunkHandler.php +++ b/application/hub/main/handler/chunks/class_ChunkHandler.php @@ -26,6 +26,7 @@ class ChunkHandler extends BaseHandler implements HandleableChunks, Registerable * Stacker for chunks with final EOP */ const STACKER_NAME_CHUNKS_WITH_FINAL_EOP = 'final_chunks'; + const STACKER_NAME_ASSEMBLED_RAW_DATA = 'chunk_raw_data'; /** * Chunk splits: @@ -40,14 +41,25 @@ class ChunkHandler extends BaseHandler implements HandleableChunks, Registerable /** * The final array for assembling the original package back together */ - private $finalPackageChunks = array( - // Array for package content - 'content' => array(), - // ... and for the hashes - 'hashes' => array(), - // ... marker for that the final array is complete for assembling all chunks - 'is_complete' => false - ); + private $finalPackageChunks = array(); + + /** + * Array of chunk hashes + */ + private $chunkHashes = array(); + + /** + * Raw EOP chunk data in an array: + * + * 0 = Final hash, + * 1 = Hash of last chunk + */ + private $eopChunk = array(); + + /** + * Raw package data + */ + private $rawPackageData = ''; /** * Protected constructor @@ -60,6 +72,9 @@ class ChunkHandler extends BaseHandler implements HandleableChunks, Registerable // Set handler name $this->setHandlerName('chunk'); + + // Initialize handler + $this->initHandler(); } /** @@ -76,6 +91,7 @@ class ChunkHandler extends BaseHandler implements HandleableChunks, Registerable // Init all stacker $stackerInstance->initStacker(self::STACKER_NAME_CHUNKS_WITH_FINAL_EOP); + $stackerInstance->initStacker(self::STACKER_NAME_ASSEMBLED_RAW_DATA); // Set the stacker in this handler $handlerInstance->setStackerInstance($stackerInstance); @@ -86,10 +102,44 @@ class ChunkHandler extends BaseHandler implements HandleableChunks, Registerable // ... and set it in this handler $handlerInstance->setCryptoInstance($cryptoInstance); + // Get a fragmenter instance for later verification of serial numbers (e.g. if all are received) + $fragmenterInstance = FragmenterFactory::createFragmenterInstance('package'); + + // Set it in this handler + $handlerInstance->setFragmenterInstance($fragmenterInstance); + // Return the prepared instance return $handlerInstance; } + /** + * Initializes the handler + * + * @return void + */ + private function initHandler () { + // Init finalPackageChunks + $this->finalPackageChunks = array( + // Array for package content + 'content' => array(), + // ... and for the hashes + 'hashes' => array(), + // ... marker for that the final array is complete for assembling all chunks + 'is_complete' => false, + // ... steps done to assemble all chunks + 'assemble_steps' => 0, + ); + + // ... chunkHashes: + $this->chunkHashes = array(); + + // ... eopChunk: + $this->eopChunk = array( + 0 => 'INVALID', + 1 => 'INVALID', + ); + } + /** * Checks whether the hash generated from package content is the same ("valid") as given * @@ -163,6 +213,133 @@ class ChunkHandler extends BaseHandler implements HandleableChunks, Registerable $this->finalPackageChunks['is_complete'] = true; } + /** + * Sorts the chunks array by using the serial number as a sorting key. In + * most situations a call of ksort() is enough to accomblish this. So this + * method may only call ksort() on the chunks array. + * + * This method sorts 'content' and 'hashes' so both must have used the + * serial numbers as array indexes. + * + * @return void + */ + private function sortChunksArray () { + // Sort 'content' first + ksort($this->finalPackageChunks['content']); + + // ... then 'hashes' + ksort($this->finalPackageChunks['hashes']); + } + + /** + * Prepares the package assemble by removing last chunks (last shall be + * hash chunk, pre-last shall be EOP chunk) and verify that all serial + * numbers are valid (same as PackageFragmenter class would generate). + * + * @return void + */ + private function preparePackageAssmble () { + // Make sure both arrays have same count (this however should always be true) + assert(count($this->finalPackageChunks['hashes']) == count($this->finalPackageChunks['content'])); + + /* + * Remove last element (hash chunk) from 'hashes'. This hash will never + * be needed, so ignore it. + */ + array_pop($this->finalPackageChunks['hashes']); + + // ... and from 'content' as well but save it for later use + $this->chunkHashes = explode(PackageFragmenter::CHUNK_HASH_SEPARATOR, substr(array_pop($this->finalPackageChunks['content']), strlen(PackageFragmenter::HASH_CHUNK_IDENTIFIER))); + + // Remove EOP chunk and keep a copy of it + array_pop($this->finalPackageChunks['hashes']); + $this->eopChunk = explode(PackageFragmenter::CHUNK_HASH_SEPARATOR, substr(array_pop($this->finalPackageChunks['content']), strlen(PackageFragmenter::END_OF_PACKAGE_IDENTIFIER))); + + // Verify all serial numbers + $this->verifyChunkSerialNumbers(); + } + + /** + * Verifies all chunk serial numbers by using a freshly initialized + * fragmenter instance. Do ALWAYS sort the array and array_pop() the hash + * chunk before calling this method to avoid re-requests of many chunks. + * + * @return void + */ + private function verifyChunkSerialNumbers () { + // Reset the serial number generator + $this->getFragmenterInstance()->resetSerialNumber(); + + // "Walk" through all (content) chunks + foreach ($this->finalPackageChunks['content'] as $serialNumber=>$content) { + // Get next serial number + $nextSerial = $this->getFragmenterInstance()->getNextHexSerialNumber(); + + // Debug output + //* NOISY-DEBUG */ $this->debugOutput('CHUNK-HANDLER: serialNumber=' . $serialNumber . ',nextSerial=' . $nextSerial); + + // Is it not the same? Then re-request it + if ($serialNumber != $nextSerial) { + // This is invalid, so remove it + unset($this->finalPackageChunks['content'][$serialNumber]); + unset($this->finalPackageChunks['hashes'][$serialNumber]); + + // And re-request it with valid serial number (and hash chunk) + $this->rerequestChunkBySerialNumber($nextSerial); + } // END - if + } // END - foreach + } + + /** + * Assembles and verifies ("final check") chunks back together to the + * original package (raw data for the start). This method should only be + * called AFTER the EOP and final-chunk chunk have been removed. + * + * @return void + */ + private function assembleAllChunksToPackage () { + // If chunkHashes is not filled, don't continue + assert(count($this->chunkHashes) > 0); + + // Init raw package data string + $this->rawPackageData = ''; + + // That went well, so start assembling all chunks + foreach ($this->finalPackageChunks['content'] as $serialNumber=>$content) { + // Is this chunk valid? This should be the case + assert($this->isChunkHashValid(array( + self::CHUNK_SPLITS_INDEX_HASH => $this->finalPackageChunks['hashes'][$serialNumber], + self::CHUNK_SPLITS_INDEX_RAW_DATA => $content + ))); + + // ... and is also in the hash chunk? + assert(in_array($this->finalPackageChunks['hashes'][$serialNumber], $this->chunkHashes)); + + // Verification okay, add it to the raw data + $this->rawPackageData .= $content; + } // END - foreach + + // Debug output + //* NOISY-DEBUG: */ $this->debugOutput('CHUNK-HANDLER: eopChunk[1]=' . $this->eopChunk[1] . ',' . chr(10) . 'index=' . (count($this->chunkHashes) - 2) . ',' . chr(10) . 'chunkHashes='.print_r($this->chunkHashes,true)); + + // The last chunk hash must match with the one from eopChunk[1] + assert($this->eopChunk[1] == $this->chunkHashes[count($this->chunkHashes) - 2]); + } + + /** + * Verifies the finally assembled raw package data by comparing it against + * the final hash. + * + * @return void + */ + private function verifyRawPackageData () { + // Hash the raw package data for final verification + $finalHash = $this->getCryptoInstance()->hashString($this->rawPackageData, $this->eopChunk[0], false); + + // Is it the same? + assert($finalHash == $this->eopChunk[0]); + } + /** * Adds all chunks if the last one verifies as a 'final chunk'. * @@ -295,7 +472,67 @@ class ChunkHandler extends BaseHandler implements HandleableChunks, Registerable // Make sure the final array is really completed assert($this->ifUnassembledChunksAvailable()); - $this->partialStub('Please implement this method.'); + // Count up stepping + $this->finalPackageChunks['assemble_steps']++; + + // Do the next step + switch ($this->finalPackageChunks['assemble_steps']) { + case 1: // Sort the chunks array (the serial number shall act as a sorting key) + $this->sortChunksArray(); + break; + + case 2: // Prepare the assemble by removing last two indexes + $this->preparePackageAssmble(); + break; + + case 3: // Assemble all chunks back together to the original package + $this->assembleAllChunksToPackage(); + break; + + case 4: // Verify the raw data by hashing it again + $this->verifyRawPackageData(); + break; + + case 5: // Re-initialize handler to reset it to the old state + $this->initHandler(); + break; + + default: // Invalid step found + $this->debugOutput('CHUNK-HANDLER: Invalid step ' . $this->finalPackageChunks['assemble_steps'] . ' detected.'); + break; + } // END - switch + } + + /** + * Checks whether the raw package data has been assembled back together. + * This can be safely assumed when rawPackageData is not empty and the + * collection of all chunks is false (because initHandler() will reset it). + * + * @return $isRawPackageDataAvailable Whether raw package data is available + */ + public function ifRawPackageDataIsAvailable () { + // Check it + $isRawPackageDataAvailable = ((!empty($this->rawPackageData)) && (!$this->ifUnassembledChunksAvailable())); + + // Return it + return $isRawPackageDataAvailable; + } + + /** + * Handles the finally assembled raw package data by feeding it into another + * stacker for further decoding/processing. + * + * @return void + */ + public function handledAssembledRawPackageData () { + // Assert to make sure that there is raw package data available + assert($this->ifRawPackageDataIsAvailable()); + + // Then feed it into the next stacker + $this->getStackerInstance()->pushNamed(self::STACKER_NAME_ASSEMBLED_RAW_DATA, $this->rawPackageData); + + // ... and reset it + $this->rawPackageData = ''; } } diff --git a/application/hub/main/helper/connection/class_BaseConnectionHelper.php b/application/hub/main/helper/connection/class_BaseConnectionHelper.php index f66bc15c6..685d079e3 100644 --- a/application/hub/main/helper/connection/class_BaseConnectionHelper.php +++ b/application/hub/main/helper/connection/class_BaseConnectionHelper.php @@ -220,6 +220,9 @@ class BaseConnectionHelper extends BaseHubHelper implements Registerable, Protoc $socketResource = $this->getSocketResource(); $timeout = $this->getConfigInstance()->getConfigEntry('socket_timeout_seconds'); + // Debug output + $this->debugOutput('CONNECTION-HELPER: Trying to connect to ' . $recipientData[0] . ':' . $recipientData[1] . ' with socketResource[' . gettype($socketResource) . ']=' . $socketResource . ' ...'); + // Try to connect until it is connected while ($isConnected = !@socket_connect($socketResource, $recipientData[0], $recipientData[1])) { // Get last socket error diff --git a/application/hub/main/lists/class_BaseList.php b/application/hub/main/lists/class_BaseList.php index a48487995..0fd7a8a80 100644 --- a/application/hub/main/lists/class_BaseList.php +++ b/application/hub/main/lists/class_BaseList.php @@ -203,7 +203,7 @@ class BaseList extends BaseHubSystem implements IteratorAggregate, Countable { // Add the hash to the index $this->listIndex[] = $hash; - //* DEBUG: */ print $groupName.'/'.count($this->listIndex).chr(10); + //* DEBUG: */ print $groupName.'/'.$this->count().chr(10); // Now add the entry to the list $this->listEntries[$hash] = $entry; diff --git a/application/hub/main/package/class_NetworkPackage.php b/application/hub/main/package/class_NetworkPackage.php index bd094561c..4e480d3e4 100644 --- a/application/hub/main/package/class_NetworkPackage.php +++ b/application/hub/main/package/class_NetworkPackage.php @@ -35,7 +35,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -class NetworkPackage extends BaseFrameworkSystem implements Deliverable, Receivable, Registerable, Visitable { +class NetworkPackage extends BaseHubSystem implements Deliverable, Receivable, Registerable, Visitable { /** * Package mask for compressing package data: * 0: Compressor extension @@ -71,6 +71,7 @@ class NetworkPackage extends BaseFrameworkSystem implements Deliverable, Receiva const INDEX_PACKAGE_RECIPIENT = 1; const INDEX_PACKAGE_CONTENT = 2; const INDEX_PACKAGE_STATUS = 3; + const INDEX_PACKAGE_SIGNATURE = 4; /** * Named array elements for package data @@ -79,20 +80,22 @@ class NetworkPackage extends BaseFrameworkSystem implements Deliverable, Receiva const PACKAGE_DATA_RECIPIENT = 'recipient'; const PACKAGE_DATA_CONTENT = 'content'; const PACKAGE_DATA_STATUS = 'status'; + const PACKAGE_DATA_SIGNATURE = 'signature'; /** * All package status */ const PACKAGE_STATUS_NEW = 'new'; const PACKAGE_STATUS_FAILED = 'failed'; + const PACKAGE_STATUS_DECODED = 'decoded'; /** - * Tags SEPARATOR + * Tags separator */ const PACKAGE_TAGS_SEPARATOR = ';'; /** - * Raw package data SEPARATOR + * Raw package data separator */ const PACKAGE_DATA_SEPARATOR = '#'; @@ -200,6 +203,10 @@ class NetworkPackage extends BaseFrameworkSystem implements Deliverable, Receiva // Set it in this package $packageInstance->setVisitorInstance($visitorInstance); + // Get crypto instance and set it in this package + $cryptoInstance = ObjectFactory::createObjectByConfiguredName('crypto_class'); + $packageInstance->setCryptoInstance($cryptoInstance); + // Return the prepared instance return $packageInstance; } @@ -267,7 +274,10 @@ class NetworkPackage extends BaseFrameworkSystem implements Deliverable, Receiva } // END - if // Pop the entry (it should be it) - $this->getStackerInstance()->popNamed($stackerName); + $nextData = $this->getStackerInstance()->popNamed($stackerName); + + // Compare both arrays + assert($nextData[self::PACKAGE_DATA_SIGNATURE] == $packageData[self::PACKAGE_DATA_SIGNATURE]); // Temporary set the new status $packageData[self::PACKAGE_DATA_STATUS] = $newStatus; @@ -368,9 +378,18 @@ class NetworkPackage extends BaseFrameworkSystem implements Deliverable, Receiva // Is it not there? if ((is_resource($socketResource)) && (!$registryInstance->isSocketRegistered($helperInstance, $socketResource))) { + // Debug message + $this->debugOutput('PACKAGE: Registering socket ' . $socketResource . ' ...'); + // Then register it $registryInstance->registerSocket($helperInstance, $socketResource, $packageData); - } // END - if + } elseif (!$helperInstance->getStateInstance()->isPeerStateConnected()) { + // Is not connected, then we cannot send + $this->debugOutput('PACKAGE: Unexpected peer state ' . $helperInstance->getStateInstance()->__toString() . ' detected.'); + + // Shutdown the socket + $this->shutdownSocket($socketResource); + } // Debug message //* NOISY-DEBUG: */ $this->debugOutput('NETWORK-PACKAGE: Reached line ' . __LINE__ . ' after isSocketRegistered() has been called.'); @@ -383,6 +402,9 @@ class NetworkPackage extends BaseFrameworkSystem implements Deliverable, Receiva // Enqueue it again on the out-going queue, the connection is up and working at this point $this->getStackerInstance()->pushNamed(self::STACKER_NAME_OUTGOING, $packageData); + + // Debug message + //* NOISY-DEBUG: */ $this->debugOutput('NETWORK-PACKAGE: Reached line ' . __LINE__ . ' after pushNamed() has been called.'); } /** @@ -412,6 +434,27 @@ class NetworkPackage extends BaseFrameworkSystem implements Deliverable, Receiva $this->storeUnsentBytesInBackBuffer($packageData, $sentBytes); } + /** + * Generates a signature for given raw package content and sender id + * + * @param $content Raw package data + * @param $senderId Sender id to generate a signature for + * @return $signature Signature as BASE64-encoded string + */ + private function generatePackageSignature ($content, $senderId) { + // ash content and sender id together, use md5() as last algo + $hash = md5($this->getCryptoInstance()->hashString($senderId . $content)); + + // Encrypt the content again with the hash as a key + $encryptedContent = $this->getCryptoInstance()->encryptString($content, $hash); + + // Encode it with BASE64 + $signature = base64_encode($encryptedContent); + + // Return it + return $signature; + } + /** * "Enqueues" raw content into this delivery class by reading the raw content * from given template instance and pushing it on the 'undeclared' stack. @@ -450,7 +493,8 @@ class NetworkPackage extends BaseFrameworkSystem implements Deliverable, Receiva self::PACKAGE_DATA_SENDER => $nodeInstance->getSessionId(), self::PACKAGE_DATA_RECIPIENT => $helperInstance->getRecipientType(), self::PACKAGE_DATA_CONTENT => $content, - self::PACKAGE_DATA_STATUS => self::PACKAGE_STATUS_NEW + self::PACKAGE_DATA_STATUS => self::PACKAGE_STATUS_NEW, + self::PACKAGE_DATA_SIGNATURE => $this->generatePackageSignature($content, $nodeInstance->getSessionId()) )); } @@ -548,7 +592,7 @@ class NetworkPackage extends BaseFrameworkSystem implements Deliverable, Receiva $this->getStackerInstance()->popNamed(self::STACKER_NAME_DECLARED); } catch (InvalidStateException $e) { // The state is not excepected (shall be 'connected') - $this->debugOutput('PACKAGE: Caught exception ' . $e->__toString() . ' with message=' . $e->getMessage()); + $this->debugOutput('PACKAGE: Caught ' . $e->__toString() . ',message=' . $e->getMessage()); // Mark the package with status failed $this->changePackageStatus($packageData, self::STACKER_NAME_DECLARED, self::PACKAGE_STATUS_FAILED); @@ -790,6 +834,32 @@ class NetworkPackage extends BaseFrameworkSystem implements Deliverable, Receiva // Remove this entry $this->getStackerInstance()->popNamed(self::STACKER_NAME_DECLARED); } + + /** + * "Decode" the package content into the same array when it was sent. + * + * @param $rawPackageContent The raw package content to be "decoded" + * @return $decodedData An array with 'sender', 'recipient', 'content' and 'status' elements + */ + public function decodeRawContent ($rawPackageContent) { + // Use the separator '#' to "decode" it + $decodedArray = explode(self::PACKAGE_DATA_SEPARATOR, $rawPackageContent); + + // Assert on count (should be always 3) + assert(count($decodedArray) == 3); + + // Create 'decodedData' array with all assoziative array elements + $decodedData = array( + self::PACKAGE_DATA_SENDER => $decodedArray[self::INDEX_PACKAGE_SENDER], + self::PACKAGE_DATA_RECIPIENT => $decodedArray[self::INDEX_PACKAGE_RECIPIENT], + self::PACKAGE_DATA_CONTENT => $decodedArray[self::INDEX_PACKAGE_CONTENT], + self::PACKAGE_DATA_STATUS => self::PACKAGE_STATUS_DECODED, + self::PACKAGE_DATA_SIGNATURE => $this->generatePackageSignature($decodedArray[self::INDEX_PACKAGE_CONTENT], $decodedArray[self::INDEX_PACKAGE_SENDER]) + ); + + // And return it + return $decodedData; + } } // [EOF] diff --git a/application/hub/main/package/fragmenter/class_PackageFragmenter.php b/application/hub/main/package/fragmenter/class_PackageFragmenter.php index 81f63f242..d1c59c7fb 100644 --- a/application/hub/main/package/fragmenter/class_PackageFragmenter.php +++ b/application/hub/main/package/fragmenter/class_PackageFragmenter.php @@ -30,7 +30,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -class PackageFragmenter extends BaseFrameworkSystem implements Fragmentable, Registerable { +class PackageFragmenter extends BaseHubSystem implements Fragmentable, Registerable { /** * Cached chunk size in bits */ @@ -284,40 +284,21 @@ class PackageFragmenter extends BaseFrameworkSystem implements Fragmentable, Reg return $hash; } - /** - * "Getter" for the next hexadecimal-encoded serial number - * - * @return $encodedSerialNumber The next hexadecimal-encoded serial number - */ - private function getNextHexSerialNumber () { - // Assert on maximum serial number length - assert($this->serialNumber <= $this->maxSerialNumber); - - // Encode the current serial number - $encodedSerialNumber = $this->dec2Hex($this->serialNumber, self::MAX_SERIAL_LENGTH); - - // Count one up - $this->serialNumber++; - - // Return the encoded serial number - return $encodedSerialNumber; - } - /** * 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 $chunkHash Last chunk's hash + * @param $lastChunk Last chunk raw data * @param $finalHash Final hash for raw (unencoded) data * @return void */ - private function appendEndOfPackageChunk ($chunkHash, $finalHash) { + private function appendEndOfPackageChunk ($lastChunk, $finalHash) { // Generate end-of-package marker $chunkData = self::END_OF_PACKAGE_IDENTIFIER . $finalHash . self::CHUNK_HASH_SEPARATOR . - $chunkHash; + $this->generateHashFromRawData($lastChunk); // Add it as regular chunk $this->addChunkData($finalHash, $chunkData); @@ -342,6 +323,7 @@ class PackageFragmenter extends BaseFrameworkSystem implements Fragmentable, Reg // Init variables $chunkHash = ''; + $chunkData = ''; // Now split it up for ($idx = 0; $idx < strlen($rawData); $idx += $dataChunkSize) { @@ -356,7 +338,7 @@ class PackageFragmenter extends BaseFrameworkSystem implements Fragmentable, Reg //* 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); + $this->appendEndOfPackageChunk($chunkData, $finalHash); } /** @@ -429,6 +411,25 @@ class PackageFragmenter extends BaseFrameworkSystem implements Fragmentable, Reg } // END - for } + /** + * "Getter" for the next hexadecimal-encoded serial number + * + * @return $encodedSerialNumber The next hexadecimal-encoded serial number + */ + public function getNextHexSerialNumber () { + // Assert on maximum serial number length + assert($this->serialNumber <= $this->maxSerialNumber); + + // Encode the current serial number + $encodedSerialNumber = $this->dec2Hex($this->serialNumber, self::MAX_SERIAL_LENGTH); + + // Count one up + $this->serialNumber++; + + // Return the encoded serial number + 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 @@ -517,6 +518,15 @@ class PackageFragmenter extends BaseFrameworkSystem implements Fragmentable, Reg // Return the chunk array return $rawDataChunk; } + + /** + * Resets the serial number to zero + * + * @return void + */ + public function resetSerialNumber () { + $this->serialNumber = 0; + } } // [EOF] diff --git a/application/hub/main/statistics/connection/class_ConnectionStatisticsHelper.php b/application/hub/main/statistics/connection/class_ConnectionStatisticsHelper.php index 4e42fe89c..c73be9a6b 100644 --- a/application/hub/main/statistics/connection/class_ConnectionStatisticsHelper.php +++ b/application/hub/main/statistics/connection/class_ConnectionStatisticsHelper.php @@ -94,7 +94,8 @@ class ConnectionStatisticsHelper extends BaseHubSystem { self::$connectionStatistics[$helperInstance->getProtocol()][$helperInstance->__toString()]['retry_count']++; } - // Create/update 'last_update' for later purging + // Create/update 'last_update' for purging + // @TODO last_update is not being used at the moment self::$connectionStatistics[$helperInstance->getProtocol()][$helperInstance->__toString()]['last_update'] = time(); } } diff --git a/application/hub/main/tasks/hub/chunks/class_HubChunkAssemblerTask.php b/application/hub/main/tasks/hub/chunks/class_HubChunkAssemblerTask.php index abedc4326..e5aaca9f7 100644 --- a/application/hub/main/tasks/hub/chunks/class_HubChunkAssemblerTask.php +++ b/application/hub/main/tasks/hub/chunks/class_HubChunkAssemblerTask.php @@ -89,6 +89,12 @@ class HubChunkAssemblerTask extends BaseTask implements Taskable, Visitable { * 'final array' for last verification. */ $this->getHandlerInstance()->handleAvailableChunksWithFinal(); + } elseif ($this->getHandlerInstance()->ifRawPackageDataIsAvailable()) { + /* + * The final raw package data is back together again. So feed it + * into the next stack for further decoding/processing + */ + $this->getHandlerInstance()->handledAssembledRawPackageData(); } } } diff --git a/application/hub/main/tasks/hub/decoder/.htaccess b/application/hub/main/tasks/hub/decoder/.htaccess new file mode 100644 index 000000000..3a4288278 --- /dev/null +++ b/application/hub/main/tasks/hub/decoder/.htaccess @@ -0,0 +1 @@ +Deny from all diff --git a/application/hub/main/tasks/hub/decoder/class_HubPackageDecoderTask.php b/application/hub/main/tasks/hub/decoder/class_HubPackageDecoderTask.php new file mode 100644 index 000000000..dd9d17791 --- /dev/null +++ b/application/hub/main/tasks/hub/decoder/class_HubPackageDecoderTask.php @@ -0,0 +1,90 @@ + + * @version 0.0.0 + * @copyright Copyright (c) 2007, 2008 Roland Haeder, 2009 - 2011 Hub Developer Team + * @license GNU GPL 3.0 or any newer version + * @link http://www.ship-simu.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 . + */ +class HubPackageDecoderTask extends BaseTask implements Taskable, Visitable { + /** + * Protected constructor + * + * @return void + */ + protected function __construct () { + // Call parent constructor + parent::__construct(__CLASS__); + } + + /** + * Creates an instance of this class + * + * @return $taskInstance An instance of a Visitable class + */ + public final static function createHubPackageDecoderTask () { + // Get new instance + $taskInstance = new HubPackageDecoderTask(); + + // Get a chunk handler instance + $handlerInstance = ChunkHandlerFactory::createChunkHandlerInstance(); + + // Get the stacker from it, we don't need the handler here + $stackerInstance = $handlerInstance->getStackerInstance(); + + // Get a decoder instance + $decoderInstance = ObjectFactory::createObjectByConfiguredName('package_decoder_class', array($stackerInstance)); + + // ... and also set the decoder instance here + $taskInstance->setDecoderInstance($decoderInstance); + + // Return the prepared instance + return $taskInstance; + } + + /** + * Accepts the visitor to process the visit "request" + * + * @param $visitorInstance An instance of a Visitor class + * @return void + * @todo Maybe visit some sub-objects + */ + public function accept (Visitor $visitorInstance) { + // Visit this task + $visitorInstance->visitTask($this); + } + + /** + * Executes the task + * + * @return void + */ + public function executeTask () { + // Check if the stacker has some entries left + if ($this->getDecoderInstance()->ifUnhandledRawPackageDataLeft()) { + // Then handle it + $this->getDecoderInstance()->handleRawPackageData(); + } elseif ($this->getDecoderInstance()->ifDeocedPackagesLeft()) { + // Some decoded packages have arrived (for this peer) + $this->getDecoderInstance()->handleDecodedPackage(); + } + } +} + +// [EOF] +?> diff --git a/application/hub/main/tools/class_HubTools.php b/application/hub/main/tools/class_HubTools.php index 2313a6162..c7063ece5 100644 --- a/application/hub/main/tools/class_HubTools.php +++ b/application/hub/main/tools/class_HubTools.php @@ -21,7 +21,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -class HubTools extends BaseFrameworkSystem { +class HubTools extends BaseHubSystem { // Constants for exceptions const EXCEPTION_SESSION_ID_IS_INVALID = 0x200; const EXCEPTION_HOSTNAME_NOT_FOUND = 0x201; diff --git a/docs/TODOs.txt b/docs/TODOs.txt index af92510b7..1613cdbb8 100644 --- a/docs/TODOs.txt +++ b/docs/TODOs.txt @@ -6,7 +6,7 @@ ./application/hub/interfaces/helper/connections/class_ConnectionHelper.php:38: * @todo We may want to implement a filter for ease notification of other objects like our pool ./application/hub/interfaces/helper/messages/class_MessageHelper.php:10: * @todo Please find another name for this interface ./application/hub/interfaces/nodes/class_NodeHelper.php:10: * @todo We need to find a better name for this interface -./application/hub/main/class_BaseHubSystem.php:331: // @TODO On some systems it is 134, on some 107? +./application/hub/main/class_BaseHubSystem.php:376: // @TODO On some systems it is 134, on some 107? ./application/hub/main/commands/console/class_HubConsoleChatCommand.php:107: * @todo Should we add some more filters? ./application/hub/main/commands/console/class_HubConsoleChatCommand.php:58: * @todo Try to create a ChatActivationTask or so ./application/hub/main/commands/console/class_HubConsoleCruncherCommand.php:107: * @todo Should we add some more filters? @@ -22,6 +22,7 @@ ./application/hub/main/cruncher/mcrypt/class_HubMcryptCruncher.php:98: // @TODO Implement this method ./application/hub/main/database/wrapper/states/class_PeerStateLookupDatabaseWrapper.php:177: * @todo Unfinished area ./application/hub/main/database/wrapper/states/class_PeerStateLookupDatabaseWrapper.php:219: * @todo Unfinished area +./application/hub/main/discovery/package/class_PackageRecipientDiscovery.php:100: * @todo Add some validation of recipient field, e.g. ip:port is found ./application/hub/main/discovery/socket/class_PackageSocketDiscovery.php:102: // @TODO We may need some logging here ./application/hub/main/factories/socket/class_SocketFactory.php:10: * @todo Find an interface for hub helper ./application/hub/main/filter/bootstrap/chat/class_ChatBootstrapGenericActivationFilter.php:54: * @todo Maybe we want to do somthing more here? @@ -87,17 +88,17 @@ ./application/hub/main/nodes/regular/class_HubRegularNode.php:58: * @todo Implement this method ./application/hub/main/nodes/regular/class_HubRegularNode.php:68: * @todo Unfinished method ./application/hub/main/nodes/regular/class_HubRegularNode.php:91: // @TODO Add some filters here -./application/hub/main/package/class_NetworkPackage.php:237: * @todo $helperInstance is unused ./application/hub/main/package/class_NetworkPackage.php:23: * @todo Needs to add functionality for handling the object's type -./application/hub/main/package/class_NetworkPackage.php:241: // @TODO crc32() is very weak, but it needs to be fast -./application/hub/main/package/class_NetworkPackage.php:404: // @TODO We may want to do somthing more here? -./application/hub/main/package/class_NetworkPackage.php:510: // @TODO Add some logging here -./application/hub/main/package/class_NetworkPackage.php:536: // @TODO Add some logging here -./application/hub/main/package/class_NetworkPackage.php:640: // @TODO Add some logging here -./application/hub/main/package/class_NetworkPackage.php:739: // @TODO Add some content here -./application/hub/main/package/class_NetworkPackage.php:778: * @todo This may be enchanced for outgoing packages? +./application/hub/main/package/class_NetworkPackage.php:244: * @todo $helperInstance is unused +./application/hub/main/package/class_NetworkPackage.php:248: // @TODO crc32() is very weak, but it needs to be fast +./application/hub/main/package/class_NetworkPackage.php:426: // @TODO We may want to do somthing more here? +./application/hub/main/package/class_NetworkPackage.php:554: // @TODO Add some logging here +./application/hub/main/package/class_NetworkPackage.php:580: // @TODO Add some logging here +./application/hub/main/package/class_NetworkPackage.php:684: // @TODO Add some logging here +./application/hub/main/package/class_NetworkPackage.php:783: // @TODO Add some content here +./application/hub/main/package/class_NetworkPackage.php:822: * @todo This may be enchanced for outgoing packages? ./application/hub/main/package/fragmenter/class_PackageFragmenter.php:274: * @todo Implement a way to send non-announcement packages with extra-salt -./application/hub/main/package/fragmenter/class_PackageFragmenter.php:441: * @todo $helperInstance is unused +./application/hub/main/package/fragmenter/class_PackageFragmenter.php:442: * @todo $helperInstance is unused ./application/hub/main/producer/cruncher/keys/class_CruncherKeyProducer.php:106: // @TODO Do something with it ./application/hub/main/producer/cruncher/keys/class_CruncherKeyProducer.php:62: * @todo Find something for init phase of this key producer ./application/hub/main/producer/cruncher/keys/class_CruncherKeyProducer.php:72: * @todo ~30% done @@ -106,6 +107,7 @@ ./application/hub/main/resolver/state/peer/class_PeerStateResolver.php:59: * @todo ~30% done ./application/hub/main/states/node/init/class_NodeInitState.php:60: * @todo We might want to move some calls to this method to fill it with life ./application/hub/main/statistics/connection/class_ConnectionStatisticsHelper.php:11: * @todo Find an interface for hub helper +./application/hub/main/statistics/connection/class_ConnectionStatisticsHelper.php:98: // @TODO last_update is not being used at the moment ./application/hub/main/streams/raw_data/input/class_RawDataInputStream.php:57: * @todo Do we need to do something more here? ./application/hub/main/streams/raw_data/output/class_RawDataOutputStream.php:53: * @todo Do we need to do something more here? ./application/hub/main/tasks/chat/class_ChatTelnetListenerTask.php:53: * @todo Maybe visit some sub-objects @@ -118,6 +120,7 @@ ./application/hub/main/tasks/hub/class_HubSelfConnectTask.php:53: * @todo 0% ./application/hub/main/tasks/hub/class_HubSocketListenerTask.php:63: // @TODO Do we need to visit this task? $visitorInstance->visitTask($this); ./application/hub/main/tasks/hub/class_HubSocketListenerTask.php:70: * @todo 0% done +./application/hub/main/tasks/hub/decoder/class_HubPackageDecoderTask.php:65: * @todo Maybe visit some sub-objects ./application/hub/main/tasks/hub/ping/class_HubPingTask.php:63: * @todo Also visit some sub-objects? ./application/hub/main/tasks/hub/ping/class_HubPingTask.php:74: * @todo 0% done ./application/hub/main/tasks/hub/update/class_HubUpdateCheckTask.php:53: * @todo 0% @@ -139,8 +142,8 @@ ./inc/classes/exceptions/main/class_MissingMethodException.php:13: * @todo Try to rewrite user/guest login classes and mark this exception as deprecated ./inc/classes/exceptions/main/class_NoConfigEntryException.php:10: * @todo Rename this class to NoFoundEntryException ./inc/classes/interfaces/class_FrameworkInterface.php:11: * @todo Find a better name for this interface -./inc/classes/main/class_BaseFrameworkSystem.php:1301: * @todo Write a logging mechanism for productive mode -./inc/classes/main/class_BaseFrameworkSystem.php:1315: // @TODO Finish this part! +./inc/classes/main/class_BaseFrameworkSystem.php:1306: * @todo Write a logging mechanism for productive mode +./inc/classes/main/class_BaseFrameworkSystem.php:1320: // @TODO Finish this part! ./inc/classes/main/class_BaseFrameworkSystem.php:195: // @todo Try to clean these constants up ./inc/classes/main/class_BaseFrameworkSystem.php:465: * @todo SearchableResult and UpdateableResult shall have a super interface to use here ./inc/classes/main/commands/web/class_WebLoginAreaCommand.php:64: * @todo Add some stuff here: Some personal data, app/game related data -- 2.39.2