X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=application%2Fhub%2Fmain%2Fhelper%2Fconnection%2Fclass_BaseConnectionHelper.php;h=44661ff12cae3a2d7053789bfdcfdf552f7d96f2;hb=62f2546efa5ec7585c5ce216e6a9676595b1b30b;hp=b14223de4f8f0ad995b2dc7186efeb6205ae41d6;hpb=e03c8858defee52b8e9d2acf1ff2b24800e8393c;p=hub.git diff --git a/application/hub/main/helper/connection/class_BaseConnectionHelper.php b/application/hub/main/helper/connection/class_BaseConnectionHelper.php index b14223de4..44661ff12 100644 --- a/application/hub/main/helper/connection/class_BaseConnectionHelper.php +++ b/application/hub/main/helper/connection/class_BaseConnectionHelper.php @@ -2,11 +2,11 @@ /** * A general ConnectionHelper class * - * @author Roland Haeder + * @author Roland Haeder * @version 0.0.0 - * @copyright Copyright (c) 2007, 2008 Roland Haeder, 2009 - 2012 Hub Developer Team + * @copyright Copyright (c) 2007, 2008 Roland Haeder, 2009 - 2014 Hub Developer Team * @license GNU GPL 3.0 or any newer version - * @link http://www.ship-simu.org + * @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 @@ -40,11 +40,6 @@ class BaseConnectionHelper extends BaseHubSystemHelper implements Registerable, */ const CONNECTION_TYPE_SERVER = 'server'; - /** - * Protocol used - */ - private $protocol = 'invalid'; - /** * Port number used */ @@ -60,11 +55,6 @@ class BaseConnectionHelper extends BaseHubSystemHelper implements Registerable, */ private $sentData = 0; - /** - * Difference - */ - private $diff = 0; - /** * Whether this connection is initialized */ @@ -95,14 +85,20 @@ class BaseConnectionHelper extends BaseHubSystemHelper implements Registerable, // Call parent constructor parent::__construct($className); + // Init state which sets the state to 'init' + $this->initState(); + // Initialize output stream $streamInstance = ObjectFactory::createObjectByConfiguredName('node_raw_data_output_stream_class'); // And add it to this connection helper $this->setOutputStreamInstance($streamInstance); - // Init state which sets the state to 'init' - $this->initState(); + // Get package instance from factory + $packageInstance = NetworkPackageFactory::createNetworkPackageInstance(); + + // ... and set it here + $this->setPackageInstance($packageInstance); // Register this connection helper Registry::getRegistry()->addInstance('connection', $this); @@ -146,25 +142,6 @@ class BaseConnectionHelper extends BaseHubSystemHelper implements Registerable, $this->port = $port; } - /** - * Getter for protocol - * - * @return $protocol Used protocol - */ - public final function getProtocol () { - return $this->protocol; - } - - /** - * Setter for protocol - * - * @param $protocol Used protocol - * @return void - */ - protected final function setProtocol ($protocol) { - $this->protocol = $protocol; - } - /** * Getter for IP address * @@ -242,7 +219,7 @@ class BaseConnectionHelper extends BaseHubSystemHelper implements Registerable, $timeout = $this->getConfigInstance()->getConfigEntry('socket_timeout_seconds'); // Debug output - self::createDebugInstance(__CLASS__)->debugOutput('CONNECTION-HELPER[' . __LINE__ . ']: Trying to connect to ' . $recipientData[0] . ':' . $recipientData[1] . ' with socketResource[' . gettype($socketResource) . ']=' . $socketResource . ' ...'); + self::createDebugInstance(__CLASS__)->debugOutput('CONNECTION-HELPER[' . __METHOD__ . ':' . __LINE__ . ']: Trying to connect to ' . $recipientData[0] . ':' . $recipientData[1] . ' with socketResource[' . gettype($socketResource) . ']=' . $socketResource . ' ...'); // Try to connect until it is connected while ($isConnected = !@socket_connect($socketResource, $recipientData[0], $recipientData[1])) { @@ -305,10 +282,7 @@ class BaseConnectionHelper extends BaseHubSystemHelper implements Registerable, * @return void */ private function initState() { - /* - * Get the state factory and create the initial state, we don't need - * the state instance here - */ + // Get the state factory and create the initial state. PeerStateFactory::createPeerStateInstanceByName('init', $this); } @@ -318,45 +292,43 @@ class BaseConnectionHelper extends BaseHubSystemHelper implements Registerable, * The rest is being held in a back-buffer and waits there for the next * cycle and while be then sent. * - * This method does 4 simple steps: - * 1) Aquire fragmenter object instance from the factory - * 2) Handle over the package data array to the fragmenter - * 3) Request a chunk - * 4) Finally return the chunk (array) to the caller + * This method does 2 simple steps: + * 1) Request a chunk from set fragmenter instance + * 2) Finally return the chunk (array) to the caller * * @param $packageData Raw package data array * @return $chunkData Raw data chunk */ private function getRawDataFromPackageArray (array $packageData) { - // Implode the package data array and fragement the resulting string, returns the final hash - $finalHash = $this->getFragmenterInstance()->fragmentPackageArray($packageData, $this); - if ($finalHash !== TRUE) { - $this->currentFinalHash = $finalHash; - } // END - if - // Debug message - //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('CONNECTION-HELPER[' . __LINE__ . ']: currentFinalHash=' . $this->currentFinalHash); + //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('CONNECTION-HELPER[' . __METHOD__ . ':' . __LINE__ . ']: currentFinalHash=' . $this->currentFinalHash); + + // Make sure the final hash is set + assert((is_string($this->currentFinalHash)) && (!empty($this->currentFinalHash))); // Get the next raw data chunk from the fragmenter $rawDataChunk = $this->getFragmenterInstance()->getNextRawDataChunk($this->currentFinalHash); + // Debug message + //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('CONNECTION-HELPER[' . __METHOD__ . ':' . __LINE__ . ']: rawDataChunk=' . print_r($rawDataChunk, TRUE)); + // Get chunk hashes and chunk data $chunkHashes = array_keys($rawDataChunk); $chunkData = array_values($rawDataChunk); // Is the required data there? - //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('CONNECTION-HELPER[' . __LINE__ . ']: chunkHashes[]=' . count($chunkHashes) . ',chunkData[]=' . count($chunkData)); + //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('CONNECTION-HELPER[' . __METHOD__ . ':' . __LINE__ . ']: chunkHashes[]=' . count($chunkHashes) . ',chunkData[]=' . count($chunkData)); //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('chunkData='.print_r($chunkData, TRUE)); if ((isset($chunkHashes[0])) && (isset($chunkData[0]))) { // Remember this chunk as queued $this->queuedChunks[$chunkHashes[0]] = $chunkData[0]; // Return the raw data - //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('CONNECTION-HELPER[' . __LINE__ . ']: Returning ' . strlen($chunkData[0]) . ' bytes from ' . __METHOD__ . ' ...'); + //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('CONNECTION-HELPER[' . __METHOD__ . ':' . __LINE__ . ']: Returning ' . strlen($chunkData[0]) . ' bytes from ' . __METHOD__ . ' ...'); return $chunkData[0]; } else { // Return zero string - //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('CONNECTION-HELPER[' . __LINE__ . ']: Returning zero bytes from ' . __METHOD__ . '!'); + //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('CONNECTION-HELPER[' . __METHOD__ . ':' . __LINE__ . ']: Returning zero bytes from ' . __METHOD__ . '!'); return ''; } } @@ -376,105 +348,70 @@ class BaseConnectionHelper extends BaseHubSystemHelper implements Registerable, * Sends raw package data to the recipient * * @param $packageData Raw package data - * @return $totalSentBytes Total sent bytes to the peer + * @return void * @throws InvalidSocketException If we got a problem with this socket */ public function sendRawPackageData (array $packageData) { // The helper's state must be 'connected' $this->getStateInstance()->validatePeerStateConnected(); - // Reset serial number - $this->getFragmenterInstance()->resetSerialNumber(); + // Implode the package data array and fragement the resulting string, returns the final hash + $finalHash = $this->getFragmenterInstance()->fragmentPackageArray($packageData, $this); - // Cache buffer length - $bufferSize = $this->getConfigInstance()->getConfigEntry($this->getProtocol() . '_buffer_length'); + // Is the final hash set? + if ($finalHash !== TRUE) { + // Debug message + //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('CONNECTION-HELPER[' . __METHOD__ . ':' . __LINE__ . ']: Setting finalHash=' . $finalHash . ',currentFinalHash[' . gettype($this->currentFinalHash) . ']=' . $this->currentFinalHash); + + // Set final hash + $this->currentFinalHash = $finalHash; + } // END - if + + // Reset serial number + $this->getFragmenterInstance()->resetSerialNumber($this->currentFinalHash); // Init variables $rawData = ''; $dataStream = ' '; - $totalSentBytes = 0; // Fill sending buffer with data while (strlen($dataStream) > 0) { // Debug message - //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('CONNECTION-HELPER[' . __LINE__ . ']: packageData=' . print_r($packageData, TRUE)); + //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('CONNECTION-HELPER[' . __METHOD__ . ':' . __LINE__ . ']: packageData=' . print_r($packageData, TRUE)); // Convert the package data array to a raw data stream $dataStream = $this->getRawDataFromPackageArray($packageData); - //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('CONNECTION-HELPER[' . __LINE__ . ']: Adding ' . strlen($dataStream) . ' bytes to the sending buffer ...'); + //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('CONNECTION-HELPER[' . __METHOD__ . ':' . __LINE__ . ']: Adding ' . strlen($dataStream) . ' bytes to the sending buffer ...'); $rawData .= $dataStream; } // END - while // Nothing to sent is bad news, so assert on it assert(strlen($rawData) > 0); + // Calculate buffer size + $bufferSize = $this->getConfigInstance()->getConfigEntry($this->getProtocolName() . '_buffer_length'); + // Encode the raw data with our output-stream $encodedData = $this->getOutputStreamInstance()->streamData($rawData); // Debug message - //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('CONNECTION-HELPER[' . __LINE__ . ']: rawData()=' . strlen($rawData) . ',encodedData()=' . strlen($encodedData)); + //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('HELPER[' . __METHOD__ . ':' . __LINE__ . ']: socketResource[]=' . gettype($this->getSocketResource()) . PHP_EOL); + + // Init array + $encodedDataArray = array( + NetworkPackage::RAW_FINAL_HASH_INDEX => $this->currentFinalHash, + NetworkPackage::RAW_ENCODED_DATA_INDEX => $encodedData, + NetworkPackage::RAW_SENT_BYTES_INDEX => 0, + NetworkPackage::RAW_SOCKET_INDEX => $this->getSocketResource(), + NetworkPackage::RAW_BUFFER_SIZE_INDEX => $bufferSize, + NetworkPackage::RAW_DIFF_INDEX => 0 + ); // Calculate difference - $this->diff = $bufferSize - strlen($encodedData); + $diff = $encodedDataArray[NetworkPackage::RAW_BUFFER_SIZE_INDEX] - strlen($encodedDataArray[NetworkPackage::RAW_ENCODED_DATA_INDEX]); - // Get socket resource - $socketResource = $this->getSocketResource(); - - // Init sent bytes - $sentBytes = 0; - - // Deliver all data - while ($sentBytes !== FALSE) { - // And deliver it - //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('CONNECTION-HELPER[' . __LINE__ . ']: Sending out ' . strlen($encodedData) . ' bytes,bufferSize=' . $bufferSize . ',diff=' . $this->diff); - - if ($this->diff >= 0) { - // Send all out (encodedData is smaller than or equal buffer size) - //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('CONNECTION-HELPER[' . __LINE__ . ']: MD5=' . md5(substr($encodedData, 0, ($bufferSize - $this->diff)))); - $sentBytes = socket_write($socketResource, $encodedData, ($bufferSize - $this->diff)); - } else { - // Send buffer size out - //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('CONNECTION-HELPER[' . __LINE__ . ']: MD5=' . md5(substr($encodedData, 0, $bufferSize))); - $sentBytes = socket_write($socketResource, $encodedData, $bufferSize); - } - - // If there was an error, we don't continue here - if ($sentBytes === FALSE) { - // Handle the error with a faked recipientData array - $this->handleSocketError(__METHOD__, __LINE__, $socketResource, array('0.0.0.0', '0')); - - // And throw it - throw new InvalidSocketException(array($this, $socketResource, $socketError, $errorMessage), BaseListener::EXCEPTION_INVALID_SOCKET); - } elseif (($sentBytes == 0) && (strlen($encodedData) > 0)) { - // Nothing sent means we are done - //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('CONNECTION-HELPER[' . __LINE__ . ']: All sent! (LINE=' . __LINE__ . ')'); - break; - } - - // The difference between sent bytes and length of raw data should not go below zero - assert((strlen($encodedData) - $sentBytes) >= 0); - - // Add total sent bytes - $totalSentBytes += $sentBytes; - - // Cut out the last unsent bytes - //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('CONNECTION-HELPER[' . __LINE__ . ']: Sent out ' . $sentBytes . ' of ' . strlen($encodedData) . ' bytes ...'); - $encodedData = substr($encodedData, $sentBytes); - - // Calculate difference again - $this->diff = $bufferSize - strlen($encodedData); - - // Can we abort? - if (strlen($encodedData) <= 0) { - // Abort here, all sent! - //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('CONNECTION-HELPER[' . __LINE__ . ']: All sent! (LINE=' . __LINE__ . ')'); - break; - } // END - if - } // END - while - - // Return sent bytes - //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('CONNECTION-HELPER[' . __LINE__ . ']: totalSentBytes=' . $totalSentBytes . ',diff=' . $this->diff); - return $totalSentBytes; + // Push raw data to the package's outgoing stack + $this->getPackageInstance()->getStackInstance()->pushNamed(NetworkPackage::STACKER_NAME_OUTGOING_STREAM, $encodedDataArray); } /** @@ -483,7 +420,7 @@ class BaseConnectionHelper extends BaseHubSystemHelper implements Registerable, * @return void */ protected final function markConnectionShuttedDown () { - //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('CONNECTION-HELPER[' . __LINE__ . ']: ' . $this->__toString() . ' has been marked as shutted down'); + //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('CONNECTION-HELPER[' . __METHOD__ . ':' . __LINE__ . ']: ' . $this->__toString() . ' has been marked as shutted down'); $this->shuttedDown = TRUE; // And remove the (now invalid) socket @@ -496,7 +433,7 @@ class BaseConnectionHelper extends BaseHubSystemHelper implements Registerable, * @return $shuttedDown Whether this connection is shutted down */ public final function isShuttedDown () { - //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('CONNECTION-HELPER[' . __LINE__ . ']: ' . $this->__toString() . ',shuttedDown=' . intval($this->shuttedDown)); + //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('CONNECTION-HELPER[' . __METHOD__ . ':' . __LINE__ . ']: ' . $this->__toString() . ',shuttedDown=' . intval($this->shuttedDown)); return $this->shuttedDown; } @@ -620,6 +557,29 @@ class BaseConnectionHelper extends BaseHubSystemHelper implements Registerable, throw new SocketConnectionException(array($this, $socketResource, $socketError, $errorMessage), BaseListener::EXCEPTION_INVALID_SOCKET); } + /** + * Handles socket error 'connection reset by peer', but does not clear it for + * later debugging purposes. + * + * @param $socketResource A valid socket resource + * @param $recipientData An array with two elements: 0=IP number, 1=port number + * @return void + * @throws SocketConnectionException The connection attempts fails with a time-out + */ + protected function socketErrorConnectionResetByPeerHandler ($socketResource, array $recipientData) { + // Get socket error code for verification + $socketError = socket_last_error($socketResource); + + // Get error message + $errorMessage = socket_strerror($socketError); + + // Shutdown this socket + $this->shutdownSocket($socketResource); + + // Throw it again + throw new SocketConnectionException(array($this, $socketResource, $socketError, $errorMessage), BaseListener::EXCEPTION_INVALID_SOCKET); + } + /** * Handles socket "error" 'operation now in progress' which can be safely * passed on with non-blocking connections. @@ -629,9 +589,7 @@ class BaseConnectionHelper extends BaseHubSystemHelper implements Registerable, * @return void */ protected function socketErrorOperationInProgressHandler ($socketResource, array $recipientData) { - $type = socket_get_option($socketResource, SOL_SOCKET, SO_TYPE); - die('type='.$type.PHP_EOL); - self::createDebugInstance(__CLASS__)->debugOutput('CONNECTION-HELPER[' . __LINE__ . ']: Operation is now in progress, this is usual for non-blocking connections and is no bug.'); + self::createDebugInstance(__CLASS__)->debugOutput('CONNECTION-HELPER[' . __METHOD__ . ':' . __LINE__ . ']: Operation is now in progress, this is usual for non-blocking connections and is no bug.'); } }