* @version 0.0.0 * @copyright Copyright (c) 2007, 2008 Roland Haeder, 2009 - 2015 Hub Developer Team * @license GNU GPL 3.0 or any newer version * @link http://www.shipsimu.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 HubTools extends BaseHubSystem { // Constants for exceptions const EXCEPTION_SESSION_ID_IS_INVALID = 0x200; const EXCEPTION_HOSTNAME_NOT_FOUND = 0x201; /** * Cache for session ids */ private $sessionIdCache = array(); /** * Length for session id (should be 32+salt_length */ private $sessionIdLength = 0; /** * Self instance */ private static $selfInstance = NULL; /** * Protected constructor * * @return void */ protected function __construct () { // Call parent constructor parent::__construct(__CLASS__); // Get a DHT instance $dhtInstance = DhtObjectFactory::createDhtInstance('node'); // Set it here $this->setDhtInstance($dhtInstance); // Init salt length $this->sessionIdLength = 32 + $this->getConfigInstance()->getConfigEntry('salt_length'); } /** * Singleton getter for self instance * * @retuen $selfInstance An instance of this class */ public static final function getSelfInstance () { // Is the instance set if (is_null(self::$selfInstance)) { // Then set it self::$selfInstance = new HubTools(); } // END - if // Return own instance return self::$selfInstance; } /** * Getter for session id length * * @return $sessionIdLength Length of session ids */ protected final function getSessionIdLength () { return $this->sessionIdLength; } /** * Resolves a session id into an instance of a LocateableNode class. The opposite method * is resolveSessionIdByUniversalNodeLocator() * * @param $sessionId A valid session id * @return $recipientUniversalNodeLocator Recipient as Universal Node Locator */ protected function resolveUniversalNodeLocatorBySessionId ($sessionId) { // Init variable $recipientUniversalNodeLocator = 'invalid://invalid:invalid'; // And ask it for Universal Node Locator by given session id $recipient = $this->getDhtInstance()->findNodeLocalBySessionId($sessionId); //* DEBUG-DIE: */ die(__METHOD__ . ': UNFINISHED: recipient[' . gettype($recipient) . ']=' . print_r($recipient, TRUE) . ',sessionId=' . $sessionId . PHP_EOL); // Is the recipient valid? if (isset($recipient[NodeDistributedHashTableDatabaseWrapper::DB_COLUMN_EXTERNAL_ADDRESS])) { // Then use this $recipientUniversalNodeLocator = $recipient[NodeDistributedHashTableDatabaseWrapper::DB_COLUMN_EXTERNAL_ADDRESS]; } else { // Get the instance, this might throw a NPE $nodeInstance = NodeObjectFactory::createNodeInstance(); // Is the session id the same? if ($nodeInstance->getSessionId() == $sessionId) { // Then get an instance of a LocateableNode class from it, assume TCP by default $recipientUniversalNodeLocator = self::determineOwnExternalAddress() . ':' . $nodeInstance->getConfigInstance()->getConfigEntry('node_listen_port'); } // END - if } // Return result return $recipientUniversalNodeLocator; } /** * Resolves a session id into a node id by asking local DHT. * * @param $sessionId Session id * @return $nodeId Node id */ public static function resolveNodeIdBySessionId ($sessionId) { // Get an own instance $selfInstance = self::getSelfInstance(); // And ask it for session id by given Universal Node Locator $nodeData = $selfInstance->getDhtInstance()->findNodeLocalBySessionId($sessionId); // Make sure the node id is there /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('HUB-TOOLS[' . __METHOD__ . ':' . __LINE__ . ']: sessionId=' . $sessionId . ', nodeData[' . gettype($nodeData) . ']=' . print_r($nodeData, TRUE)); assert(isset($nodeData[NodeDistributedHashTableDatabaseWrapper::DB_COLUMN_NODE_ID])); // Return it return $nodeData[NodeDistributedHashTableDatabaseWrapper::DB_COLUMN_NODE_ID]; } /** * Resolves a Universal Node Locator into a session id. The "opposite" method * is resolveUniversalNodeLocatorBySessionId(). * * @param $unlInstance Universal Node Locator * @return $sessionId Valid session id */ public static function resolveSessionIdByUniversalNodeLocator (LocateableNode $unlInstance) { // Get an own instance $selfInstance = self::getSelfInstance(); // And ask it for session id by given Universal Node Locator $recipient = $selfInstance->getDhtInstance()->findNodeByUniversalNodeLocator($unlInstance); die(__METHOD__.':recipient='.print_r($recipient, TRUE)); // Return result return $sessionId; } /** * Resolves given session id into an instance of a LocateableNode class, if Universal Node Locator is set, it won't be translated * * @param $address Session id or Universal Node Locator * @return $recipient Recipient as Universal Node Locator * @throws InvalidSessionIdException If the provided session id is invalid (and no Universal Node Locator) * @throws NoValidHostnameException If the provided hostname cannot be resolved into an IP address */ public static function resolveSessionId ($address) { // Get an own instance $selfInstance = self::getSelfInstance(); // Default is direct Universal Node Locator $recipient = $address; // Does it match a direct Universal Node Locator? (hint: see www.regexlib.com for the regular expression) if (preg_match('/([a-z0-9]{3,10})\/\/:([a-z0-9\.]{5,})/', $address)) { // @TODO ((25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9])\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[0-9])):([0-9]{3,5}) // Direct Universal Node Locator found self::createDebugInstance(__CLASS__)->debugOutput('HUB-TOOLS[' . __METHOD__ . ':' . __LINE__ . ']: Direct Universal Node Locator ' . $address . ' detected.'); } elseif (isset($selfInstance->sessionIdCache[$address])) { // Debug message self::createDebugInstance(__CLASS__)->debugOutput('HUB-TOOLS[' . __METHOD__ . ':' . __LINE__ . ']: Using entry from sessionIdCache[] array.'); // Found in cache! $recipient = $selfInstance->sessionIdCache[$address]; // Debug message self::createDebugInstance(__CLASS__)->debugOutput('HUB-TOOLS[' . __METHOD__ . ':' . __LINE__ . ']: sessionIdCache[' . $address . ']=' . $recipient); } elseif (preg_match('/([a-f0-9]{' . $selfInstance->getSessionIdLength() . '})/', $address)) { // Debug message self::createDebugInstance(__CLASS__)->debugOutput('HUB-TOOLS[' . __METHOD__ . ':' . __LINE__ . ']: Using internal session id resolver.'); // Resolve session id into an instance of a LocateableNode class $recipient = $selfInstance->resolveUniversalNodeLocatorBySessionId($address); // Debug message self::createDebugInstance(__CLASS__)->debugOutput('HUB-TOOLS[' . __METHOD__ . ':' . __LINE__ . ']: Session id ' . $address . ' resolved to ' . $recipient); } else { // Invalid session id/UNL throw new InvalidSessionIdException($address, self::EXCEPTION_SESSION_ID_IS_INVALID); } // Return it return $recipient; } /** * Determine UNL or 'external_address' if set * * @return $unl The determined external UNL of this node */ public static function determineOwnExternalAddress () { // Is the external_address config entry set? if (FrameworkConfiguration::getSelfInstance()->getConfigEntry('external_address') != '') { // Use it as external address $unl = FrameworkConfiguration::getSelfInstance()->getConfigEntry('external_address'); } else { // Determine own external address by connecting to my (coder) server at 188.138.90.169 $unl = self::determineExternalUniversalNodeLocator(); } // Return it return $unl; } /** * Determine UNL or 'internal_address' if set * * @return $unl The determined internal UNL of this node */ public static function determineOwnInternalAddress () { // Debug message //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('NODE[' . __METHOD__ . ':' . __LINE__ . ']: CALLED!'); // Is the internal_address config entry set? if (FrameworkConfiguration::getSelfInstance()->getConfigEntry('allow_publish_internal_address') == 'N') { // Debug message //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('NODE[' . __METHOD__ . ':' . __LINE__ . ']: Calling self::determineOwnExternalAddress() as allow_publish_internal_address=N is set ...'); // Not allowed to publish internal address, so use external $unl = self::determineOwnExternalAddress(); } elseif (FrameworkConfiguration::getSelfInstance()->getConfigEntry('internal_address') != '') { // Debug message //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('NODE[' . __METHOD__ . ':' . __LINE__ . ']: Getting config entry internal_address ...'); // Use it as internal address $unl = FrameworkConfiguration::getSelfInstance()->getConfigEntry('internal_address'); } else { // Debug message //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('NODE[' . __METHOD__ . ':' . __LINE__ . ']: Calling self::determineInternalUniversalNodeLocator() ...'); // Determine own internal address $unl = self::determineInternalUniversalNodeLocator(); } // Debug message //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('NODE[' . __METHOD__ . ':' . __LINE__ . ']: unl=' . $unl . ' - EXIT!'); // Return it return $unl; } /** * Determines the UNL (Universal Node Locator) for the internal address * * @return $internalUnl Internal UNL */ public static function determineInternalUniversalNodeLocator () { // Debug message //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('NODE[' . __METHOD__ . ':' . __LINE__ . ']: CALLED!'); // Is there cache? (This shortens a lot calls) if (!isset($GLOBALS[__METHOD__])) { // Determine UNL based on this node: // 1) Get discovery class $discoveryInstance = ObjectFactory::createObjectByConfiguredName('unl_discovery_class'); // 2) "Determine" it $GLOBALS[__METHOD__] = $discoveryInstance->discoverUniversalNodeLocatorByConfiguredAddress('internal'); // Make sure it is valid // @TODO Find a better validation than empty() assert(!empty($GLOBALS[__METHOD__])); } // END - if // Return it //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('NODE[' . __METHOD__ . ':' . __LINE__ . ']: unl=' . $GLOBALS[__METHOD__] . ' - EXIT!'); return $GLOBALS[__METHOD__]; } /** * Determines the UNL (Universal Node Locator) for the external address * * @return $externalUnl External UNL */ public static function determineExternalUniversalNodeLocator () { // Debug message //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('NODE[' . __METHOD__ . ':' . __LINE__ . ']: CALLED!'); // Is there cache? (This shortens a lot calls) if (!isset($GLOBALS[__METHOD__])) { // Determine UNL based on this node: // 1) Get discovery class $discoveryInstance = ObjectFactory::createObjectByConfiguredName('unl_discovery_class'); // 2) "Determine" it $GLOBALS[__METHOD__] = $discoveryInstance->discoverUniversalNodeLocatorByConfiguredAddress('external'); // Make sure it is valid // @TODO Find a better validation than empty() assert(!empty($GLOBALS[__METHOD__])); } // END - if // Return it //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('NODE[' . __METHOD__ . ':' . __LINE__ . ']: unl=' . $GLOBALS[__METHOD__] . ' - EXIT!'); return $GLOBALS[__METHOD__]; } } // [EOF] ?>