From 70200208cada6be0e537b4476a0374cac2d0e906 Mon Sep 17 00:00:00 2001
From: =?utf8?q?Roland=20H=C3=A4der?= <roland@mxchange.org>
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 <roland@mxchange.org>
---
 .../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