X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=application%2Fhub%2Fmain%2Fhelper%2Fconnection%2Fclass_BaseConnectionHelper.php;h=685d079e31ff7fd774788dcbbe9de3a006cc66dd;hb=a350963ce5cca9cce90c958a34287cec1743ac55;hp=d7ad4ee35274342ec066fbfb72de7175a8d04b5a;hpb=ec8c0a417affae2d6099dd4446e788b3dc826fbb;p=hub.git diff --git a/application/hub/main/helper/connection/class_BaseConnectionHelper.php b/application/hub/main/helper/connection/class_BaseConnectionHelper.php index d7ad4ee35..685d079e3 100644 --- a/application/hub/main/helper/connection/class_BaseConnectionHelper.php +++ b/application/hub/main/helper/connection/class_BaseConnectionHelper.php @@ -51,7 +51,12 @@ class BaseConnectionHelper extends BaseHubHelper implements Registerable, Protoc private $diff = 0; /** - * Wether this connection is shutted down + * Whether this connection is initialized + */ + private $isInitialized = false; + + /** + * Whether this connection is shutted down */ private $shuttedDown = false; @@ -101,6 +106,150 @@ class BaseConnectionHelper extends BaseHubHelper implements Registerable, Protoc return $class; } + /** + * Getter for port number to satify ProtocolHandler + * + * @return $port The port number + */ + public final function getPort () { + return $this->port; + } + + /** + * Setter for port number to satify ProtocolHandler + * + * @param $port The port number + * @return void + */ + protected final function setPort ($port) { + $this->port = $port; + } + + /** + * Getter for protocol + * + * @return $protocol Used protocol + */ + public final function getProtocol () { + return $this->protocol; + } + + /** + * Setter for protocol + * + * @param $protocol Used protocol + * @return void + */ + protected final function setProtocol ($protocol) { + $this->protocol = $protocol; + } + + /** + * Getter for IP address + * + * @return $address The IP address + */ + public final function getAddress () { + return $this->address; + } + + /** + * Setter for IP address + * + * @param $address The IP address + * @return void + */ + protected final function setAddress ($address) { + $this->address = $address; + } + + /** + * Initializes the current connection + * + * @return void + * @throws SocketOptionException If setting any socket option fails + */ + protected function initConnection () { + // Get socket resource + $socketResource = $this->getSocketResource(); + + // Set the option to reuse the port + if (!socket_set_option($socketResource, SOL_SOCKET, SO_REUSEADDR, 1)) { + // Handle this socket error with a faked recipientData array + $this->handleSocketError($socketResource, array('0.0.0.0', '0')); + + // And throw again + // @TODO Move this to the socket error handler + throw new SocketOptionException(array($this, $socketResource, $socketError, $errorMessage), BaseListener::EXCEPTION_INVALID_SOCKET); + } // END - if + + /* + * Set socket to non-blocking mode before trying to establish a link to + * it. This is now the default behaviour for all connection helpers who + * call initConnection(); . + */ + if (!socket_set_nonblock($socketResource)) { + // Handle this socket error with a faked recipientData array + $helperInstance->handleSocketError($socketResource, array('0.0.0.0', '0')); + + // And throw again + throw new SocketOptionException(array($helperInstance, $socketResource, $socketError, $errorMessage), BaseListener::EXCEPTION_INVALID_SOCKET); + } // END - if + + // Last step: mark connection as initialized + $this->isInitialized = true; + } + + /** + * Attempts to connect to a peer by given IP number and port from a valid + * recipientData array with currently configured timeout. + * + * @param $recipientData A valid recipient data array, 0=IP; 1=PORT + * @return $isConnected Whether the connection went fine + * @see Please see http://de.php.net/manual/en/function.socket-connect.php#84465 for original code + * @todo Rewrite the while() loop to a iterator to not let the software stay very long here + */ + protected function connectToPeerByRecipientDataArray (array $recipientData) { + // Only call this if the connection is initialized by initConnection() + assert($this->isInitialized === true); + + // Get current time + $time = time(); + + // "Cache" socket resource and timeout config + $socketResource = $this->getSocketResource(); + $timeout = $this->getConfigInstance()->getConfigEntry('socket_timeout_seconds'); + + // Debug output + $this->debugOutput('CONNECTION-HELPER: Trying to connect to ' . $recipientData[0] . ':' . $recipientData[1] . ' with socketResource[' . gettype($socketResource) . ']=' . $socketResource . ' ...'); + + // Try to connect until it is connected + while ($isConnected = !@socket_connect($socketResource, $recipientData[0], $recipientData[1])) { + // Get last socket error + $socketError = socket_last_error($socketResource); + + // Skip any errors which may happen on non-blocking connections + if (($socketError == SOCKET_EINPROGRESS) || ($socketError == SOCKET_EALREADY)) { + // Now, is that attempt within parameters? + if ((time() - $time) >= $timeout) { + // Didn't work within timeout + $isConnected = false; + break; + } // END - if + + // Sleep about one second + $this->idle(1000); + } elseif ($socketError != 0) { + // Stop on everything else pronto + $isConnected = false; + break; + } + } // END - while + + // Return status + return $isConnected; + } + /** * Static "getter" for this connection class' name * @@ -179,63 +328,6 @@ class BaseConnectionHelper extends BaseHubHelper implements Registerable, Protoc } } - /** - * Getter for port number to satify ProtocolHandler - * - * @return $port The port number - */ - public final function getPort () { - return $this->port; - } - - /** - * Setter for port number to satify ProtocolHandler - * - * @param $port The port number - * @return void - */ - protected final function setPort ($port) { - $this->port = $port; - } - - /** - * Getter for protocol - * - * @return $protocol Used protocol - */ - public final function getProtocol () { - return $this->protocol; - } - - /** - * Setter for protocol - * - * @param $protocol Used protocol - * @return void - */ - protected final function setProtocol ($protocol) { - $this->protocol = $protocol; - } - - /** - * Getter for IP address - * - * @return $address The IP address - */ - public final function getAddress () { - return $this->address; - } - - /** - * Setter for IP address - * - * @param $address The IP address - * @return void - */ - protected final function setAddress ($address) { - $this->address = $address; - } - /** * "Accept" a visitor by simply calling it back * @@ -342,12 +434,15 @@ class BaseConnectionHelper extends BaseHubHelper implements Registerable, Protoc protected final function markConnectionShuttedDown () { /* NOISY-DEBUG: */ $this->debugOutput('CONNECTION: ' . $this->__toString() . ' has been marked as shutted down'); $this->shuttedDown = true; + + // And remove the (now invalid) socket + $this->setSocketResource(false); } /** * Getter for shuttedDown * - * @return $shuttedDown Wether this connection is shutted down + * @return $shuttedDown Whether this connection is shutted down */ public final function isShuttedDown () { /* NOISY-DEBUG: */ $this->debugOutput('CONNECTION: ' . $this->__toString() . ',shuttedDown=' . intval($this->shuttedDown)); @@ -363,9 +458,10 @@ class BaseConnectionHelper extends BaseHubHelper implements Registerable, Protoc * later debugging purposes. * * @param $socketResource A valid socket resource + * @return void * @throws SocketConnectionException The connection attempts fails with a time-out */ - private function socketErrorConnectionTimedOutHandler ($socketResource) { + protected function socketErrorConnectionTimedOutHandler ($socketResource) { // Get socket error code for verification $socketError = socket_last_error($socketResource); @@ -378,6 +474,106 @@ class BaseConnectionHelper extends BaseHubHelper implements Registerable, Protoc // Throw it again throw new SocketConnectionException(array($this, $socketResource, $socketError, $errorMessage), BaseListener::EXCEPTION_INVALID_SOCKET); } + + /** + * Handles socket error 'resource temporary unavailable', but does not + * clear it for later debugging purposes. + * + * @param $socketResource A valid socket resource + * @return void + * @throws SocketConnectionException The connection attempts fails with a time-out + */ + protected function socketErrorResourceUnavailableHandler ($socketResource) { + // Get socket error code for verification + $socketError = socket_last_error($socketResource); + + // Get error message + $errorMessage = socket_strerror($socketError); + + // Shutdown this socket + $this->shutdownSocket($socketResource); + + // Throw it again + throw new SocketConnectionException(array($this, $socketResource, $socketError, $errorMessage), BaseListener::EXCEPTION_INVALID_SOCKET); + } + + /** + * Handles socket error 'connection refused', but does not clear it for + * later debugging purposes. + * + * @param $socketResource A valid socket resource + * @return void + * @throws SocketConnectionException The connection attempts fails with a time-out + */ + protected function socketErrorConnectionRefusedHandler ($socketResource) { + // Get socket error code for verification + $socketError = socket_last_error($socketResource); + + // Get error message + $errorMessage = socket_strerror($socketError); + + // Shutdown this socket + $this->shutdownSocket($socketResource); + + // Throw it again + throw new SocketConnectionException(array($this, $socketResource, $socketError, $errorMessage), BaseListener::EXCEPTION_INVALID_SOCKET); + } + + /** + * Handles socket error 'no route to host', but does not clear it for later + * debugging purposes. + * + * @param $socketResource A valid socket resource + * @return void + * @throws SocketConnectionException The connection attempts fails with a time-out + */ + protected function socketErrorNoRouteToHostHandler ($socketResource) { + // Get socket error code for verification + $socketError = socket_last_error($socketResource); + + // Get error message + $errorMessage = socket_strerror($socketError); + + // Shutdown this socket + $this->shutdownSocket($socketResource); + + // Throw it again + throw new SocketConnectionException(array($this, $socketResource, $socketError, $errorMessage), BaseListener::EXCEPTION_INVALID_SOCKET); + } + + /** + * Handles socket error 'operation already in progress' which happens in + * method connectToPeerByRecipientDataArray() on timed out connection + * attempts. + * + * @param $socketResource A valid socket resource + * @return void + * @throws SocketConnectionException The connection attempts fails with a time-out + */ + protected function socketErrorOperationAlreadyProgressHandler ($socketResource) { + // Get socket error code for verification + $socketError = socket_last_error($socketResource); + + // Get error message + $errorMessage = socket_strerror($socketError); + + // Half-shutdown this socket (see there for difference to shutdownSocket()) + $this->halfShutdownSocket($socketResource); + + // Throw it again + throw new SocketConnectionException(array($this, $socketResource, $socketError, $errorMessage), BaseListener::EXCEPTION_INVALID_SOCKET); + } + + /** + * Handles socket "error" 'operation now in progress' which can be safely + * passed on with non-blocking connections. + * + * @param $socketResource A valid socket resource + * @return void + */ + protected function socketErrorOperationInProgressHandler ($socketResource) { + $this->debugOutput('CONNECTION: Operation is now in progress, this is usual for non-blocking connections and is no bug.'); + } } // [EOF]