From f884d1738b81b893f44001100f51661f307ad9a3 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Roland=20H=C3=A4der?= Date: Sat, 11 Feb 2012 00:13:26 +0000 Subject: [PATCH] Continued on development of 'hub' project with many refactorings/addings: - Added new exception UnexpectedPackageStatusException which will be thrown if the package status is not the expected one before it got 'pop-ed' from the stack - Added HalfShutdownSocketVisitor which will remove the first failing entry from the list - Added ability to change package status by 'pop-ing' it from the stack and then re-adding it - Added (unused ATM) ConnectionRegistry which will serve for outgoing connections - Many medium/minor refacturings, still there is a while() loop that needs refacturing to an iterator to not let the software stay to long in that method (which would cause other connections being paused) - TODOs.txt updated --- .gitattributes | 8 + application/hub/config.php | 19 +- application/hub/exceptions/package/.htaccess | 1 + ...class_UnexpectedPackageStatusException.php | 49 +++ .../discovery/class_DiscoverableRecipient.php | 7 + .../hub/interfaces/lists/class_Listable.php | 7 + application/hub/main/class_BaseHubSystem.php | 37 +++ .../class_PackageRecipientDiscovery.php | 27 +- .../socket/class_PackageSocketDiscovery.php | 23 +- .../factories/socket/class_SocketFactory.php | 18 + .../network/class_BaseRawDataHandler.php | 22 +- .../connection/class_BaseConnectionHelper.php | 307 ++++++++++++++---- .../tcp/class_TcpConnectionHelper.php | 52 +-- .../hub/main/listener/class_BaseListener.php | 10 +- application/hub/main/lists/class_ | 20 ++ application/hub/main/lists/class_BaseList.php | 37 ++- .../main/lists/groups/class_ListGroupList.php | 10 + .../hub/main/lists/hub/class_HubList.php | 12 +- .../main/lists/pool/class_PoolEntriesList.php | 10 + .../query/local/class_LocalQueryList.php | 10 + .../lists/recipient/class_RecipientList.php | 12 +- .../hub/main/lists/tasks/class_TaskList.php | 12 +- .../hub/main/package/class_NetworkPackage.php | 71 +++- .../main/pools/peer/class_DefaultPeerPool.php | 3 + .../hub/main/registry/connection/.htaccess | 1 + .../connection/class_ConnectionRegistry.php | 238 ++++++++++++++ .../registry/socket/class_SocketRegistry.php | 4 +- .../state/peer/class_PeerStateResolver.php | 7 + application/hub/main/states/peer/class_ | 2 +- .../connected/class_ConnectedPeerState.php | 2 +- .../class_ConnectionRefusedPeerState.php | 2 +- .../class_ConnectionTimedOutPeerState.php | 2 +- .../errors/class_NoRouteToHostPeerState.php | 53 +++ ...lass_OperationAlreadyProgressPeerState.php | 53 +++ .../class_TransportEndpointGonePeerState.php | 53 +++ .../class_TransportEndpointGonePeerState.php | 52 +-- .../class_ConnectionStatisticsHelper.php | 10 +- .../class_HalfShutdownSocketVisitor.php | 87 +++++ docs/TODOs.txt | 68 ++-- 39 files changed, 1193 insertions(+), 225 deletions(-) create mode 100644 application/hub/exceptions/package/.htaccess create mode 100644 application/hub/exceptions/package/class_UnexpectedPackageStatusException.php create mode 100644 application/hub/main/registry/connection/.htaccess create mode 100644 application/hub/main/registry/connection/class_ConnectionRegistry.php create mode 100644 application/hub/main/states/peer/errors/class_NoRouteToHostPeerState.php create mode 100644 application/hub/main/states/peer/errors/class_OperationAlreadyProgressPeerState.php create mode 100644 application/hub/main/states/peer/errors/class_TransportEndpointGonePeerState.php create mode 100644 application/hub/main/visitor/socket/class_HalfShutdownSocketVisitor.php diff --git a/.gitattributes b/.gitattributes index b8dd0a023..906de4510 100644 --- a/.gitattributes +++ b/.gitattributes @@ -16,6 +16,8 @@ application/hub/exceptions/lists/.htaccess -text svneol=unset#text/plain application/hub/exceptions/lists/class_InvalidListHashException.php svneol=native#text/plain application/hub/exceptions/lists/class_ListGroupAlreadyAddedException.php svneol=native#text/plain application/hub/exceptions/lists/class_NoListGroupException.php svneol=native#text/plain +application/hub/exceptions/package/.htaccess -text svneol=unset#text/plain +application/hub/exceptions/package/class_UnexpectedPackageStatusException.php -text application/hub/exceptions/peer/.htaccess -text svneol=unset#text/plain application/hub/exceptions/peer/class_PeerAlreadyRegisteredException.php svneol=native#text/plain application/hub/exceptions/resolver/.htaccess svneol=native#text/plain @@ -423,6 +425,8 @@ application/hub/main/queues/class_BaseQueue.php svneol=native#text/plain application/hub/main/queues/peer/.htaccess -text svneol=unset#text/plain application/hub/main/queues/peer/class_LocalPeerQueue.php svneol=native#text/plain application/hub/main/registry/.htaccess -text svneol=unset#text/plain +application/hub/main/registry/connection/.htaccess -text svneol=unset#text/plain +application/hub/main/registry/connection/class_ConnectionRegistry.php svneol=native#text/plain application/hub/main/registry/objects/.htaccess -text svneol=unset#text/plain application/hub/main/registry/objects/class_ObjectTypeRegistry.php svneol=native#text/plain application/hub/main/registry/socket/.htaccess -text svneol=unset#text/plain @@ -477,6 +481,9 @@ application/hub/main/states/peer/connected/class_ConnectedPeerState.php svneol=n application/hub/main/states/peer/errors/.htaccess -text svneol=unset#text/plain application/hub/main/states/peer/errors/class_ConnectionRefusedPeerState.php svneol=native#text/plain application/hub/main/states/peer/errors/class_ConnectionTimedOutPeerState.php svneol=native#text/plain +application/hub/main/states/peer/errors/class_NoRouteToHostPeerState.php svneol=native#text/plain +application/hub/main/states/peer/errors/class_OperationAlreadyProgressPeerState.php svneol=native#text/plain +application/hub/main/states/peer/errors/class_TransportEndpointGonePeerState.php svneol=native#text/plain application/hub/main/states/peer/init/.htaccess -text svneol=unset#text/plain application/hub/main/states/peer/init/class_InitPeerState.php svneol=native#text/plain application/hub/main/states/peer/new/.htaccess -text svneol=unset#text/plain @@ -548,6 +555,7 @@ application/hub/main/visitor/pool/monitor/.htaccess -text application/hub/main/visitor/pool/shutdown/.htaccess -text svneol=unset#text/plain application/hub/main/visitor/pool/shutdown/class_ShutdownListenerPoolVisitor.php svneol=native#text/plain application/hub/main/visitor/socket/.htaccess -text svneol=unset#text/plain +application/hub/main/visitor/socket/class_HalfShutdownSocketVisitor.php svneol=native#text/plain application/hub/main/visitor/socket/class_ShutdownSocketVisitor.php svneol=native#text/plain application/hub/main/visitor/tasks/.htaccess -text svneol=unset#text/plain application/hub/main/visitor/tasks/class_ActiveTaskVisitor.php svneol=native#text/plain diff --git a/application/hub/config.php b/application/hub/config.php index 345abce40..2bbb4a634 100644 --- a/application/hub/config.php +++ b/application/hub/config.php @@ -114,6 +114,9 @@ $cfg->setConfigEntry('shutdown_task_visitor_class', 'ShutdownTaskVisitor'); // CFG: SHUTDOWN-SOCKET-VISITOR-CLASS $cfg->setConfigEntry('shutdown_socket_visitor_class', 'ShutdownSocketVisitor'); +// CFG: HALF-SHUTDOWN-SOCKET-VISITOR-CLASS +$cfg->setConfigEntry('half_shutdown_socket_visitor_class', 'HalfShutdownSocketVisitor'); + // CFG: ACTIVE-TASK-VISITOR-CLASS $cfg->setConfigEntry('active_task_visitor_class', 'ActiveTaskVisitor'); @@ -490,10 +493,10 @@ $cfg->setConfigEntry('tcp_buffer_length', 1024); $cfg->setConfigEntry('udp_buffer_length', 1024); // CFG: TCP-CONNECT-RETRY-MAX -$cfg->setConfigEntry('tcp_connect_retry_max', 10); +$cfg->setConfigEntry('tcp_connect_retry_max', 5); // CFG: UDP-CONNECT-RETRY-MAX -$cfg->setConfigEntry('udp_connect_retry_max', 10); +$cfg->setConfigEntry('udp_connect_retry_max', 5); // CFG: NODE-STATE-CHECKED-PACKAGE-CLASS $cfg->setConfigEntry('node_state_checked_package_class', 'NewConnectionNodeState'); @@ -519,6 +522,12 @@ $cfg->setConfigEntry('node_raw_data_input_stream_class', 'RawDataInputStream'); // CFG: DEBUG-OUTPUT-TIMINGS $cfg->setConfigEntry('debug_output_timings', 'Y'); +// CFG: SOCKET-TIMEOUT-SECONDS +$cfg->setConfigEntry('socket_timeout_seconds', 3); + +// CFG: SOCKET-TIMEOUT-MICROSECONDS +$cfg->setConfigEntry('socket_timeout_microseconds', 0); + /////////////////////////////////////////////////////////////////////////////// // Peer states /////////////////////////////////////////////////////////////////////////////// @@ -538,6 +547,12 @@ $cfg->setConfigEntry('peer_connection_timed_out_state_class', 'ConnectionTimedOu // CFG: PEER-TRANSPORT-ENDPOINT-STATE-CLASS $cfg->setConfigEntry('peer_transport_endpoint_state_class', 'TransportEndpointGonePeerState'); +// CFG: PEER-OPERATION-ALREADY-PROGRESS-STATE-CLASS +$cfg->setConfigEntry('peer_operation_already_progress_state_class', 'OperationAlreadyProgressPeerState'); + +// CFG: PEER-NO-ROUTE-TO-HOST-STATE-CLASS +$cfg->setConfigEntry('peer_no_route_to_host_state_class', 'NoRouteToHostPeerState'); + /////////////////////////////////////////////////////////////////////////////// // Cruncher configuration /////////////////////////////////////////////////////////////////////////////// diff --git a/application/hub/exceptions/package/.htaccess b/application/hub/exceptions/package/.htaccess new file mode 100644 index 000000000..3a4288278 --- /dev/null +++ b/application/hub/exceptions/package/.htaccess @@ -0,0 +1 @@ +Deny from all diff --git a/application/hub/exceptions/package/class_UnexpectedPackageStatusException.php b/application/hub/exceptions/package/class_UnexpectedPackageStatusException.php new file mode 100644 index 000000000..a2bd25b08 --- /dev/null +++ b/application/hub/exceptions/package/class_UnexpectedPackageStatusException.php @@ -0,0 +1,49 @@ + + * @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 UnexpectedPackageStatusException extends FrameworkException { + /** + * The super constructor for all exceptions + * + * @param $messageArray Error message array + * @param $code Error code + * @return void + */ + public function __construct (array $messageArray, $code) { + // Construct the message + $message = sprintf("[%s:%d] Unexpected package status %s!=%s detected, recipient=%s, sender=%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] + ); + + // Call parent exception constructor + parent::__construct($message, $code); + } +} + +// [EOF] +?> diff --git a/application/hub/interfaces/discovery/class_DiscoverableRecipient.php b/application/hub/interfaces/discovery/class_DiscoverableRecipient.php index d452311c3..20189ad6f 100644 --- a/application/hub/interfaces/discovery/class_DiscoverableRecipient.php +++ b/application/hub/interfaces/discovery/class_DiscoverableRecipient.php @@ -36,6 +36,13 @@ interface DiscoverableRecipient extends FrameworkInterface { * @return $iteratorInstance An instance of a Iterateable object */ function getIterator (); + + /** + * Clears all recipients for e.g. another package to deliver + * + * @return void + */ + function clearRecipients (); } // [EOF] diff --git a/application/hub/interfaces/lists/class_Listable.php b/application/hub/interfaces/lists/class_Listable.php index caac23f3c..0ad651960 100644 --- a/application/hub/interfaces/lists/class_Listable.php +++ b/application/hub/interfaces/lists/class_Listable.php @@ -76,6 +76,13 @@ interface Listable extends FrameworkInterface, IteratorAggregate { * @return $iteratorInstance An instance of a Iterator class */ function getListIterator (); + + /** + * Clears this list (mostly by clearing all groups together) + * + * @return void + */ + function clearList (); } // [EOF] diff --git a/application/hub/main/class_BaseHubSystem.php b/application/hub/main/class_BaseHubSystem.php index c0c3f6936..36645bb15 100644 --- a/application/hub/main/class_BaseHubSystem.php +++ b/application/hub/main/class_BaseHubSystem.php @@ -291,6 +291,10 @@ class BaseHubSystem extends BaseFrameworkSystem { case 0: // Silently ignored, the socket is connected break; + case 11: // "Resource temporary unavailable" + $errorName = BaseRawDataHandler::SOCKET_ERROR_RESOURCE_UNAVAILABLE; + break; + case 107: // "Transport end-point not connected" case 134: // On some (?) systems for 'transport end-point not connected' // @TODO On some systems it is 134, on some 107? @@ -305,6 +309,18 @@ class BaseHubSystem extends BaseFrameworkSystem { $errorName = BaseRawDataHandler::SOCKET_ERROR_CONNECTION_REFUSED; break; + case 113: // "No route to host" + $errorName = BaseRawDataHandler::SOCKET_ERROR_NO_ROUTE_TO_HOST; + break; + + case 114: // "Operation already in progress" + $errorName = BaseRawDataHandler::SOCKET_ERROR_OPERATION_ALREADY_PROGRESS; + break; + + case 115: // "Operation now in progress" + $errorName = BaseRawDataHandler::SOCKET_ERROR_OPERATION_IN_PROGRESS; + break; + default: // Everything else <> 0 // Unhandled error code detected, so first debug it because we may want to handle it like the others $this->debugOutput('[' . __METHOD__ . ':' . __LINE__ . '] UNKNOWN ERROR CODE = ' . $errorCode . ', MESSAGE = ' . socket_strerror($errorCode)); @@ -339,6 +355,27 @@ class BaseHubSystem extends BaseFrameworkSystem { $this->accept($visitorInstance); } + /** + * Half-shuts down a given socket resource. This method does only ease calling + * an other visitor than shutdownSocket() does. + * + * @param $socketResource A valid socket resource + * @return void + */ + public function halfShutdownSocket ($socketResource) { + // Debug message + $this->debugOutput('HUB-SYSTEM: Half-shutting down socket resource ' . $socketResource . ' with state ' . $this->getPrintableState() . ' ...'); + + // Set socket resource + $this->setSocketResource($socketResource); + + // Get a visitor instance + $visitorInstance = ObjectFactory::createObjectByConfiguredName('half_shutdown_socket_visitor_class'); + + // Call the visitor + $this->accept($visitorInstance); + } + /** * "Getter" for a printable state name * diff --git a/application/hub/main/discovery/package/class_PackageRecipientDiscovery.php b/application/hub/main/discovery/package/class_PackageRecipientDiscovery.php index 4a687ddbc..651f99e09 100644 --- a/application/hub/main/discovery/package/class_PackageRecipientDiscovery.php +++ b/application/hub/main/discovery/package/class_PackageRecipientDiscovery.php @@ -44,6 +44,10 @@ class PackageRecipientDiscovery extends BaseHubDiscovery implements Discoverable // Output debug message $discoveryInstance->debugOutput('RECIPIENT-DISCOVERY: Initialized.'); + // Get recipients list instance and set it + $listInstance = RecipientListFactory::createRecipientListInstance(); + $discoveryInstance->setListInstance($listInstance); + // Return the prepared instance return $discoveryInstance; } @@ -55,9 +59,6 @@ class PackageRecipientDiscovery extends BaseHubDiscovery implements Discoverable * @return void */ public function discoverRecipients (array $packageData) { - // Get recipients list instance - $listInstance = RecipientListFactory::createRecipientListInstance(); - // We do some rudimentary checks but this might be a bit ugly switch ($packageData[NetworkPackage::PACKAGE_DATA_RECIPIENT]) { // All upper hubs, these are currently the bootstrap nodes and later on prepended list-nodes @@ -68,7 +69,7 @@ class PackageRecipientDiscovery extends BaseHubDiscovery implements Discoverable /* DEBUG: */ $this->debugOutput('DISCOVERY: Adding node ' . $node . ' as recipient.'); // Add the entry - $listInstance->addEntry('ip_port', $node); + $this->getListInstance()->addEntry('ip_port', $node); } // END - foreach break; @@ -81,7 +82,7 @@ class PackageRecipientDiscovery extends BaseHubDiscovery implements Discoverable $ipPort = $ip . ':' . $this->getConfigInstance()->getConfigEntry('node_' . $this->determineProtocolByPackageData($packageData) . '_listen_port'); // Add it to the list - $listInstance->addEntry('ip_port', $ipPort); + $this->getListInstance()->addEntry('ip_port', $ipPort); break; // This may be a direct recipient (node's session id) @@ -97,15 +98,23 @@ class PackageRecipientDiscovery extends BaseHubDiscovery implements Discoverable * @return $iteratorInstance An instance of a Iterateable object */ public function getIterator () { - // Get list instance - $listInstance = RecipientListFactory::createRecipientListInstance(); - // Get iterator from it - $iteratorInstance = $listInstance->getIterator(); + $iteratorInstance = $this->getListInstance()->getIterator(); // Return it return $iteratorInstance; } + + /** + * Clears all recipients for e.g. another package to deliver. This method + * simply clears the inner list instance. + * + * @return void + */ + public function clearRecipients () { + // Clear the list + $this->getListInstance()->clearList(); + } } // [EOF] diff --git a/application/hub/main/discovery/socket/class_PackageSocketDiscovery.php b/application/hub/main/discovery/socket/class_PackageSocketDiscovery.php index f061c1791..d08dbb3f2 100644 --- a/application/hub/main/discovery/socket/class_PackageSocketDiscovery.php +++ b/application/hub/main/discovery/socket/class_PackageSocketDiscovery.php @@ -113,7 +113,7 @@ class PackageSocketDiscovery extends BaseHubDiscovery implements DiscoverableSoc $socketResource = $listenerInstance->getPoolInstance()->getSocketFromPackageData($packageData); // Is it false, the recipient isn't known to us and we have no connection to it - if ((!is_resource($socketResource)) || (socket_last_error($socketResource) > 0)) { + if (($socketResource === false) || (!is_resource($socketResource)) || (socket_last_error($socketResource) > 0)) { // Try to create a new socket resource try { // Possibly noisy debug message @@ -129,14 +129,23 @@ class PackageSocketDiscovery extends BaseHubDiscovery implements DiscoverableSoc } } // END - if - // Get the helper instance from registry - $helperInstance = Registry::getRegistry()->getInstance('connection'); + // Try to resolve the socket resource + try { + // Get the helper instance from registry + $helperInstance = Registry::getRegistry()->getInstance('connection'); - // Possibly noisy debug message - /* NOISY-DEBUG: */ $this->debugOutput('SOCKET-DISCOVERY: Going to resolve state by given package data ...'); + // Possibly noisy debug message + /* NOISY-DEBUG: */ $this->debugOutput('SOCKET-DISCOVERY: Going to resolve socket from peer state and given package data ...'); - // Resolve the peer's state (but ignore return value) - PeerStateResolver::resolveStateByPackage($helperInstance, $packageData, $socketResource); + // Resolve the peer's state (but ignore return value) + PeerStateResolver::resolveStateByPackage($helperInstance, $packageData, $socketResource); + } catch (InvalidSocketException $e) { + // This cannot be fixed, so log it away + $this->debugOutput('SOCKET-DISCOVERY: Cannot discover socket resource for recipient ' . $packageData[NetworkPackage::PACKAGE_DATA_RECIPIENT] . ': ' . $e->getMessage()); + + // Make any failed attempts to 'false' + $socketResource = false; + } // And return it return $socketResource; diff --git a/application/hub/main/factories/socket/class_SocketFactory.php b/application/hub/main/factories/socket/class_SocketFactory.php index a3eae6e97..6ec3fc6fb 100644 --- a/application/hub/main/factories/socket/class_SocketFactory.php +++ b/application/hub/main/factories/socket/class_SocketFactory.php @@ -41,9 +41,15 @@ class SocketFactory extends BaseHubHelper { * @return $socketResource Socket resource */ public static function createSocketFromPackageData (array $packageData, $protocolName) { + // Get an instance + $factoryInstance = new SocketFactory(); + // Construct registry key $registryKey = 'socket_' . $protocolName . '_' . $packageData[NetworkPackage::PACKAGE_DATA_RECIPIENT]; + // Debug message + $factoryInstance->debugOutput('SOCKET-FACTORY: Trying to find a socket with registryKey=' . $registryKey); + // Is the key there? if (Registry::getRegistry()->instanceExists($registryKey)) { // Get container instance @@ -51,18 +57,30 @@ class SocketFactory extends BaseHubHelper { // Get socket back $socketResource = $containerInstance->getSocketResource(); + + // Debug message + $factoryInstance->debugOutput('SOCKET-FACTORY: Using socket ' . $socketResource . '(' . gettype($socketResource) . ') from registry.'); } else { // Construct configuration entry for object factory and get it $className = FrameworkConfiguration::getSelfInstance()->getConfigEntry($protocolName . '_connection_helper_class'); + // Debug message + $factoryInstance->debugOutput('SOCKET-FACTORY: Going to use class ' . $className . ' for creating a socket resource ...'); + // And call the static method $socketResource = call_user_func($className . '::createConnectionFromPackageData', $packageData); + // Debug message + $factoryInstance->debugOutput('SOCKET-FACTORY: Created socket ' . $socketResource . '(' . gettype($socketResource) . ') from class ' . $className . '.'); + // Construct container class, this won't be reached if an exception is thrown $containerInstance = ObjectFactory::CreateObjectByConfiguredName('socket_container_class', array($socketResource, NULL, $packageData)); // Register it with the registry Registry::getRegistry()->addInstance($registryKey, $containerInstance); + + // Debug message + $factoryInstance->debugOutput('SOCKET-FACTORY: Socket is now registered in registry.'); } // Return the resource diff --git a/application/hub/main/handler/network/class_BaseRawDataHandler.php b/application/hub/main/handler/network/class_BaseRawDataHandler.php index 50710956e..f35d7d52b 100644 --- a/application/hub/main/handler/network/class_BaseRawDataHandler.php +++ b/application/hub/main/handler/network/class_BaseRawDataHandler.php @@ -24,15 +24,19 @@ class BaseRawDataHandler extends BaseHandler { // Error codes: // - Socket raw data stream errors - const SOCKET_ERROR_UNKNOWN = 'unknown_error'; // Unknown error (should not happen) - const SOCKET_ERROR_TRANSPORT_ENDPOINT = 'transport_endpoint'; // Transport endpoint has closed - const SOCKET_ERROR_EMPTY_DATA = 'empty_data'; // Other peer has sent nothing - const SOCKET_ERROR_INVALID_BASE64_MODULO = 'base64_modulo'; // Length is not modulo 4 - const SOCKET_ERROR_INVALID_BASE64_MESSAGE = 'base64_message'; // Raw data is not Base64-encoded - const SOCKET_ERROR_UNHANDLED = 'unhandled_package'; // Unhandled raw data (not bad) - const SOCKET_ERROR_CONNECTION_REFUSED = 'connection_refused'; // The name says it: connection refused - const SOCKET_ERROR_CONNECTION_TIMED_OUT = 'connection_timed_out'; // The name says it: connection attempt has timed-out - const SOCKET_CONNECTED = 'connected'; // Nothing errorous happens, socket is connected + const SOCKET_ERROR_UNKNOWN = 'unknown_error'; // Unknown error (should not happen) + const SOCKET_ERROR_TRANSPORT_ENDPOINT = 'transport_endpoint'; // Transport endpoint has closed + const SOCKET_ERROR_EMPTY_DATA = 'empty_data'; // Other peer has sent nothing + const SOCKET_ERROR_INVALID_BASE64_MODULO = 'base64_modulo'; // Length is not modulo 4 + const SOCKET_ERROR_INVALID_BASE64_MESSAGE = 'base64_message'; // Raw data is not Base64-encoded + const SOCKET_ERROR_UNHANDLED = 'unhandled_package'; // Unhandled raw data (not bad) + const SOCKET_ERROR_CONNECTION_REFUSED = 'connection_refused'; // The name says it: connection refused + const SOCKET_ERROR_CONNECTION_TIMED_OUT = 'connection_timed_out'; // The name says it: connection attempt has timed-out + const SOCKET_ERROR_OPERATION_IN_PROGRESS = 'operation_in_progress'; // 'Operation now in progress' + const SOCKET_ERROR_OPERATION_ALREADY_PROGRESS = 'operation_already_progress'; // 'Operation already in progress' + const SOCKET_ERROR_RESOURCE_UNAVAILABLE = 'resource_unavailable'; // 'Resource temporary unavailable' + const SOCKET_ERROR_NO_ROUTE_TO_HOST = 'no_route_to_host'; // The name says it: no route to host + const SOCKET_CONNECTED = 'connected'; // Nothing errorous happens, socket is connected // - Package errors const PACKAGE_ERROR_INVALID_DATA = 'invalid_data'; // Invalid data in package found diff --git a/application/hub/main/helper/connection/class_BaseConnectionHelper.php b/application/hub/main/helper/connection/class_BaseConnectionHelper.php index e2b2dd171..27ced2e42 100644 --- a/application/hub/main/helper/connection/class_BaseConnectionHelper.php +++ b/application/hub/main/helper/connection/class_BaseConnectionHelper.php @@ -50,6 +50,11 @@ class BaseConnectionHelper extends BaseHubHelper implements Registerable, Protoc */ private $diff = 0; + /** + * Whether this connection is initialized + */ + private $isInitialized = false; + /** * Wether this connection is shutted down */ @@ -101,6 +106,147 @@ class BaseConnectionHelper extends BaseHubHelper implements Registerable, Protoc return $class; } + /** + * Getter for port number to satify ProtocolHandler + * + * @return $port The port number + */ + public final function getPort () { + return $this->port; + } + + /** + * Setter for port number to satify ProtocolHandler + * + * @param $port The port number + * @return void + */ + protected final function setPort ($port) { + $this->port = $port; + } + + /** + * Getter for protocol + * + * @return $protocol Used protocol + */ + public final function getProtocol () { + return $this->protocol; + } + + /** + * Setter for protocol + * + * @param $protocol Used protocol + * @return void + */ + protected final function setProtocol ($protocol) { + $this->protocol = $protocol; + } + + /** + * Getter for IP address + * + * @return $address The IP address + */ + public final function getAddress () { + return $this->address; + } + + /** + * Setter for IP address + * + * @param $address The IP address + * @return void + */ + protected final function setAddress ($address) { + $this->address = $address; + } + + /** + * Initializes the current connection + * + * @return void + * @throws SocketOptionException If setting any socket option fails + */ + protected function initConnection () { + // Get socket resource + $socketResource = $this->getSocketResource(); + + // Set the option to reuse the port + if (!socket_set_option($socketResource, SOL_SOCKET, SO_REUSEADDR, 1)) { + // Handle this socket error with a faked recipientData array + $this->handleSocketError($socketResource, array('0.0.0.0', '0')); + + // And throw again + // @TODO Move this to the socket error handler + throw new SocketOptionException(array($this, $socketResource, $socketError, $errorMessage), BaseListener::EXCEPTION_INVALID_SOCKET); + } // END - if + + /* + * Set socket to non-blocking mode before trying to establish a link to + * it. This is now the default behaviour for all connection helpers who + * call initConnection(); . + */ + if (!socket_set_nonblock($socketResource)) { + // Handle this socket error with a faked recipientData array + $helperInstance->handleSocketError($socketResource, array('0.0.0.0', '0')); + + // And throw again + throw new SocketOptionException(array($helperInstance, $socketResource, $socketError, $errorMessage), BaseListener::EXCEPTION_INVALID_SOCKET); + } // END - if + + // Last step: mark connection as initialized + $this->isInitialized = true; + } + + /** + * Attempts to connect to a peer by given IP number and port from a valid + * recipientData array with currently configured timeout. + * + * @param $recipientData A valid recipient data array, 0=IP; 1=PORT + * @return $isConnected Wether the connection went fine + * @see Please see http://de.php.net/manual/en/function.socket-connect.php#84465 for original code + * @todo Rewrite the while() loop to a iterator to not let the software stay very long here + */ + protected function connectToPeerByRecipientDataArray (array $recipientData) { + // Only call this if the connection is initialized by initConnection() + assert($this->isInitialized === true); + + // Get current time + $time = time(); + + // "Cache" socket resource and timeout config + $socketResource = $this->getSocketResource(); + $timeout = $this->getConfigInstance()->getConfigEntry('socket_timeout_seconds'); + + // Try to connect until it is connected + while ($isConnected = !@socket_connect($socketResource, $recipientData[0], $recipientData[1])) { + // Get last socket error + $socketError = socket_last_error($socketResource); + + // Skip any errors which may happen on non-blocking connections + if (($socketError == SOCKET_EINPROGRESS) || ($socketError == SOCKET_EALREADY)) { + // Now, is that attempt within parameters? + if ((time() - $time) >= $timeout) { + // Didn't work within timeout + $isConnected = false; + break; + } // END - if + + // Sleep about one second + $this->idle(1000); + } elseif ($socketError != 0) { + // Stop on everything else pronto + $isConnected = false; + break; + } + } // END - while + + // Return status + return $isConnected; + } + /** * Static "getter" for this connection class' name * @@ -179,63 +325,6 @@ class BaseConnectionHelper extends BaseHubHelper implements Registerable, Protoc } } - /** - * Getter for port number to satify ProtocolHandler - * - * @return $port The port number - */ - public final function getPort () { - return $this->port; - } - - /** - * Setter for port number to satify ProtocolHandler - * - * @param $port The port number - * @return void - */ - protected final function setPort ($port) { - $this->port = $port; - } - - /** - * Getter for protocol - * - * @return $protocol Used protocol - */ - public final function getProtocol () { - return $this->protocol; - } - - /** - * Setter for protocol - * - * @param $protocol Used protocol - * @return void - */ - protected final function setProtocol ($protocol) { - $this->protocol = $protocol; - } - - /** - * Getter for IP address - * - * @return $address The IP address - */ - public final function getAddress () { - return $this->address; - } - - /** - * Setter for IP address - * - * @param $address The IP address - * @return void - */ - protected final function setAddress ($address) { - $this->address = $address; - } - /** * "Accept" a visitor by simply calling it back * @@ -342,6 +431,9 @@ class BaseConnectionHelper extends BaseHubHelper implements Registerable, Protoc protected final function markConnectionShuttedDown () { /* NOISY-DEBUG: */ $this->debugOutput('CONNECTION: ' . $this->__toString() . ' has been marked as shutted down'); $this->shuttedDown = true; + + // And remove the (now invalid) socket + $this->setSocketResource(false); } /** @@ -363,6 +455,7 @@ class BaseConnectionHelper extends BaseHubHelper implements Registerable, Protoc * later debugging purposes. * * @param $socketResource A valid socket resource + * @return void * @throws SocketConnectionException The connection attempts fails with a time-out */ protected function socketErrorConnectionTimedOutHandler ($socketResource) { @@ -378,6 +471,106 @@ class BaseConnectionHelper extends BaseHubHelper implements Registerable, Protoc // Throw it again throw new SocketConnectionException(array($this, $socketResource, $socketError, $errorMessage), BaseListener::EXCEPTION_INVALID_SOCKET); } + + /** + * Handles socket error 'resource temporary unavailable', but does not + * clear it for later debugging purposes. + * + * @param $socketResource A valid socket resource + * @return void + * @throws SocketConnectionException The connection attempts fails with a time-out + */ + protected function socketErrorResourceUnavailableHandler ($socketResource) { + // Get socket error code for verification + $socketError = socket_last_error($socketResource); + + // Get error message + $errorMessage = socket_strerror($socketError); + + // Shutdown this socket + $this->shutdownSocket($socketResource); + + // Throw it again + throw new SocketConnectionException(array($this, $socketResource, $socketError, $errorMessage), BaseListener::EXCEPTION_INVALID_SOCKET); + } + + /** + * Handles socket error 'connection refused', but does not clear it for + * later debugging purposes. + * + * @param $socketResource A valid socket resource + * @return void + * @throws SocketConnectionException The connection attempts fails with a time-out + */ + protected function socketErrorConnectionRefusedHandler ($socketResource) { + // Get socket error code for verification + $socketError = socket_last_error($socketResource); + + // Get error message + $errorMessage = socket_strerror($socketError); + + // Shutdown this socket + $this->shutdownSocket($socketResource); + + // Throw it again + throw new SocketConnectionException(array($this, $socketResource, $socketError, $errorMessage), BaseListener::EXCEPTION_INVALID_SOCKET); + } + + /** + * Handles socket error 'no route to host', but does not clear it for later + * debugging purposes. + * + * @param $socketResource A valid socket resource + * @return void + * @throws SocketConnectionException The connection attempts fails with a time-out + */ + protected function socketErrorNoRouteToHostHandler ($socketResource) { + // Get socket error code for verification + $socketError = socket_last_error($socketResource); + + // Get error message + $errorMessage = socket_strerror($socketError); + + // Shutdown this socket + $this->shutdownSocket($socketResource); + + // Throw it again + throw new SocketConnectionException(array($this, $socketResource, $socketError, $errorMessage), BaseListener::EXCEPTION_INVALID_SOCKET); + } + + /** + * Handles socket error 'operation already in progress' which happens in + * method connectToPeerByRecipientDataArray() on timed out connection + * attempts. + * + * @param $socketResource A valid socket resource + * @return void + * @throws SocketConnectionException The connection attempts fails with a time-out + */ + protected function socketErrorOperationAlreadyProgressHandler ($socketResource) { + // Get socket error code for verification + $socketError = socket_last_error($socketResource); + + // Get error message + $errorMessage = socket_strerror($socketError); + + // Half-shutdown this socket (see there for difference to shutdownSocket()) + $this->halfShutdownSocket($socketResource); + + // Throw it again + throw new SocketConnectionException(array($this, $socketResource, $socketError, $errorMessage), BaseListener::EXCEPTION_INVALID_SOCKET); + } + + /** + * Handles socket "error" 'operation now in progress' which can be safely + * passed on with non-blocking connections. + * + * @param $socketResource A valid socket resource + * @return void + */ + protected function socketErrorOperationInProgressHandler ($socketResource) { + $this->debugOutput('CONNECTION: Operation is now in progress, this is usual for non-blocking connections and no bug.'); + } } // [EOF] diff --git a/application/hub/main/helper/connection/tcp/class_TcpConnectionHelper.php b/application/hub/main/helper/connection/tcp/class_TcpConnectionHelper.php index d22f150fd..d0bec3e01 100644 --- a/application/hub/main/helper/connection/tcp/class_TcpConnectionHelper.php +++ b/application/hub/main/helper/connection/tcp/class_TcpConnectionHelper.php @@ -75,27 +75,12 @@ class TcpConnectionHelper extends BaseConnectionHelper implements ConnectionHelp throw new SocketCreationException(array($helperInstance, gettype($socketResource), $socketError, socket_strerror($socketError)), BaseListener::EXCEPTION_SOCKET_CREATION_FAILED); } // END - if - // Set the option to reuse the port - if (!socket_set_option($socketResource, SOL_SOCKET, SO_REUSEADDR, 1)) { - // Handle this socket error with a faked recipientData array - $helperInstance->handleSocketError($socketResource, array('0.0.0.0', '0')); - - // And throw again - throw new SocketOptionException(array($helperInstance, $socketResource, $socketError, $errorMessage), BaseListener::EXCEPTION_INVALID_SOCKET); - } // END - if - - // Set socket in non-blocking mode - if (!socket_set_nonblock($socketResource)) { - // Handle this socket error with a faked recipientData array - $helperInstance->handleSocketError($socketResource, array('0.0.0.0', '0')); - - // And throw again - throw new SocketOptionException(array($helperInstance, $socketResource, $socketError, $errorMessage), BaseListener::EXCEPTION_INVALID_SOCKET); - } // END - if - // Set the resource $helperInstance->setSocketResource($socketResource); + // Init connection + $helperInstance->initConnection(); + // @TODO The whole resolving part should be moved out and made more configurable // Init recipient data $recipientData = NULL; @@ -138,29 +123,9 @@ class TcpConnectionHelper extends BaseConnectionHelper implements ConnectionHelp $helperInstance->debugOutput('CONNECTION: Connecting to ' . $recipientData[0] . ':' . $recipientData[1]); // Now connect to it - if (!@socket_connect($socketResource, $recipientData[0], $recipientData[1])) { + if (!$helperInstance->connectToPeerByRecipientDataArray($recipientData)) { // Handle socket error - // @TODO Handle 115 error ("operation in progress") $helperInstance->handleSocketError($socketResource, $recipientData); - /* - // Get socket error code for verification - $socketError = socket_last_error($socketResource); - - // And throw again, but not for 'Operation now in progress'; the shutdownSocket() method should wait a little - if ($socketError != 115) { - // Get error message - $errorMessage = socket_strerror($socketError); - - // Shutdown this socket - $helperInstance->shutdownSocket($socketResource); - - // Throw it again - throw new SocketConnectionException(array($helperInstance, $socketResource, $socketError, $errorMessage), BaseListener::EXCEPTION_INVALID_SOCKET); - } else { - // Debug output - $helperInstance->debugOutput('CONNECTION: Operation is in progress, this usual for non-blocking connections.'); - } - */ } // END - if // Connection is fully established here, so change the state @@ -193,6 +158,15 @@ class TcpConnectionHelper extends BaseConnectionHelper implements ConnectionHelp } // END - if } // END - if + // Try to make blocking IO for socket_close() + socket_set_block($this->getSocketResource()); + + // Drop all data (don't sent any on socket closure) + socket_set_option($this->getSocketResource(), SOL_SOCKET, SO_LINGER, array('l_onoff' => 1, 'l_linger' => 0)); + + // Finally free some resources + socket_close($this->getSocketResource()); + // Mark this connection as shutted down $this->markConnectionShuttedDown(); } diff --git a/application/hub/main/listener/class_BaseListener.php b/application/hub/main/listener/class_BaseListener.php index f0907e595..a95bc9763 100644 --- a/application/hub/main/listener/class_BaseListener.php +++ b/application/hub/main/listener/class_BaseListener.php @@ -23,10 +23,12 @@ */ class BaseListener extends BaseHubSystem implements Visitable { // Exception code constants - const EXCEPTION_INVALID_SOCKET = 0xa00; - const EXCEPTION_SOCKET_ALREADY_REGISTERED = 0xa01; - const EXCEPTION_SOCKET_CREATION_FAILED = 0xa02; - const EXCEPTION_NO_SOCKET_ERROR = 0xa03; + const EXCEPTION_INVALID_SOCKET = 0xa00; + const EXCEPTION_SOCKET_ALREADY_REGISTERED = 0xa01; + const EXCEPTION_SOCKET_CREATION_FAILED = 0xa02; + const EXCEPTION_NO_SOCKET_ERROR = 0xa03; + const EXCEPTION_CONNECTION_ALREADY_REGISTERED = 0xa04; + const EXCEPTION_UNEXPECTED_PACKAGE_STATUS = 0xa05; /** * Used protocol (Default: invalid, which is indeed invalid...) diff --git a/application/hub/main/lists/class_ b/application/hub/main/lists/class_ index 6e1f5c201..ce34ca88e 100644 --- a/application/hub/main/lists/class_ +++ b/application/hub/main/lists/class_ @@ -44,6 +44,26 @@ class ???List extends BaseList implements Listable { // Return the prepared instance return $listInstance; } + + /** + * "Getter" for an iterator instance of this list + * + * @return $iteratorInstance An instance of a Iterator class + * @todo 0% done + */ + public function getListIterator () { + $this->partialStub('Please implement this method.'); + } + + /** + * Clears this list by cleaning up all groups together. + * + * @return void + * @todo 0% done + */ + public function clearList () { + $this->partialStub('Please implement this method.'); + } } // [EOF] diff --git a/application/hub/main/lists/class_BaseList.php b/application/hub/main/lists/class_BaseList.php index af4cd69d3..3bc2933e3 100644 --- a/application/hub/main/lists/class_BaseList.php +++ b/application/hub/main/lists/class_BaseList.php @@ -154,7 +154,7 @@ class BaseList extends BaseHubSystem implements IteratorAggregate, Countable { // Is there another list? if (!is_null($list)) { // Then get it as well - $array = $this->listGroups[$list]->getArrayFromList(null); + $array = $this->listGroups[$list]->getArrayFromList(NULL); } // END - if // Walk through all entries @@ -275,6 +275,41 @@ class BaseList extends BaseHubSystem implements IteratorAggregate, Countable { return $hash; } + /** + * Clears an array of groups, all are being checked for existence + * + * @param $groupNames An array with existing list groups + * @return void + */ + protected function clearGroups (array $groupNames) { + // Walk through all groups + foreach ($groupNames as $groupName) { + // Clear this group + $this->clearGroup($groupName); + } // END - foreach + } + + /** + * Clears a single group by resetting it to its initial state (empty array) + * + * @param $groupName Name of an existing group to clear + * @return void + */ + protected function clearGroup ($groupName) { + // Does this group exist? + if (!$this->isGroupSet($groupName)) { + // Throw the exception here + throw new NoListGroupException(array($this, $groupName), self::EXCEPTION_GROUP_NOT_FOUND); + } // END - if + + // Then clear this group list + $this->listGroups[$groupName]->clearList(); + + // Clear this list + $this->listIndex = array(); + $this->listEntries = array(); + } + /** * Counts all entries in this list * diff --git a/application/hub/main/lists/groups/class_ListGroupList.php b/application/hub/main/lists/groups/class_ListGroupList.php index 9499afe58..1648bc6f6 100644 --- a/application/hub/main/lists/groups/class_ListGroupList.php +++ b/application/hub/main/lists/groups/class_ListGroupList.php @@ -54,6 +54,16 @@ class ListGroupList extends BaseList implements Listable { public function getListIterator () { $this->partialStub('Please implement this method.'); } + + /** + * Clears this list by cleaning up all groups together. + * + * @return void + * @todo 0% done + */ + public function clearList () { + $this->partialStub('Please implement this method.'); + } } // [EOF] diff --git a/application/hub/main/lists/hub/class_HubList.php b/application/hub/main/lists/hub/class_HubList.php index c663de19d..857ee895d 100644 --- a/application/hub/main/lists/hub/class_HubList.php +++ b/application/hub/main/lists/hub/class_HubList.php @@ -53,11 +53,21 @@ class HubList extends BaseList implements Listable { * "Getter" for an iterator instance of this list * * @return $iteratorInstance An instance of a Iterator class - * @todo0% done + * @todo 0% done */ public function getListIterator () { $this->partialStub('Please implement this method.'); } + + /** + * Clears this list by cleaning up all groups together. + * + * @return void + */ + public function clearList () { + // Clear both groups together + $this->clearGroups(array('connected', 'disconnected')); + } } // [EOF] diff --git a/application/hub/main/lists/pool/class_PoolEntriesList.php b/application/hub/main/lists/pool/class_PoolEntriesList.php index 485f2cd84..5e1777d21 100644 --- a/application/hub/main/lists/pool/class_PoolEntriesList.php +++ b/application/hub/main/lists/pool/class_PoolEntriesList.php @@ -63,6 +63,16 @@ class PoolEntriesList extends BaseList implements Listable { // ... and return it return $iteratorInstance; } + + /** + * Clears this list by cleaning up all groups together. + * + * @return void + */ + public function clearList () { + // Clear the only one group + $this->clearGroup('pool'); + } } // [EOF] diff --git a/application/hub/main/lists/query/local/class_LocalQueryList.php b/application/hub/main/lists/query/local/class_LocalQueryList.php index e364c0ff4..4702cb84f 100644 --- a/application/hub/main/lists/query/local/class_LocalQueryList.php +++ b/application/hub/main/lists/query/local/class_LocalQueryList.php @@ -60,6 +60,16 @@ class LocalQueryList extends BaseList implements Listable { // ... and return it return $iteratorInstance; } + + /** + * Clears this list by cleaning up all groups together. + * + * @return void + * @todo 0% done + */ + public function clearList () { + $this->partialStub('Please implement this method.'); + } } // [EOF] diff --git a/application/hub/main/lists/recipient/class_RecipientList.php b/application/hub/main/lists/recipient/class_RecipientList.php index 538eb7476..6375f63d1 100644 --- a/application/hub/main/lists/recipient/class_RecipientList.php +++ b/application/hub/main/lists/recipient/class_RecipientList.php @@ -56,11 +56,21 @@ class RecipientList extends BaseList implements Listable, Registerable { * "Getter" for an iterator instance of this list * * @return $iteratorInstance An instance of a Iterator class - * @todo0% done + * @todo 0% done */ public function getListIterator () { $this->partialStub('Please implement this method.'); } + + /** + * Clears this list by cleaning up all groups together. + * + * @return void + */ + public function clearList () { + // Clear both groups + $this->clearGroups(array('ip_port', 'session_id')); + } } // [EOF] diff --git a/application/hub/main/lists/tasks/class_TaskList.php b/application/hub/main/lists/tasks/class_TaskList.php index d5402dc72..6640fe058 100644 --- a/application/hub/main/lists/tasks/class_TaskList.php +++ b/application/hub/main/lists/tasks/class_TaskList.php @@ -52,11 +52,21 @@ class TaskList extends BaseList implements Listable { * "Getter" for an iterator instance of this list * * @return $iteratorInstance An instance of a Iterator class - * @todo0% done + * @todo 0% done */ public function getListIterator () { $this->partialStub('Please implement this method.'); } + + /** + * Clears this list by cleaning up all groups together. + * + * @return void + */ + public function clearList () { + // Clear the only one group + $this->clearGroup('tasks'); + } } // [EOF] diff --git a/application/hub/main/package/class_NetworkPackage.php b/application/hub/main/package/class_NetworkPackage.php index 9a8bcd023..b1d770715 100644 --- a/application/hub/main/package/class_NetworkPackage.php +++ b/application/hub/main/package/class_NetworkPackage.php @@ -70,6 +70,7 @@ class NetworkPackage extends BaseFrameworkSystem implements Deliverable, Receiva const INDEX_PACKAGE_SENDER = 0; const INDEX_PACKAGE_RECIPIENT = 1; const INDEX_PACKAGE_CONTENT = 2; + const INDEX_PACKAGE_STATUS = 3; /** * Named array elements for package data @@ -77,6 +78,13 @@ class NetworkPackage extends BaseFrameworkSystem implements Deliverable, Receiva const PACKAGE_DATA_SENDER = 'sender'; const PACKAGE_DATA_RECIPIENT = 'recipient'; const PACKAGE_DATA_CONTENT = 'content'; + const PACKAGE_DATA_STATUS = 'status'; + + /** + * All package status + */ + const PACKAGE_STATUS_NEW = 'new'; + const PACKAGE_STATUS_FAILED = 'failed'; /** * Tags seperator @@ -211,7 +219,7 @@ class NetworkPackage extends BaseFrameworkSystem implements Deliverable, Receiva */ private function getHashFromContent ($content, HelpableHub $helperInstance, NodeHelper $nodeInstance) { // Create the hash - // @TODO crc32() is not very strong, but it needs to be fast + // @TODO crc32() is very weak, but it needs to be fast $hash = crc32( $content . self::PACKAGE_CHECKSUM_SEPERATOR . @@ -224,6 +232,31 @@ class NetworkPackage extends BaseFrameworkSystem implements Deliverable, Receiva return $hash; } + /** + * Change the package with given status in given stack + * + * @param $packageData Raw package data in an array + * @param $stackerName Name of the stacker + * @param $newStatus New status to set + * @return void + */ + private function changePackageStatus (array $packageData, $stackerName, $newStatus) { + // Skip this for empty stacks + if ($this->getStackerInstance()->isStackEmpty($stackerName)) { + // This avoids an exception after all packages has failed + return; + } // END - if + + // Pop the entry (it should be it) + $this->getStackerInstance()->popNamed($stackerName); + + // Temporary set the new status + $packageData[self::PACKAGE_DATA_STATUS] = $newStatus; + + // And push it again + $this->getStackerInstance()->pushNamed($stackerName, $packageData); + } + /////////////////////////////////////////////////////////////////////////// // Delivering packages / raw data /////////////////////////////////////////////////////////////////////////// @@ -259,6 +292,7 @@ class NetworkPackage extends BaseFrameworkSystem implements Deliverable, Receiva // Set the recipient $packageData[self::PACKAGE_DATA_RECIPIENT] = $currentRecipient; + var_dump($packageData); // And enqueue it to the writer class $this->getStackerInstance()->pushNamed(self::STACKER_NAME_DECLARED, $packageData); @@ -329,7 +363,7 @@ class NetworkPackage extends BaseFrameworkSystem implements Deliverable, Receiva // Debug message //* NOISY-DEBUG: */ $this->debugOutput('NETWORK-PACKAGE: Reached line ' . __LINE__ . ' after validatePeerStateConnected() has been called.'); - // We enqueue it again, but now in the out-going queue + // 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); } @@ -392,6 +426,7 @@ 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 )); } @@ -478,7 +513,7 @@ class NetworkPackage extends BaseFrameworkSystem implements Deliverable, Receiva return; } // END - if - // Get the package again + // Get the package $packageData = $this->getStackerInstance()->getNamed(self::STACKER_NAME_DECLARED); try { @@ -490,6 +525,9 @@ class NetworkPackage extends BaseFrameworkSystem implements Deliverable, Receiva } catch (InvalidStateException $e) { // The state is not excepected (shall be 'connected') $this->debugOutput('PACKAGE: Caught exception ' . $e->__toString() . ' with message=' . $e->getMessage()); + + // Mark the package with status failed + $this->changePackageStatus($packageData, self::STACKER_NAME_DECLARED, self::PACKAGE_STATUS_FAILED); } } @@ -509,7 +547,7 @@ class NetworkPackage extends BaseFrameworkSystem implements Deliverable, Receiva return; } // END - if - // Get the package again + // Get the package $packageData = $this->getStackerInstance()->getNamed(self::STACKER_NAME_OUTGOING); try { @@ -521,6 +559,9 @@ class NetworkPackage extends BaseFrameworkSystem implements Deliverable, Receiva } catch (InvalidSocketException $e) { // Output exception message $this->debugOutput('PACKAGE: Package was not delivered: ' . $e->getMessage()); + + // Mark package as failed + $this->changePackageStatus($packageData, self::STACKER_NAME_OUTGOING, self::PACKAGE_STATUS_FAILED); } } @@ -694,6 +735,28 @@ class NetworkPackage extends BaseFrameworkSystem implements Deliverable, Receiva // Debug message /* DEBUG: */ $this->debugOutput('PACKAGE: All stacker have been re-initialized.'); } + + /** + * Removes the first failed outoging package from the stack to continue + * with next one (it will never work until the issue is fixed by you). + * + * @return void + * @throws UnexpectedPackageStatusException If the package status is not 'failed' + * @todo This may be enchanced for outgoing packages? + */ + public function removeFirstFailedPackage () { + // Get the package again + $packageData = $this->getStackerInstance()->getNamed(self::STACKER_NAME_DECLARED); + + // Is the package status 'failed'? + if ($packageData[self::PACKAGE_DATA_STATUS] != self::PACKAGE_STATUS_FAILED) { + // Not failed! + throw new UnexpectedPackageStatusException(array($this, $packageData, self::PACKAGE_STATUS_FAILED), BaseListener::EXCEPTION_UNEXPECTED_PACKAGE_STATUS); + } // END - if + + // Remove this entry + $this->getStackerInstance()->popNamed(self::STACKER_NAME_DECLARED); + } } // [EOF] diff --git a/application/hub/main/pools/peer/class_DefaultPeerPool.php b/application/hub/main/pools/peer/class_DefaultPeerPool.php index 1ec9cba62..b5fd4a945 100644 --- a/application/hub/main/pools/peer/class_DefaultPeerPool.php +++ b/application/hub/main/pools/peer/class_DefaultPeerPool.php @@ -146,6 +146,9 @@ class DefaultPeerPool extends BasePool implements PoolablePeer { // Default is no socket $socketResource = false; + // Debug message + /* DEBUG: */ $this->debugOutput('POOL: Checking ' . count($this->getAllSockets()) . ' socket(s) ...'); + // Get all sockets and check them, skip the server socket foreach ($this->getAllSockets() as $socket) { // Is this a server socket? diff --git a/application/hub/main/registry/connection/.htaccess b/application/hub/main/registry/connection/.htaccess new file mode 100644 index 000000000..3a4288278 --- /dev/null +++ b/application/hub/main/registry/connection/.htaccess @@ -0,0 +1 @@ +Deny from all diff --git a/application/hub/main/registry/connection/class_ConnectionRegistry.php b/application/hub/main/registry/connection/class_ConnectionRegistry.php new file mode 100644 index 000000000..ea124312c --- /dev/null +++ b/application/hub/main/registry/connection/class_ConnectionRegistry.php @@ -0,0 +1,238 @@ + + * @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 ConnectionRegistry extends BaseRegistry implements Register, RegisterableConnection { + // Exception constants + const CONNECTION_NOT_REGISTERED = 0xd100; + + /** + * Instance of this class + */ + private static $registryInstance = NULL; + + /** + * Protected constructor + * + * @return void + */ + protected function __construct () { + // Call parent constructor + parent::__construct(__CLASS__); + } + + /** + * Creates a singleton instance of this registry class + * + * @return $registryInstance An instance of this class + */ + public static final function createConnectionRegistry () { + // Is an instance there? + if (is_null(self::$registryInstance)) { + // Not yet, so create one + self::$registryInstance = new ConnectionRegistry(); + } // END - if + + // Return the instance + return self::$registryInstance; + } + + /** + * "Getter" to get a string respresentation for a key for the sub-registry + * in this format: class:protocol:port + * + * @param $connectionInstance An instance of a ConnectionHelper class + * @return $key A string representation of the socket for the registry + */ + private function getSubRegistryKey (ConnectionHelper $connectionInstance) { + // Get protocol and port number and add both together + $key = sprintf("%s:%s:%s", + $connectionInstance->__toString(), + $connectionInstance->getProtocol(), + $connectionInstance->getPort() + ); + + // Return resulting key + return $key; + } + + /** + * "Getter" to get a string respresentation of the protocol + * + * @param $connectionInstance An instance of a ConnectionHelper class + * @return $key A string representation of the protocol for the registry + */ + private function getRegistryKeyFromProtocol (ConnectionHelper $connectionInstance) { + // Get the key + $key = $connectionInstance->getProtocol(); + + // Return resulting key + return $key; + } + + /** + * Checks wether the given protocol is registered + * + * @param $connectionInstance An instance of a ConnectionHelper class + * @return $isRegistered Wether the protocol is registered + */ + private function isProtocolRegistered (ConnectionHelper $connectionInstance) { + // Get the key + $key = $this->getRegistryKeyFromProtocol($connectionInstance); + + // Determine it + $isRegistered = $this->instanceExists($key); + + // Return result + return $isRegistered; + } + + /** + * Checks wether given socket resource is registered. If $socketResource is + * false only the instance will be checked. + * + * @param $connectionInstance An instance of a ConnectionHelper class + * @param $socketResource A valid socket resource + * @return $isRegistered Wether the given socket resource is registered + */ + public function isConnectionRegistered (ConnectionHelper $connectionInstance, $socketResource) { + // Default is not registered + $isRegistered = false; + + // First, check for the instance, there can be only once + if ($this->isProtocolRegistered($connectionInstance)) { + // That one is found so "get" a registry key from it + $key = $this->getRegistryKeyFromProtocol($connectionInstance); + + // Get the registry + $registryInstance = $this->getInstance($key); + + // "Get" a key for the socket + $socketKey = $this->getSubRegistryKey($connectionInstance); + + // And simply ask it + $isRegistered = $registryInstance->instanceExists($socketKey); + } // END - if + + // Return the result + return $isRegistered; + } + + /** + * Registeres given socket for listener or throws an exception if it is already registered + * + * @param $connectionInstance An instance of a ConnectionHelper class + * @param $socketResource A valid socket resource + * @param $packageData Optional raw package data + * @throws ConnectionAlreadyRegisteredException If the given socket is already registered + * @return void + */ + public function registerConnection (ConnectionHelper $connectionInstance, $socketResource, array $packageData = array()) { + // Is the socket already registered? + if ($this->isConnectionRegistered($connectionInstance, $socketResource)) { + // Throw the exception + throw new ConnectionAlreadyRegisteredException(array($connectionInstance, $socketResource), BaseListener::EXCEPTION_CONNECTION_ALREADY_REGISTERED); + } // END - if + + // Does the instance exist? + if (!$this->isProtocolRegistered($connectionInstance)) { + // No, not found so we create a sub registry (not needed to configure!) + $registryInstance = SubRegistry::createSubRegistry(); + + // Now we can create the sub-registry for this protocol + $this->addInstance($this->getRegistryKeyFromProtocol($connectionInstance), $registryInstance); + } else { + // Get the sub-registry back + $registryInstance = $this->getInstance($this->getRegistryKeyFromProtocol($connectionInstance)); + } + + // Get a key for sub-registries + $socketKey = $this->getSubRegistryKey($connectionInstance); + + // Get a socket container + $socketInstance = ObjectFactory::CreateObjectByConfiguredName('socket_container_class', array($socketResource, $connectionInstance, $packageData)); + + // We have a sub-registry, the socket key and the socket, now we need to put all together + /* DEBUG: */ $this->debugOutput('CONNECTION-REGISTRY: socketKey=' . $socketKey . ',socketResource=' . $socketResource . ' - adding socket container instance ...'); + $registryInstance->addInstance($socketKey, $socketInstance); + } + + /** + * Getter for given listener's socket resource + * + * @param $connectionInstance An instance of a ConnectionHelper class + * @return $socketResource A valid socket resource + * @throws NoConnectionRegisteredException If the requested socket is not registered + */ + public function getRegisteredConnectionResource (ConnectionHelper $connectionInstance) { + // The socket must be registered before we can return it + if (!$this->isConnectionRegistered($connectionInstance, false)) { + // Throw the exception + throw new NoConnectionRegisteredException ($connectionInstance, self::CONNECTION_NOT_REGISTERED); + } // END - if + + // Now get the key from the protocol + $key = $this->getRegistryKeyFromProtocol($connectionInstance); + + // And get the registry + $registryInstance = $this->getInstance($key); + + // Get a socket key + $socketKey = $this->getSubRegistryKey($connectionInstance); + + // And the final socket resource + $socketResource = $registryInstance->getInstance($socketKey)->getConnectionResource(); + + // Return the resource + return $socketResource; + } + + /** + * "Getter" for protocol/connection instance from given package data + * + * @param $packageData Raw package data + * @return $connectionInstance An instance of a ConnectionHelper class + */ + public function getHandlerInstanceFromPackageData (array $packageData) { + // Init protocol instance + $connectionInstance = NULL; + + // Get all keys and check them + foreach ($this->getInstanceRegistry() as $key=>$registryInstance) { + // This is always a SubRegistry instance + foreach ($registryInstance->getInstanceRegistry() as $subKey=>$containerInstance) { + // This is a ConnectionContainer instance, so does the recipient match? + if ($containerInstance->ifAddressMatches($packageData[NetworkPackage::PACKAGE_DATA_RECIPIENT])) { + // Found one, so get the protocol instance and abort any further search + $connectionInstance = $containerInstance->getProtocolInstance(); + break; + } // END - if + } // END - foreach + } // END - foreach + + // Return the protocol instance + return $connectionInstance; + } +} + +// [EOF] +?> diff --git a/application/hub/main/registry/socket/class_SocketRegistry.php b/application/hub/main/registry/socket/class_SocketRegistry.php index a8aa3330f..bc72879d0 100644 --- a/application/hub/main/registry/socket/class_SocketRegistry.php +++ b/application/hub/main/registry/socket/class_SocketRegistry.php @@ -150,7 +150,7 @@ class SocketRegistry extends BaseRegistry implements Register, RegisterableSocke // Is the socket already registered? if ($this->isSocketRegistered($protocolInstance, $socketResource)) { // Throw the exception - throw new SocketAlreadyRegisteredException($protocolInstance, BaseListener::EXCEPTION_SOCKET_ALREADY_REGISTERED); + throw new SocketAlreadyRegisteredException(array($protocolInstance, $socketResource), BaseListener::EXCEPTION_SOCKET_ALREADY_REGISTERED); } // END - if // Does the instance exist? @@ -172,7 +172,7 @@ class SocketRegistry extends BaseRegistry implements Register, RegisterableSocke $socketInstance = ObjectFactory::CreateObjectByConfiguredName('socket_container_class', array($socketResource, $protocolInstance, $packageData)); // We have a sub-registry, the socket key and the socket, now we need to put all together - /* DEBUG: */ $this->debugOutput('SOCKET-REGISTRY: socketKey=' . $socketKey . ',socketResource=' . $socketResource); + /* DEBUG: */ $this->debugOutput('SOCKET-REGISTRY: socketKey=' . $socketKey . ',socketResource=' . $socketResource . ' - adding socket container instance ...'); $registryInstance->addInstance($socketKey, $socketInstance); } diff --git a/application/hub/main/resolver/state/peer/class_PeerStateResolver.php b/application/hub/main/resolver/state/peer/class_PeerStateResolver.php index 6f3afd67d..b51175fd8 100644 --- a/application/hub/main/resolver/state/peer/class_PeerStateResolver.php +++ b/application/hub/main/resolver/state/peer/class_PeerStateResolver.php @@ -55,6 +55,7 @@ class PeerStateResolver extends BaseStateResolver implements StateResolver { * @param $packageData Raw package data * @param $socketResource A valid socket resource * @return $stateInstance An instance of the resolved state + * @throws InvalidSocketException If socketResource, even from getSocketResource() is no valid resource * @todo ~30% done */ public static function resolveStateByPackage (ConnectionHelper $helperInstance, array $packageData, $socketResource) { @@ -68,6 +69,12 @@ class PeerStateResolver extends BaseStateResolver implements StateResolver { if (!is_resource($socketResource)) { // No, so get socket resource from helper $socketResource = $helperInstance->getSocketResource(); + + // Still no socket resource? + if (!is_resource($socketResource)) { + // Then abort here with an exception (may happen after socket_shutdown()) + throw new InvalidSocketException(array($helperInstance, $socketResource, 'unknown', 'unknown'), BaseListener::EXCEPTION_INVALID_SOCKET); + } // END - if } // END - if // Get error code from it diff --git a/application/hub/main/states/peer/class_ b/application/hub/main/states/peer/class_ index 83be3f3e3..41820c47a 100644 --- a/application/hub/main/states/peer/class_ +++ b/application/hub/main/states/peer/class_ @@ -32,7 +32,7 @@ class ???PeerState extends BasePeerState implements PeerStateable { parent::__construct(__CLASS__); // Set state name - $this->setStateName('!!!'); + $this->setStateName(BaseRawDataHandler::SOCKET_ERROR_!!!); } /** diff --git a/application/hub/main/states/peer/connected/class_ConnectedPeerState.php b/application/hub/main/states/peer/connected/class_ConnectedPeerState.php index a9ffe2021..09d0221c4 100644 --- a/application/hub/main/states/peer/connected/class_ConnectedPeerState.php +++ b/application/hub/main/states/peer/connected/class_ConnectedPeerState.php @@ -32,7 +32,7 @@ class ConnectedPeerState extends BasePeerState implements PeerStateable { parent::__construct(__CLASS__); // Set state name - $this->setStateName('connected'); + $this->setStateName(BaseRawDataHandler::SOCKET_CONNECTED); } /** diff --git a/application/hub/main/states/peer/errors/class_ConnectionRefusedPeerState.php b/application/hub/main/states/peer/errors/class_ConnectionRefusedPeerState.php index 60ad54cfe..5d3dbc51f 100644 --- a/application/hub/main/states/peer/errors/class_ConnectionRefusedPeerState.php +++ b/application/hub/main/states/peer/errors/class_ConnectionRefusedPeerState.php @@ -32,7 +32,7 @@ class ConnectionRefusedPeerState extends BasePeerState implements PeerStateable parent::__construct(__CLASS__); // Set state name - $this->setStateName('connection_refused'); + $this->setStateName(BaseRawDataHandler::SOCKET_ERROR_CONNECTION_REFUSED); } /** diff --git a/application/hub/main/states/peer/errors/class_ConnectionTimedOutPeerState.php b/application/hub/main/states/peer/errors/class_ConnectionTimedOutPeerState.php index 43855844f..55d982ddc 100644 --- a/application/hub/main/states/peer/errors/class_ConnectionTimedOutPeerState.php +++ b/application/hub/main/states/peer/errors/class_ConnectionTimedOutPeerState.php @@ -32,7 +32,7 @@ class ConnectionTimedOutPeerState extends BasePeerState implements PeerStateable parent::__construct(__CLASS__); // Set state name - $this->setStateName('connection_timed_out'); + $this->setStateName(BaseRawDataHandler::SOCKET_ERROR_CONNECTION_TIMED_OUT); } /** diff --git a/application/hub/main/states/peer/errors/class_NoRouteToHostPeerState.php b/application/hub/main/states/peer/errors/class_NoRouteToHostPeerState.php new file mode 100644 index 000000000..4582bbb8c --- /dev/null +++ b/application/hub/main/states/peer/errors/class_NoRouteToHostPeerState.php @@ -0,0 +1,53 @@ + + * @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 NoRouteToHostPeerState extends BasePeerState implements PeerStateable { + /** + * Protected constructor + * + * @return void + */ + protected function __construct () { + // Call parent constructor + parent::__construct(__CLASS__); + + // Set state name + $this->setStateName(BaseRawDataHandler::SOCKET_ERROR_NO_ROUTE_TO_HOST); + } + + /** + * Creates an instance of this class + * + * @return $stateInstance An instance of a PeerStateable class + */ + public final static function createNoRouteToHostPeerState () { + // Get new instance + $stateInstance = new NoRouteToHostPeerState(); + + // Return the prepared instance + return $stateInstance; + } +} + +// [EOF] +?> diff --git a/application/hub/main/states/peer/errors/class_OperationAlreadyProgressPeerState.php b/application/hub/main/states/peer/errors/class_OperationAlreadyProgressPeerState.php new file mode 100644 index 000000000..d851026e1 --- /dev/null +++ b/application/hub/main/states/peer/errors/class_OperationAlreadyProgressPeerState.php @@ -0,0 +1,53 @@ + + * @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 OperationAlreadyProgressPeerState extends BasePeerState implements PeerStateable { + /** + * Protected constructor + * + * @return void + */ + protected function __construct () { + // Call parent constructor + parent::__construct(__CLASS__); + + // Set state name + $this->setStateName(BaseRawDataHandler::SOCKET_ERROR_OPERATION_ALREADY_PROGRESS); + } + + /** + * Creates an instance of this class + * + * @return $stateInstance An instance of a PeerStateable class + */ + public final static function createOperationAlreadyProgressPeerState () { + // Get new instance + $stateInstance = new OperationAlreadyProgressPeerState(); + + // Return the prepared instance + return $stateInstance; + } +} + +// [EOF] +?> diff --git a/application/hub/main/states/peer/errors/class_TransportEndpointGonePeerState.php b/application/hub/main/states/peer/errors/class_TransportEndpointGonePeerState.php new file mode 100644 index 000000000..02175fb34 --- /dev/null +++ b/application/hub/main/states/peer/errors/class_TransportEndpointGonePeerState.php @@ -0,0 +1,53 @@ + + * @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 TransportEndpointGonePeerState extends BasePeerState implements PeerStateable { + /** + * Protected constructor + * + * @return void + */ + protected function __construct () { + // Call parent constructor + parent::__construct(__CLASS__); + + // Set state name + $this->setStateName(BaseRawDataHandler::SOCKET_ERROR_TRANSPORT_ENDPOINT); + } + + /** + * Creates an instance of this class + * + * @return $stateInstance An instance of a PeerStateable class + */ + public final static function createTransportEndpointGonePeerState () { + // Get new instance + $stateInstance = new TransportEndpointGonePeerState(); + + // Return the prepared instance + return $stateInstance; + } +} + +// [EOF] +?> diff --git a/application/hub/main/states/peer/transport_endpoint/class_TransportEndpointGonePeerState.php b/application/hub/main/states/peer/transport_endpoint/class_TransportEndpointGonePeerState.php index ee17be818..f551ef47b 100644 --- a/application/hub/main/states/peer/transport_endpoint/class_TransportEndpointGonePeerState.php +++ b/application/hub/main/states/peer/transport_endpoint/class_TransportEndpointGonePeerState.php @@ -1,53 +1,3 @@ - * @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 TransportEndpointGonePeerState extends BasePeerState implements PeerStateable { - /** - * Protected constructor - * - * @return void - */ - protected function __construct () { - // Call parent constructor - parent::__construct(__CLASS__); - - // Set state name - $this->setStateName('transport_endpoint'); - } - - /** - * Creates an instance of this class - * - * @return $stateInstance An instance of a PeerStateable class - */ - public final static function createTransportEndpointGonePeerState () { - // Get new instance - $stateInstance = new TransportEndpointGonePeerState(); - - // Return the prepared instance - return $stateInstance; - } -} - -// [EOF] +// @DEPRECATED ?> diff --git a/application/hub/main/statistics/connection/class_ConnectionStatisticsHelper.php b/application/hub/main/statistics/connection/class_ConnectionStatisticsHelper.php index 8ff6d0225..2a448e3e1 100644 --- a/application/hub/main/statistics/connection/class_ConnectionStatisticsHelper.php +++ b/application/hub/main/statistics/connection/class_ConnectionStatisticsHelper.php @@ -57,7 +57,7 @@ class ConnectionStatisticsHelper extends BaseHubSystem { * @return $isExhausted Wether the retry count has been reached */ public static function isConnectRetryExhausted (ConnectionHelper $helperInstance) { - //* DEBUG: */ $helperInstance->debugOutput('[' . __METHOD__ . ':' . __LINE__ . ']: helperInstance=' . $helperInstance->__toString() . ' - ENTERED!'); + //* NOISY-DEBUG: */ $helperInstance->debugOutput('[' . __METHOD__ . ':' . __LINE__ . ']: helperInstance=' . $helperInstance->__toString() . ' - ENTERED!'); // Construct config entry $configEntry = $helperInstance->getProtocol() . '_connect_retry_max'; @@ -71,7 +71,7 @@ class ConnectionStatisticsHelper extends BaseHubSystem { ); // Return it - //* DEBUG: */ $helperInstance->debugOutput('[' . __METHOD__ . ':' . __LINE__ . ']: helperInstance=' . $helperInstance->__toString() . ',isExhausted=' . intval($isExhausted) . ' - EXIT!'); + //* NOISY-DEBUG: */ $helperInstance->debugOutput('[' . __METHOD__ . ':' . __LINE__ . ']: helperInstance=' . $helperInstance->__toString() . ',isExhausted=' . intval($isExhausted) . ' - EXIT!'); return $isExhausted; } @@ -82,15 +82,15 @@ class ConnectionStatisticsHelper extends BaseHubSystem { * @return void */ public static function increaseConnectRetry (ConnectionHelper $helperInstance) { - //* DEBUG: */ $helperInstance->debugOutput('[' . __METHOD__ . ':' . __LINE__ . ']: helperInstance=' . $helperInstance->__toString() . ' - ENTERED!'); + //* NOISY-DEBUG: */ $helperInstance->debugOutput('[' . __METHOD__ . ':' . __LINE__ . ']: helperInstance=' . $helperInstance->__toString() . ' - ENTERED!'); // Is the counter there if (!isset(self::$connectionStatistics[$helperInstance->getProtocol()][$helperInstance->__toString()]['retry_count'])) { // First attempt - //* DEBUG: */ $helperInstance->debugOutput('[' . __METHOD__ . ':' . __LINE__ . ']: helperInstance=' . $helperInstance->__toString() . ' - FIRST!'); + //* NOISY-DEBUG: */ $helperInstance->debugOutput('[' . __METHOD__ . ':' . __LINE__ . ']: helperInstance=' . $helperInstance->__toString() . ' - FIRST!'); self::$connectionStatistics[$helperInstance->getProtocol()][$helperInstance->__toString()]['retry_count'] = 1; } else { // Next attempt - //* DEBUG: */ $helperInstance->debugOutput('[' . __METHOD__ . ':' . __LINE__ . ']: helperInstance=' . $helperInstance->__toString() . ' - INCREMENT!'); + //* NOISY-DEBUG: */ $helperInstance->debugOutput('[' . __METHOD__ . ':' . __LINE__ . ']: helperInstance=' . $helperInstance->__toString() . ' - INCREMENT!'); self::$connectionStatistics[$helperInstance->getProtocol()][$helperInstance->__toString()]['retry_count']++; } diff --git a/application/hub/main/visitor/socket/class_HalfShutdownSocketVisitor.php b/application/hub/main/visitor/socket/class_HalfShutdownSocketVisitor.php new file mode 100644 index 000000000..599cdc59e --- /dev/null +++ b/application/hub/main/visitor/socket/class_HalfShutdownSocketVisitor.php @@ -0,0 +1,87 @@ + + * @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 HalfShutdownSocketVisitor extends BaseVisitor implements Visitor { + /** + * Protected constructor + * + * @return void + */ + protected function __construct () { + // Call parent constructor + parent::__construct(__CLASS__); + + // Set visitor mode + $this->setVisitorMode('socket'); + } + + /** + * Creates an instance of this class + * + * @return $visitorInstance An instance a Visitorable class + */ + public static final function createHalfShutdownSocketVisitor () { + // Get new instance + $visitorInstance = new HalfShutdownSocketVisitor(); + + // Return the prepared instance + return $visitorInstance; + } + + /** + * "Visit" method to do the actual request. Here we want to shutdown the + * attached socket. + * + * @param $helperInstance An instance of a ConnectionHelper class + * @return void + */ + public function visitConnectionHelper (ConnectionHelper $helperInstance) { + // Do we have reached the retry count? + if (ConnectionStatisticsHelper::isConnectRetryExhausted($helperInstance)) { + // Also visit the network package to clear any out-going packages + NetworkPackageFactory::createNetworkPackageInstance()->accept($this); + + // Still shutdown the visitor (look in visitNetworkPackage() for details) + $helperInstance->doShutdown(); + } else { + // We can still move on and retry the connection attempt + ConnectionStatisticsHelper::increaseConnectRetry($helperInstance); + } + } + + /** + * "Visit" method to do the actual request. This method does remove the last + * failed package from the stack because all retries are fully exhausted + * (see visitConnectionHelper() for the logic). + * + * @param $packageInstance An instance of a Deliverable class + * @return void + */ + public function visitNetworkPackage (Deliverable $packageInstance) { + // Just call it back + $packageInstance->removeFirstFailedPackage(); + } +} + +// [EOF] +?> diff --git a/docs/TODOs.txt b/docs/TODOs.txt index 16c006c42..7e88dab52 100644 --- a/docs/TODOs.txt +++ b/docs/TODOs.txt @@ -6,6 +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:300: // @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? @@ -19,8 +20,8 @@ ./application/hub/main/cruncher/mcrypt/class_HubMcryptCruncher.php:108: * @todo Implement this method ./application/hub/main/cruncher/mcrypt/class_HubMcryptCruncher.php:138: * @todo 0% done ./application/hub/main/cruncher/mcrypt/class_HubMcryptCruncher.php:98: // @TODO Implement this method -./application/hub/main/database/wrapper/states/class_PeerStateLookupDatabaseWrapper.php:170: * @todo Unfinished area -./application/hub/main/database/wrapper/states/class_PeerStateLookupDatabaseWrapper.php:212: * @todo Unfinished area +./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/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? @@ -43,14 +44,18 @@ ./application/hub/main/filter/task/chat/class_ChatTaskHandlerInitializerFilter.php:55: * @todo 5% done ./application/hub/main/filter/task/cruncher/class_CruncherTaskHandlerInitializerFilter.php:55: * @todo 5% done ./application/hub/main/filter/task/node/class_NodeTaskHandlerInitializerFilter.php:55: * @todo Maybe some more tasks needs to be added? -./application/hub/main/handler/network/class_BaseRawDataHandler.php:144: * @todo This method will be moved to a better place -./application/hub/main/handler/network/class_BaseRawDataHandler.php:151: // @TODO Numeric or alpha-numeric index? +./application/hub/main/handler/network/class_BaseRawDataHandler.php:149: * @todo This method will be moved to a better place +./application/hub/main/handler/network/class_BaseRawDataHandler.php:156: // @TODO Numeric or alpha-numeric index? ./application/hub/main/handler/network/udp/class_UdpRawDataHandler.php:58: * @todo 0% ./application/hub/main/handler/tasks/class_TaskHandler.php:140: // @TODO Messurement can be added around this call +./application/hub/main/helper/connection/class_BaseConnectionHelper.php:182: // @TODO Move this to the socket error handler +./application/hub/main/helper/connection/class_BaseConnectionHelper.php:210: * @todo Rewrite the while() loop to a iterator to not let the software stay very long here ./application/hub/main/helper/connection/tcp/class_TcpConnectionHelper.php:10: * @todo Find an interface for hub helper -./application/hub/main/helper/connection/tcp/class_TcpConnectionHelper.php:149: * @todo We may want to implement a filter for ease notification of other objects like our pool +./application/hub/main/helper/connection/tcp/class_TcpConnectionHelper.php:143: * @todo We may want to implement a filter for ease notification of other objects like our pool +./application/hub/main/helper/connection/tcp/class_TcpConnectionHelper.php:47: * @todo $errorCode/-Message are now in handleSocketError()'s call-back methods +./application/hub/main/helper/connection/tcp/class_TcpConnectionHelper.php:84: // @TODO The whole resolving part should be moved out and made more configurable ./application/hub/main/helper/connection/udp/class_UdpConnectionHelper.php:10: * @todo Find an interface for hub helper -./application/hub/main/helper/connection/udp/class_UdpConnectionHelper.php:54: * @todo We may want to implement a filter for ease notification of other objects like our pool +./application/hub/main/helper/connection/udp/class_UdpConnectionHelper.php:54: * @todo Implement a filter for ease notification of other objects like the pool ./application/hub/main/helper/hub/announcement/class_HubDescriptorHelper.php:10: * @todo Find an interface for hub helper ./application/hub/main/helper/hub/announcement/class_HubDescriptorHelper.php:61: * @todo Rewrite the ->renderXmlContent() call to no arguments ./application/hub/main/helper/hub/connection/class_HubSelfConnectHelper.php:10: * @todo Find an interface for hub helper @@ -64,12 +69,14 @@ ./application/hub/main/iterator/pool/monitor/class_MonitorPoolIterator.php:11: * @todo latency-based iteration or similar approaches ./application/hub/main/iterator/pool/tasks/class_TaskPoolIterator.php:10: * @todo This current implementation is not recommended, use a ./application/hub/main/iterator/pool/tasks/class_TaskPoolIterator.php:11: * @todo latency-based iteration or similar approaches -./application/hub/main/listener/udp/class_UdpListener.php:139: * @todo ~50% done +./application/hub/main/listener/udp/class_UdpListener.php:151: * @todo ~50% done ./application/hub/main/lists/class_BaseList.php:264: // @TODO Extend this somehow? ./application/hub/main/lists/groups/class_ListGroupList.php:52: * @todo 0% done -./application/hub/main/lists/hub/class_HubList.php:56: * @todo0% done -./application/hub/main/lists/recipient/class_RecipientList.php:59: * @todo0% done -./application/hub/main/lists/tasks/class_TaskList.php:55: * @todo0% done +./application/hub/main/lists/groups/class_ListGroupList.php:62: * @todo 0% done +./application/hub/main/lists/hub/class_HubList.php:56: * @todo 0% done +./application/hub/main/lists/query/local/class_LocalQueryList.php:68: * @todo 0% done +./application/hub/main/lists/recipient/class_RecipientList.php:59: * @todo 0% done +./application/hub/main/lists/tasks/class_TaskList.php:55: * @todo 0% done ./application/hub/main/nodes/boot/class_HubBootNode.php:119: // @TODO Add some filters here ./application/hub/main/nodes/boot/class_HubBootNode.php:58: * @todo add some more special bootstrap things for this boot node ./application/hub/main/nodes/boot/class_HubBootNode.php:99: * @todo Unfinished method @@ -85,34 +92,36 @@ ./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:210: * @todo $helperInstance is unused -./application/hub/main/package/class_NetworkPackage.php:214: // @TODO crc32() is not very strong, but it needs to be fast +./application/hub/main/package/class_NetworkPackage.php:218: * @todo $helperInstance is unused +./application/hub/main/package/class_NetworkPackage.php:222: // @TODO crc32() is very weak, but it needs to be fast ./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:336: // @TODO We may want to do somthing more here? -./application/hub/main/package/class_NetworkPackage.php:435: // @TODO Add some logging here -./application/hub/main/package/class_NetworkPackage.php:461: // @TODO Add some logging here -./application/hub/main/package/class_NetworkPackage.php:559: // @TODO Add some logging here -./application/hub/main/package/class_NetworkPackage.php:637: // @TODO Add some content here -./application/hub/main/package/fragmenter/class_PackageFragmenter.php:426: * @todo $helperInstance is unused -./application/hub/main/pools/peer/class_DefaultPeerPool.php:149: // @TODO Check for IP +./application/hub/main/package/class_NetworkPackage.php:386: // @TODO We may want to do somthing more here? +./application/hub/main/package/class_NetworkPackage.php:486: // @TODO Add some logging here +./application/hub/main/package/class_NetworkPackage.php:512: // @TODO Add some logging here +./application/hub/main/package/class_NetworkPackage.php:616: // @TODO Add some logging here +./application/hub/main/package/class_NetworkPackage.php:695: // @TODO Add some content here +./application/hub/main/package/class_NetworkPackage.php:745: * @todo This may be enchanced for outgoing packages? +./application/hub/main/package/fragmenter/class_PackageFragmenter.php:427: * @todo $helperInstance is unused +./application/hub/main/pools/peer/class_DefaultPeerPool.php:160: // @TODO Check for IP ./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 ./application/hub/main/producer/cruncher/work_units/class_CruncherTestUnitProducer.php:79: * @todo ~60% done ./application/hub/main/producer/cruncher/work_units/class_CruncherTestUnitProducer.php:99: // @TODO Unfinished work here -./application/hub/main/resolver/state/peer/class_PeerStateResolver.php:58: * @todo ~30% done -./application/hub/main/resolver/state/peer/class_PeerStateResolver.php:79: // @TODO On some systems it is 134, on some 107? +./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/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 +./application/hub/main/tasks/chat/class_ChatTelnetListenerTask.php:64: * @todo 0% ./application/hub/main/tasks/cruncher/class_CruncherKeyProducerTask.php:53: * @todo Maybe visit some sub-objects ./application/hub/main/tasks/cruncher/class_CruncherTestUnitProducerTask.php:53: * @todo Maybe visit some sub-objects ./application/hub/main/tasks/cruncher/class_CruncherWorkUnitFetcherTask.php:54: * @todo Maybe visit some sub-objects ./application/hub/main/tasks/hub/announcement/class_HubSelfAnnouncementTask.php:53: * @todo 0% ./application/hub/main/tasks/hub/class_HubSelfConnectTask.php:53: * @todo 0% -./application/hub/main/tasks/hub/class_HubSocketListenerTask.php:62: // @TODO Do we need to visit this task? $visitorInstance->visitTask($this); -./application/hub/main/tasks/hub/class_HubSocketListenerTask.php:69: * @todo 0% done +./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/ping/class_HubPingTask.php:73: * @todo 0% done ./application/hub/main/tasks/hub/update/class_HubUpdateCheckTask.php:53: * @todo 0% ./application/hub/main/template/announcement/class_XmlAnnouncementTemplateEngine.php:10: * @todo This template engine does not make use of setTemplateType() @@ -131,10 +140,10 @@ ./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:1263: * @todo Write a logging mechanism for productive mode -./inc/classes/main/class_BaseFrameworkSystem.php:1277: // @TODO Finish this part! +./inc/classes/main/class_BaseFrameworkSystem.php:1294: * @todo Write a logging mechanism for productive mode +./inc/classes/main/class_BaseFrameworkSystem.php:1308: // @TODO Finish this part! ./inc/classes/main/class_BaseFrameworkSystem.php:195: // @todo Try to clean these constants up -./inc/classes/main/class_BaseFrameworkSystem.php:434: * @todo SearchableResult and UpdateableResult shall have a super interface to use here +./inc/classes/main/class_BaseFrameworkSystem.php:458: * @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 ./inc/classes/main/commands/web/class_WebProblemCommand.php:58: * @todo 0% done ./inc/classes/main/commands/web/class_WebStatusCommand.php:58: * @todo 0% done @@ -223,14 +232,14 @@ ./inc/classes/main/user/member/class_Member.php:84: * @todo Add more ways over creating user classes ./inc/classes/middleware/debug/class_DebugMiddleware.php:112: // @TODO Initialization phase ./inc/classes.php:10: * @todo We should minimize these includes -./inc/config/class_FrameworkConfiguration.php:172: * @todo We have to add some more entries from $_SERVER here +./inc/config/class_FrameworkConfiguration.php:175: * @todo We have to add some more entries from $_SERVER here ./inc/database.php:11: * @todo We should minimize these includes ./inc/database.php:51:// @TODO Rewrite this ./inc/hooks.php:11: * @todo We should minimize these includes ./inc/hooks.php:28:// @TODO This makes the core depending on the SPL. But it should be installed anyway. ./inc/includes.php:11: * @todo We should minimize these includes ./inc/includes.php:38:// @TODO Find a nicer OOP-ed way for this -./inc/loader/class_ClassLoader.php:264: /* @todo: Do not die here. */ +./inc/loader/class_ClassLoader.php:273: /* @todo: Do not die here. */ ./inc/output.php:11: * @todo We should minimize these includes ./inc/selector.php:11: * @todo We should minimize these includes ./index.php:57: * @todo This method is old code and needs heavy rewrite and should be moved to ApplicationHelper @@ -273,8 +282,10 @@ ./application/hub/main/lookup/peer/class_PeerStateLookupTable.php:2:// @DEPRECATED ./application/hub/main/nodes/class_BaseHubNode.php:53: * @deprecated ./application/hub/main/resolver/state/network/class_NetworkStateResolver.php:2:// @DEPRECATED +./application/hub/main/states/hub/class_BaseHubState.php:2:// @DEPRECATED ./application/hub/main/states/peer/new/class_NewConnectionNodeState.php:2:// @DEPRECATED ./application/hub/main/states/peer/new/class_NewConnectionPeerState.php:2:// @DEPRECATED +./application/hub/main/states/peer/transport_endpoint/class_TransportEndpointGonePeerState.php:2:// @DEPRECATED ./application/hub/main/streams/package/input/class_PackageInputStream.php:2:// @DEPRECATED ./application/hub/main/streams/package/output/class_PackageOutputStream.php:2:// @DEPRECATED ./application/hub/main/template/announcement/class_AnnouncementTemplateEngine.php:2:// @DEPRECATED @@ -288,6 +299,7 @@ ./inc/classes/exceptions/main/class_ClassNotFoundException.php:2:// @DEPRECATED ./inc/classes/exceptions/main/class_ConfigEntryNotFoundException.php:2:// @DEPRECATED ./inc/classes/exceptions/main/class_MissingMethodException.php:14: * @deprecated Please do no longer use this exception +./inc/classes/exceptions/state/class_InvalidStateException.php:2:// @DEPRECATED ./inc/classes/interfaces/helper/class_HelpableLogin.php:2:// @DEPRECATED ./inc/classes/interfaces/helper/class_HelpableTemplate.php:2:// @DEPRECATED ./inc/classes/main/streams/input/class_BaseInputStream.php:2:// @DEPRECATED -- 2.39.5