From: Roland Haeder Date: Thu, 20 Mar 2014 20:36:54 +0000 (+0100) Subject: Introduced enableAcceptDhtBootstrap() + updated core. X-Git-Url: https://git.mxchange.org/?a=commitdiff_plain;h=c57682d8462527d5cc6064e03dd205c3ed0d8b95;p=hub.git Introduced enableAcceptDhtBootstrap() + updated core. Signed-off-by: Roland Haeder --- diff --git a/application/hub/interfaces/distributable/class_Distributable.php b/application/hub/interfaces/distributable/class_Distributable.php index 0743d683e..4ed84d86a 100644 --- a/application/hub/interfaces/distributable/class_Distributable.php +++ b/application/hub/interfaces/distributable/class_Distributable.php @@ -106,6 +106,13 @@ interface Distributable extends FrameworkInterface { * @return $recipientList Array with DHT recipients from given key/value pair */ function findRecipientsByKey ($key, $value); + + /** + * Enable DHT bootstrap request acceptance for local node + * + * @return void + */ + function enableAcceptDhtBootstrap (); } // [EOF] diff --git a/application/hub/interfaces/wrapper/class_NodeDhtWrapper.php b/application/hub/interfaces/wrapper/class_NodeDhtWrapper.php index b962cc9de..9b8ba7a8d 100644 --- a/application/hub/interfaces/wrapper/class_NodeDhtWrapper.php +++ b/application/hub/interfaces/wrapper/class_NodeDhtWrapper.php @@ -158,6 +158,13 @@ interface NodeDhtWrapper extends DatabaseWrapper { * @return $recipients An indexed array with DHT recipients */ function getResultFromKeyValue ($key, $value); + + /** + * Enable DHT bootstrap request acceptance for local node + * + * @return void + */ + function enableAcceptDhtBootstrap (); } // [EOF] diff --git a/application/hub/main/database/.htaccess b/application/hub/main/database/.htaccess deleted file mode 100644 index 3a4288278..000000000 --- a/application/hub/main/database/.htaccess +++ /dev/null @@ -1 +0,0 @@ -Deny from all diff --git a/application/hub/main/database/wrapper/.htaccess b/application/hub/main/database/wrapper/.htaccess deleted file mode 100644 index 3a4288278..000000000 --- a/application/hub/main/database/wrapper/.htaccess +++ /dev/null @@ -1 +0,0 @@ -Deny from all diff --git a/application/hub/main/database/wrapper/cruncher/.htaccess b/application/hub/main/database/wrapper/cruncher/.htaccess deleted file mode 100644 index 3a4288278..000000000 --- a/application/hub/main/database/wrapper/cruncher/.htaccess +++ /dev/null @@ -1 +0,0 @@ -Deny from all diff --git a/application/hub/main/database/wrapper/cruncher/class_CruncherUnitDatabaseWrapper.php b/application/hub/main/database/wrapper/cruncher/class_CruncherUnitDatabaseWrapper.php deleted file mode 100644 index 32bf47667..000000000 --- a/application/hub/main/database/wrapper/cruncher/class_CruncherUnitDatabaseWrapper.php +++ /dev/null @@ -1,84 +0,0 @@ - - * @version 0.0.0 - * @copyright Copyright (c) 2011 - 2012 Cruncher 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 CruncherUnitDatabaseWrapper extends BaseDatabaseWrapper implements UnitDatabaseWrapper, Registerable { - // Constants for database table names - const DB_TABLE_CRUNCHER_UNITS = 'cruncher_units'; - - // Constants for database column names - const DB_COLUMN_UNIT_TYPE = 'unit_type'; - const DB_COLUMN_UNIT_STATUS = 'unit_status'; - - /** - * Protected constructor - * - * @return void - */ - protected function __construct () { - // Call parent constructor - parent::__construct(__CLASS__); - } - - /** - * Creates an instance of this database wrapper by a provided user class - * - * @return $wrapperInstance An instance of the created wrapper class - */ - public static final function createCruncherUnitDatabaseWrapper () { - // Get a new instance - $wrapperInstance = new CruncherUnitDatabaseWrapper(); - - // Set (primary!) table name - $wrapperInstance->setTableName(self::DB_TABLE_CRUNCHER_UNITS); - - // Return the instance - return $wrapperInstance; - } - - /** - * Checks whether a test unit has been produced - * - * @return $isProduced Whether a test unit has already been produced - */ - public function isTestUnitProduced () { - // Now get a search instance - $searchInstance = ObjectFactory::createObjectByConfiguredName('search_criteria_class'); - - // Add criteria for looking up already created and available test units - $searchInstance->addCriteria(self::DB_COLUMN_UNIT_TYPE , BaseUnitProducer::UNIT_TYPE_TEST_UNIT); - $searchInstance->addCriteria(self::DB_COLUMN_UNIT_STATUS, BaseUnitProducer::UNIT_STATUS_AVAILABLE); - $searchInstance->setConfiguredLimit('cruncher_test_unit_max_count'); - - // Search for our units - $resultInstance = $this->doSelectByCriteria($searchInstance); - - // Do we have some entries? - $isProduced = $resultInstance->next(); - - // Return it - return $isProduced; - } -} - -// [EOF] -?> diff --git a/application/hub/main/database/wrapper/node/.htaccess b/application/hub/main/database/wrapper/node/.htaccess deleted file mode 100644 index 3a4288278..000000000 --- a/application/hub/main/database/wrapper/node/.htaccess +++ /dev/null @@ -1 +0,0 @@ -Deny from all diff --git a/application/hub/main/database/wrapper/node/class_NodeDistributedHashTableDatabaseWrapper.php b/application/hub/main/database/wrapper/node/class_NodeDistributedHashTableDatabaseWrapper.php deleted file mode 100644 index 08c8a7716..000000000 --- a/application/hub/main/database/wrapper/node/class_NodeDistributedHashTableDatabaseWrapper.php +++ /dev/null @@ -1,569 +0,0 @@ - - * @version 0.0.0 - * @copyright Copyright (c) 2007, 2008 Roland Haeder, 2009 - 2012 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 NodeDistributedHashTableDatabaseWrapper extends BaseDatabaseWrapper implements NodeDhtWrapper, Registerable { - /** - * "Cached" results for dabase for looking for unpublished entries - */ - private $unpublishedEntriesInstance = NULL; - - // Constants for database table names - const DB_TABLE_NODE_DHT = 'node_dht'; - - // Constants for database column names - const DB_COLUMN_NODE_ID = 'node_id'; - const DB_COLUMN_SESSION_ID = 'session_id'; - const DB_COLUMN_EXTERNAL_IP = 'external_ip'; - const DB_COLUMN_LISTEN_PORT = 'listen_port'; - const DB_COLUMN_PRIVATE_KEY_HASH = 'private_key_hash'; - const DB_COLUMN_NODE_MODE = 'node_mode'; - const DB_COLUMN_ACCEPTED_OBJECTS = 'accepted_object_types'; - const DB_COLUMN_NODE_LIST = 'node_list'; - const DB_COLUMN_PUBLICATION_STATUS = 'publication_status'; - const DB_COLUMN_ANSWER_STATUS = 'answer_status'; - const DB_COLUMN_ACCEPT_BOOTSTRAP = 'accept_bootstrap'; - - // Publication status' - const PUBLICATION_STATUS_PENDING = 'PENDING'; - - // Exception codes - const EXCEPTION_NODE_ALREADY_REGISTERED = 0x800; - const EXCEPTION_NODE_NOT_REGISTERED = 0x801; - - /** - * Protected constructor - * - * @return void - */ - protected function __construct () { - // Call parent constructor - parent::__construct(__CLASS__); - } - - /** - * Creates an instance of this database wrapper by a provided user class - * - * @return $wrapperInstance An instance of the created wrapper class - */ - public static final function createNodeDistributedHashTableDatabaseWrapper () { - // Get a new instance - $wrapperInstance = new NodeDistributedHashTableDatabaseWrapper(); - - // Set (primary!) table name - $wrapperInstance->setTableName(self::DB_TABLE_NODE_DHT); - - // Return the instance - return $wrapperInstance; - } - - /** - * Static getter for an array of all DHT database entries - * - * @return $elements All elements for the DHT dabase - */ - public static final function getAllElements () { - // Create array and ... - $elements = array( - self::DB_COLUMN_NODE_ID, - self::DB_COLUMN_SESSION_ID, - self::DB_COLUMN_EXTERNAL_IP, - self::DB_COLUMN_LISTEN_PORT, - self::DB_COLUMN_PRIVATE_KEY_HASH, - self::DB_COLUMN_NODE_MODE, - self::DB_COLUMN_ACCEPTED_OBJECTS, - self::DB_COLUMN_NODE_LIST - ); - - // ... return it - return $elements; - } - - /** - * Prepares a search instance for given node data - * - * @param $nodeData An array with valid node data - * @return $searchInstance An instance of a SearchCriteria class - */ - private function prepareSearchInstance (array $nodeData) { - // Assert on array elements - assert(isset($nodeData[self::DB_COLUMN_NODE_ID])); - - // Get instance - $searchInstance = ObjectFactory::createObjectByConfiguredName('search_criteria_class'); - - // Search for node id and limit it to one entry - $searchInstance->addCriteria(self::DB_COLUMN_NODE_ID, $nodeData[self::DB_COLUMN_NODE_ID]); - $searchInstance->setLimit(1); - - // Return it - return $searchInstance; - } - - /** - * Getter for result instance for unpublished entries - * - * @return $unpublishedEntriesInstance Result instance - */ - public final function getUnpublishedEntriesInstance () { - return $this->unpublishedEntriesInstance; - } - - /** - * Prepares a "local" instance of a StoreableCriteria class with all node - * data for insert/update queries. This data set contains data from *this* - * (local) node. - * - * @return $dataSetInstance An instance of a StoreableCriteria class - */ - private function prepareLocalDataSetInstance () { - // Get node/request instances - $nodeInstance = NodeObjectFactory::createNodeInstance(); - $requestInstance = ApplicationHelper::getSelfInstance()->getRequestInstance(); - - // Get a dataset instance - $dataSetInstance = ObjectFactory::createObjectByConfiguredName('dataset_criteria_class', array(self::DB_TABLE_NODE_DHT)); - - // Set the primary key - $dataSetInstance->setUniqueKey(self::DB_COLUMN_NODE_ID); - - // Get ip:port combination and "explode" it - $ipPort = $nodeInstance->getAddressPortArray(); - - // Make sure both is valid - assert(($ipPort[0] !== 'invalid') && ($ipPort[1] !== 'invalid')); - - // Get an array of all accepted object types - $objectList = $nodeInstance->getListFromAcceptedObjectTypes(); - - // Make sure this is an array - assert(is_array($objectList)); - - // Add public node data - $dataSetInstance->addCriteria(self::DB_COLUMN_NODE_MODE , $requestInstance->getRequestElement('mode')); - $dataSetInstance->addCriteria(self::DB_COLUMN_EXTERNAL_IP , $ipPort[0]); - $dataSetInstance->addCriteria(self::DB_COLUMN_LISTEN_PORT , $ipPort[1]); - $dataSetInstance->addCriteria(self::DB_COLUMN_NODE_ID , $nodeInstance->getNodeId()); - $dataSetInstance->addCriteria(self::DB_COLUMN_SESSION_ID , $nodeInstance->getSessionId()); - $dataSetInstance->addCriteria(self::DB_COLUMN_PRIVATE_KEY_HASH, $nodeInstance->getPrivateKeyHash()); - $dataSetInstance->addCriteria(self::DB_COLUMN_ACCEPTED_OBJECTS, implode(BaseHubNode::OBJECT_LIST_SEPARATOR, $objectList)); - - // Return it - return $dataSetInstance; - } - - /** - * Checks whether the local (*this*) node is registered in the DHT by - * checking if the external ip/port is found. - * - * @return $isRegistered Whether *this* node is registered in the DHT - */ - public function isLocalNodeRegistered () { - // Is there cache? - if (!isset($GLOBALS[__METHOD__])) { - // Get a search criteria instance - $searchInstance = ObjectFactory::createObjectByConfiguredName('search_criteria_class'); - - // Get node instance - $nodeInstance = NodeObjectFactory::createNodeInstance(); - - // Get ip:port combination and "explode" it - $ipPort = $nodeInstance->getAddressPortArray(); - - /* - * Make sure both is not 'invalid' which means that the resolver - * didn't work. - */ - assert(($ipPort[0] !== 'invalid') && ($ipPort[1] !== 'invalid')); - - // Add ip:port/node id as criteria - $searchInstance->addCriteria(self::DB_COLUMN_EXTERNAL_IP, $ipPort[0]); - $searchInstance->addCriteria(self::DB_COLUMN_LISTEN_PORT, $ipPort[1]); - $searchInstance->addCriteria(self::DB_COLUMN_NODE_ID , $nodeInstance->getNodeId()); - $searchInstance->setLimit(1); - - // Query database and get a result instance back - $resultInstance = $this->doSelectByCriteria($searchInstance); - - // Cache result of if there is an entry, valid() will tell us if an entry is there - $GLOBALS[__METHOD__] = $resultInstance->valid(); - } // END - if - - // Return result - return $GLOBALS[__METHOD__]; - } - - /** - * Registeres the local (*this*) node with its data in the DHT. - * - * @return void - */ - public function registerLocalNode () { - // Assert to make sure this method is called with no record in DB (the actual backend of the DHT) - assert(!$this->isLocalNodeRegistered()); - - // Get prepared data set instance - $dataSetInstance = $this->prepareLocalDataSetInstance(); - - // "Insert" this dataset instance completely into the database - $this->queryInsertDataSet($dataSetInstance); - } - - /** - * Updates local (*this*) node data in DHT, this is but not limited to the - * session id, ip number (and/or hostname) and port number. - * - * @return void - */ - public function updateLocalNode () { - // Assert to make sure this method is called with one record in DB (the actual backend of the DHT) - assert($this->isLocalNodeRegistered()); - - // Get node instance - $nodeInstance = NodeObjectFactory::createNodeInstance(); - - // Get search criteria - $searchInstance = ObjectFactory::createObjectByConfiguredName('search_criteria_class'); - - // Search for node id and limit it to one entry - $searchInstance->addCriteria(self::DB_COLUMN_NODE_ID, $nodeInstance->getNodeId()); - $searchInstance->setLimit(1); - - // Get a prepared dataset instance - $dataSetInstance = $this->prepareLocalDataSetInstance(); - - // Set search instance - $dataSetInstance->setSearchInstance($searchInstance); - - // Update DHT database record - $this->queryUpdateDataSet($dataSetInstance); - } - - /** - * Finds a node locally by given session id - * - * @param $sessionId Session id to lookup - * @return $nodeData Node data array - */ - public function findNodeLocalBySessionId ($sessionId) { - // Get search criteria - $searchInstance = ObjectFactory::createObjectByConfiguredName('search_criteria_class'); - - // Search for session id and limit it to one entry - $searchInstance->addCriteria(self::DB_COLUMN_SESSION_ID, $sessionId); - $searchInstance->setLimit(1); - - // Query database and get a result instance back - $resultInstance = $this->doSelectByCriteria($searchInstance); - - // Return result instance - return $resultInstance; - } - - /** - * Registeres a node by given message data. - * - * @param $messageData An array of all message data - * @param $handlerInstance An instance of a Handleable class - * @return void - */ - public function registerNodeByMessageData (array $messageData, Handleable $handlerInstance) { - // Get a data set instance - $dataSetInstance = ObjectFactory::createObjectByConfiguredName('dataset_criteria_class', array(self::DB_TABLE_NODE_DHT)); - - // Set primary key (session id) - $dataSetInstance->setUniqueKey(self::DB_COLUMN_SESSION_ID); - - // Add all array elements - $handlerInstance->addArrayToDataSet($dataSetInstance, $messageData); - - // Remove 'node_list' - $dataSetInstance->unsetCriteria(self::DB_COLUMN_NODE_LIST); - - // Run the "INSERT" query - $this->queryInsertDataSet($dataSetInstance); - } - - /** - * Updates an existing entry in node list - * - * @param $messageData An array of all message data - * @param $handlerInstance An instance of a Handleable class - * @param $searchInstance An instance of LocalSearchCriteria class - * @return void - */ - public function updateNodeByMessageData (array $messageData, Handleable $handlerInstance, LocalSearchCriteria $searchInstance) { - // Get a data set instance - $dataSetInstance = ObjectFactory::createObjectByConfiguredName('dataset_criteria_class', array(self::DB_TABLE_NODE_DHT)); - - // Add search instance - $dataSetInstance->setSearchInstance($searchInstance); - - // Set primary key (session id) - $dataSetInstance->setUniqueKey(self::DB_COLUMN_SESSION_ID); - - // Add all array elements - $handlerInstance->addArrayToDataSet($dataSetInstance, $messageData); - - // Remove 'node_list' - $dataSetInstance->unsetCriteria(self::DB_COLUMN_NODE_LIST); - - // Run the "UPDATE" query - $this->queryUpdateDataSet($dataSetInstance); - } - - /** - * Determines whether the given node data is already inserted in the DHT - * - * @param $nodeData An array with valid node data - * @return $isRegistered Whether the given node data is already inserted - */ - public function isNodeRegistered (array $nodeData) { - // Assert on array elements - assert(isset($nodeData[self::DB_COLUMN_NODE_ID])); - - // Get search criteria - $searchInstance = $this->prepareSearchInstance($nodeData); - - // Query database and get a result instance back - $resultInstance = $this->doSelectByCriteria( - // Search instance - $searchInstance, - // Only look for these array elements ("keys") - array( - self::DB_COLUMN_NODE_ID => TRUE, - self::DB_COLUMN_EXTERNAL_IP => TRUE, - self::DB_COLUMN_LISTEN_PORT => TRUE, - ) - ); - - // Check if there is an entry - $isRegistered = $resultInstance->valid(); - - // Return registration status - return $isRegistered; - } - - /** - * Registers a node with given data in the DHT. If the node is already - * registered this method shall throw an exception. - * - * @param $nodeData An array with valid node data - * @return void - * @throws NodeAlreadyRegisteredException If the node is already registered - */ - public function registerNode (array $nodeData) { - // Assert on array elements - assert(isset($nodeData[self::DB_COLUMN_NODE_ID])); - - // Is the node registered? - if ($this->isNodeRegistered($nodeData)) { - // Throw an exception - throw new NodeAlreadyRegisteredException(array($this, $nodeData), self::EXCEPTION_NODE_ALREADY_REGISTERED); - } // END - if - - // @TODO Unimplemented part - $this->partialStub('nodeData=' . print_r($nodeData, TRUE)); - } - - /** - * Updates a node's entry in the DHT with given data. This will enrich or - * just update already exsiting data. If the node is not found this method - * shall throw an exception. - * - * @param $nodeData An array with valid node data - * @return void - * @throws NodeDataMissingException If the node's data is missing - */ - public function updateNode (array $nodeData) { - // Assert on array elements - assert(isset($nodeData[self::DB_COLUMN_NODE_ID])); - - // Is the node registered? - if (!$this->isNodeRegistered($nodeData)) { - // No, then throw an exception - throw new NodeDataMissingException(array($this, $nodeData), self::EXCEPTION_NODE_NOT_REGISTERED); - } // END - if - - // Get a search instance - $searchInstance = $this->prepareSearchInstance($nodeData); - - // Get a data set instance - $dataSetInstance = ObjectFactory::createObjectByConfiguredName('dataset_criteria_class', array(self::DB_TABLE_NODE_DHT)); - - // Add search instance - $dataSetInstance->setSearchInstance($searchInstance); - - // Set primary key (session id) - $dataSetInstance->setUniqueKey(self::DB_COLUMN_SESSION_ID); - - // Get node instance - $nodeInstance = NodeObjectFactory::createNodeInstance(); - - // Add all array elements - $nodeInstance->addArrayToDataSet($dataSetInstance, $nodeData); - - // Remove 'node_list' - $dataSetInstance->unsetCriteria(self::DB_COLUMN_NODE_LIST); - - // Run the "UPDATE" query - $this->queryUpdateDataSet($dataSetInstance); - } - - /** - * Checks whether there are unpublished entries - * - * @return $hasUnpublished Whether there are unpublished entries - * @todo Add minimum/maximum age limitations - */ - public function hasUnpublishedEntries () { - // Get search instance - $searchInstance = ObjectFactory::createObjectByConfiguredName('search_criteria_class'); - - // Add exclusion key which is the publish status - $searchInstance->addExcludeCriteria(NodeDistributedHashTableDatabaseWrapper::DB_COLUMN_PUBLICATION_STATUS, NodeDistributedHashTableDatabaseWrapper::PUBLICATION_STATUS_PENDING); - - // Remember search instance - $this->setSearchInstance($searchInstance); - - // Run the query - $this->unpublishedEntriesInstance = $this->doSelectByCriteria($searchInstance); - - // Check pending entries - $hasUnpublished = $this->unpublishedEntriesInstance->valid(); - - // Return it - return $hasUnpublished; - } - - /** - * Initializes publication of DHT entries. This does only prepare - * publication. The next step is to pickup such prepared entries and publish - * them by uploading to other (recently appeared) DHT members. - * - * @return void - * @todo Add timestamp to dataset instance - */ - public function initEntryPublication () { - /* - * Make sure that hasUnpublishedEntries() has been called first by - * asserting on the "cached" object instance. This "caching" saves some - * needless queries as this method shall be called immediately after - * hasUnpublishedEntries() returns TRUE. - */ - assert($this->unpublishedEntriesInstance instanceof SearchableResult); - - // Result is still okay? - assert($this->unpublishedEntriesInstance->valid()); - - // Remove 'publication_status' - $this->getSearchInstance()->unsetCriteria(self::DB_COLUMN_PUBLICATION_STATUS); - - // Make sure all entries are marked as pending, first get a dataset instance. - $dataSetInstance = ObjectFactory::createObjectByConfiguredName('dataset_criteria_class', array(self::DB_TABLE_NODE_DHT)); - - // Add search instance - $dataSetInstance->setSearchInstance($this->getSearchInstance()); - - // Set primary key (node id) - $dataSetInstance->setUniqueKey(self::DB_COLUMN_NODE_ID); - - // Add criteria (that should be set) - $dataSetInstance->addCriteria(self::DB_COLUMN_PUBLICATION_STATUS, self::PUBLICATION_STATUS_PENDING); - - // Run the "UPDATE" query - $this->queryUpdateDataSet($dataSetInstance); - } - - /** - * Removes non-public data from given array. - * - * @param $data An array with possible non-public data that needs to be removed. - * @return $data A cleaned up array with only public data. - */ - public function removeNonPublicDataFromArray(array $data) { - // Currently call only inner method - //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('DHT-WRAPPER[' . $this->__toString() . ']: Calling parent::removeNonPublicDataFromArray(data) ...'); - $data = parent::removeNonPublicDataFromArray($data); - //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('DHT-WRAPPER[' . $this->__toString() . ']: data[]=' . gettype($data)); - - // Return cleaned data - return $data; - } - - /** - * Find recipients for given package data and exclude the sender - * - * @param $packageData An array of valid package data - * @return $recipients An indexed array with DHT recipients - */ - public function getResultFromExcludedSender (array $packageData) { - // Assert on required array field - assert(isset($packageData[NetworkPackage::PACKAGE_DATA_SENDER])); - - // Get max recipients - $maxRecipients = $this->getConfigInstance()->getConfigEntry('max_dht_recipients'); - - // First creata a search instance - $searchInstance = ObjectFactory::createObjectByConfiguredName('search_criteria_class'); - - // Then exclude 'sender' field as the sender is the current (*this*) node - $searchInstance->addExcludeCriteria(NodeDistributedHashTableDatabaseWrapper::DB_COLUMN_SESSION_ID, $packageData[NetworkPackage::PACKAGE_DATA_SENDER]); - - // Set limit to maximum DHT recipients - $searchInstance->setLimit($maxRecipients); - - // Get a result instance back from DHT database wrapper. - $resultInstance = $this->doSelectByCriteria($searchInstance); - - // Return result instance - return $resultInstance; - } - - /** - * Find recopients by given key/value pair. First look for the key and if it - * matches, compare the value. - * - * @param $key Key to look for - * @param $value Value to compare if key matches - * @return $recipients An indexed array with DHT recipients - */ - public function getResultFromKeyValue ($key, $value) { - // Get max recipients - $maxRecipients = $this->getConfigInstance()->getConfigEntry('max_dht_recipients'); - - // First creata a search instance - $searchInstance = ObjectFactory::createObjectByConfiguredName('search_criteria_class'); - - // Find the key/value pair - $searchInstance->addCriteria($key, $value); - - // Get a result instance back from DHT database wrapper. - $resultInstance = $this->doSelectByCriteria($searchInstance); - - // Return result instance - return $resultInstance; - } -} - -// [EOF] -?> diff --git a/application/hub/main/database/wrapper/node/class_NodeInformationDatabaseWrapper.php b/application/hub/main/database/wrapper/node/class_NodeInformationDatabaseWrapper.php deleted file mode 100644 index 820102f50..000000000 --- a/application/hub/main/database/wrapper/node/class_NodeInformationDatabaseWrapper.php +++ /dev/null @@ -1,184 +0,0 @@ - - * @version 0.0.0 - * @copyright Copyright (c) 2007, 2008 Roland Haeder, 2009 - 2012 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 NodeInformationDatabaseWrapper extends BaseDatabaseWrapper implements NodeInformationWrapper, Registerable { - // Constants for database table names - const DB_TABLE_NODE_INFORMATION = 'node_data'; - - // Constants for database column names - const DB_COLUMN_NODE_NR = 'node_nr'; - const DB_COLUMN_NODE_ID = 'node_id'; - const DB_COLUMN_SESSION_ID = 'session_id'; - const DB_COLUMN_PRIVATE_KEY = 'private_key'; - const DB_COLUMN_PRIVATE_KEY_HASH = 'private_key_hash'; - const DB_COLUMN_NODE_MODE = 'node_mode'; - - /** - * Protected constructor - * - * @return void - */ - protected function __construct () { - // Call parent constructor - parent::__construct(__CLASS__); - } - - /** - * Creates an instance of this database wrapper by a provided user class - * - * @return $wrapperInstance An instance of the created wrapper class - */ - public static final function createNodeInformationDatabaseWrapper () { - // Get a new instance - $wrapperInstance = new NodeInformationDatabaseWrapper(); - - // Set (primary!) table name - $wrapperInstance->setTableName(self::DB_TABLE_NODE_INFORMATION); - - // Return the instance - return $wrapperInstance; - } - - /** - * Checks whether there is an entry for given node instance - * - * @param $nodeInstance An instance of a NodeHelper class - * @return $isFound Whether a node id has been found for this node - */ - public function ifNodeDataIsFound (NodeHelper $nodeInstance) { - // Is there cache? - if (!isset($GLOBALS[__METHOD__])) { - // Now get a search criteria instance - $searchInstance = ObjectFactory::createObjectByConfiguredName('search_criteria_class'); - - // Search for the node number one which is hard-coded the default - $searchInstance->addCriteria(NodeInformationDatabaseWrapper::DB_COLUMN_NODE_NR , 1); - $searchInstance->addCriteria(NodeInformationDatabaseWrapper::DB_COLUMN_NODE_MODE, $nodeInstance->getRequestInstance()->getRequestElement('mode')); - $searchInstance->setLimit(1); - - // Get a result back - $resultInstance = $this->doSelectByCriteria($searchInstance); - - // Set result instance in node instance - $nodeInstance->setResultInstance($resultInstance); - - // Is it valid? - $GLOBALS[__METHOD__] = $resultInstance->next(); - } // END - if - - // Return it - return $GLOBALS[__METHOD__]; - } - - /** - * 'Registers' a new node id along with data provided in the node instance. - * This may sound confusing but avoids double code very nicely... - * - * @param $nodeInstance A node instance - * @param $requestInstance An instance of a Requestable class - * @return void - */ - public function registerNodeId (BaseHubNode $nodeInstance, Requestable $requestInstance) { - // Get a dataset instance - $dataSetInstance = ObjectFactory::createObjectByConfiguredName('dataset_criteria_class', array(self::DB_TABLE_NODE_INFORMATION)); - - // Set the primary key - $dataSetInstance->setUniqueKey(self::DB_COLUMN_NODE_ID); - - // Add registration elements to the dataset - $nodeInstance->addElementsToDataSet($dataSetInstance, $requestInstance); - - // "Insert" this dataset instance completely into the database - $this->queryInsertDataSet($dataSetInstance); - } - - /** - * 'Registers' a new session id along with data provided in the node instance. - * This may sound confusing but avoids double code very nicely... - * - * @param $nodeInstance An instance of a BaseHubNode class - * @param $requestInstance An instance of a Requestable class - * @param $searchInstance An instance of a LocalSearchCriteria class - * @return void - */ - public function registerSessionId (BaseHubNode $nodeInstance, Requestable $requestInstance, LocalSearchCriteria $searchInstance) { - // Get a dataset instance - $dataSetInstance = ObjectFactory::createObjectByConfiguredName('dataset_criteria_class', array(self::DB_TABLE_NODE_INFORMATION)); - - // Set search instance - $dataSetInstance->setSearchInstance($searchInstance); - - // Set the primary key - $dataSetInstance->setUniqueKey(self::DB_COLUMN_NODE_ID); - - // Add registration elements to the dataset - $nodeInstance->addElementsToDataSet($dataSetInstance, $requestInstance); - - // Update database record - $this->queryUpdateDataSet($dataSetInstance); - } - - /** - * 'Registers' a private key along with data provided in the node instance. - * This may sound confusing but avoids double code very nicely... - * - * @param $nodeInstance An instance of a BaseHubNode class - * @param $requestInstance An instance of a Requestable class - * @param $searchInstance An instance of a LocalSearchCriteria class - * @return void - */ - public function registerPrivateKey (BaseHubNode $nodeInstance, Requestable $requestInstance, LocalSearchCriteria $searchInstance) { - // Get a dataset instance - $dataSetInstance = ObjectFactory::createObjectByConfiguredName('dataset_criteria_class', array(self::DB_TABLE_NODE_INFORMATION)); - - // Set the primary key - $dataSetInstance->setUniqueKey(self::DB_COLUMN_NODE_ID); - - // Set search instance - $dataSetInstance->setSearchInstance($searchInstance); - - // Add registration elements to the dataset - $nodeInstance->addElementsToDataSet($dataSetInstance, $requestInstance); - - // Update database record - $this->queryUpdateDataSet($dataSetInstance); - } - - /** - * Removes non-public data from given array. - * - * @param $data An array with possible non-public data that needs to be removed. - * @return $data A cleaned up array with only public data. - */ - public function removeNonPublicDataFromArray(array $data) { - // Currently call only inner method - /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('NODE-WRAPPER[' . $this->__toString() . ']: Calling parent::removeNonPublicDataFromArray(data) ...'); - $data = parent::removeNonPublicDataFromArray($data); - - // Return cleaned data - return $data; - } -} - -// [EOF] -?> diff --git a/application/hub/main/database/wrapper/node/class_NodeListDatabaseWrapper.php b/application/hub/main/database/wrapper/node/class_NodeListDatabaseWrapper.php deleted file mode 100644 index f551ef47b..000000000 --- a/application/hub/main/database/wrapper/node/class_NodeListDatabaseWrapper.php +++ /dev/null @@ -1,3 +0,0 @@ - diff --git a/application/hub/main/database/wrapper/states/.htaccess b/application/hub/main/database/wrapper/states/.htaccess deleted file mode 100644 index 3a4288278..000000000 --- a/application/hub/main/database/wrapper/states/.htaccess +++ /dev/null @@ -1 +0,0 @@ -Deny from all diff --git a/application/hub/main/database/wrapper/states/class_PeerStateLookupDatabaseWrapper.php b/application/hub/main/database/wrapper/states/class_PeerStateLookupDatabaseWrapper.php deleted file mode 100644 index 1c740fdb0..000000000 --- a/application/hub/main/database/wrapper/states/class_PeerStateLookupDatabaseWrapper.php +++ /dev/null @@ -1,274 +0,0 @@ - - * @version 0.0.0 - * @copyright Copyright (c) 2007, 2008 Roland Haeder, 2009 - 2012 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 PeerStateLookupDatabaseWrapper extends BaseDatabaseWrapper implements LookupablePeerState { - // 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'; - const DB_COLUMN_PEER_STATE = 'peer_state'; - const DB_COLUMN_SOCKET_ERROR_CODE = 'socket_error_code'; - const DB_COLUMN_SOCKET_ERROR_MSG = 'socket_error_msg'; - - /** - * Protected constructor - * - * @return void - */ - protected function __construct () { - // Call parent constructor - parent::__construct(__CLASS__); - } - - /** - * Creates an instance of this database wrapper by a provided user class - * - * @return $wrapperInstance An instance of the created wrapper class - */ - public static final function createPeerStateLookupDatabaseWrapper () { - // Get a new instance - $wrapperInstance = new PeerStateLookupDatabaseWrapper(); - - // Set (primary!) table name - $wrapperInstance->setTableName(self::DB_TABLE_PEER_LOOKUP); - - // Return the instance - return $wrapperInstance; - } - - /** - * "Getter" for a LocalSearchCriteria from given package data's sender - * - * @param $packageData Valid raw package data array - * @return $searchInstance An instance of a LocalSearchCriteria class - */ - private function getSenderSearchInstanceFromPackageData (array $packageData) { - // Get the instance - //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('DATABASE-WRAPPER: Searching for sender ' . $packageData[NetworkPackage::PACKAGE_DATA_SENDER]); - $searchInstance = ObjectFactory::createObjectByConfiguredName('search_criteria_class'); - - // Add 'sender' as the peer's IP address - $searchInstance->addCriteria(self::DB_COLUMN_PEER_SESSION_ID, $packageData[NetworkPackage::PACKAGE_DATA_SENDER]); - $searchInstance->setLimit(1); - - // Return the instance - return $searchInstance; - } - - /** - * Checks whether given 'sender' is a new peer - * - * @param $packageData Raw package data - * @param $dataSetInstance An optional instance of a StoreableCriteria class - * @return $isNewPeer Whether 'sender' is a new peer to this peer - */ - public function isSenderNewPeer (array $packageData, StoreableCriteria $dataSetInstance = NULL) { - // Debug message - //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('DATABASE-WRAPPER: ' . __FUNCTION__ . ' called with packageData()=' . count($packageData) . ' - ENTERED!'); - - // Is the package valid? - if (!isset($packageData[NetworkPackage::PACKAGE_DATA_SENDER])) { - // Invalid package found, please report this - $this->debugBackTrace('[' . __METHOD__ . ':' . __LINE__ . ']: packageData=' . print_r($packageData, TRUE)); - } // END - if - - // Get a search criteria instance from package data - $searchInstance = $this->getSenderSearchInstanceFromPackageData($packageData); - - // Is the dataset instance set? - if ($dataSetInstance instanceof StoreableCriteria) { - // Then remember the search instance in it - $dataSetInstance->setSearchInstance($searchInstance); - } // END - if - - // Count the query - $entries = $this->doSelectCountByCriteria($searchInstance, array(self::DB_COLUMN_PEER_SESSION_ID => TRUE)); - - // Is it there? - //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('DATABASE-WRAPPER: entries=' . $entries); - $isNewPeer = ($entries != 1); - - // Return the result - //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('DATABASE-WRAPPER: isNewPeer=' . intval($isNewPeer) . ' - EXIT!'); - 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 - */ - 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::PACKAGE_DATA_SENDER]); - - // Get peer name - if (!@socket_getpeername($socketResource, $peerName, $peerPort)) { - // Get last error - $lastError = socket_last_error($socketResource); - - // ... and cleartext message from it and put both into criteria - $dataSetInstance->addCriteria(self::DB_COLUMN_SOCKET_ERROR_CODE, $lastError); - $dataSetInstance->addCriteria(self::DB_COLUMN_SOCKET_ERROR_MSG , socket_strerror($lastError)); - } // 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->queryInsertDataSet($dataSetInstance, array(self::DB_COLUMN_PEER_SESSION_ID => TRUE)); - - // Debug message - //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('DATABASE-WRAPPER: Peer ' . $packageData[NetworkPackage::PACKAGE_DATA_SENDER] . ' has been registered.'); - } - - /** - * Registers the given peer state and raw package data - * - * @param $stateInstance A PeerStateable class instance - * @param $packageData Valid package data array - * @return void - * @throws PeerAlreadyRegisteredException If a peer is already registered - * @todo Unfinished area - */ - public function registerPeerState (PeerStateable $stateInstance, array $packageData) { - // 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::PACKAGE_DATA_SENDER]); - $dataSetInstance->addCriteria(self::DB_COLUMN_PEER_STATE , $stateInstance->getStateName()); - - // Try to resolve sender's session id - $senderData = explode(':', HubTools::resolveSessionId($packageData[NetworkPackage::PACKAGE_DATA_SENDER])); - - // Just make sure that 'invalid:invalid' is not being processed - assert(($senderData[0] != 'invalid') && ($senderData[1] != 'invalid')); - - // Add ip address and port - $dataSetInstance->addCriteria(self::DB_COLUMN_PEER_IP , $senderData[0]); - $dataSetInstance->addCriteria(self::DB_COLUMN_PEER_PORT, $senderData[1]); - - // Is this a new peer? - if ($this->isSenderNewPeer($packageData, $dataSetInstance)) { - // "Insert" the data set - $this->queryInsertDataSet($dataSetInstance, array(self::DB_COLUMN_PEER_SESSION_ID => TRUE)); - } else { - // Update the data set - $this->queryUpdateDataSet($dataSetInstance, array(self::DB_COLUMN_PEER_SESSION_ID => TRUE)); - } - - // Debug message - //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('DATABASE-WRAPPER: Peer ' . $packageData[NetworkPackage::PACKAGE_DATA_SENDER] . ' has been registered/updated with state ' . $stateInstance->getStateName()); - } - - /** - * 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 - * @todo Unfinished area - */ - 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, $socketResource, $lastError, socket_strerror($lastError)), BaseListener::EXCEPTION_INVALID_SOCKET); - } // END - if - - // Debug message - //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('DATABASE-WRAPPER: peerName=' . $peerName . ',peerPort=' . $peerPort . ' - UNFINISHED!'); - } - - /** - * Checks whether a given peer state (in helper instance) is same as stored - * in database compared with the one from $helperInstance. - * - * @param $helperInstance An instance of a ConnectionHelper class - * @param $packageData Valid package data array - * @return $isSamePeerState Whether the peer's state is the same - */ - public function isSamePeerState (ConnectionHelper $helperInstance, array $packageData) { - // Debug message - //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('DATABASE-WRAPPER: State ' . $helperInstance->getPrintableState() . ' needs to be checked it has changed ...'); - - // Now get the search instance from given package data - $searchInstance = $this->getSenderSearchInstanceFromPackageData($packageData); - - // With this search instance query the database for the peer and get a result instance - $resultInstance = $this->doSelectByCriteria($searchInstance); - - // Do we have an entry? This should always the case - assert($resultInstance->next()); - - // Yes, so get the current (=first) entry from it - $rowData = $resultInstance->current(); - - // Debug message - //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('DATABASE-WRAPPER: rowData[' . gettype($rowData) . ']=' . print_r($rowData, TRUE)); - - // Assert on important elements - assert(isset($rowData[self::DB_COLUMN_PEER_STATE])); - - // Now just compare it with given state from helper instance - $isSamePeerState = ($rowData[self::DB_COLUMN_PEER_STATE] == $helperInstance->getPrintableState()); - - // Debug message - //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('DATABASE-WRAPPER: state in database: ' . $rowData[self::DB_COLUMN_PEER_STATE] . ', new state: ' . $helperInstance->getPrintableState() . ',isSamePeerState=' . intval($isSamePeerState)); - - // Return it - return $isSamePeerState; - } -} - -// [EOF] -?> diff --git a/application/hub/main/dht/class_BaseDht.php b/application/hub/main/dht/class_BaseDht.php index 7a667811a..64dda6e47 100644 --- a/application/hub/main/dht/class_BaseDht.php +++ b/application/hub/main/dht/class_BaseDht.php @@ -246,6 +246,18 @@ abstract class BaseDht extends BaseHubSystem implements Distributable { */ public function hasFullyBootstrapped () { // Get state and check it + $this->partialStub('Please implement this method.'); + } + + /** + * Enable DHT bootstrap request acceptance for local node + * + * @return void + * @todo Switch flag 'accept_bootstrap' + */ + public function enableAcceptDhtBootstrap () { + // Call method on database wrapper + $this->getWrapperInstance()->enableAcceptDhtBootstrap(); } } diff --git a/application/hub/main/states/dht/virgin/class_DhtVirginState.php b/application/hub/main/states/dht/virgin/class_DhtVirginState.php index 838bc570d..69882f367 100644 --- a/application/hub/main/states/dht/virgin/class_DhtVirginState.php +++ b/application/hub/main/states/dht/virgin/class_DhtVirginState.php @@ -54,6 +54,9 @@ class DhtVirginState extends BaseDhtState implements Stateable { // Get node instance and enable DHT bootstrap requests NodeObjectFactory::createNodeInstance()->enableAcceptDhtBootstrap(); + // Update DHT node info as well + $dhtInstance->enableAcceptDhtBootstrap(); + // Return the prepared instance return $stateInstance; } diff --git a/application/hub/main/wrapper/.htaccess b/application/hub/main/wrapper/.htaccess new file mode 100644 index 000000000..3a4288278 --- /dev/null +++ b/application/hub/main/wrapper/.htaccess @@ -0,0 +1 @@ +Deny from all diff --git a/application/hub/main/wrapper/cruncher/.htaccess b/application/hub/main/wrapper/cruncher/.htaccess new file mode 100644 index 000000000..3a4288278 --- /dev/null +++ b/application/hub/main/wrapper/cruncher/.htaccess @@ -0,0 +1 @@ +Deny from all diff --git a/application/hub/main/wrapper/cruncher/class_CruncherUnitDatabaseWrapper.php b/application/hub/main/wrapper/cruncher/class_CruncherUnitDatabaseWrapper.php new file mode 100644 index 000000000..32bf47667 --- /dev/null +++ b/application/hub/main/wrapper/cruncher/class_CruncherUnitDatabaseWrapper.php @@ -0,0 +1,84 @@ + + * @version 0.0.0 + * @copyright Copyright (c) 2011 - 2012 Cruncher 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 CruncherUnitDatabaseWrapper extends BaseDatabaseWrapper implements UnitDatabaseWrapper, Registerable { + // Constants for database table names + const DB_TABLE_CRUNCHER_UNITS = 'cruncher_units'; + + // Constants for database column names + const DB_COLUMN_UNIT_TYPE = 'unit_type'; + const DB_COLUMN_UNIT_STATUS = 'unit_status'; + + /** + * Protected constructor + * + * @return void + */ + protected function __construct () { + // Call parent constructor + parent::__construct(__CLASS__); + } + + /** + * Creates an instance of this database wrapper by a provided user class + * + * @return $wrapperInstance An instance of the created wrapper class + */ + public static final function createCruncherUnitDatabaseWrapper () { + // Get a new instance + $wrapperInstance = new CruncherUnitDatabaseWrapper(); + + // Set (primary!) table name + $wrapperInstance->setTableName(self::DB_TABLE_CRUNCHER_UNITS); + + // Return the instance + return $wrapperInstance; + } + + /** + * Checks whether a test unit has been produced + * + * @return $isProduced Whether a test unit has already been produced + */ + public function isTestUnitProduced () { + // Now get a search instance + $searchInstance = ObjectFactory::createObjectByConfiguredName('search_criteria_class'); + + // Add criteria for looking up already created and available test units + $searchInstance->addCriteria(self::DB_COLUMN_UNIT_TYPE , BaseUnitProducer::UNIT_TYPE_TEST_UNIT); + $searchInstance->addCriteria(self::DB_COLUMN_UNIT_STATUS, BaseUnitProducer::UNIT_STATUS_AVAILABLE); + $searchInstance->setConfiguredLimit('cruncher_test_unit_max_count'); + + // Search for our units + $resultInstance = $this->doSelectByCriteria($searchInstance); + + // Do we have some entries? + $isProduced = $resultInstance->next(); + + // Return it + return $isProduced; + } +} + +// [EOF] +?> diff --git a/application/hub/main/wrapper/node/.htaccess b/application/hub/main/wrapper/node/.htaccess new file mode 100644 index 000000000..3a4288278 --- /dev/null +++ b/application/hub/main/wrapper/node/.htaccess @@ -0,0 +1 @@ +Deny from all diff --git a/application/hub/main/wrapper/node/class_NodeDistributedHashTableDatabaseWrapper.php b/application/hub/main/wrapper/node/class_NodeDistributedHashTableDatabaseWrapper.php new file mode 100644 index 000000000..1dd336996 --- /dev/null +++ b/application/hub/main/wrapper/node/class_NodeDistributedHashTableDatabaseWrapper.php @@ -0,0 +1,580 @@ + + * @version 0.0.0 + * @copyright Copyright (c) 2007, 2008 Roland Haeder, 2009 - 2012 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 NodeDistributedHashTableDatabaseWrapper extends BaseDatabaseWrapper implements NodeDhtWrapper, Registerable { + /** + * "Cached" results for dabase for looking for unpublished entries + */ + private $unpublishedEntriesInstance = NULL; + + // Constants for database table names + const DB_TABLE_NODE_DHT = 'node_dht'; + + // Constants for database column names + const DB_COLUMN_NODE_ID = 'node_id'; + const DB_COLUMN_SESSION_ID = 'session_id'; + const DB_COLUMN_EXTERNAL_IP = 'external_ip'; + const DB_COLUMN_LISTEN_PORT = 'listen_port'; + const DB_COLUMN_PRIVATE_KEY_HASH = 'private_key_hash'; + const DB_COLUMN_NODE_MODE = 'node_mode'; + const DB_COLUMN_ACCEPTED_OBJECTS = 'accepted_object_types'; + const DB_COLUMN_NODE_LIST = 'node_list'; + const DB_COLUMN_PUBLICATION_STATUS = 'publication_status'; + const DB_COLUMN_ANSWER_STATUS = 'answer_status'; + const DB_COLUMN_ACCEPT_BOOTSTRAP = 'accept_bootstrap'; + + // Publication status' + const PUBLICATION_STATUS_PENDING = 'PENDING'; + + // Exception codes + const EXCEPTION_NODE_ALREADY_REGISTERED = 0x800; + const EXCEPTION_NODE_NOT_REGISTERED = 0x801; + + /** + * Protected constructor + * + * @return void + */ + protected function __construct () { + // Call parent constructor + parent::__construct(__CLASS__); + } + + /** + * Creates an instance of this database wrapper by a provided user class + * + * @return $wrapperInstance An instance of the created wrapper class + */ + public static final function createNodeDistributedHashTableDatabaseWrapper () { + // Get a new instance + $wrapperInstance = new NodeDistributedHashTableDatabaseWrapper(); + + // Set (primary!) table name + $wrapperInstance->setTableName(self::DB_TABLE_NODE_DHT); + + // Return the instance + return $wrapperInstance; + } + + /** + * Static getter for an array of all DHT database entries + * + * @return $elements All elements for the DHT dabase + */ + public static final function getAllElements () { + // Create array and ... + $elements = array( + self::DB_COLUMN_NODE_ID, + self::DB_COLUMN_SESSION_ID, + self::DB_COLUMN_EXTERNAL_IP, + self::DB_COLUMN_LISTEN_PORT, + self::DB_COLUMN_PRIVATE_KEY_HASH, + self::DB_COLUMN_NODE_MODE, + self::DB_COLUMN_ACCEPTED_OBJECTS, + self::DB_COLUMN_NODE_LIST + ); + + // ... return it + return $elements; + } + + /** + * Prepares a search instance for given node data + * + * @param $nodeData An array with valid node data + * @return $searchInstance An instance of a SearchCriteria class + */ + private function prepareSearchInstance (array $nodeData) { + // Assert on array elements + assert(isset($nodeData[self::DB_COLUMN_NODE_ID])); + + // Get instance + $searchInstance = ObjectFactory::createObjectByConfiguredName('search_criteria_class'); + + // Search for node id and limit it to one entry + $searchInstance->addCriteria(self::DB_COLUMN_NODE_ID, $nodeData[self::DB_COLUMN_NODE_ID]); + $searchInstance->setLimit(1); + + // Return it + return $searchInstance; + } + + /** + * Getter for result instance for unpublished entries + * + * @return $unpublishedEntriesInstance Result instance + */ + public final function getUnpublishedEntriesInstance () { + return $this->unpublishedEntriesInstance; + } + + /** + * Prepares a "local" instance of a StoreableCriteria class with all node + * data for insert/update queries. This data set contains data from *this* + * (local) node. + * + * @return $dataSetInstance An instance of a StoreableCriteria class + */ + private function prepareLocalDataSetInstance () { + // Get node/request instances + $nodeInstance = NodeObjectFactory::createNodeInstance(); + $requestInstance = ApplicationHelper::getSelfInstance()->getRequestInstance(); + + // Get a dataset instance + $dataSetInstance = ObjectFactory::createObjectByConfiguredName('dataset_criteria_class', array(self::DB_TABLE_NODE_DHT)); + + // Set the primary key + $dataSetInstance->setUniqueKey(self::DB_COLUMN_NODE_ID); + + // Get ip:port combination and "explode" it + $ipPort = $nodeInstance->getAddressPortArray(); + + // Make sure both is valid + assert(($ipPort[0] !== 'invalid') && ($ipPort[1] !== 'invalid')); + + // Get an array of all accepted object types + $objectList = $nodeInstance->getListFromAcceptedObjectTypes(); + + // Make sure this is an array + assert(is_array($objectList)); + + // Add public node data + $dataSetInstance->addCriteria(self::DB_COLUMN_NODE_MODE , $requestInstance->getRequestElement('mode')); + $dataSetInstance->addCriteria(self::DB_COLUMN_EXTERNAL_IP , $ipPort[0]); + $dataSetInstance->addCriteria(self::DB_COLUMN_LISTEN_PORT , $ipPort[1]); + $dataSetInstance->addCriteria(self::DB_COLUMN_NODE_ID , $nodeInstance->getNodeId()); + $dataSetInstance->addCriteria(self::DB_COLUMN_SESSION_ID , $nodeInstance->getSessionId()); + $dataSetInstance->addCriteria(self::DB_COLUMN_PRIVATE_KEY_HASH, $nodeInstance->getPrivateKeyHash()); + $dataSetInstance->addCriteria(self::DB_COLUMN_ACCEPTED_OBJECTS, implode(BaseHubNode::OBJECT_LIST_SEPARATOR, $objectList)); + $dataSetInstance->addCriteria(self::DB_COLUMN_ACCEPT_BOOTSTRAP, $this->translateBooleanToYesNo($nodeInstance->isAcceptingDhtBootstrap())); + + // Return it + return $dataSetInstance; + } + + /** + * Checks whether the local (*this*) node is registered in the DHT by + * checking if the external ip/port is found. + * + * @return $isRegistered Whether *this* node is registered in the DHT + */ + public function isLocalNodeRegistered () { + // Is there cache? + if (!isset($GLOBALS[__METHOD__])) { + // Get a search criteria instance + $searchInstance = ObjectFactory::createObjectByConfiguredName('search_criteria_class'); + + // Get node instance + $nodeInstance = NodeObjectFactory::createNodeInstance(); + + // Get ip:port combination and "explode" it + $ipPort = $nodeInstance->getAddressPortArray(); + + /* + * Make sure both is not 'invalid' which means that the resolver + * didn't work. + */ + assert(($ipPort[0] !== 'invalid') && ($ipPort[1] !== 'invalid')); + + // Add ip:port/node id as criteria + $searchInstance->addCriteria(self::DB_COLUMN_EXTERNAL_IP, $ipPort[0]); + $searchInstance->addCriteria(self::DB_COLUMN_LISTEN_PORT, $ipPort[1]); + $searchInstance->addCriteria(self::DB_COLUMN_NODE_ID , $nodeInstance->getNodeId()); + $searchInstance->setLimit(1); + + // Query database and get a result instance back + $resultInstance = $this->doSelectByCriteria($searchInstance); + + // Cache result of if there is an entry, valid() will tell us if an entry is there + $GLOBALS[__METHOD__] = $resultInstance->valid(); + } // END - if + + // Return result + return $GLOBALS[__METHOD__]; + } + + /** + * Registeres the local (*this*) node with its data in the DHT. + * + * @return void + */ + public function registerLocalNode () { + // Assert to make sure this method is called with no record in DB (the actual backend of the DHT) + assert(!$this->isLocalNodeRegistered()); + + // Get prepared data set instance + $dataSetInstance = $this->prepareLocalDataSetInstance(); + + // "Insert" this dataset instance completely into the database + $this->queryInsertDataSet($dataSetInstance); + } + + /** + * Updates local (*this*) node data in DHT, this is but not limited to the + * session id, ip number (and/or hostname) and port number. + * + * @return void + */ + public function updateLocalNode () { + // Assert to make sure this method is called with one record in DB (the actual backend of the DHT) + assert($this->isLocalNodeRegistered()); + + // Get node instance + $nodeInstance = NodeObjectFactory::createNodeInstance(); + + // Get search criteria + $searchInstance = ObjectFactory::createObjectByConfiguredName('search_criteria_class'); + + // Search for node id and limit it to one entry + $searchInstance->addCriteria(self::DB_COLUMN_NODE_ID, $nodeInstance->getNodeId()); + $searchInstance->setLimit(1); + + // Get a prepared dataset instance + $dataSetInstance = $this->prepareLocalDataSetInstance(); + + // Set search instance + $dataSetInstance->setSearchInstance($searchInstance); + + // Update DHT database record + $this->queryUpdateDataSet($dataSetInstance); + } + + /** + * Finds a node locally by given session id + * + * @param $sessionId Session id to lookup + * @return $nodeData Node data array + */ + public function findNodeLocalBySessionId ($sessionId) { + // Get search criteria + $searchInstance = ObjectFactory::createObjectByConfiguredName('search_criteria_class'); + + // Search for session id and limit it to one entry + $searchInstance->addCriteria(self::DB_COLUMN_SESSION_ID, $sessionId); + $searchInstance->setLimit(1); + + // Query database and get a result instance back + $resultInstance = $this->doSelectByCriteria($searchInstance); + + // Return result instance + return $resultInstance; + } + + /** + * Registeres a node by given message data. + * + * @param $messageData An array of all message data + * @param $handlerInstance An instance of a Handleable class + * @return void + */ + public function registerNodeByMessageData (array $messageData, Handleable $handlerInstance) { + // Get a data set instance + $dataSetInstance = ObjectFactory::createObjectByConfiguredName('dataset_criteria_class', array(self::DB_TABLE_NODE_DHT)); + + // Set primary key (session id) + $dataSetInstance->setUniqueKey(self::DB_COLUMN_SESSION_ID); + + // Add all array elements + $handlerInstance->addArrayToDataSet($dataSetInstance, $messageData); + + // Remove 'node_list' + $dataSetInstance->unsetCriteria(self::DB_COLUMN_NODE_LIST); + + // Run the "INSERT" query + $this->queryInsertDataSet($dataSetInstance); + } + + /** + * Updates an existing entry in node list + * + * @param $messageData An array of all message data + * @param $handlerInstance An instance of a Handleable class + * @param $searchInstance An instance of LocalSearchCriteria class + * @return void + */ + public function updateNodeByMessageData (array $messageData, Handleable $handlerInstance, LocalSearchCriteria $searchInstance) { + // Get a data set instance + $dataSetInstance = ObjectFactory::createObjectByConfiguredName('dataset_criteria_class', array(self::DB_TABLE_NODE_DHT)); + + // Add search instance + $dataSetInstance->setSearchInstance($searchInstance); + + // Set primary key (session id) + $dataSetInstance->setUniqueKey(self::DB_COLUMN_SESSION_ID); + + // Add all array elements + $handlerInstance->addArrayToDataSet($dataSetInstance, $messageData); + + // Remove 'node_list' + $dataSetInstance->unsetCriteria(self::DB_COLUMN_NODE_LIST); + + // Run the "UPDATE" query + $this->queryUpdateDataSet($dataSetInstance); + } + + /** + * Determines whether the given node data is already inserted in the DHT + * + * @param $nodeData An array with valid node data + * @return $isRegistered Whether the given node data is already inserted + */ + public function isNodeRegistered (array $nodeData) { + // Assert on array elements + assert(isset($nodeData[self::DB_COLUMN_NODE_ID])); + + // Get search criteria + $searchInstance = $this->prepareSearchInstance($nodeData); + + // Query database and get a result instance back + $resultInstance = $this->doSelectByCriteria( + // Search instance + $searchInstance, + // Only look for these array elements ("keys") + array( + self::DB_COLUMN_NODE_ID => TRUE, + self::DB_COLUMN_EXTERNAL_IP => TRUE, + self::DB_COLUMN_LISTEN_PORT => TRUE, + ) + ); + + // Check if there is an entry + $isRegistered = $resultInstance->valid(); + + // Return registration status + return $isRegistered; + } + + /** + * Registers a node with given data in the DHT. If the node is already + * registered this method shall throw an exception. + * + * @param $nodeData An array with valid node data + * @return void + * @throws NodeAlreadyRegisteredException If the node is already registered + */ + public function registerNode (array $nodeData) { + // Assert on array elements + assert(isset($nodeData[self::DB_COLUMN_NODE_ID])); + + // Is the node registered? + if ($this->isNodeRegistered($nodeData)) { + // Throw an exception + throw new NodeAlreadyRegisteredException(array($this, $nodeData), self::EXCEPTION_NODE_ALREADY_REGISTERED); + } // END - if + + // @TODO Unimplemented part + $this->partialStub('nodeData=' . print_r($nodeData, TRUE)); + } + + /** + * Updates a node's entry in the DHT with given data. This will enrich or + * just update already exsiting data. If the node is not found this method + * shall throw an exception. + * + * @param $nodeData An array with valid node data + * @return void + * @throws NodeDataMissingException If the node's data is missing + */ + public function updateNode (array $nodeData) { + // Assert on array elements + assert(isset($nodeData[self::DB_COLUMN_NODE_ID])); + + // Is the node registered? + if (!$this->isNodeRegistered($nodeData)) { + // No, then throw an exception + throw new NodeDataMissingException(array($this, $nodeData), self::EXCEPTION_NODE_NOT_REGISTERED); + } // END - if + + // Get a search instance + $searchInstance = $this->prepareSearchInstance($nodeData); + + // Get a data set instance + $dataSetInstance = ObjectFactory::createObjectByConfiguredName('dataset_criteria_class', array(self::DB_TABLE_NODE_DHT)); + + // Add search instance + $dataSetInstance->setSearchInstance($searchInstance); + + // Set primary key (session id) + $dataSetInstance->setUniqueKey(self::DB_COLUMN_SESSION_ID); + + // Get node instance + $nodeInstance = NodeObjectFactory::createNodeInstance(); + + // Add all array elements + $nodeInstance->addArrayToDataSet($dataSetInstance, $nodeData); + + // Remove 'node_list' + $dataSetInstance->unsetCriteria(self::DB_COLUMN_NODE_LIST); + + // Run the "UPDATE" query + $this->queryUpdateDataSet($dataSetInstance); + } + + /** + * Checks whether there are unpublished entries + * + * @return $hasUnpublished Whether there are unpublished entries + * @todo Add minimum/maximum age limitations + */ + public function hasUnpublishedEntries () { + // Get search instance + $searchInstance = ObjectFactory::createObjectByConfiguredName('search_criteria_class'); + + // Add exclusion key which is the publish status + $searchInstance->addExcludeCriteria(NodeDistributedHashTableDatabaseWrapper::DB_COLUMN_PUBLICATION_STATUS, NodeDistributedHashTableDatabaseWrapper::PUBLICATION_STATUS_PENDING); + + // Remember search instance + $this->setSearchInstance($searchInstance); + + // Run the query + $this->unpublishedEntriesInstance = $this->doSelectByCriteria($searchInstance); + + // Check pending entries + $hasUnpublished = $this->unpublishedEntriesInstance->valid(); + + // Return it + return $hasUnpublished; + } + + /** + * Initializes publication of DHT entries. This does only prepare + * publication. The next step is to pickup such prepared entries and publish + * them by uploading to other (recently appeared) DHT members. + * + * @return void + * @todo Add timestamp to dataset instance + */ + public function initEntryPublication () { + /* + * Make sure that hasUnpublishedEntries() has been called first by + * asserting on the "cached" object instance. This "caching" saves some + * needless queries as this method shall be called immediately after + * hasUnpublishedEntries() returns TRUE. + */ + assert($this->unpublishedEntriesInstance instanceof SearchableResult); + + // Result is still okay? + assert($this->unpublishedEntriesInstance->valid()); + + // Remove 'publication_status' + $this->getSearchInstance()->unsetCriteria(self::DB_COLUMN_PUBLICATION_STATUS); + + // Make sure all entries are marked as pending, first get a dataset instance. + $dataSetInstance = ObjectFactory::createObjectByConfiguredName('dataset_criteria_class', array(self::DB_TABLE_NODE_DHT)); + + // Add search instance + $dataSetInstance->setSearchInstance($this->getSearchInstance()); + + // Set primary key (node id) + $dataSetInstance->setUniqueKey(self::DB_COLUMN_NODE_ID); + + // Add criteria (that should be set) + $dataSetInstance->addCriteria(self::DB_COLUMN_PUBLICATION_STATUS, self::PUBLICATION_STATUS_PENDING); + + // Run the "UPDATE" query + $this->queryUpdateDataSet($dataSetInstance); + } + + /** + * Removes non-public data from given array. + * + * @param $data An array with possible non-public data that needs to be removed. + * @return $data A cleaned up array with only public data. + */ + public function removeNonPublicDataFromArray(array $data) { + // Currently call only inner method + //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('DHT-WRAPPER[' . $this->__toString() . ']: Calling parent::removeNonPublicDataFromArray(data) ...'); + $data = parent::removeNonPublicDataFromArray($data); + //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('DHT-WRAPPER[' . $this->__toString() . ']: data[]=' . gettype($data)); + + // Return cleaned data + return $data; + } + + /** + * Find recipients for given package data and exclude the sender + * + * @param $packageData An array of valid package data + * @return $recipients An indexed array with DHT recipients + */ + public function getResultFromExcludedSender (array $packageData) { + // Assert on required array field + assert(isset($packageData[NetworkPackage::PACKAGE_DATA_SENDER])); + + // Get max recipients + $maxRecipients = $this->getConfigInstance()->getConfigEntry('max_dht_recipients'); + + // First creata a search instance + $searchInstance = ObjectFactory::createObjectByConfiguredName('search_criteria_class'); + + // Then exclude 'sender' field as the sender is the current (*this*) node + $searchInstance->addExcludeCriteria(NodeDistributedHashTableDatabaseWrapper::DB_COLUMN_SESSION_ID, $packageData[NetworkPackage::PACKAGE_DATA_SENDER]); + + // Set limit to maximum DHT recipients + $searchInstance->setLimit($maxRecipients); + + // Get a result instance back from DHT database wrapper. + $resultInstance = $this->doSelectByCriteria($searchInstance); + + // Return result instance + return $resultInstance; + } + + /** + * Find recopients by given key/value pair. First look for the key and if it + * matches, compare the value. + * + * @param $key Key to look for + * @param $value Value to compare if key matches + * @return $recipients An indexed array with DHT recipients + */ + public function getResultFromKeyValue ($key, $value) { + // Get max recipients + $maxRecipients = $this->getConfigInstance()->getConfigEntry('max_dht_recipients'); + + // First creata a search instance + $searchInstance = ObjectFactory::createObjectByConfiguredName('search_criteria_class'); + + // Find the key/value pair + $searchInstance->addCriteria($key, $value); + + // Get a result instance back from DHT database wrapper. + $resultInstance = $this->doSelectByCriteria($searchInstance); + + // Return result instance + return $resultInstance; + } + + /** + * Enable DHT bootstrap request acceptance for local node + * + * @return void + */ + public function enableAcceptDhtBootstrap () { + // Just update our record + $this->updateLocalNode(); + } +} + +// [EOF] +?> diff --git a/application/hub/main/wrapper/node/class_NodeInformationDatabaseWrapper.php b/application/hub/main/wrapper/node/class_NodeInformationDatabaseWrapper.php new file mode 100644 index 000000000..820102f50 --- /dev/null +++ b/application/hub/main/wrapper/node/class_NodeInformationDatabaseWrapper.php @@ -0,0 +1,184 @@ + + * @version 0.0.0 + * @copyright Copyright (c) 2007, 2008 Roland Haeder, 2009 - 2012 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 NodeInformationDatabaseWrapper extends BaseDatabaseWrapper implements NodeInformationWrapper, Registerable { + // Constants for database table names + const DB_TABLE_NODE_INFORMATION = 'node_data'; + + // Constants for database column names + const DB_COLUMN_NODE_NR = 'node_nr'; + const DB_COLUMN_NODE_ID = 'node_id'; + const DB_COLUMN_SESSION_ID = 'session_id'; + const DB_COLUMN_PRIVATE_KEY = 'private_key'; + const DB_COLUMN_PRIVATE_KEY_HASH = 'private_key_hash'; + const DB_COLUMN_NODE_MODE = 'node_mode'; + + /** + * Protected constructor + * + * @return void + */ + protected function __construct () { + // Call parent constructor + parent::__construct(__CLASS__); + } + + /** + * Creates an instance of this database wrapper by a provided user class + * + * @return $wrapperInstance An instance of the created wrapper class + */ + public static final function createNodeInformationDatabaseWrapper () { + // Get a new instance + $wrapperInstance = new NodeInformationDatabaseWrapper(); + + // Set (primary!) table name + $wrapperInstance->setTableName(self::DB_TABLE_NODE_INFORMATION); + + // Return the instance + return $wrapperInstance; + } + + /** + * Checks whether there is an entry for given node instance + * + * @param $nodeInstance An instance of a NodeHelper class + * @return $isFound Whether a node id has been found for this node + */ + public function ifNodeDataIsFound (NodeHelper $nodeInstance) { + // Is there cache? + if (!isset($GLOBALS[__METHOD__])) { + // Now get a search criteria instance + $searchInstance = ObjectFactory::createObjectByConfiguredName('search_criteria_class'); + + // Search for the node number one which is hard-coded the default + $searchInstance->addCriteria(NodeInformationDatabaseWrapper::DB_COLUMN_NODE_NR , 1); + $searchInstance->addCriteria(NodeInformationDatabaseWrapper::DB_COLUMN_NODE_MODE, $nodeInstance->getRequestInstance()->getRequestElement('mode')); + $searchInstance->setLimit(1); + + // Get a result back + $resultInstance = $this->doSelectByCriteria($searchInstance); + + // Set result instance in node instance + $nodeInstance->setResultInstance($resultInstance); + + // Is it valid? + $GLOBALS[__METHOD__] = $resultInstance->next(); + } // END - if + + // Return it + return $GLOBALS[__METHOD__]; + } + + /** + * 'Registers' a new node id along with data provided in the node instance. + * This may sound confusing but avoids double code very nicely... + * + * @param $nodeInstance A node instance + * @param $requestInstance An instance of a Requestable class + * @return void + */ + public function registerNodeId (BaseHubNode $nodeInstance, Requestable $requestInstance) { + // Get a dataset instance + $dataSetInstance = ObjectFactory::createObjectByConfiguredName('dataset_criteria_class', array(self::DB_TABLE_NODE_INFORMATION)); + + // Set the primary key + $dataSetInstance->setUniqueKey(self::DB_COLUMN_NODE_ID); + + // Add registration elements to the dataset + $nodeInstance->addElementsToDataSet($dataSetInstance, $requestInstance); + + // "Insert" this dataset instance completely into the database + $this->queryInsertDataSet($dataSetInstance); + } + + /** + * 'Registers' a new session id along with data provided in the node instance. + * This may sound confusing but avoids double code very nicely... + * + * @param $nodeInstance An instance of a BaseHubNode class + * @param $requestInstance An instance of a Requestable class + * @param $searchInstance An instance of a LocalSearchCriteria class + * @return void + */ + public function registerSessionId (BaseHubNode $nodeInstance, Requestable $requestInstance, LocalSearchCriteria $searchInstance) { + // Get a dataset instance + $dataSetInstance = ObjectFactory::createObjectByConfiguredName('dataset_criteria_class', array(self::DB_TABLE_NODE_INFORMATION)); + + // Set search instance + $dataSetInstance->setSearchInstance($searchInstance); + + // Set the primary key + $dataSetInstance->setUniqueKey(self::DB_COLUMN_NODE_ID); + + // Add registration elements to the dataset + $nodeInstance->addElementsToDataSet($dataSetInstance, $requestInstance); + + // Update database record + $this->queryUpdateDataSet($dataSetInstance); + } + + /** + * 'Registers' a private key along with data provided in the node instance. + * This may sound confusing but avoids double code very nicely... + * + * @param $nodeInstance An instance of a BaseHubNode class + * @param $requestInstance An instance of a Requestable class + * @param $searchInstance An instance of a LocalSearchCriteria class + * @return void + */ + public function registerPrivateKey (BaseHubNode $nodeInstance, Requestable $requestInstance, LocalSearchCriteria $searchInstance) { + // Get a dataset instance + $dataSetInstance = ObjectFactory::createObjectByConfiguredName('dataset_criteria_class', array(self::DB_TABLE_NODE_INFORMATION)); + + // Set the primary key + $dataSetInstance->setUniqueKey(self::DB_COLUMN_NODE_ID); + + // Set search instance + $dataSetInstance->setSearchInstance($searchInstance); + + // Add registration elements to the dataset + $nodeInstance->addElementsToDataSet($dataSetInstance, $requestInstance); + + // Update database record + $this->queryUpdateDataSet($dataSetInstance); + } + + /** + * Removes non-public data from given array. + * + * @param $data An array with possible non-public data that needs to be removed. + * @return $data A cleaned up array with only public data. + */ + public function removeNonPublicDataFromArray(array $data) { + // Currently call only inner method + /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('NODE-WRAPPER[' . $this->__toString() . ']: Calling parent::removeNonPublicDataFromArray(data) ...'); + $data = parent::removeNonPublicDataFromArray($data); + + // Return cleaned data + return $data; + } +} + +// [EOF] +?> diff --git a/application/hub/main/wrapper/node/class_NodeListDatabaseWrapper.php b/application/hub/main/wrapper/node/class_NodeListDatabaseWrapper.php new file mode 100644 index 000000000..f551ef47b --- /dev/null +++ b/application/hub/main/wrapper/node/class_NodeListDatabaseWrapper.php @@ -0,0 +1,3 @@ + diff --git a/application/hub/main/wrapper/states/.htaccess b/application/hub/main/wrapper/states/.htaccess new file mode 100644 index 000000000..3a4288278 --- /dev/null +++ b/application/hub/main/wrapper/states/.htaccess @@ -0,0 +1 @@ +Deny from all diff --git a/application/hub/main/wrapper/states/class_PeerStateLookupDatabaseWrapper.php b/application/hub/main/wrapper/states/class_PeerStateLookupDatabaseWrapper.php new file mode 100644 index 000000000..1c740fdb0 --- /dev/null +++ b/application/hub/main/wrapper/states/class_PeerStateLookupDatabaseWrapper.php @@ -0,0 +1,274 @@ + + * @version 0.0.0 + * @copyright Copyright (c) 2007, 2008 Roland Haeder, 2009 - 2012 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 PeerStateLookupDatabaseWrapper extends BaseDatabaseWrapper implements LookupablePeerState { + // 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'; + const DB_COLUMN_PEER_STATE = 'peer_state'; + const DB_COLUMN_SOCKET_ERROR_CODE = 'socket_error_code'; + const DB_COLUMN_SOCKET_ERROR_MSG = 'socket_error_msg'; + + /** + * Protected constructor + * + * @return void + */ + protected function __construct () { + // Call parent constructor + parent::__construct(__CLASS__); + } + + /** + * Creates an instance of this database wrapper by a provided user class + * + * @return $wrapperInstance An instance of the created wrapper class + */ + public static final function createPeerStateLookupDatabaseWrapper () { + // Get a new instance + $wrapperInstance = new PeerStateLookupDatabaseWrapper(); + + // Set (primary!) table name + $wrapperInstance->setTableName(self::DB_TABLE_PEER_LOOKUP); + + // Return the instance + return $wrapperInstance; + } + + /** + * "Getter" for a LocalSearchCriteria from given package data's sender + * + * @param $packageData Valid raw package data array + * @return $searchInstance An instance of a LocalSearchCriteria class + */ + private function getSenderSearchInstanceFromPackageData (array $packageData) { + // Get the instance + //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('DATABASE-WRAPPER: Searching for sender ' . $packageData[NetworkPackage::PACKAGE_DATA_SENDER]); + $searchInstance = ObjectFactory::createObjectByConfiguredName('search_criteria_class'); + + // Add 'sender' as the peer's IP address + $searchInstance->addCriteria(self::DB_COLUMN_PEER_SESSION_ID, $packageData[NetworkPackage::PACKAGE_DATA_SENDER]); + $searchInstance->setLimit(1); + + // Return the instance + return $searchInstance; + } + + /** + * Checks whether given 'sender' is a new peer + * + * @param $packageData Raw package data + * @param $dataSetInstance An optional instance of a StoreableCriteria class + * @return $isNewPeer Whether 'sender' is a new peer to this peer + */ + public function isSenderNewPeer (array $packageData, StoreableCriteria $dataSetInstance = NULL) { + // Debug message + //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('DATABASE-WRAPPER: ' . __FUNCTION__ . ' called with packageData()=' . count($packageData) . ' - ENTERED!'); + + // Is the package valid? + if (!isset($packageData[NetworkPackage::PACKAGE_DATA_SENDER])) { + // Invalid package found, please report this + $this->debugBackTrace('[' . __METHOD__ . ':' . __LINE__ . ']: packageData=' . print_r($packageData, TRUE)); + } // END - if + + // Get a search criteria instance from package data + $searchInstance = $this->getSenderSearchInstanceFromPackageData($packageData); + + // Is the dataset instance set? + if ($dataSetInstance instanceof StoreableCriteria) { + // Then remember the search instance in it + $dataSetInstance->setSearchInstance($searchInstance); + } // END - if + + // Count the query + $entries = $this->doSelectCountByCriteria($searchInstance, array(self::DB_COLUMN_PEER_SESSION_ID => TRUE)); + + // Is it there? + //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('DATABASE-WRAPPER: entries=' . $entries); + $isNewPeer = ($entries != 1); + + // Return the result + //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('DATABASE-WRAPPER: isNewPeer=' . intval($isNewPeer) . ' - EXIT!'); + 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 + */ + 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::PACKAGE_DATA_SENDER]); + + // Get peer name + if (!@socket_getpeername($socketResource, $peerName, $peerPort)) { + // Get last error + $lastError = socket_last_error($socketResource); + + // ... and cleartext message from it and put both into criteria + $dataSetInstance->addCriteria(self::DB_COLUMN_SOCKET_ERROR_CODE, $lastError); + $dataSetInstance->addCriteria(self::DB_COLUMN_SOCKET_ERROR_MSG , socket_strerror($lastError)); + } // 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->queryInsertDataSet($dataSetInstance, array(self::DB_COLUMN_PEER_SESSION_ID => TRUE)); + + // Debug message + //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('DATABASE-WRAPPER: Peer ' . $packageData[NetworkPackage::PACKAGE_DATA_SENDER] . ' has been registered.'); + } + + /** + * Registers the given peer state and raw package data + * + * @param $stateInstance A PeerStateable class instance + * @param $packageData Valid package data array + * @return void + * @throws PeerAlreadyRegisteredException If a peer is already registered + * @todo Unfinished area + */ + public function registerPeerState (PeerStateable $stateInstance, array $packageData) { + // 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::PACKAGE_DATA_SENDER]); + $dataSetInstance->addCriteria(self::DB_COLUMN_PEER_STATE , $stateInstance->getStateName()); + + // Try to resolve sender's session id + $senderData = explode(':', HubTools::resolveSessionId($packageData[NetworkPackage::PACKAGE_DATA_SENDER])); + + // Just make sure that 'invalid:invalid' is not being processed + assert(($senderData[0] != 'invalid') && ($senderData[1] != 'invalid')); + + // Add ip address and port + $dataSetInstance->addCriteria(self::DB_COLUMN_PEER_IP , $senderData[0]); + $dataSetInstance->addCriteria(self::DB_COLUMN_PEER_PORT, $senderData[1]); + + // Is this a new peer? + if ($this->isSenderNewPeer($packageData, $dataSetInstance)) { + // "Insert" the data set + $this->queryInsertDataSet($dataSetInstance, array(self::DB_COLUMN_PEER_SESSION_ID => TRUE)); + } else { + // Update the data set + $this->queryUpdateDataSet($dataSetInstance, array(self::DB_COLUMN_PEER_SESSION_ID => TRUE)); + } + + // Debug message + //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('DATABASE-WRAPPER: Peer ' . $packageData[NetworkPackage::PACKAGE_DATA_SENDER] . ' has been registered/updated with state ' . $stateInstance->getStateName()); + } + + /** + * 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 + * @todo Unfinished area + */ + 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, $socketResource, $lastError, socket_strerror($lastError)), BaseListener::EXCEPTION_INVALID_SOCKET); + } // END - if + + // Debug message + //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('DATABASE-WRAPPER: peerName=' . $peerName . ',peerPort=' . $peerPort . ' - UNFINISHED!'); + } + + /** + * Checks whether a given peer state (in helper instance) is same as stored + * in database compared with the one from $helperInstance. + * + * @param $helperInstance An instance of a ConnectionHelper class + * @param $packageData Valid package data array + * @return $isSamePeerState Whether the peer's state is the same + */ + public function isSamePeerState (ConnectionHelper $helperInstance, array $packageData) { + // Debug message + //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('DATABASE-WRAPPER: State ' . $helperInstance->getPrintableState() . ' needs to be checked it has changed ...'); + + // Now get the search instance from given package data + $searchInstance = $this->getSenderSearchInstanceFromPackageData($packageData); + + // With this search instance query the database for the peer and get a result instance + $resultInstance = $this->doSelectByCriteria($searchInstance); + + // Do we have an entry? This should always the case + assert($resultInstance->next()); + + // Yes, so get the current (=first) entry from it + $rowData = $resultInstance->current(); + + // Debug message + //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('DATABASE-WRAPPER: rowData[' . gettype($rowData) . ']=' . print_r($rowData, TRUE)); + + // Assert on important elements + assert(isset($rowData[self::DB_COLUMN_PEER_STATE])); + + // Now just compare it with given state from helper instance + $isSamePeerState = ($rowData[self::DB_COLUMN_PEER_STATE] == $helperInstance->getPrintableState()); + + // Debug message + //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('DATABASE-WRAPPER: state in database: ' . $rowData[self::DB_COLUMN_PEER_STATE] . ', new state: ' . $helperInstance->getPrintableState() . ',isSamePeerState=' . intval($isSamePeerState)); + + // Return it + return $isSamePeerState; + } +} + +// [EOF] +?> diff --git a/core b/core index 932873c41..fa613fa89 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit 932873c41ad866ed0745ceb78e8c9323ada0c31b +Subproject commit fa613fa892ae8ba73305814719f5b09bd27e64a8