From 515f76d42e561646a9e7550d05d87050703c448c Mon Sep 17 00:00:00 2001 From: =?utf8?q?Roland=20H=C3=A4der?= Date: Sun, 21 May 2017 22:51:32 +0200 Subject: [PATCH] Continued rewrite: - rewrote TcpListener (should be working, untested) towards SocketFactory - added missing but needed methods in BaseListenerDecorator which extends BaseDecorator which is framework (generic) - renamed method to enableSocketReuseAddress() to make it similar to existings - added missing namespaces MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Signed-off-by: Roland Häder --- .../factories/socket/class_SocketFactory.php | 71 +++++++++- .../listener/class_BaseListenerDecorator.php | 133 ++++++++++++++++++ .../socket/class_SocketFileListener.php | 2 +- .../listener/tcp/class_TcpListener.php | 115 +-------------- application/hub/config.php | 4 +- 5 files changed, 213 insertions(+), 112 deletions(-) diff --git a/application/hub/classes/factories/socket/class_SocketFactory.php b/application/hub/classes/factories/socket/class_SocketFactory.php index 44cd11ff7..19301d24a 100644 --- a/application/hub/classes/factories/socket/class_SocketFactory.php +++ b/application/hub/classes/factories/socket/class_SocketFactory.php @@ -222,7 +222,7 @@ class SocketFactory extends ObjectFactory { } // END - if // Set the option to reuse the port - if (!$socketInstance->enableReuseAddress()) { + if (!$socketInstance->enableSocketReuseAddress()) { // Handle this socket error with a faked recipientData array $socketInstance->handleSocketError(__METHOD__, __LINE__, array('0.0.0.0', '0')); } // END - if @@ -241,4 +241,73 @@ class SocketFactory extends ObjectFactory { return $socketInstance; } + /** + * Creates a listening socket instance from given listener instance + * + * @param $listenerInstance An instance of a Listenable class + * @return $socketInstance An instance of a StorableSocket class + * @throws InvalidSocketException Thrown if the socket could not be initialized + */ + public static function createListenTcpSocket (Listenable $listenerInstance) { + // Create a streaming socket, of type TCP/IP + $socketResource = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); + + // @TODO Init fake package data with address/port from listener + $packageData = array( + ); + + // Create socket instance + $socketInstance = self::createObjectByConfiguredName('socket_container_class', array($socketResource, 'file', $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 + + // Get socket error code for verification + $socketError = $socketInstance->getLastSocketErrorCode(); + + // Check if there was an error else + if ($socketError > 0) { + // Handle this socket error with a faked recipientData array + $socketInstance->handleSocketError(__METHOD__, __LINE__, array('0.0.0.0', '0')); + } // END - if + + // Set the option to reuse the port + // @TODO: , SOL_SOCKET, SO_REUSEADDR, 1 + if (!$socketInstance->enableSocketReuseAddress()) { + // Handle this socket error with a faked recipientData array + $socketInstance->handleSocketError(__METHOD__, __LINE__, array('0.0.0.0', '0')); + } // END - if + + /* + * "Bind" the socket to the given address, on given port so this means + * that all connections on this port are now our resposibility to + * send/recv data, disconnect, etc.. + */ + self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('TCP-LISTENER: Binding to address ' . $listenerInstance->getListenAddress() . ':' . $listenerInstance->getListenPort()); + if (!$socketInstance->bindSocketTo($listenerInstance->getListenAddress(), $listenerInstance->getListenPort())) { + // Handle this socket error with a faked recipientData array + $socketInstance->handleSocketError(__METHOD__, __LINE__, array('0.0.0.0', '0')); + } // END - if + + // Start listen for connections + self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('TCP-LISTENER: Listening for connections.'); + if (!$socketInstance->listenToSocket()) { + // Handle this socket error with a faked recipientData array + $socketInstance->handleSocketError(__METHOD__, __LINE__, array('0.0.0.0', '0')); + } // END - if + + // Now, we want non-blocking mode + self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('TCP-LISTENER: Setting non-blocking mode.'); + 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 prepepared socket + return $socketInstance; + } + } diff --git a/application/hub/classes/listener/class_BaseListenerDecorator.php b/application/hub/classes/listener/class_BaseListenerDecorator.php index 0fb77065a..2b438e565 100644 --- a/application/hub/classes/listener/class_BaseListenerDecorator.php +++ b/application/hub/classes/listener/class_BaseListenerDecorator.php @@ -3,6 +3,8 @@ namespace Hub\Listener; // Import application-specific stuff +use Hub\Container\Socket\StorableSocket; +use Hub\Listener\Listenable; use Hub\Network\Networkable; // Import framework stuff @@ -38,6 +40,16 @@ class BaseListenerDecorator extends BaseDecorator implements Visitable { */ private $listenerType = 'invalid'; + /** + * Name of used protocol + */ + private $protocolName = 'invalid'; + + /** + * The decorated listener instance + */ + private $listenerInstance = NULL; + /** * Protected constructor * @@ -159,4 +171,125 @@ class BaseListenerDecorator extends BaseDecorator implements Visitable { $receiverInstance->addRawDataToIncomingStack($handlerInstance); } + /** + * Setter for socket instance + * + * @param $socketInstance A StorableSocket instance + * @return void + */ + public final function setSocketInstance (StorableSocket $socketInstance) { + $this->socketInstance = $socketInstance; + } + + /** + * Getter for socket instance + * + * @return $socketInstance An instance of a StorableSocket class + */ + public final function getSocketInstance () { + return $this->socketInstance; + } + + /** + * Checks whether start/end marker are set + * + * @param $data Data to be checked + * @return $isset Whether start/end marker are set + */ + public function ifStartEndMarkersSet ($data) { + $this->partialSub('Please implement this method.'); + } + + /** + * Getter for listener pool instance + * + * @return $listenerPoolInstance Our current listener pool instance + */ + public function getListenerPoolInstance () { + $this->partialSub('Please implement this method.'); + } + + /** + * Getter for info instance + * + * @return $infoInstance An instance of a ShareableInfo class + */ + public function getInfoInstance () { + $this->partialSub('Please implement this method.'); + } + + /** + * Getter for node id + * + * @return $nodeId Current node id + */ + public function getNodeId () { + $this->partialSub('Please implement this method.'); + } + + /** + * Getter for private key + * + * @return $privateKey Current private key + */ + public function getPrivateKey () { + $this->partialSub('Please implement this method.'); + } + + /** + * Getter for private key hash + * + * @return $privateKeyHash Current private key hash + */ + public function getPrivateKeyHash () { + $this->partialSub('Please implement this method.'); + } + + /** + * Getter for session id + * + * @return $sessionId Current session id + */ + public function getSessionId () { + $this->partialSub('Please implement this method.'); + } + + /** + * Setter for listener instance + * + * @param $listenerInstance A Listenable instance + * @return void + */ + protected final function setListenerInstance (Listenable $listenerInstance) { + $this->listenerInstance = $listenerInstance; + } + + /** + * Getter for listener instance + * + * @return $listenerInstance A Listenable instance + */ + protected final function getListenerInstance () { + return $this->listenerInstance; + } + + /** + * Getter for protocol name + * + * @return $protocolName Name of used protocol + */ + public final function getProtocolName () { + return $this->protocolName; + } + + /** + * Setter for protocol name + * + * @param $protocolName Name of used protocol + * @return void + */ + protected final function setProtocolName ($protocolName) { + $this->protocolName = $protocolName; + } + } diff --git a/application/hub/classes/listener/socket/class_SocketFileListener.php b/application/hub/classes/listener/socket/class_SocketFileListener.php index 823924977..62a086ae3 100644 --- a/application/hub/classes/listener/socket/class_SocketFileListener.php +++ b/application/hub/classes/listener/socket/class_SocketFileListener.php @@ -96,7 +96,7 @@ class SocketFileListener extends BaseListener implements Listenable { $this->setHandlerInstance($handlerInstance); // Output message - self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('SOCKET-FILE-LISTENER: Socket listener now ready on socket ' . $socketFile . ' for service.'); + self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('SOCKET-FILE-LISTENER: Socket listener now ready on socket ' . $socketInstance->getSocketResource() . ' for service.'); } /** diff --git a/application/hub/classes/listener/tcp/class_TcpListener.php b/application/hub/classes/listener/tcp/class_TcpListener.php index 58c902172..9c39cad4d 100644 --- a/application/hub/classes/listener/tcp/class_TcpListener.php +++ b/application/hub/classes/listener/tcp/class_TcpListener.php @@ -3,6 +3,7 @@ namespace Hub\Listener\Tcp; // Import application-specific stuff +use Hub\Factory\Socket\SocketFactory; use Hub\Helper\Connection\BaseConnectionHelper; use Hub\Listener\BaseListener; use Hub\Listener\Listenable; @@ -68,119 +69,17 @@ class TcpListener extends BaseListener implements Listenable { * @todo Needs rewrite! */ public function initListener () { - // Create a streaming socket, of type TCP/IP - $mainSocket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); - - // Is the socket resource valid? - if (!is_resource($mainSocket)) { - // Something bad happened - throw new InvalidSocketException(array($this, $mainSocket), self::EXCEPTION_INVALID_SOCKET); - } // END - if - - // Get socket error code for verification - $socketError = socket_last_error($mainSocket); - - // Check if there was an error else - if ($socketError > 0) { - // Handle this socket error with a faked recipientData array - $this->handleSocketError(__METHOD__, __LINE__, $mainSocket, array('0.0.0.0', '0')); - /* - // Then throw again - throw new InvalidSocketException(array($this, $mainSocket, $socketError, socket_strerror($socketError)), self::EXCEPTION_INVALID_SOCKET); - */ - } // END - if - - // Set the option to reuse the port - if (!socket_set_option($mainSocket, SOL_SOCKET, SO_REUSEADDR, 1)) { - // Handle this socket error with a faked recipientData array - $this->handleSocketError(__METHOD__, __LINE__, $mainSocket, array('0.0.0.0', '0')); - /* - // Get socket error code for verification - $socketError = socket_last_error($mainSocket); - - // Get error message - $errorMessage = socket_strerror($socketError); - - // Shutdown this socket - $this->shutdownSocket($mainSocket); - - // And throw again - throw new InvalidSocketException(array($this, $mainSocket, $socketError, $errorMessage), self::EXCEPTION_INVALID_SOCKET); - */ - } // END - if - - /* - * "Bind" the socket to the given address, on given port so this means - * that all connections on this port are now our resposibility to - * send/recv data, disconnect, etc.. - */ - self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('TCP-LISTENER: Binding to address ' . $this->getListenAddress() . ':' . $this->getListenPort()); - if (!socket_bind($mainSocket, $this->getListenAddress(), $this->getListenPort())) { - // Handle this socket error with a faked recipientData array - $this->handleSocketError(__METHOD__, __LINE__, $mainSocket, array('0.0.0.0', '0')); - /* - // Get socket error code for verification - $socketError = socket_last_error($mainSocket); - - // Get error message - $errorMessage = socket_strerror($socketError); - - // Shutdown this socket - $this->shutdownSocket($mainSocket); - - // And throw again - throw new InvalidSocketException(array($this, $mainSocket, $socketError, $errorMessage), self::EXCEPTION_INVALID_SOCKET); - */ - } // END - if - - // Start listen for connections - self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('TCP-LISTENER: Listening for connections.'); - if (!socket_listen($mainSocket)) { - // Handle this socket error with a faked recipientData array - $this->handleSocketError(__METHOD__, __LINE__, $mainSocket, array('0.0.0.0', '0')); - /* - // Get socket error code for verification - $socketError = socket_last_error($mainSocket); - - // Get error message - $errorMessage = socket_strerror($socketError); - - // Shutdown this socket - $this->shutdownSocket($mainSocket); - - // And throw again - throw new InvalidSocketException(array($this, $mainSocket, $socketError, $errorMessage), self::EXCEPTION_INVALID_SOCKET); - */ - } // END - if - - // Now, we want non-blocking mode - self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('TCP-LISTENER: Setting non-blocking mode.'); - if (!socket_set_nonblock($mainSocket)) { - // Handle this socket error with a faked recipientData array - $this->handleSocketError(__METHOD__, __LINE__, $mainSocket, array('0.0.0.0', '0')); - /* - // Get socket error code for verification - $socketError = socket_last_error($mainSocket); - - // Get error message - $errorMessage = socket_strerror($socketError); - - // Shutdown this socket - $this->shutdownSocket($mainSocket); - - // And throw again - throw new InvalidSocketException(array($this, $mainSocket, $socketError, $errorMessage), self::EXCEPTION_INVALID_SOCKET); - */ - } // END - if - - // Set the main socket - $this->registerServerSocketInstance($mainSocket); + // Get instance from socket factory + $socketInstance = SocketFactory::createListenTcpSocket($this); + + // Set socket instance + $this->registerServerSocketInstance($socketInstance); // Initialize the peer pool instance $poolInstance = ObjectFactory::createObjectByConfiguredName('node_pool_class', array($this)); // Add main socket - $poolInstance->addPeer($mainSocket, BaseConnectionHelper::CONNECTION_TYPE_SERVER); + $poolInstance->addPeer($socketInstance, BaseConnectionHelper::CONNECTION_TYPE_SERVER); // And add it to this listener $this->setPoolInstance($poolInstance); diff --git a/application/hub/config.php b/application/hub/config.php index b3da98405..79997cf3d 100644 --- a/application/hub/config.php +++ b/application/hub/config.php @@ -70,10 +70,10 @@ $cfg->setConfigEntry('web_content_type', ''); $cfg->setConfigEntry('listener_pool_class', 'Hub\Pool\Listener\DefaultListenerPool'); // CFG: TCP-LISTENER-CLASS -$cfg->setConfigEntry('tcp_listener_class', 'TcpListener'); +$cfg->setConfigEntry('tcp_listener_class', 'Hub\Listener\Tcp\TcpListener'); // CFG: UDP-LISTENER-CLASS -$cfg->setConfigEntry('udp_listener_class', 'UdpListener'); +$cfg->setConfigEntry('udp_listener_class', 'Hub\Listener\Udp\UdpListener'); // CFG: SOCKET-FILE-LISTENER-CLASS $cfg->setConfigEntry('socket_file_listener_class', 'Hub\Listener\Socket\SocketFileListener'); -- 2.39.5