+++ /dev/null
-<?php
-/**
- * A database wrapper for peer state lookups
- *
- * @author Roland Haeder <webmaster@shipsimu.org>
- * @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 <http://www.gnu.org/licenses/>.
- */
-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) . ' - CALLED!');
-
- // 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') && ($senderData[2] != '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]
-?>