From 5da5340791e28b37799dd9bedf850aa2d6ae1875 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Roland=20H=C3=A4der?= Date: Mon, 29 May 2017 17:56:08 +0200 Subject: [PATCH] More rewrites: - rewrote more parts towards SocketContainer/StorableStocket class/interface - still UdpListener is half-finished - added missing namespace - imported BaseNodeHelper MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Signed-off-by: Roland Häder --- .../socket/class_SocketContainer.php | 189 ++++++++++++++++-- .../socket/class_PackageSocketDiscovery.php | 4 +- .../factories/socket/class_SocketFactory.php | 108 ++++++++++ ...class_NodeTaskHandlerInitializerFilter.php | 6 +- .../class_NodeAnnouncementHelper.php | 1 + .../node/answer/class_BaseHubAnswerHelper.php | 6 + application/hub/classes/helper/node/class_ | 1 + .../helper/node/class_BaseNodeHelper.php | 4 +- .../class_NodeSelfConnectHelper.php | 1 + .../class_NodeRequestNodeListHelper.php | 1 + .../classes/listener/class_BaseListener.php | 140 ++++--------- .../socket/class_SocketFileListener.php | 2 +- .../listener/tcp/class_TcpListener.php | 6 +- .../listener/udp/class_UdpListener.php | 7 +- .../lists/pool/class_PoolEntriesList.php | 4 +- .../hub/classes/pools/class_BasePool.php | 60 +++--- application/hub/config.php | 8 +- .../container/socket/class_StorableSocket.php | 29 +++ .../peer_states/class_LookupablePeerState.php | 7 +- .../hub/interfaces/pool/class_Poolable.php | 19 +- core | 2 +- 21 files changed, 436 insertions(+), 169 deletions(-) diff --git a/application/hub/classes/container/socket/class_SocketContainer.php b/application/hub/classes/container/socket/class_SocketContainer.php index 04c7b89e2..f718d9ce9 100644 --- a/application/hub/classes/container/socket/class_SocketContainer.php +++ b/application/hub/classes/container/socket/class_SocketContainer.php @@ -4,6 +4,7 @@ namespace Hub\Container\Socket; // Import application-specific stuff use Hub\Handler\Network\RawData\BaseRawDataHandler; +use Hub\Factory\Socket\SocketFactory; use Hub\Helper\Connection\BaseConnectionHelper; use Hub\Information\ShareableInfo; use Hub\Listener\BaseListener; @@ -61,6 +62,11 @@ class SocketContainer extends BaseContainer implements StorableSocket, Visitable */ private $connectionTypes = array(); + /** + * Timeout in usec for socket_select() + */ + private $socketSelectTimeout = 0; + /** * Protected constructor * @@ -70,6 +76,9 @@ class SocketContainer extends BaseContainer implements StorableSocket, Visitable // Call parent constructor parent::__construct(__CLASS__); + // Init value + $this->socketSelectTimeout = $this->getConfigInstance()->getConfigEntry('socket_select_timeout_usec'); + // Init array of connection types $this->connectionTypes = array( StorableSocket::CONNECTION_TYPE_INCOMING, @@ -421,7 +430,7 @@ class SocketContainer extends BaseContainer implements StorableSocket, Visitable } // END - if // Tries to set option - $result = socket_set_option($this->getSocketResource(), SOL_SOCKET, SO_REUSEADDR, 1); + $result = $this->setSocketOption(SOL_SOCKET, SO_REUSEADDR, 1); // Return result return $result; @@ -466,6 +475,144 @@ class SocketContainer extends BaseContainer implements StorableSocket, Visitable $this->markConnectionShuttedDown(); } + /** + * Checks whether the given connection type is valid + * + * @param $connectionType Type of connection, can be 'incoming', 'outgoing' or 'server' + * @return $isValid Whether the provided connection type is valid + */ + public function isValidConnectionType ($connectionType) { + // Is it valid? + $isValid = in_array($connectionType, $this->connectionTypes, TRUE); + + // Return result + return $isValid; + } + + /** + * Calls socket_select() on stored socket resource + * + * @return $socketInstance An instance of a StorableSocket class + * @throws InvalidSocketException If stored socket is invalid + */ + public function acceptNewIncomingSocket () { + // Should be valid socket + if (!$this->isValidSocket()) { + // Throw exception + throw new InvalidSocketException(array($this, $this->getSocketResource()), self::EXCEPTION_INVALID_SOCKET); + } // END - if + + // Init all arrays, at least readers + $readers = array($this->getSocketResource()); + $writers = array(); + $excepts = array(); + + // Check if we have some peers left + $left = socket_select( + $readers, + $writers, + $excepts, + 0, + $this->socketSelectTimeout + ); + + // Some new peers found? + if ($left < 1) { + // Debug message + //* EXTREME-NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(strtoupper($this->getSocketProtocol()) . '-SOCKET: left=' . $left . ',serverSocket=' . $this->getSocketResource() . ',readers=' . print_r($readers, true)); + + // Nothing new found + return NULL; + } // END - if + + // Debug message + //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(strtoupper($this->getSocketProtocol()) . '-SOCKET: serverSocket=' . $this->getSocketResource() . ',readers=' . print_r($readers, true)); + + // Do we have changed peers? + if (!in_array($this->getSocketResource(), $readers)) { + // Abort here + return NULL; + } // END - if + + /* + * Then accept it, if this socket is set to non-blocking IO and the + * connection is NOT sending any data, socket_read() may throw + * error 11 (Resource temporary unavailable). This really nasty + * because if you have blocking IO socket_read() will wait and wait + * and wait ... + */ + $socketResource = socket_accept($this->getSocketResource()); + + // Debug message + //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(strtoupper($this->getSocketProtocol()) . '-SOCKET: socketResource=' . $socketResource . ',serverSocket=' .$this->getSocketResource()); + + // Create socket instance from it + $socketInstance = SocketFactory::createIncomingSocketInstance($socketResource, $this->getSocketProtocol()); + + // Return accepted socket instance + return $socketInstance; + } + + /** + * Tries to identify the socket peer by calling socket_getpeer() and stores + * it in package data array. + * + * @return $result Whether identifying socket peer was successfull + */ + public function identifySocketPeer () { + // Init peer address (IP)/port + $peerAddress = '0.0.0.0'; + $peerPort = '0'; + + // Call other method + $result = $this->getSocketPeerName($peerAddress, $peerPort); + + // Valid? + if ($result === TRUE) { + // Get package data + $packageData = $this->getPackageData(); + + // Set both + $packageData[StorableSocket::SOCKET_ARRAY_INDEX_ADDRESS] = $peerAddress; + $packageData[StorableSocket::SOCKET_ARRAY_INDEX_PORT] = $peerPort; + + // Set it back + $this->setPackageData($packageData); + } // END - if + + // Return result + return $result; + } + + /** + * Tries to set socket timeout option + * + * @return $result Whether the option has been set + */ + public function setSocketTimeoutOptions () { + // Array for timeout settings + $options = array( + // Seconds + 'sec' => $this->getConfigInstance()->getConfigEntry($this->getSocketProtocol() . '_socket_accept_wait_sec'), + // Milliseconds + 'usec' => $this->getConfigInstance()->getConfigEntry($this->getSocketProtocol() . '_socket_accept_wait_usec') + ); + + // Call inner method + $result = $this->setSocketOption(SOL_SOCKET, SO_RCVTIMEO, $options); + + // Return result + return $result; + } + + /** + * Tries to enable out-of-band (OOB) data + * + * @return $result Whether OOB has been enabled + */ + public function enableSocketOutOfBandData () { + } + /** * Handles socket error for given socket resource and peer data. This method * validates socket resource stored in given container if it is a valid @@ -816,6 +963,32 @@ class SocketContainer extends BaseContainer implements StorableSocket, Visitable $this->socketProtocol = $socketProtocol; } + /** + * Tries to set given socket option + * + * @param $level Level to set, e.g. use SOL_SOCKET + * @param $optionName Option name to set + * @param $optionValue Option value to set + * @return $result Whether calling socket_set_option() was successfull + * @throws InvalidSocketException If stored socket is invalid + */ + private function setSocketOption ($level, $optionName, $optionValue) { + // Trace message + /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('%s-SOCKET: level=%s,optionName=%s,optionValue[%s]=%s - CALLED!', strtoupper($this->getSocketProtocol()), $level, $optionName, gettype($optionValue), $optionValue)); + + // Should be valid socket + if (!$this->isValidSocket()) { + // Throw exception + throw new InvalidSocketException(array($this, $this->getSocketResource()), self::EXCEPTION_INVALID_SOCKET); + } // END - if + + // Set it + $result = socket_set_option($this->getSocketResource(), $level, $optionName, $optionValue); + + // Return result + return $result; + } + /** * Clears last socket error * @@ -843,18 +1016,4 @@ class SocketContainer extends BaseContainer implements StorableSocket, Visitable /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(strtoupper($this->getSocketProtocol()) . '-SOCKET: Error cleared - EXIT!'); } - /** - * Checks whether the given connection type is valid - * - * @param $connectionType Type of connection, can be 'incoming', 'outgoing' or 'server' - * @return $isValid Whether the provided connection type is valid - */ - public function isValidConnectionType ($connectionType) { - // Is it valid? - $isValid = in_array($connectionType, $this->connectionTypes, TRUE); - - // Return result - return $isValid; - } - } diff --git a/application/hub/classes/discovery/recipient/socket/class_PackageSocketDiscovery.php b/application/hub/classes/discovery/recipient/socket/class_PackageSocketDiscovery.php index 177c8d821..ed2fd132f 100644 --- a/application/hub/classes/discovery/recipient/socket/class_PackageSocketDiscovery.php +++ b/application/hub/classes/discovery/recipient/socket/class_PackageSocketDiscovery.php @@ -90,14 +90,14 @@ class PackageSocketDiscovery extends BaseRecipientDiscovery implements Discovera $protocolName = $protocolInstance->getProtocolName(); // Debug message - //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('SOCKET-DISCOVERY: protocolName=' . $protocolName . ',poolEntriesInstance=' . $poolInstance->getPoolEntriesInstance()->__toString()); + //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('SOCKET-DISCOVERY: protocolName=' . $protocolName); /* * 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) { + foreach ($poolInstance->getArrayFromList($protocolName) as $listenerInstance) { // Debug output //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('SOCKET-DISCOVERY: protocolName=' . $protocolName . ',listenerInstance[' . gettype($listenerInstance) . ']=' . $listenerInstance); diff --git a/application/hub/classes/factories/socket/class_SocketFactory.php b/application/hub/classes/factories/socket/class_SocketFactory.php index cae3daeef..1fb67772c 100644 --- a/application/hub/classes/factories/socket/class_SocketFactory.php +++ b/application/hub/classes/factories/socket/class_SocketFactory.php @@ -8,6 +8,7 @@ use Hub\Handler\Protocol\HandleableProtocol; use Hub\Listener\BaseListener; use Hub\Listener\Listenable; use Hub\Network\Package\NetworkPackage; +use Hub\Pool\Poolable; // Import framework stuff use CoreFramework\Bootstrap\FrameworkBootstrap; @@ -16,6 +17,9 @@ use CoreFramework\Factory\ObjectFactory; use CoreFramework\Registry\Registry; use CoreFramework\Socket\InvalidSocketException; +// Import SPL stuff +use \LogicException; + /** * A socket factory class * @@ -364,4 +368,108 @@ class SocketFactory extends ObjectFactory { return $socketInstance; } + /** + * Creates a socket from given pool instance by calling socket_accept() on + * the pooled listening socket. If socket_select() has found no changes, + * NULL is being returned + * + * @param $poolInstance An instance of a Poolable class + * @param $socketInstance The listening instance of a StorableSocket + * @return $socketInstance A new instance of a StorableSocket or NULL if no changes has been detected. + * @throws LogicException If the current instance is not valid + */ + public static final function createNextAcceptedSocketFromPool (Poolable $poolInstance, StorableSocket $socketInstance) { + // Is the an iterator instance? + if (!Registry::getRegistry()->instanceExists('pool_iterator')) { + // Create iterator instance + $iteratorInstance = $poolInstance->createListIteratorInstance('pool'); + + // Now store it in registry + Registry::getRegistry()->addInstance('pool_iterator', $iteratorInstance); + } else { + // Get iterator from registry + $iteratorInstance = Registry::getRegistry()->getInstance('pool_iterator'); + } + + // Is it valid? + if (!$iteratorInstance->valid()) { + // Try to rewind it + $iteratorInstance->rewind(); + } // END - if + + // Get current socket instance + $current = $iteratorInstance->current(); + + // Make sure it is valid + if (!is_array($current)) { + // Opps, should not happen + throw new LogicException(sprintf('current[]=%s is not an array.', gettype($current))); + } elseif (!isset($current[Poolable::SOCKET_ARRAY_INSTANCE])) { + // Not set + throw new LogicException(sprintf('current[%s] is not set.', Poolable::SOCKET_ARRAY_INSTANCE)); + } elseif (!isset($current[Poolable::SOCKET_ARRAY_CONN_TYPE])) { + // Not set + throw new LogicException(sprintf('current[%s] is not set.', Poolable::SOCKET_ARRAY_CONN_TYPE)); + } elseif ($current[Poolable::SOCKET_ARRAY_CONN_TYPE] != StorableSocket::CONNECTION_TYPE_SERVER) { + // Not expected type + throw new LogicException(sprintf('current[%s]=%s is not expected: %s', Poolable::SOCKET_ARRAY_CONN_TYPE, $current[Poolable::SOCKET_ARRAY_CONN_TYPE], StorableSocket::CONNECTION_TYPE_SERVER)); + } + + // Try to accept a new (incoming) socket from current listener instance + $acceptedSocketInstance = $current[Poolable::SOCKET_ARRAY_INSTANCE]->acceptNewIncomingSocket(); + + // Return found socket instance + return $acceptedSocketInstance; + } + + /** + * Creates a StorableSocket instance from given socket resource + * + * @param $socketResource Valid socket resource from calling socket_accept() + * @param $socketProtocol Protcol of socket (e.g. 'tcp', 'udp', see StorableSocket interface for valid values + * @return $socketInstance An instance of a StorableSocket class + */ + public static final function createIncomingSocketInstance ($socketResource, $socketProtocol) { + // Fake package data array (must be set later on) + $packageData = array( + StorableSocket::SOCKET_ARRAY_INDEX_ADDRESS => 'invalid', + StorableSocket::SOCKET_ARRAY_INDEX_PORT => '0', + ); + + // Create socket instance + $socketInstance = self::createObjectByConfiguredName('socket_container_class', array($socketResource, $socketProtocol, $packageData, NULL)); + + // Is the socket resource valid? + if (!$socketInstance->isValidSocket()) { + // Something bad happened + throw new InvalidSocketException(array($listenerInstance, $socketInstance), self::EXCEPTION_INVALID_SOCKET); + } // END - if + + // Try to identify socket peer + if (!$socketInstance->identifySocketPeer()) { + // Handle this socket error with a faked recipientData array + $socketInstance->handleSocketEror(__METHOD__, __LINE__, array('0.0.0.0', '0')); + } // END - if + + // Set timeout to configured seconds + if (!$socketinstance->setSocketTimeoutOptions()) { + // Handle this socket error with a faked recipientData array + $socketInstance->handleSocketEror(__METHOD__, __LINE__, array('0.0.0.0', '0')); + } // END - if + + // Enable SO_OOBINLINE + if (!$socketInstance->enableSocketOutOfBandData()) { + // Handle this socket error with a faked recipientData array + $socketInstance->handleSocketEror(__METHOD__, __LINE__, array('0.0.0.0', '0')); + } // END - if + + // Set non-blocking + if (!$socketInstance->enableSocketNonBlocking()) { + // Handle this socket error with a faked recipientData array + $socketInstance->handleSocketError(__METHOD__, __LINE__, array('0.0.0.0', '0')); + } // END - if + + // Return found socket instance + return $socketInstance; + } } diff --git a/application/hub/classes/filter/task/node/class_NodeTaskHandlerInitializerFilter.php b/application/hub/classes/filter/task/node/class_NodeTaskHandlerInitializerFilter.php index 5d60f98bb..d55ba25cc 100644 --- a/application/hub/classes/filter/task/node/class_NodeTaskHandlerInitializerFilter.php +++ b/application/hub/classes/filter/task/node/class_NodeTaskHandlerInitializerFilter.php @@ -150,7 +150,7 @@ class NodeTaskHandlerInitializerFilter extends BaseNodeFilter implements Filtera // Register it $handlerInstance->registerTask('update_check', $taskInstance); - // Get the list instance here + // Get list instance here $listInstance = $nodeInstance->getListenerPoolInstance()->getPoolEntriesInstance(); // Prepare a ping task @@ -166,7 +166,5 @@ class NodeTaskHandlerInitializerFilter extends BaseNodeFilter implements Filtera */ $nodeInstance->addExtraTasks($handlerInstance); } -} -// [EOF] -?> +} diff --git a/application/hub/classes/helper/node/announcement/class_NodeAnnouncementHelper.php b/application/hub/classes/helper/node/announcement/class_NodeAnnouncementHelper.php index 1df415462..003985fdb 100644 --- a/application/hub/classes/helper/node/announcement/class_NodeAnnouncementHelper.php +++ b/application/hub/classes/helper/node/announcement/class_NodeAnnouncementHelper.php @@ -4,6 +4,7 @@ namespace Hub\Node\Helper\Announcement; // Import application-specific stuff use Hub\Factory\Network\NetworkPackageFactory; +use Hub\Helper\Node\BaseNodeHelper; use Hub\Helper\Node\NodeHelper; use Hub\Network\Package\NetworkPackage; diff --git a/application/hub/classes/helper/node/answer/class_BaseHubAnswerHelper.php b/application/hub/classes/helper/node/answer/class_BaseHubAnswerHelper.php index 2d699f18e..89d5c0a88 100644 --- a/application/hub/classes/helper/node/answer/class_BaseHubAnswerHelper.php +++ b/application/hub/classes/helper/node/answer/class_BaseHubAnswerHelper.php @@ -1,4 +1,10 @@ +} diff --git a/application/hub/classes/helper/node/connection/class_NodeSelfConnectHelper.php b/application/hub/classes/helper/node/connection/class_NodeSelfConnectHelper.php index 5ec6c8dca..59bba1473 100644 --- a/application/hub/classes/helper/node/connection/class_NodeSelfConnectHelper.php +++ b/application/hub/classes/helper/node/connection/class_NodeSelfConnectHelper.php @@ -4,6 +4,7 @@ namespace Hub\Node\Helper\SelfConnect; // Import application-specific stuff use Hub\Factory\Network\NetworkPackageFactory; +use Hub\Helper\Node\BaseNodeHelper; use Hub\Helper\Node\NodeHelper; use Hub\Network\Package\NetworkPackage; use Hub\Tag\Tagable; diff --git a/application/hub/classes/helper/node/requests/class_NodeRequestNodeListHelper.php b/application/hub/classes/helper/node/requests/class_NodeRequestNodeListHelper.php index 9d5880a75..f1ae9860d 100644 --- a/application/hub/classes/helper/node/requests/class_NodeRequestNodeListHelper.php +++ b/application/hub/classes/helper/node/requests/class_NodeRequestNodeListHelper.php @@ -4,6 +4,7 @@ namespace Hub\Node\Helper\Request\NodeList; // Import application-specific stuff use Hub\Factory\Network\NetworkPackageFactory; +use Hub\Helper\Node\BaseNodeHelper; use Hub\Helper\Node\NodeHelper; use Hub\Network\Package\NetworkPackage; diff --git a/application/hub/classes/listener/class_BaseListener.php b/application/hub/classes/listener/class_BaseListener.php index 9c8902227..f367f33cc 100644 --- a/application/hub/classes/listener/class_BaseListener.php +++ b/application/hub/classes/listener/class_BaseListener.php @@ -6,6 +6,7 @@ namespace Hub\Listener; use Hub\Container\Socket\StorableSocket; use Hub\Factory\Information\Connection\ConnectionInfoFactory; use Hub\Factory\Node\NodeObjectFactory; +use Hub\Factory\Socket\SocketFactory; use Hub\Generic\BaseHubSystem; use Hub\Network\Package\NetworkPackage; use Hub\Pool\Peer\PoolablePeer; @@ -260,116 +261,47 @@ class BaseListener extends BaseHubSystem implements Visitable { assert($this->getPoolInstance() instanceof Poolable); assert($this->getSocketInstance()->isValidSocket()); - // Get all readers - $readers = $this->getPoolInstance()->getAllSingleSockets(); - $writers = array(); - $excepts = array(); - die('readers='.print_r($readers, TRUE)); - - // Check if we have some peers left - $left = socket_select( - $readers, - $writers, - $excepts, - 0, - 150 - ); - - // Some new peers found? - if ($left < 1) { - // Debug message - //* EXTREME-NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('TCP-LISTENER: left=' . $left . ',serverSocket=' . $this->getSocketInstance() . ',readers=' . print_r($readers, true)); + // Get next socket instance from pool over the factory + $socketInstance = SocketFactory::createNextAcceptedSocketFromPool($this->getPoolInstance(), $this->getSocketInstance()); - // Nothing new found + // Is socket instance set? + if (!($socketInstance instanceof StorableSocket)) { + // Nothing has changed on the listener return; } // END - if - // Debug message - //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('TCP-LISTENER: serverSocket=' . $this->getSocketInstance() . ',readers=' . print_r($readers, true)); - - // Do we have changed peers? - if (in_array($this->getSocketInstance(), $readers)) { - /* - * Then accept it, if this socket is set to non-blocking IO and the - * connection is NOT sending any data, socket_read() may throw - * error 11 (Resource temporary unavailable). This really nasty - * because if you have blocking IO socket_read() will wait and wait - * and wait ... - */ - $newSocket = socket_accept($this->getSocketInstance()); - - // Debug message - //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('TCP-LISTENER: newSocket=' . $newSocket . ',serverSocket=' .$this->getSocketInstance()); - - // Array for timeout settings - $options = array( - // Seconds - 'sec' => $this->getConfigInstance()->getConfigEntry('tcp_socket_accept_wait_sec'), - // Milliseconds - 'usec' => $this->getConfigInstance()->getConfigEntry('tcp_socket_accept_wait_usec') - ); - - // Set timeout to configured seconds - // @TODO Does this work on Windozer boxes??? - if (!socket_set_option($newSocket, SOL_SOCKET, SO_RCVTIMEO, $options)) { - // Handle this socket error with a faked recipientData array - $this->handleSocketError(__METHOD__, __LINE__, $newSocket, array('0.0.0.0', '0')); - } // END - if - - // Output result (only for debugging!) - /* - $option = socket_get_option($newSocket, SOL_SOCKET, SO_RCVTIMEO); - self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('SO_RCVTIMEO[' . gettype($option) . ']=' . print_r($option, true)); - */ - - // Enable SO_OOBINLINE - if (!socket_set_option($newSocket, SOL_SOCKET, SO_OOBINLINE ,1)) { - // Handle this socket error with a faked recipientData array - $this->handleSocketError(__METHOD__, __LINE__, $newSocket, array('0.0.0.0', '0')); - } // END - if - - // Set non-blocking - if (!socket_set_nonblock($newSocket)) { - // Handle this socket error with a faked recipientData array - $this->handleSocketError(__METHOD__, __LINE__, $newSocket, array('0.0.0.0', '0')); - } // END - if - - // Add it to the peers - $this->getPoolInstance()->addPeer($newSocket, StorableSocket::CONNECTION_TYPE_INCOMING); - - // Init peer address/port - $peerAddress = '0.0.0.0'; - $peerPort = '0'; - - // Get peer name - if (!socket_getpeername($newSocket, $peerAddress, $peerPort)) { - // Handle this socket error with a faked recipientData array - $this->handleSocketError(__METHOD__, __LINE__, $newSocket, array('0.0.0.0', '0')); - } // END - if - - // Get node instance - $nodeInstance = NodeObjectFactory::createNodeInstance(); - - // Create a faked package data array - $packageData = array( - NetworkPackage::PACKAGE_DATA_SENDER => $peerAddress . $peerSuffix, - NetworkPackage::PACKAGE_DATA_RECIPIENT => $nodeInstance->getSessionId(), - NetworkPackage::PACKAGE_DATA_STATUS => NetworkPackage::PACKAGE_STATUS_FAKED - ); - - // Get a connection info instance - $infoInstance = ConnectionInfoFactory::createConnectionInfoInstance($this->getProtocolName(), 'listener'); - - // Will the info instance with listener data - $infoInstance->fillWithListenerInformation($this); - - // Get a socket registry - $registryInstance = SocketRegistryFactory::createSocketRegistryInstance(); - - // Register the socket with the registry and with the faked array - $registryInstance->registerSocketInstance($infoInstance, $newSocket, $packageData); + // Init peer address/port + $peerAddress = '0.0.0.0'; + $peerPort = '0'; + + // Get peer name + if (!$socketInstance->getSocketPeerName($peerAddress, $peerPort)) { + // Handle this socket error with a faked recipientData array + $socketInstance->handleSocketError(__METHOD__, __LINE__, array('0.0.0.0', '0')); } // END - if + // Get node instance + $nodeInstance = NodeObjectFactory::createNodeInstance(); + + // Create a faked package data array + $packageData = array( + NetworkPackage::PACKAGE_DATA_SENDER => $peerAddress . $peerSuffix, + NetworkPackage::PACKAGE_DATA_RECIPIENT => $nodeInstance->getSessionId(), + NetworkPackage::PACKAGE_DATA_STATUS => NetworkPackage::PACKAGE_STATUS_FAKED + ); + + // Get a connection info instance + $infoInstance = ConnectionInfoFactory::createConnectionInfoInstance($this->getProtocolName(), 'listener'); + + // Will the info instance with listener data + $infoInstance->fillWithListenerInformation($this); + + // Get a socket registry + $registryInstance = SocketRegistryFactory::createSocketRegistryInstance(); + + // Register the socket with the registry and with the faked array + $registryInstance->registerSocketInstance($infoInstance, $socketInstance, $packageData); + // Do we have to rewind? if (!$this->getIteratorInstance()->valid()) { // Rewind the list diff --git a/application/hub/classes/listener/socket/class_SocketFileListener.php b/application/hub/classes/listener/socket/class_SocketFileListener.php index 10abef303..002b09486 100644 --- a/application/hub/classes/listener/socket/class_SocketFileListener.php +++ b/application/hub/classes/listener/socket/class_SocketFileListener.php @@ -83,7 +83,7 @@ class SocketFileListener extends BaseListener implements Listenable { $this->setPoolInstance($poolInstance); // Initialize iterator for listening on packages - $iteratorInstance = ObjectFactory::createObjectByConfiguredName('socket_listen_iterator_class', array($poolInstance->getPoolEntriesInstance())); + $iteratorInstance = $poolInstance->createListIteratorInstance('socket_listen'); // Rewind it and remember it in this class $iteratorInstance->rewind(); diff --git a/application/hub/classes/listener/tcp/class_TcpListener.php b/application/hub/classes/listener/tcp/class_TcpListener.php index 6d09063ef..04497715f 100644 --- a/application/hub/classes/listener/tcp/class_TcpListener.php +++ b/application/hub/classes/listener/tcp/class_TcpListener.php @@ -83,7 +83,7 @@ class TcpListener extends BaseListener implements Listenable { $this->setPoolInstance($poolInstance); // Initialize iterator for listening on packages - $iteratorInstance = ObjectFactory::createObjectByConfiguredName('network_listen_iterator_class', array($poolInstance->getPoolEntriesInstance())); + $iteratorInstance = $poolInstance->createListIteratorInstance('network_listen'); // Rewind it and remember it in this class $iteratorInstance->rewind(); @@ -120,7 +120,5 @@ class TcpListener extends BaseListener implements Listenable { // Please don't call this throw new UnsupportedOperationException(array($this, __FUNCTION__), self::EXCEPTION_UNSPPORTED_OPERATION); } -} -// [EOF] -?> +} diff --git a/application/hub/classes/listener/udp/class_UdpListener.php b/application/hub/classes/listener/udp/class_UdpListener.php index ec41c1c26..5c9dc4aaa 100644 --- a/application/hub/classes/listener/udp/class_UdpListener.php +++ b/application/hub/classes/listener/udp/class_UdpListener.php @@ -89,11 +89,14 @@ class UdpListener extends BaseListener implements Listenable { * @todo ~50% done */ public function doListen() { + $this->partialStub('Please rewrite this part.'); + return; + // Read a package and determine the peer $amount = @socket_recvfrom($this->getSocketInstance(), $rawData, $this->getConfigInstance()->getConfigEntry('udp_buffer_length'), MSG_DONTWAIT, $peer, $port); // Get last error - $lastError = socket_last_error($this->getSocketInstance()); + $lastError = $this->getSocketInstance()->getSocketLastErrorCode(); // Do we have an error at the line? if ($lastError == 11) { @@ -103,7 +106,7 @@ class UdpListener extends BaseListener implements Listenable { * "listener" won't read any packages except if the UDP sender * starts the transmission before this "listener" came up... */ - socket_clear_error($this->getSocketInstance()); + $this->getSocketInstance()->clearLastSocketError(); // Skip further processing return; diff --git a/application/hub/classes/lists/pool/class_PoolEntriesList.php b/application/hub/classes/lists/pool/class_PoolEntriesList.php index f8c394ebd..4745e9321 100644 --- a/application/hub/classes/lists/pool/class_PoolEntriesList.php +++ b/application/hub/classes/lists/pool/class_PoolEntriesList.php @@ -81,7 +81,5 @@ class PoolEntriesList extends BaseList implements Listable { // Clear the only one group $this->clearGroup('pool'); } -} -// [EOF] -?> +} diff --git a/application/hub/classes/pools/class_BasePool.php b/application/hub/classes/pools/class_BasePool.php index 37bb41277..837d47f46 100644 --- a/application/hub/classes/pools/class_BasePool.php +++ b/application/hub/classes/pools/class_BasePool.php @@ -54,15 +54,6 @@ abstract class BasePool extends BaseHubSystem implements Poolable, Visitable { $this->poolEntriesInstance = ObjectFactory::createObjectByConfiguredName('pool_entries_list_class'); } - /** - * Getter for pool entries instance - * - * @return $poolEntriesInstance An instance for pool entries (list) - */ - public final function getPoolEntriesInstance () { - return $this->poolEntriesInstance; - } - /** * Adds an instance to a pool segment * @@ -101,6 +92,29 @@ abstract class BasePool extends BaseHubSystem implements Poolable, Visitable { $this->getPoolEntriesInstance()->addEntry('pool', $poolEntry); } + /** + * Gets the array from specified list + * + * @param $list The list identifier we should return + * @return $array The requested array + */ + protected final function getArrayFromList ($list) { + // Get the array + $array = $this->getPoolEntriesInstance()->getArrayFromList($list); + + // Return it + return $array; + } + + /** + * Getter for pool entries instance + * + * @return $poolEntriesInstance An instance for pool entries (list) + */ + public final function getPoolEntriesInstance () { + return $this->poolEntriesInstance; + } + /** * Accepts the visitor to process the visit "request" * @@ -152,20 +166,6 @@ abstract class BasePool extends BaseHubSystem implements Poolable, Visitable { //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('POOL: ' . $visitorInstance->__toString() . ' has visited - EXIT!'); } - /** - * Gets the array from specified list - * - * @param $list The list identifier we should return - * @return $array The requested array - */ - protected final function getArrayFromList ($list) { - // Get the array - $array = $this->getPoolEntriesInstance()->getArrayFromList($list); - - // Return it - return $array; - } - /** * Run the pre-shutdown seqeuence by a visitor pattern * @@ -185,4 +185,18 @@ abstract class BasePool extends BaseHubSystem implements Poolable, Visitable { /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('POOL: Shutting down listener pool - EXIT!'); } + /** + * Creates an iterator instance from inner list instance + * + * @param $poolType Pool type (e.g. socket_listen) + * @return $iteratorInstance An instance of a Iterator class + */ + public function createListIteratorInstance ($poolType) { + // Create iterator instance + $iteratorInstance = ObjectFactory::createObjectByConfiguredName($poolType . '_iterator_class', array($this->getPoolEntriesInstance())); + + // Return it + return $iteratorInstance; + } + } diff --git a/application/hub/config.php b/application/hub/config.php index 466580767..89f6d8e52 100644 --- a/application/hub/config.php +++ b/application/hub/config.php @@ -102,6 +102,9 @@ $cfg->setConfigEntry('application_pool_class', 'Hub\Pool\Peer\DefaultPeerPool'); // CFG: POOL-ENTRIES-LIST-CLASS $cfg->setConfigEntry('pool_entries_list_class', 'Hub\Lists\Pool\PoolEntriesList'); +// CFG: POOL-ITERATOR-CLASS +$cfg->setConfigEntry('pool_iterator_class', 'CoreFramework\Iterator\DefaultIterator'); + // CFG: SHUTDOWN-POOL-ITERATOR-CLASS $cfg->setConfigEntry('shutdown_pool_iterator_class', 'ShutdownPoolIterator'); @@ -142,7 +145,7 @@ $cfg->setConfigEntry('active_task_visitor_class', 'Hub\Visitor\Task\Active\Activ $cfg->setConfigEntry('node_announcement_helper_class', 'NodeAnnouncementHelper'); // CFG: NODE-SELF-CONNECT-HELPER-CLASS -$cfg->setConfigEntry('node_self_connect_helper_class', 'NodeSelfConnectHelper'); +$cfg->setConfigEntry('node_self_connect_helper_class', 'Hub\Node\Helper\SelfConnect\NodeSelfConnectHelper'); // CFG: DHT-BOOTSTRAP-HELPER-CLASS $cfg->setConfigEntry('dht_bootstrap_helper_class', 'Hub\Helper\Dht\Bootstrap\DhtBootstrapHelper'); @@ -820,6 +823,9 @@ $cfg->setConfigEntry('socket_timeout_seconds', 3); // CFG: SOCKET-TIMEOUT-MICROSECONDS $cfg->setConfigEntry('socket_timeout_microseconds', 0); +// CFG: SOCKET-SELECT-TIMEOUT-USEC +$cfg->setConfigEntry('socket_select_timeout_usec', 50); + // CFG: CHUNK-HANDLER-CLASS $cfg->setConfigEntry('chunk_handler_class', 'Hub\Handler\Network\RawData\Chunks\ChunkHandler'); diff --git a/application/hub/interfaces/container/socket/class_StorableSocket.php b/application/hub/interfaces/container/socket/class_StorableSocket.php index 09687e8f2..67797780d 100644 --- a/application/hub/interfaces/container/socket/class_StorableSocket.php +++ b/application/hub/interfaces/container/socket/class_StorableSocket.php @@ -116,6 +116,35 @@ interface StorableSocket extends FrameworkInterface { */ function getSocketPeerName (&$peerAddress, &$peerPort); + /** + * Calls socket_select() on stored socket resource + * + * @return $socketInstance An instance of a StorableSocket class + * @throws InvalidSocketException If stored socket is invalid + */ + function acceptNewIncomingSocket (); + + /** + * Tries to identify the socket peer by calling socket_getpeer() + * + * @return $result Whether the peer has been identified + */ + function identifySocketPeer(); + + /** + * Tries to set socket timeout option + * + * @return $result Whether the option has been set + */ + function setSocketTimeoutOptions(); + + /** + * Tries to enable out-of-band (OOB) data + * + * @return $result Whether OOB has been enabled + */ + function enableSocketOutOfBandData(); + /** * Getter for socket procotol field * diff --git a/application/hub/interfaces/lookup/peer_states/class_LookupablePeerState.php b/application/hub/interfaces/lookup/peer_states/class_LookupablePeerState.php index 3184887b4..7385a22e5 100644 --- a/application/hub/interfaces/lookup/peer_states/class_LookupablePeerState.php +++ b/application/hub/interfaces/lookup/peer_states/class_LookupablePeerState.php @@ -3,6 +3,7 @@ namespace Hub\State\Peer\Lookup; // Import application-specific stuff +use Hub\Container\Socket\StorableSocket; use Hub\Helper\Connection\ConnectionHelper; // Import framework stuff @@ -43,10 +44,10 @@ interface LookupablePeerState extends Lookupable { * Registers a peer with given package data. We use the session id from it * * @param $packageData Valid raw package data - * @param $socketResource A valid socket resource - * @return<>void + * @param $socketInstance An instance of a StorableSocket class + * @return void */ - function registerPeerByPackageData (array $packageData, $socketResource); + function registerPeerByPackageData (array $packageData, StorableSocket $socketInstance); /** * Registers the given peer state and raw package data diff --git a/application/hub/interfaces/pool/class_Poolable.php b/application/hub/interfaces/pool/class_Poolable.php index 653421a32..5f764a0cf 100644 --- a/application/hub/interfaces/pool/class_Poolable.php +++ b/application/hub/interfaces/pool/class_Poolable.php @@ -28,12 +28,17 @@ use Hub\Generic\HubInterface; * along with this program. If not, see . */ interface Poolable extends HubInterface { - /** - * Socket array elements - */ + // Socket array elements const SOCKET_ARRAY_INSTANCE = 'instance'; const SOCKET_ARRAY_CONN_TYPE = 'connection_type'; + /** + * Getter for pool entries instance + * + * @return $poolEntriesInstance An instance for pool entries (list) + */ + function getPoolEntriesInstance (); + /** * Pre-shuts down the pool * @@ -41,4 +46,12 @@ interface Poolable extends HubInterface { */ function preShutdown (); + /** + * Creates an iterator from inner list instance. + * + * @param $poolType Pool type (e.g. 'socket_listen', 'network_listen') + * @return $iteratorInstance An instance of a Iterator class + */ + function createListIteratorInstance ($poolType); + } diff --git a/core b/core index 5301f9dd1..ba6776b5d 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit 5301f9dd1ac83bc13ebfedda721477ec0405e228 +Subproject commit ba6776b5d9b04fd6916224c088cabf255643c6d7 -- 2.39.5