From 892e2113731fa21e0e60891394ed0b19cc360e85 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Roland=20H=C3=A4der?= Date: Sun, 13 Jun 2010 21:38:38 +0000 Subject: [PATCH] New Exception added, registering of session ids added: - New PeerAlreadyRegisteredException added which is thrown when the peer is already registered with the same session id - Registering of peers with their session id basicly added, purging unfinished --- .gitattributes | 2 + application/hub/config.php | 6 ++ application/hub/exceptions/peer/.htaccess | 1 + .../class_PeerAlreadyRegisteredException.php | 45 +++++++++++++ .../peer_states/class_LookupablePeerState.php | 17 +++++ .../class_PeerStateLookupDatabaseWrapper.php | 65 +++++++++++++++++++ .../states/peer/class_PeerStateFactory.php | 15 +++-- .../tcp/class_TcpNetworkPackageHandler.php | 2 +- .../peer/class_PeerStateLookupTable.php | 24 ++++++- .../hub/main/nodes/boot/class_HubBootNode.php | 2 +- .../hub/main/nodes/class_BaseHubNode.php | 16 ++++- .../network/class_NetworkStateResolver.php | 5 +- application/hub/main/tools/class_HubTools.php | 6 ++ 13 files changed, 195 insertions(+), 11 deletions(-) create mode 100644 application/hub/exceptions/peer/.htaccess create mode 100644 application/hub/exceptions/peer/class_PeerAlreadyRegisteredException.php diff --git a/.gitattributes b/.gitattributes index ea3e01466..af852c6f9 100644 --- a/.gitattributes +++ b/.gitattributes @@ -16,6 +16,8 @@ application/hub/exceptions/lists/.htaccess -text application/hub/exceptions/lists/class_InvalidListHashException.php -text application/hub/exceptions/lists/class_ListGroupAlreadyAddedException.php -text application/hub/exceptions/lists/class_NoListGroupException.php -text +application/hub/exceptions/peer/.htaccess -text +application/hub/exceptions/peer/class_PeerAlreadyRegisteredException.php -text application/hub/exceptions/state/.htaccess -text application/hub/exceptions/state/class_InvalidStateException.php -text application/hub/exceptions/tags/.htaccess -text diff --git a/application/hub/config.php b/application/hub/config.php index f86fdd3a3..a96da58c2 100644 --- a/application/hub/config.php +++ b/application/hub/config.php @@ -33,6 +33,12 @@ $cfg->setConfigEntry('node_tcp_listen_port', 9060); // CFG: NODE-UDP-LISTEN-PORT $cfg->setConfigEntry('node_udp_listen_port', 9060); +// CFG: BOOT-NODE-TCP-LISTEN-PORT +$cfg->setConfigEntry('boot_node_tcp_listen_port', 9061); + +// CFG: BOOT-NODE-UDP-LISTEN-PORT +$cfg->setConfigEntry('boot_node_udp_listen_port', 9061); + // CFG: NODE-MODE (can be 'regular', 'list', 'master' or 'boot', default is 'regular') $cfg->setConfigEntry('node_mode', 'regular'); diff --git a/application/hub/exceptions/peer/.htaccess b/application/hub/exceptions/peer/.htaccess new file mode 100644 index 000000000..3a4288278 --- /dev/null +++ b/application/hub/exceptions/peer/.htaccess @@ -0,0 +1 @@ +Deny from all diff --git a/application/hub/exceptions/peer/class_PeerAlreadyRegisteredException.php b/application/hub/exceptions/peer/class_PeerAlreadyRegisteredException.php new file mode 100644 index 000000000..2cc655cff --- /dev/null +++ b/application/hub/exceptions/peer/class_PeerAlreadyRegisteredException.php @@ -0,0 +1,45 @@ + + * @version 0.0.0 + * @copyright Copyright (c) 2007, 2008 Roland Haeder, 2009, 2010 Hub Developer Team + * @license GNU GPL 3.0 or any newer version + * @link http://www.ship-simu.org + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +class PeerAlreadyRegisteredException extends FrameworkException { + /** + * The super constructor for all exceptions + * + * @param $messageArray Error message array + * @param $code Error code + * @return void + */ + public function __construct (array $messageArray, $code) { + // Construct the message + $message = sprintf("[%s] Sender %s is already registered.", + $messageArray[0]->__toString(), + $messageArray[NetworkPackage::INDEX_PACKAGE_SENDER] + ); + + // Call parent exception constructor + parent::__construct($message, $code); + } +} + +// [EOF] +?> diff --git a/application/hub/interfaces/lookup/peer_states/class_LookupablePeerState.php b/application/hub/interfaces/lookup/peer_states/class_LookupablePeerState.php index 94f7d0970..d31521715 100644 --- a/application/hub/interfaces/lookup/peer_states/class_LookupablePeerState.php +++ b/application/hub/interfaces/lookup/peer_states/class_LookupablePeerState.php @@ -30,6 +30,15 @@ interface LookupablePeerState extends Lookupable { */ function isSenderNewPeer (array $packageData); + /** + * Registers a peer with given package data. We use the session id from it + * + * @param $packageData Valid raw package data + * @param $socketResource A valid socket resource + * @return<>void + */ + function registerPeerByPackageData (array $packageData, $socketResource); + /** * Registers the given peer state and raw package data * @@ -38,6 +47,14 @@ interface LookupablePeerState extends Lookupable { * @return void */ function registerPeerState (PeerStateable $stateInstance, array $packageData); + + /** + * Purges old entries of given socket resource. We use the IP address from that resource. + * + * @param $socketResource A valid socket resource + * @return void + */ + function purgeOldEntriesBySocketResource ($socketResource); } // [EOF] diff --git a/application/hub/main/database/wrapper/class_PeerStateLookupDatabaseWrapper.php b/application/hub/main/database/wrapper/class_PeerStateLookupDatabaseWrapper.php index 10c2813b5..d1f44cea0 100644 --- a/application/hub/main/database/wrapper/class_PeerStateLookupDatabaseWrapper.php +++ b/application/hub/main/database/wrapper/class_PeerStateLookupDatabaseWrapper.php @@ -22,11 +22,16 @@ * along with this program. If not, see . */ class PeerStateLookupDatabaseWrapper extends BaseDatabaseWrapper { + // Exception constants + const EXCEPTION_PEER_ALREADY_REGISTERED = 0x300; + // Constants for database table names const DB_TABLE_PEER_LOOKUP = 'peer_states'; // Constants for database column names const DB_COLUMN_PEER_IP = 'peer_ip'; + const DB_COLUMN_PEER_PORT = 'peer_port'; + const DB_COLUMN_PEER_SESSION_ID = 'peer_session_id'; /** * Protected constructor @@ -95,6 +100,66 @@ class PeerStateLookupDatabaseWrapper extends BaseDatabaseWrapper { // Return the result return $isNewPeer; } + + /** + * Registers a new peer with given package data. We use the session id from it. + * + * @param $packageData Raw package data + * @param $socketResource A valid socket resource + * @return void + * @throws PeerAlreadyRegisteredException If a peer is already registered + * @throws InvalidSocketException If the socket resource was invalid + */ + public function registerPeerByPackageData (array $packageData, $socketResource) { + // Make sure only new peers can be registered with package data + if (!$this->isSenderNewPeer($packageData)) { + // Throw an exception because this should normally not happen + throw new PeerAlreadyRegisteredException(array($this, $packageData), self::EXCEPTION_PEER_ALREADY_REGISTERED); + } // END - if + + // Generate a dataset instance + $dataSetInstance = ObjectFactory::createObjectByConfiguredName('dataset_criteria_class', array(self::DB_TABLE_PEER_LOOKUP)); + + // Session ids must be unique + $dataSetInstance->setUniqueKey(self::DB_COLUMN_PEER_SESSION_ID); + + // Add session id + $dataSetInstance->addCriteria(self::DB_COLUMN_PEER_SESSION_ID, $packageData[NetworkPackage::INDEX_PACKAGE_SENDER]); + + // Get peer name + if (!socket_getpeername($socketResource, $peerName, $peerPort)) { + // Get last error + $lastError = socket_last_error($socketResource); + + // Doesn't work! + throw new InvalidSocketException(array($this, gettype($socketResource), $lastError, socket_strerror($lastError)), BaseListener::EXCEPTION_INVALID_SOCKET); + } // END - if + + // Add ip address and port + $dataSetInstance->addCriteria(self::DB_COLUMN_PEER_IP , $peerName); + $dataSetInstance->addCriteria(self::DB_COLUMN_PEER_PORT, $peerPort); + + // "Insert" the data set + $this->getDatabaseInstance()->queryInsertDataSet($dataSetInstance); + } + + /** + * Purges old entries of given socket resource. We use the IP address from that resource. + * + * @param $socketResource A valid socket resource + * @return void + * @throws InvalidSocketException If the socket resource was invalid + */ + public function purgeOldEntriesBySocketResource ($socketResource) { + // Get peer name + if (!socket_getpeername($socketResource, $peerName, $peerPort)) { + // Get last error + $lastError = socket_last_error($socketResource); + + // Doesn't work! + throw new InvalidSocketException(array($this, gettype($socketResource), $lastError, socket_strerror($lastError)), BaseListener::EXCEPTION_INVALID_SOCKET); + } // END - if + } } // [EOF] diff --git a/application/hub/main/factories/states/peer/class_PeerStateFactory.php b/application/hub/main/factories/states/peer/class_PeerStateFactory.php index 22e340239..1256fa6e6 100644 --- a/application/hub/main/factories/states/peer/class_PeerStateFactory.php +++ b/application/hub/main/factories/states/peer/class_PeerStateFactory.php @@ -42,19 +42,26 @@ class PeerStateFactory extends ObjectFactory { * for the peer given in $packageData 'sender' element or it changes the state if it differs * from current state. * - * @param $errorCode The last error code - * @param $packageData Raw package data - * @return $stateInstance A Stateable class instance + * @param $errorCode The last error code + * @param $packageData Raw package data + * @param $socketResource A valid socket resource + * @return $stateInstance A Stateable class instance */ - public static final function createPeerStateInstanceByErrorCode ($errorCode, array $packageData) { + public static final function createPeerStateInstanceByErrorCode ($errorCode, array $packageData, $socketResource) { // So first we need our lookup table $tableInstance = self::getTableInstance(); + // Purge old entries + $tableInstance->purgeOldEntriesBySocketResource($socketResource); + // Do we have an entry? if ($tableInstance->isSenderNewPeer($packageData)) { // Is a new peer so create the state instance based on error code, first we need a config entry $configEntry = 'peer_state_' . $errorCode . '_class'; + // Register the new peer with its session id + $tableInstance->registerPeerByPackageData($packageData, $socketResource); + // Then get it $stateInstance = ObjectFactory::createObjectByConfiguredName($configEntry); diff --git a/application/hub/main/handler/network/tcp/class_TcpNetworkPackageHandler.php b/application/hub/main/handler/network/tcp/class_TcpNetworkPackageHandler.php index a5d09ed7d..1bc410064 100644 --- a/application/hub/main/handler/network/tcp/class_TcpNetworkPackageHandler.php +++ b/application/hub/main/handler/network/tcp/class_TcpNetworkPackageHandler.php @@ -136,7 +136,7 @@ class TcpNetworkPackageHandler extends BaseNetworkPackageHandler implements Netw } // Get a state from the resolver for this package - $stateInstance = $this->getResolverInstance()->resolveStateByPackage($this, $packageData); + $stateInstance = $this->getResolverInstance()->resolveStateByPackage($this, $packageData, $resource); die('UNFINISHED:'.$stateInstance->__toString()."\n"); } } diff --git a/application/hub/main/lookup/peer/class_PeerStateLookupTable.php b/application/hub/main/lookup/peer/class_PeerStateLookupTable.php index 60b452196..2447a1d9f 100644 --- a/application/hub/main/lookup/peer/class_PeerStateLookupTable.php +++ b/application/hub/main/lookup/peer/class_PeerStateLookupTable.php @@ -65,6 +65,18 @@ class PeerStateLookupTable extends BaseLookupTable implements LookupablePeerStat return $isNewPeer; } + /** + * Registers a peer with given package data. We use the session id from it + * + * @param $packageData Valid raw package data + * @param $socketResource A valid socket resource + * @return void + */ + public function registerPeerByPackageData (array $packageData, $socketResource) { + // Just handle it over + $this->getWrapperInstance()->registerPeerByPackageData($packageData, $socketResource); + } + /** * Registers the given peer state and raw package data * @@ -75,7 +87,17 @@ class PeerStateLookupTable extends BaseLookupTable implements LookupablePeerStat public function registerPeerState (PeerStateable $stateInstance, array $packageData) { die(__METHOD__."\n"); } -} + + /** + * Purges old entries of given socket resource. We use the IP address from that resource. + * + * @param $socketResource A valid socket resource + * @return void + */ + public function purgeOldEntriesBySocketResource ($socketResource) { + // Just handle it over + $this->getWrapperInstance()->purgeOldEntriesBySocketResource($socketResource); + } // [EOF] ?> diff --git a/application/hub/main/nodes/boot/class_HubBootNode.php b/application/hub/main/nodes/boot/class_HubBootNode.php index e4cf363dc..f884f53bb 100644 --- a/application/hub/main/nodes/boot/class_HubBootNode.php +++ b/application/hub/main/nodes/boot/class_HubBootNode.php @@ -61,7 +61,7 @@ class HubBootNode extends BaseHubNode implements NodeHelper, Registerable { // Now check if the IP address matches one of the bootstrap nodes if ($this->ifAddressMatchesBootstrappingNodes($this->getConfigInstance()->detectServerAddress())) { // Get our port from configuration - $ourPort = $this->getConfigInstance()->getConfigEntry('node_tcp_listen_port'); + $ourPort = $this->getConfigInstance()->getConfigEntry('boot_node_tcp_listen_port'); // Extract port $bootPort = substr($this->getBootIpPort(), -strlen($ourPort), strlen($ourPort)); diff --git a/application/hub/main/nodes/class_BaseHubNode.php b/application/hub/main/nodes/class_BaseHubNode.php index e28e339b0..e3c1dc3bb 100644 --- a/application/hub/main/nodes/class_BaseHubNode.php +++ b/application/hub/main/nodes/class_BaseHubNode.php @@ -550,7 +550,13 @@ class BaseHubNode extends BaseHubSystem implements Updateable { // Setup address and port $listenerInstance->setListenAddressByConfiguration('node_listen_addr'); - $listenerInstance->setListenPortByConfiguration('node_tcp_listen_port'); + if ($this instanceof HubBootNode) { + // Bootstrap have different listening port + $listenerInstance->setListenPortByConfiguration('boot_node_tcp_listen_port'); + } else { + // All other nodes use the default port + $listenerInstance->setListenPortByConfiguration('node_tcp_listen_port'); + } // Initialize the listener $listenerInstance->initListener(); @@ -572,7 +578,13 @@ class BaseHubNode extends BaseHubSystem implements Updateable { // Setup address and port $listenerInstance->setListenAddressByConfiguration('node_listen_addr'); - $listenerInstance->setListenPortByConfiguration('node_udp_listen_port'); + if ($this instanceof HubBootNode) { + // Bootstrap have different listening port + $listenerInstance->setListenPortByConfiguration('boot_node_udp_listen_port'); + } else { + // All other nodes use the default port + $listenerInstance->setListenPortByConfiguration('node_udp_listen_port'); + } // Initialize the listener $listenerInstance->initListener(); diff --git a/application/hub/main/resolver/state/network/class_NetworkStateResolver.php b/application/hub/main/resolver/state/network/class_NetworkStateResolver.php index 203a87149..5b8de9646 100644 --- a/application/hub/main/resolver/state/network/class_NetworkStateResolver.php +++ b/application/hub/main/resolver/state/network/class_NetworkStateResolver.php @@ -63,10 +63,11 @@ class NetworkStateResolver extends BaseStateResolver implements StateResolver { * * @param $packageInstance An instance of a package class * @param $packageData Raw package data + * @param $socketResource A valid socket resource * @return $stateInstance An instance of the resolved state * @todo ~30% done */ - public function resolveStateByPackage (Networkable $packageInstance, array $packageData) { + public function resolveStateByPackage (Networkable $packageInstance, array $packageData, $socketResource) { // Init state instance $stateInstance = null; @@ -87,7 +88,7 @@ class NetworkStateResolver extends BaseStateResolver implements StateResolver { } // END - if // Create a state instance based on $errorCode. This factory does the hard work for us - $stateInstance = PeerStateFactory::createPeerStateInstanceByErrorCode($errorCode, $packageData); + $stateInstance = PeerStateFactory::createPeerStateInstanceByErrorCode($errorCode, $packageData, $socketResource); // Return the prepared instance return $stateInstance; diff --git a/application/hub/main/tools/class_HubTools.php b/application/hub/main/tools/class_HubTools.php index 9f51a9947..4525f503e 100644 --- a/application/hub/main/tools/class_HubTools.php +++ b/application/hub/main/tools/class_HubTools.php @@ -113,12 +113,18 @@ class HubTools extends BaseFrameworkSystem { if (!preg_match('/((?:2[0-5]{2}|1\d{2}|[1-9]\d|[1-9])\.(?:(?:2[0-5]{2}|1\d{2}|[1-9]\d|\d)\.){2}(?:2[0-5]{2}|1\d{2}|[1-9]\d|\d)):(\d|[1-9]\d|[1-9]\d{2,3}|[1-5]\d{4}|6[0-4]\d{3}|654\d{2}|655[0-2]\d|6553[0-5])/', $sessionId)) { // Is it in cache? if (isset($selfInstance->sessionIdCache[$sessionId])) { + // Debug message + $selfInstance->debugOutput('HUB-TOOLS: Using entry from sessionIdCache[] array.'); + // Then use it $recipient = $selfInstance->sessionIdCache[$sessionId]; } elseif (!preg_match('/([a-f0-9]{' . $selfInstance->getSessionIdLength() . '})/', $sessionId)) { // Invalid session id throw new InvalidSessionIdException($sessionId, self::EXCEPTION_SESSION_ID_IS_INVALID); } else { + // Debug message + $selfInstance->debugOutput('HUB-TOOLS: Using internal resolver.'); + // Resolve it here $recipient = $selfInstance->resolveIpPortBySessionId($sessionId); } -- 2.39.5