From 1a97bd3eff556623099970d5a548fb24ecb4408b Mon Sep 17 00:00:00 2001 From: Roland Haeder Date: Tue, 6 Oct 2015 20:28:29 +0200 Subject: [PATCH] Moved some code from TcpListener and made it a bit more generic, maybe just enough. MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Signed-off-by: Roland Häder --- .../classes/listener/class_BaseListener.php | 137 ++++++++++++++++++ .../socket/class_SocketFileListener.php | 4 +- 2 files changed, 139 insertions(+), 2 deletions(-) diff --git a/inc/main/classes/listener/class_BaseListener.php b/inc/main/classes/listener/class_BaseListener.php index bd807bd7..83b2b9ef 100644 --- a/inc/main/classes/listener/class_BaseListener.php +++ b/inc/main/classes/listener/class_BaseListener.php @@ -499,6 +499,143 @@ class BaseListener extends BaseFrameworkSystem implements Visitable { // Throw it again throw new SocketBindingException(array($this, $socketData, $socketResource, $socketError, $errorMessage), BaseListener::EXCEPTION_INVALID_SOCKET); } + + /** + * "Listens" for incoming network packages + * + * @param $peerSuffix Suffix for peer name (e.g. :0 for TCP(/UDP?) connections) + * @return void + * @throws InvalidSocketException If an invalid socket resource has been found + */ + protected function doListenSocketSelect ($peerSuffix) { + // Check on all instances + assert($this->getPoolInstance() instanceof Poolable); + assert(is_resource($this->getSocketResource())); + + // Get all readers + $readers = $this->getPoolInstance()->getAllSingleSockets(); + $writers = array(); + $excepts = array(); + + // 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__)->debugOutput('TCP-LISTENER[' . __METHOD__ . ':' . __LINE__ . ']: left=' . $left . ',serverSocket=' . $this->getSocketResource() . ',readers=' . print_r($readers, TRUE)); + + // Nothing new found + return; + } // END - if + + // Debug message + //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('TCP-LISTENER[' . __METHOD__ . ':' . __LINE__ . ']: serverSocket=' . $this->getSocketResource() . ',readers=' . print_r($readers, TRUE)); + + // Do we have changed peers? + if (in_array($this->getSocketResource(), $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->getSocketResource()); + + // Debug message + //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('TCP-LISTENER[' . __METHOD__ . ':' . __LINE__ . ']: newSocket=' . $newSocket . ',serverSocket=' .$this->getSocketResource()); + + // 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__)->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, BaseConnectionHelper::CONNECTION_TYPE_INCOMING); + + // Get peer name + if (!socket_getpeername($newSocket, $peerName)) { + // 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 => $peerName . $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->registerSocket($infoInstance, $newSocket, $packageData); + } // END - if + + // Do we have to rewind? + if (!$this->getIteratorInstance()->valid()) { + // Rewind the list + $this->getIteratorInstance()->rewind(); + } // END - if + + // Get the current value + $currentSocket = $this->getIteratorInstance()->current(); + + // Handle it here, if not main server socket + //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('TCP-LISTENER[' . __METHOD__ . ':' . __LINE__ . ']: currentSocket=' . $currentSocket[BasePool::SOCKET_ARRAY_RESOURCE] . ',type=' . $currentSocket[BasePool::SOCKET_ARRAY_CONN_TYPE] . ',serverSocket=' . $this->getSocketResource()); + if (($currentSocket[BasePool::SOCKET_ARRAY_CONN_TYPE] != BaseConnectionHelper::CONNECTION_TYPE_SERVER) && ($currentSocket[BasePool::SOCKET_ARRAY_RESOURCE] != $this->getSocketResource())) { + // ... or else it will raise warnings like 'Transport endpoint is not connected' + $this->getHandlerInstance()->processRawDataFromResource($currentSocket); + } // END - if + + // Advance to next entry. This should be the last line. + $this->getIteratorInstance()->next(); + } } // [EOF] diff --git a/inc/main/classes/listener/socket/class_SocketFileListener.php b/inc/main/classes/listener/socket/class_SocketFileListener.php index 4da87b61..50a242f0 100644 --- a/inc/main/classes/listener/socket/class_SocketFileListener.php +++ b/inc/main/classes/listener/socket/class_SocketFileListener.php @@ -188,10 +188,10 @@ class SocketFileListener extends BaseListener implements Listenable { * "Listens" for incoming network packages * * @return void - * @todo 0% done */ public function doListen() { - $this->partialStub('Need to implement this method.'); + // Call super method + $this->doListenSocketSelect(''); } /** -- 2.39.5