*
* @author Roland Haeder <webmaster@ship-simu.org>
* @version 0.0.0
- * @copyright Copyright (c) 2007, 2008 Roland Haeder, 2009, 2010 Core Developer Team
+ * @copyright Copyright (c) 2007, 2008 Roland Haeder, 2009 - 2011 Core Developer Team
* @license GNU GPL 3.0 or any newer version
* @link http://www.ship-simu.org
* @todo Find an interface for hub helper
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-class TcpConnectionHelper extends BaseConnectionHelper {
+class TcpConnectionHelper extends BaseConnectionHelper implements ConnectionHelper {
/**
* Protected constructor
*
*
* @param $packageData Raw package data
* @return $socketResource Socket resource
- * @throws InvalidSocketException If the socket is invalid
+ * @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
*/
public static function createConnectionFromPackageData (array $packageData) {
// Create an instance
// Is the socket resource valid?
if (!is_resource($socketResource)) {
// Something bad happened
- throw new InvalidSocketException(array($helperInstance, gettype($socketResource), 0, 'invalid'), BaseListener::EXCEPTION_INVALID_SOCKET);
+ throw new SocketCreationException(array($helperInstance, gettype($socketResource), 0, 'invalid'), BaseListener::EXCEPTION_SOCKET_CREATION_FAILED);
} // END - if
// Get socket error code for verification
// Check if there was an error else
if ($socketError > 0) {
- // Then throw again
- throw new InvalidSocketException(array($helperInstance, gettype($socketResource), $socketError, socket_strerror($socketError)), BaseListener::EXCEPTION_INVALID_SOCKET);
- } // END - if
-
- // Set the option to reuse the port
- if (!socket_set_option($socketResource, SOL_SOCKET, SO_REUSEADDR, 1)) {
- // Get socket error code for verification
- $socketError = socket_last_error($socketResource);
-
- // Get error message
- $errorMessage = socket_strerror($socketError);
-
// Shutdown this socket
$helperInstance->shutdownSocket($socketResource);
- // And throw again
- throw new InvalidSocketException(array($helperInstance, gettype($socketResource), $socketError, $errorMessage), BaseListener::EXCEPTION_INVALID_SOCKET);
+ // Then throw again
+ throw new SocketCreationException(array($helperInstance, gettype($socketResource), $socketError, socket_strerror($socketError)), BaseListener::EXCEPTION_SOCKET_CREATION_FAILED);
} // END - if
- // Now, we want non-blocking mode
- if (!socket_set_nonblock($socketResource)) {
+ // Set the option to reuse the port
+ if (!socket_set_option($socketResource, SOL_SOCKET, SO_REUSEADDR, 1)) {
// Get socket error code for verification
$socketError = socket_last_error($socketResource);
$helperInstance->shutdownSocket($socketResource);
// And throw again
- throw new InvalidSocketException(array($helperInstance, gettype($socketResource), $socketError, $errorMessage), BaseListener::EXCEPTION_INVALID_SOCKET);
+ throw new SocketOptionException(array($helperInstance, gettype($socketResource), $socketError, $errorMessage), BaseListener::EXCEPTION_INVALID_SOCKET);
} // END - if
// Set the resource
$helperInstance->setSocketResource($socketResource);
- // Resolve any session ids; 0 = IP, 1 = Port
- $recipientData = explode(':', HubTools::resolveSessionId($packageData['recipient']));
+ // @TODO The whole resolving part should be moved out and made more configurable
+ // Init recipient data
+ $recipientData = NULL;
+
+ // Try to solve the recipient
+ try {
+ // Resolve any session ids; 0 = IP, 1 = Port
+ $recipientData = explode(':', HubTools::resolveSessionId($packageData[NetworkPackage::PACKAGE_DATA_RECIPIENT]));
+ } catch (NoValidHostnameException $e) {
+ // Debug message
+ $helperInstance->debugOutput('CONNECTION: Failed to resolve ' . $packageData[NetworkPackage::PACKAGE_DATA_RECIPIENT] . ':' . $e->getMessage());
+
+ // Is the recipient equal as configured IP
+ if (substr($packageData[NetworkPackage::PACKAGE_DATA_RECIPIENT], 0, strlen($helperInstance->getConfigInstance()->getConfigEntry('external_ip'))) == $helperInstance->getConfigInstance()->getConfigEntry('external_ip')) {
+ // This connects to ship-simu.org and requests /ip.php which will return our external IP number
+ $recipientData[0] = ConsoleTools::determineExternalIp();
+
+ // Do we have hostname:ip match?
+ if (strpos($packageData[NetworkPackage::PACKAGE_DATA_RECIPIENT], ':') === false) {
+ // No hostname:ip!
+ $helperInstance->debugInstance($packageData[NetworkPackage::PACKAGE_DATA_RECIPIENT] . ' does not contain ":". Please fix this.');
+ } // END - if
+
+ // "explode" the hostname:ip, so index 1 will be the port number
+ $recipientArray = explode(':', $packageData[NetworkPackage::PACKAGE_DATA_RECIPIENT]);
+
+ // Add the port
+ $recipientData[1] = $recipientArray[1];
+ } else {
+ // It doesn't match, we need to take care of this later
+ $helperInstance->debugInstance($packageData[NetworkPackage::PACKAGE_DATA_RECIPIENT] . '!=' . $helperInstance->getConfigInstance()->getConfigEntry('external_ip'));
+ }
+ }
// Set ip/port
$helperInstance->setAddress($recipientData[0]);
$helperInstance->shutdownSocket($socketResource);
// Throw it again
- throw new InvalidSocketException(array($helperInstance, gettype($socketResource), $socketError, $errorMessage), BaseListener::EXCEPTION_INVALID_SOCKET);
+ throw new SocketConnectionException(array($helperInstance, gettype($socketResource), $socketError, $errorMessage), BaseListener::EXCEPTION_INVALID_SOCKET);
} else {
// Debug output
$helperInstance->debugOutput('CONNECTION: Operation is in progress, this usual for non-blocking connections.');
}
} // END - if
+ // Now, we want non-blocking mode
+ if (!socket_set_nonblock($socketResource)) {
+ // Get socket error code for verification
+ $socketError = socket_last_error($socketResource);
+
+ // Get error message
+ $errorMessage = socket_strerror($socketError);
+
+ // Shutdown this socket
+ $helperInstance->shutdownSocket($socketResource);
+
+ // And throw again
+ throw new SocketOptionException(array($helperInstance, gettype($socketResource), $socketError, $errorMessage), BaseListener::EXCEPTION_INVALID_SOCKET);
+ } // END - if
+
+ // We have a connection, so change the state
+ PeerStateFactory::createPeerStateInstanceByName('connected', $helperInstance);
+
// Okay, that should be it. So return it...
return $socketResource;
}
/**
- * Do the shutdown sequence for TCP connections
+ * Do the shutdown sequence for this connection helper
*
- * @todo We may want to implement a filter for ease notification of other objects like our pool
* @return void
* @throws SocketShutdownException If the current socket could not be shut down
+ * @todo We may want to implement a filter for ease notification of other objects like our pool
*/
public function doShutdown () {
+ // Debug message
+ $this->debugOutput('HELPER: Shutting down socket resource ' . $this->getSocketResource());
+
// Clear any previous errors
socket_clear_error($this->getSocketResource());
} // END - if
// Mark this connection as shutted down
- $this->markConnectionShutdown();
+ $this->markConnectionShuttedDown();
}
}