X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=application%2Fhub%2Fclasses%2Fdiscovery%2Frecipient%2Fsocket%2Fclass_PackageSocketDiscovery.php;fp=application%2Fhub%2Fclasses%2Fdiscovery%2Frecipient%2Fsocket%2Fclass_PackageSocketDiscovery.php;h=698c44cb186f296907f0061fd88d76f2d76d0f54;hb=f3400989268a1994de44909e5d968cabf72de5b1;hp=0000000000000000000000000000000000000000;hpb=73aff29b9bc78031853b0b8c0fe0a8e04f66ac29;p=hub.git diff --git a/application/hub/classes/discovery/recipient/socket/class_PackageSocketDiscovery.php b/application/hub/classes/discovery/recipient/socket/class_PackageSocketDiscovery.php new file mode 100644 index 000000000..698c44cb1 --- /dev/null +++ b/application/hub/classes/discovery/recipient/socket/class_PackageSocketDiscovery.php @@ -0,0 +1,206 @@ + + * @version 0.0.0 + * @copyright Copyright (c) 2007, 2008 Roland Haeder, 2009 - 2015 Hub Developer Team + * @license GNU GPL 3.0 or any newer version + * @link http://www.shipsimu.org + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +class PackageSocketDiscovery extends BaseRecipientDiscovery implements DiscoverableSocket, Registerable { + /** + * Protected constructor + * + * @return void + */ + protected function __construct () { + // Call parent constructor + parent::__construct(__CLASS__); + } + + /** + * Create an instance of this class + * + * @return $discoveryInstance An instance of this discovery class + */ + public static final function createPackageSocketDiscovery () { + // Get an instance of this class + $discoveryInstance = new PackageSocketDiscovery(); + + // Output debug message + self::createDebugInstance(__CLASS__)->debugOutput('SOCKET-DISCOVERY[' . __METHOD__ . ':' . __LINE__ . ']: Initialized.'); + + // Return the prepared instance + return $discoveryInstance; + } + + /** + * Tries to dicover the right listener instance + * + * @param $protocolInstance An instance of a HandleableProtocol class + * @param $packageData Raw package data + * @return $listenerInstance An instance of a Listenable instance or null + */ + public function discoverListenerInstance (HandleableProtocol $protocolInstance, array $packageData) { + // Debug message + //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('SOCKET-DISCOVERY[' . __METHOD__ . ':' . __LINE__ . ']: protocolInstance=' . $protocolInstance->__toString() . ' - CALLED!'); + + /* + * Get the listener pool instance, we need to lookup the matching + * listener->poolInstance chain there. + */ + $poolInstance = NodeObjectFactory::createNodeInstance()->getListenerPoolInstance(); + + // Init listener instance + $listenerInstance = NULL; + + // Get handler name + $protocolName = $protocolInstance->getProtocolName(); + + // Debug message + //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('SOCKET-DISCOVERY[' . __METHOD__ . ':' . __LINE__ . ']: protocolName=' . $protocolName . ',poolEntriesInstance=' . $poolInstance->getPoolEntriesInstance()->__toString()); + + /* + * Now we need to choose again. It is whether we are speaking with a hub + * or with a client. So just handle it over to all listeners in this + * pool. + */ + foreach ($poolInstance->getPoolEntriesInstance()->getArrayFromList($protocolName) as $listenerInstance) { + // Debug output + //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('SOCKET-DISCOVERY[' . __METHOD__ . ':' . __LINE__ . ']: protocolName=' . $protocolName . ',listenerInstance[' . gettype($listenerInstance) . ']=' . $listenerInstance); + + // Make sure the instance is valid + assert($listenerInstance instanceof Listenable); + + // Does the listener want that package? + if ($listenerInstance->ifListenerAcceptsPackageData($packageData)) { + // This listener likes our package data, so abort here + //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('SOCKET-DISCOVERY[' . __METHOD__ . ':' . __LINE__ . ']: Listener is accepting package data.'); + break; + } // END - if + + // Debug message + //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('SOCKET-DISCOVERY[' . __METHOD__ . ':' . __LINE__ . ']: Listener is NOT accepting package data.'); + } // END - foreach + + // Debug message + //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('SOCKET-DISCOVERY[' . __METHOD__ . ':' . __LINE__ . ']: listenerInstance=' . $listenerInstance->__toString()); + + // Return it + return $listenerInstance; + } + + /** + * Tries to discover the right socket for given package data and returns a + * matching socket resource for that protocol. + * + * @param $packageData Raw package data array + * @param $connectionType Type of connection, can be 'incoming' or 'outgoing', *NEVER* 'server'! + * @return $socketResource A valid socket resource or FALSE if an error occured + * @throws NoListGroupException If the procol group is not found in peer list + * @throws NullPointerException If listenerInstance is NULL + * @throws InvalidUnlException If the provided UNL cannot be validated by the protocol handler + */ + public function discoverSocket (array $packageData, $connectionType) { + // Debug message + //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('[' . __METHOD__ . ':' . __LINE__ . ']: connectionType=' . $connectionType . ' - CALLED!'); + + // Assert on type and recipient + assert($connectionType != BaseConnectionHelper::CONNECTION_TYPE_SERVER); + assert(isset($packageData[NetworkPackage::PACKAGE_DATA_RECIPIENT])); + + // Determine protocol instance + $protocolInstance = ProtocolDiscovery::determineProtocolByPackageData($packageData); + + // Is it valid? + assert($protocolInstance instanceof HandleableProtocol); + + // Does the UNL validate? + if (!$protocolInstance->isValidUniversalNodeLocatorByPackageData($packageData)) { + // Not valid, throw exception + throw new InvalidUnlException(array($this, $protocolInstance, $packageData), BaseHubSystem::EXCEPTION_INVALID_UNL); + } // END - if + + // Get the listener instance + $listenerInstance = $this->discoverListenerInstance($protocolInstance, $packageData); + + // If there is no listener who wants to have that package, we simply drop it here + if (is_null($listenerInstance)) { + // Abort with no resource + throw new NullPointerException($this, self::EXCEPTION_IS_NULL_POINTER); + } // END - if + + // Debug message + //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('protocolInstance=' . $protocolInstance . ',packageData=' . print_r($packageData, TRUE)); + + /* + * Now we have the listener instance, we can determine the right + * resource to continue. The first step is to get the attached pool + * instance and pass over the whole package data to get the right + * socket. + */ + $socketResource = $listenerInstance->getPoolInstance()->getSocketFromPackageData($packageData, $connectionType); + + // Debug message + // @TODO FIXME: I don't like these abuse of variables, better strict types + if (is_resource($socketResource)) { + //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('socketResource[' . gettype($socketResource) . ']=' . $socketResource . ',error=' . socket_strerror(socket_last_error($socketResource)) . ',packageData=' . print_r($packageData, TRUE)); + } else { + //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('socketResource[' . gettype($socketResource) . ']=' . $socketResource . ',packageData=' . print_r($packageData, TRUE)); + } + + // Is it FALSE, the recipient isn't known to us and we have no connection to it + if (($socketResource === FALSE) || (!is_resource($socketResource)) || (socket_last_error($socketResource) > 0)) { + // Try to create a new socket resource + try { + // Possibly noisy debug message + //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('SOCKET-DISCOVERY[' . __METHOD__ . ':' . __LINE__ . ']: Trying to establish a ' . strtoupper($protocolInstance) . ' connection to ' . $packageData[NetworkPackage::PACKAGE_DATA_RECIPIENT] . ' ...'); + + // Get a socket resource from our factory (if succeeded) + $socketResource = SocketFactory::createSocketFromPackageData($packageData, $protocolInstance); + } catch (SocketConnectionException $e) { + // The connection fails of being established, so log it away + self::createDebugInstance(__CLASS__)->debugOutput('SOCKET-DISCOVERY[' . __METHOD__ . ':' . __LINE__ . ']: Caught ' . $e->__toString() . ',message=' . $e->getMessage()); + } + } // END - if + + // Try to resolve the socket resource + try { + // Get the helper instance from registry + $helperInstance = Registry::getRegistry()->getInstance('connection'); + + // Possibly noisy debug message + //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('SOCKET-DISCOVERY[' . __METHOD__ . ':' . __LINE__ . ']: 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); + } catch (InvalidSocketException $e) { + // This cannot be fixed, so log it away + self::createDebugInstance(__CLASS__)->debugOutput('SOCKET-DISCOVERY[' . __METHOD__ . ':' . __LINE__ . ']: Cannot discover socket resource for recipient ' . $packageData[NetworkPackage::PACKAGE_DATA_RECIPIENT] . ': ' . $e->getMessage()); + + // Make any failed attempts to 'FALSE' + $socketResource = FALSE; + } + + // And return it + //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('SOCKET-DISCOVERY[' . __METHOD__ . ':' . __LINE__ . ']: socketResource=' . $socketResource . ',packageData=' . print_r($packageData, TRUE)); + return $socketResource; + } +} + +// [EOF] +?>