From 70200208cada6be0e537b4476a0374cac2d0e906 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Roland=20H=C3=A4der?= Date: Mon, 22 May 2017 15:59:11 +0200 Subject: [PATCH] Continued rewrite: - rewrote UDP listener to SocketFactory - imported BadMethodCallException - use SOCKET_PROTOCOL_FOO and not 'foo' MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Signed-off-by: Roland Häder --- .../socket/class_SocketContainer.php | 5 +- .../factories/socket/class_SocketFactory.php | 63 ++++++++++++++++++- .../listener/udp/class_UdpListener.php | 43 ++----------- .../locator/class_UniversalNodeLocator.php | 3 + 4 files changed, 75 insertions(+), 39 deletions(-) diff --git a/application/hub/classes/container/socket/class_SocketContainer.php b/application/hub/classes/container/socket/class_SocketContainer.php index 89d5d914e..ab45aca98 100644 --- a/application/hub/classes/container/socket/class_SocketContainer.php +++ b/application/hub/classes/container/socket/class_SocketContainer.php @@ -23,6 +23,9 @@ use CoreFramework\Socket\UnsupportedSocketErrorHandlerException; use CoreFramework\Visitor\Visitable; use CoreFramework\Visitor\Visitor; +// Import SPL stuff +use \BadMethodCallException; + /** * A Socket Container class * @@ -297,7 +300,7 @@ class SocketContainer extends BaseContainer implements StorableSocket, Visitable * support socket_getpeername(): * http://de2.php.net/manual/en/function.socket-getpeername.php#35656 */ - if ($this->getSocketProtocol() == 'udp') { + if ($this->getSocketProtocol() == StorableSocket::SOCKET_PROTOCOL_UDP) { // UDP is WIP: $this->partialStub('UDP sockets are unfinished.'); } else { diff --git a/application/hub/classes/factories/socket/class_SocketFactory.php b/application/hub/classes/factories/socket/class_SocketFactory.php index c652e29ff..cae3daeef 100644 --- a/application/hub/classes/factories/socket/class_SocketFactory.php +++ b/application/hub/classes/factories/socket/class_SocketFactory.php @@ -236,7 +236,7 @@ class SocketFactory extends ObjectFactory { } /** - * Creates a listening socket instance from given listener instance + * Creates a listening TCP socket instance from given listener instance * * @param $listenerInstance An instance of a Listenable class * @return $socketInstance An instance of a StorableSocket class @@ -303,4 +303,65 @@ class SocketFactory extends ObjectFactory { return $socketInstance; } + /** + * Creates a "listening" UDP 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 createListenUdpSocket (Listenable $listenerInstance) { + // Create a streaming socket, of type TCP/IP + $socketResource = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP); + + // Init fake package data with address/port from listener + $packageData = array( + StorableSocket::SOCKET_ARRAY_INDEX_ADDRESS => $listenerInstance->getListenAddress(), + StorableSocket::SOCKET_ARRAY_INDEX_PORT => $listenerInstance->getListenPort(), + ); + + // Create socket instance + $socketInstance = self::createObjectByConfiguredName('socket_container_class', array($socketResource, StorableSocket::SOCKET_PROTOCOL_UDP, $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 + + // Check if there was an error else + if ($socketInstance->getLastSocketErrorCode() > 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 + self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('SOCKET-FACTORY: Enabling re-use address ...'); + 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('SOCKET-FACTORY: 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 + + // Now, we want non-blocking mode + self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('SOCKET-FACTORY: 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/udp/class_UdpListener.php b/application/hub/classes/listener/udp/class_UdpListener.php index e31de1d4c..7bb83e9ed 100644 --- a/application/hub/classes/listener/udp/class_UdpListener.php +++ b/application/hub/classes/listener/udp/class_UdpListener.php @@ -3,6 +3,8 @@ namespace Hub\Listener\Udp; // Import application-specific stuff +use Hub\Container\Socket\StorableSocket; +use Hub\Factory\Socket\SocketFactory; use Hub\Listener\BaseListener; use Hub\Listener\Listenable; @@ -42,7 +44,7 @@ class UdpListener extends BaseListener implements Listenable { parent::__construct(__CLASS__); // Set the protocol to UDP - $this->setProtocolName('udp'); + $this->setProtocolName(StorableSocket::SOCKET_PROTOCOL_UDP); } /** @@ -62,46 +64,13 @@ class UdpListener extends BaseListener implements Listenable { * Initializes the listener by setting up the required socket server * * @return void - * @throws InvalidSocketException Thrown if the socket is invalid or an error was detected. - * @todo Needs rewrite! */ public function initListener () { - // Try to open a UDP socket - $mainSocket = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP); - - // Is the socket a valid resource or do we have any error? - if (!is_resource($mainSocket)) { - // Then throw an InvalidSocketException - throw new InvalidSocketException(array($this, $mainSocket), 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('UDP-LISTENER: Binding to address ' . $this->getListenAddress() . ':' . $this->getListenPort()); - if (!socket_bind($mainSocket, $this->getListenAddress(), $this->getListenPort())) { - // Handle the socket error with a faked recipientData array - $this->handleSocketError(__METHOD__, __LINE__, $mainSocket, array('0.0.0.0', '0')); - } // END - if - - // Now, we want non-blocking mode - self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('UDP-LISTENER: Setting non-blocking mode.'); - if (!socket_set_nonblock($mainSocket)) { - // Handle the socket error with a faked recipientData array - $this->handleSocketError(__METHOD__, __LINE__, $mainSocket, array('0.0.0.0', '0')); - } // END - if - - // Set the option to reuse the port - self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('UDP-LISTENER: Setting re-use address option.'); - if (!socket_set_option($mainSocket, SOL_SOCKET, SO_REUSEADDR, 1)) { - // Handle the socket error with a faked recipientData array - $this->handleSocketError(__METHOD__, __LINE__, $mainSocket, array('0.0.0.0', '0')); - } // END - if + // Get socket instance + $socketInstance = SocketFactory::createListenUdpSocket($this); // Remember the socket in our class - $this->registerServerSocketInstance($mainSocket); + $this->registerServerSocketInstance($socketInstance); // Initialize the network package handler $handlerInstance = ObjectFactory::createObjectByConfiguredName('udp_raw_data_handler_class'); diff --git a/application/hub/classes/locator/class_UniversalNodeLocator.php b/application/hub/classes/locator/class_UniversalNodeLocator.php index 25d92a783..11d47f5d4 100644 --- a/application/hub/classes/locator/class_UniversalNodeLocator.php +++ b/application/hub/classes/locator/class_UniversalNodeLocator.php @@ -6,6 +6,9 @@ namespace Hub\Locator\Node; use Hub\Database\Frontend\Node\Information\NodeInformationDatabaseWrapper; use Hub\Generic\BaseHubSystem; +// Import SPL stuff +use \BadMethodCallException; + /** * A class for UNLs (Universal Node Locator) * -- 2.39.5