* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
class SocketContainer extends BaseContainer implements StorableSocket, Visitable, Registerable {
+ /**
+ * Socket protocol:
+ * - 'tcp' for TCP/IPv4 connections
+ * - 'file' for Unix* file-based sockets
+ */
+ private $socketProtocol = 'invalid';
+
/**
* Protected constructor
*
* Creates an instance of this Container class and prepares it for usage
*
* @param $socketResource A valid socket resource
- * @param $infoInstance An instance of a ShareableInfo class
+ * @param $socketProtocol Socket protocol
* @param $packageData Raw package data
- * @return $socketInstance An instance of this Container class
+ * @param $infoInstance An instance of a ShareableInfo class
+ * @return $socketInstance An instance of this Container class
*/
- public static final function createSocketContainer ($socketResource, ShareableInfo $infoInstance = NULL, array $packageData = array()) {
+ public static final function createSocketContainer ($socketResource, $socketProtocol, array $packageData, ShareableInfo $infoInstance = NULL) {
// Get a new instance
$socketInstance = new SocketContainer();
+ // Set protocol
+ $socketInstance->setSocketProtocol($socketProtocol);
+
// Remove unneeded entries
unset($packageData[NetworkPackage::PACKAGE_DATA_CONTENT]);
unset($packageData[NetworkPackage::PACKAGE_DATA_HASH]);
return $result;
}
+ /**
+ * Getter for socket procotol field
+ *
+ * @return $socketProtocol Socket protocol
+ */
+ public function getSocketProtocol () {
+ // Return it
+ return $this->socketProtocol;
+ }
+
/**
* Some "getter" for socket type of stored socket
*
$this->clearLastSocketError();
}
- /**
- * Translates socket error codes into our own internal names which can be
- * used for call-backs.
- *
- * @param $errorCode The error code from socket_last_error() to be translated
- * @return $errorName The translated name (all lower-case, with underlines)
- */
- public function translateSocketErrorCodeToName ($errorCode) {
- // Nothing bad happened by default
- $errorName = StorableSocket::SOCKET_CONNECTED;
-
- // Is the code a number, then we have to change it
- switch ($errorCode) {
- case 0: // Silently ignored, the socket is connected
- break;
-
- case 11: // "Resource temporary unavailable"
- $errorName = StorableSocket::SOCKET_ERROR_RESOURCE_UNAVAILABLE;
- break;
-
- case 13: // "Permission denied"
- $errorName = StorableSocket::SOCKET_ERROR_PERMISSION_DENIED;
- break;
-
- case 32: // "Broken pipe"
- $errorName = StorableSocket::SOCKET_ERROR_BROKEN_PIPE;
- break;
-
- case 95: // "Operation not supported"
- $errorName = StorableSocket::SOCKET_ERROR_OPERATION_NOT_SUPPORTED;
- break;
-
- case 104: // "Connection reset by peer"
- $errorName = StorableSocket::SOCKET_ERROR_CONNECTION_RESET_BY_PEER;
- break;
-
- case 107: // "Transport end-point not connected"
- case 134: // On some (?) systems for 'transport end-point not connected'
- // @TODO On some systems it is 134, on some 107?
- $errorName = StorableSocket::SOCKET_ERROR_TRANSPORT_ENDPOINT;
- break;
-
- case 110: // "Connection timed out"
- $errorName = StorableSocket::SOCKET_ERROR_CONNECTION_TIMED_OUT;
- break;
-
- case 111: // "Connection refused"
- $errorName = StorableSocket::SOCKET_ERROR_CONNECTION_REFUSED;
- break;
-
- case 113: // "No route to host"
- $errorName = StorableSocket::SOCKET_ERROR_NO_ROUTE_TO_HOST;
- break;
-
- case 114: // "Operation already in progress"
- $errorName = StorableSocket::SOCKET_ERROR_OPERATION_ALREADY_PROGRESS;
- break;
-
- case 115: // "Operation now in progress"
- $errorName = StorableSocket::SOCKET_ERROR_OPERATION_IN_PROGRESS;
- break;
-
- default: // Everything else <> 0
- // Unhandled error code detected, so first debug it because we may want to handle it like the others
- self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf(strtoupper($this->getSocketProtocol()) . '-SOCKET: Unsupported errorCode=%d,message=%s', $errorCode, socket_strerror($errorCode)));
-
- // Change it only in this class
- $errorName = StorableSocket::SOCKET_ERROR_UNKNOWN;
- break;
- } // END - switch
-
- // Return translated name
- return $errorName;
- }
-
/**
* Constructs a callable method name from given socket error code. If the
* method is not found, a generic one is used.
self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('CONNECTION-HELPER: Operation is now in progress, this is usual for non-blocking connections and is no bug.');
}
+ /************************************************************************
+ * Private methods follow *
+ ************************************************************************/
+
+ /**
+ * Translates socket error codes into our own internal names which can be
+ * used for call-backs.
+ *
+ * @param $errorCode The error code from socket_last_error() to be translated
+ * @return $errorName The translated name (all lower-case, with underlines)
+ */
+ private function translateSocketErrorCodeToName ($errorCode) {
+ // Nothing bad happened by default
+ $errorName = StorableSocket::SOCKET_CONNECTED;
+
+ // Is the code a number, then we have to change it
+ switch ($errorCode) {
+ case 0: // Silently ignored, the socket is connected
+ break;
+
+ case 11: // "Resource temporary unavailable"
+ $errorName = StorableSocket::SOCKET_ERROR_RESOURCE_UNAVAILABLE;
+ break;
+
+ case 13: // "Permission denied"
+ $errorName = StorableSocket::SOCKET_ERROR_PERMISSION_DENIED;
+ break;
+
+ case 32: // "Broken pipe"
+ $errorName = StorableSocket::SOCKET_ERROR_BROKEN_PIPE;
+ break;
+
+ case 95: // "Operation not supported"
+ $errorName = StorableSocket::SOCKET_ERROR_OPERATION_NOT_SUPPORTED;
+ break;
+
+ case 104: // "Connection reset by peer"
+ $errorName = StorableSocket::SOCKET_ERROR_CONNECTION_RESET_BY_PEER;
+ break;
+
+ case 107: // "Transport end-point not connected"
+ case 134: // On some (?) systems for 'transport end-point not connected'
+ // @TODO On some systems it is 134, on some 107?
+ $errorName = StorableSocket::SOCKET_ERROR_TRANSPORT_ENDPOINT;
+ break;
+
+ case 110: // "Connection timed out"
+ $errorName = StorableSocket::SOCKET_ERROR_CONNECTION_TIMED_OUT;
+ break;
+
+ case 111: // "Connection refused"
+ $errorName = StorableSocket::SOCKET_ERROR_CONNECTION_REFUSED;
+ break;
+
+ case 113: // "No route to host"
+ $errorName = StorableSocket::SOCKET_ERROR_NO_ROUTE_TO_HOST;
+ break;
+
+ case 114: // "Operation already in progress"
+ $errorName = StorableSocket::SOCKET_ERROR_OPERATION_ALREADY_PROGRESS;
+ break;
+
+ case 115: // "Operation now in progress"
+ $errorName = StorableSocket::SOCKET_ERROR_OPERATION_IN_PROGRESS;
+ break;
+
+ default: // Everything else <> 0
+ // Unhandled error code detected, so first debug it because we may want to handle it like the others
+ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf(strtoupper($this->getSocketProtocol()) . '-SOCKET: Unsupported errorCode=%d,message=%s', $errorCode, socket_strerror($errorCode)));
+
+ // Change it only in this class
+ $errorName = StorableSocket::SOCKET_ERROR_UNKNOWN;
+ break;
+ } // END - switch
+
+ // Return translated name
+ return $errorName;
+ }
+
+ /**
+ * Setter for socket protocol field
+ *
+ * @param $socketProtocol Socket protocol
+ * @return void
+ */
+ private function setSocketProtocol ($socketProtocol) {
+ $this->socketProtocol = $socketProtocol;
+ }
+
}
$socketResource = socket_create(AF_UNIX, SOCK_STREAM, 0);
// Get container from it
- $socketInstance = self::createObjectByConfiguredName('socket_container_class', array($socketResource, NULL, $packageData));
+ // @TODO Somehow handle $infoInstance to this factory
+ $socketInstance = self::createObjectByConfiguredName('socket_container_class', array($socketResource, 'file', $packageData, NULL));
// Debug message
/* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('SOCKET-FILE_LISTENER: socketInstance[]=%s', gettype($socketInstance)));
return $socketInstance;
}
+ /**
+ * Creates a socket instance from given package data. The socket then
+ * can be used to make outgoing TCP/IPv4/6 connections.
+ *
+ * @param $packageData Valid package data
+ * @return $socketInstance An instance of a StorableSocket class
+ * @throws SocketCreationException If the socket cannot be created
+ * @todo Rewrite this to also handle IPv6 addresses and sockets
+ */
+ public static final function createTcpOutgoingSocketFromPackageData (array $packageData) {
+ // Create a socket instance
+ $socketResource = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
+
+ // Debug message
+ //*NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('SOCKET-FACTORY: Created socket ' . $socketResource . '(' . gettype($socketResource) . ') from class ' . $className . '.');
+
+ // Construct container class, this won't be reached if an exception is thrown
+ // @TODO Somehow handle $infoInstance to this factory
+ $socketInstance = ObjectFactory::createObjectByConfiguredName('socket_container_class', array($socketResource, 'tcp', $packageData, NULL));
+
+ // Is the socket resource valid?
+ if (!$socketInstance->isValidSocket()) {
+ /*
+ * Something bad happened, calling handleSocketError() is not
+ * possible here because that method would throw an
+ * InvalidSocketException back.
+ */
+ throw new SocketCreationException(array($factoryInstance, $socketInstance->getSocketResource()), StorableSocket::EXCEPTION_SOCKET_CREATION_FAILED);
+ } // END - if
+
+ // Get socket error code for verification
+ $socketError = $socketInstance->getLastSocketError();
+
+ // Check if there was an error else
+ if ($socketError > 0) {
+ // Handle this socket error with a faked recipientData array
+ $helperInstance->handleSocketError(__METHOD__, __LINE__, $socketInstance, array('0.0.0.0', '0'));
+ } // END - if
+
+ // Set the option to reuse the port
+ if (!$socketInstance->enableReuseAddress()) {
+ // Handle this socket error with a faked recipientData array
+ $socketInstance->handleSocketError(__METHOD__, __LINE__, array('0.0.0.0', '0'));
+ } // 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 (!$socketInstance->enableSocketNonBlocking()) {
+ // Handle this socket error with a faked recipientData array
+ $socketInstance->handleSocketError(__METHOD__, __LINE__, array('0.0.0.0', '0'));
+ } // END - if
+
+ // Return it
+ return $socketInstance;
+ }
+
}
$this->connectionPort = $connectionPort;
}
- /**
- * Initializes the current connection
- *
- * @return void
- */
- protected function initConnection () {
- // Set the option to reuse the port
- if (!$this->getSocketInstance()->enableReuseAddress()) {
- // Handle this socket error with a faked recipientData array
- $this->getSocketInstance()->handleSocketError(__METHOD__, __LINE__, array('0.0.0.0', '0'));
- } // 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 (!$this->getSocketInstance()->enableSocketNonBlocking()) {
- // Handle this socket error with a faked recipientData array
- $this->getSocketInstance()->handleSocketError(__METHOD__, __LINE__, array('0.0.0.0', '0'));
- } // END - if
-
- // Last step: mark connection as initialized
- $this->setIsInitialized(TRUE);
- }
-
/**
* Attempts to connect to a peer by given IP number and port from an UNL
* instance with currently configured timeout.
* @todo Rewrite the while() loop to a iterator to not let the software stay very long here
*/
protected function connectToPeerByUnlInstance (LocateableNode $unlInstance) {
- // Only call this if the connection is initialized by initConnection()
+ // Only call this if the connection is fully initialized
assert($this->isInitialized());
// Is the UNL data complete?
namespace Hub\Helper\Connection\Tcp;
// Import application-specific stuff
+use Hub\Factory\Socket\SocketFactory;
use Hub\Helper\Connection\ConnectionHelper;
use Hub\Locator\Node\LocateableNode;
use Hub\Network\Package\NetworkPackage;
use Hub\Tools\HubTools;
// Import framework stuff
-use CoreFramework\Factory\ObjectFactory;
/**
* A TCP connection helper class
* connect to the other node.
*
* @param $packageData Raw package data
- * @return $socketResource Socket resource
- * @throws SocketCreationException If the socket could not be created
- * @throws SocketOptionException If a socket option could not be set
- * @throws SocketConnectionException If a connection could not be opened
- * @todo $errorCode/-Message are now in handleSocketError()'s call-back methods
+ * @return $socketInstance An instance of a StorableSocket class
*/
public static function createConnectionFromPackageData (array $packageData) {
// Create an instance
$helperInstance = new TcpConnectionHelper();
- // Create a socket instance
- $socketResource = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
-
- // Debug message
- //*NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('SOCKET-FACTORY: Created socket ' . $socketResource . '(' . gettype($socketResource) . ') from class ' . $className . '.');
-
// Construct container class, this won't be reached if an exception is thrown
- $socketInstance = ObjectFactory::createObjectByConfiguredName('socket_container_class', array($socketResource, NULL, $packageData));
-
- // Is the socket resource valid?
- if (!$socketInstance->isValidSocket()) {
- /*
- * Something bad happened, calling handleSocketError() is not
- * possible here because that method would throw an
- * InvalidSocketException back.
- */
- throw new SocketCreationException(array($helperInstance, gettype($socketResource)), StorableSocket::EXCEPTION_SOCKET_CREATION_FAILED);
- } // END - if
-
- // Get socket error code for verification
- $socketError = $socketInstance->getLastSocketError();
-
- // Check if there was an error else
- if ($socketError > 0) {
- // Handle this socket error with a faked recipientData array
- $helperInstance->handleSocketError(__METHOD__, __LINE__, $socketInstance, array('0.0.0.0', '0'));
-
- // Then throw again
- throw new SocketCreationException(array($helperInstance, gettype($socketResource), $socketError, socket_strerror($socketError)), StorableSocket::EXCEPTION_SOCKET_CREATION_FAILED);
- } // END - if
-
- // Debug message
- //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('HELPER: Setting socket instance ... (' . $socketInstance->__toString() . ')');
+ $socketInstance = SocketFactory::createTcpOutgoingSocketFromPackageData($packageData));
// Set the resource
$helperInstance->setSocketInstance($socketInstance);
- // Init connection
- $helperInstance->initConnection();
-
// @TODO The whole resolving part should be moved out and made more configurable
// Init recipient data
$unlInstance = NULL;
// Get the instance
$registeredInstance = $registryInstance->getInstance($socketKey);
- // Is it SocketContainer and same socket?
- $isRegistered = (($registeredInstance instanceof SocketContainer) && ($registeredInstance->equals($socketInstance)));
+ // Is it StorableSocket and same socket?
+ $isRegistered = (($registeredInstance instanceof StorableSocket) && ($registeredInstance->equals($socketInstance)));
// Debug message
//* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('SOCKET-REGISTRY: Final result: isRegistered(' . $socketInstance->getSocketResource() . ')=' . intval($isRegistered));
// Debug message
//* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('SOCKET-REGISTRY: key=' . $key . ',subKey=' . $subKey . ',containerInstance=' . $containerInstance->__toString());
- // Is this a SocketContainer instance and is the address the same?
- if (($containerInstance instanceof SocketContainer) && ($containerInstance->ifAddressMatches($packageData[NetworkPackage::PACKAGE_DATA_RECIPIENT]))) {
+ // Is this a StorableSocket instance and is the address the same?
+ if (($containerInstance instanceof StorableSocket) && ($containerInstance->ifAddressMatches($packageData[NetworkPackage::PACKAGE_DATA_RECIPIENT]))) {
// Debug die
//* DEBUG-DIE: */ die(__METHOD__ . ': containerInstance=' . print_r($containerInstance, TRUE));
*/
function getSocketType ();
+ /**
+ * Getter for socket procotol field
+ *
+ * @return $socketProtocol Socket protocol (e.g. 'tcp' for TCP/IPv4, 'file' for Uni* file sockets)
+ */
+ function getSocketProtocol ();
+
/**
* Checks whether the given Universal Node Locator matches with the one from package data
*
*/
function handleSocketError ($method, $line, array $socketData);
- /**
- * Translates socket error codes into our own internal names which can be
- * used for call-backs.
- *
- * @param $errorCode The error code from socket_last_error() to be translated
- * @return $errorName The translated name (all lower-case, with underlines)
- */
- function translateSocketErrorCodeToName ($errorCode);
-
/**
* Do the shutdown sequence for this connection helper
*