const PACKAGE_MASK_SEPARATOR = '^';
/**
- * SEPARATOR for checksum
+ * Size of an array created by invoking
+ * explode(NetworkPackage::PACKAGE_MASK_SEPARATOR, $content).
+ */
+ const PACKAGE_CONTENT_ARRAY_SIZE = 4;
+
+ /**
+ * Separator for checksum
*/
const PACKAGE_CHECKSUM_SEPARATOR = '_';
const INDEX_PACKAGE_STATUS = 3;
const INDEX_PACKAGE_SIGNATURE = 4;
+ /**
+ * Size of the decoded data array ('status' is not included)
+ */
+ const DECODED_DATA_ARRAY_SIZE = 4;
+
+ /**
+ * Named array elements for decoded package content
+ */
+ const PACKAGE_CONTENT_EXTENSION = 'compressor';
+ const PACKAGE_CONTENT_MESSAGE = 'message';
+ const PACKAGE_CONTENT_TAGS = 'tags';
+ const PACKAGE_CONTENT_CHECKSUM = 'checksum';
+
/**
* Named array elements for package data
*/
*/
const TCP_PACKAGE_SIZE = 512;
- /**
- * Size of the decoded data array
- */
- const DECODED_DATA_ARRAY_SIZE = 4;
-
/**************************************************************************
* Stacker for out-going packages *
**************************************************************************/
*/
const STACKER_NAME_DECODED_CHUNKED = 'package_chunked_decoded';
+ /**
+ * Stacker name for new messages
+ */
+ const STACKER_NAME_NEW_MESSAGE = 'package_new_message';
+
/**************************************************************************
* Stacker for other/internal purposes *
**************************************************************************/
self::STACKER_NAME_DECODED_INCOMING,
self::STACKER_NAME_DECODED_HANDLED,
self::STACKER_NAME_DECODED_CHUNKED,
+ self::STACKER_NAME_NEW_MESSAGE,
self::STACKER_NAME_BACK_BUFFER
) as $stackerName) {
// Init this stacker
}
/**
- * "Getter" for hash from given content and helper instance
+ * "Getter" for hash from given content
*
- * @param $content Raw package content
- * @param $helperInstance An instance of a HelpableHub class
- * @param $nodeInstance An instance of a NodeHelper class
- * @return $hash Hash for given package content
+ * @param $content Raw package content
+ * @return $hash Hash for given package content
*/
private function getHashFromContent ($content) {
+ // Debug message
+ //* NOISY-DEBUG: */ $this->debugOutput('NETWORK-PACKAGE: content[md5]=' . md5($content) . ',sender=' . $this->getSessionId() . ',compressor=' . $this->getCompressorInstance()->getCompressorExtension());
+
// Create the hash
// @TODO crc32() is very weak, but it needs to be fast
$hash = crc32(
return $hash;
}
+ /**
+ * Checks whether the checksum (sometimes called "hash") is the same
+ *
+ * @param $decodedContent Package raw content
+ * @param $decodedData Whole raw package data array
+ * @return $isChecksumValid Whether the checksum is the same
+ */
+ private function isChecksumValid (array $decodedContent, array $decodedData) {
+ // Get checksum
+ $checksum = $this->getHashFromContentSessionId($decodedContent, $decodedData[self::PACKAGE_DATA_SENDER]);
+
+ // Is it the same?
+ $isChecksumValid = ($checksum == $decodedContent[self::PACKAGE_CONTENT_CHECKSUM]);
+
+ // Return it
+ return $isChecksumValid;
+ }
+
/**
* Change the package with given status in given stack
*
// Pop the entry (it should be it)
$nextData = $this->getStackerInstance()->popNamed($stackerName);
- // Compare both arrays
+ // Compare both signatures
assert($nextData[self::PACKAGE_DATA_SIGNATURE] == $packageData[self::PACKAGE_DATA_SIGNATURE]);
// Temporary set the new status
$this->getStackerInstance()->pushNamed($stackerName, $packageData);
}
+ /**
+ * "Getter" for hash from given content and sender's session id
+ *
+ * @param $decodedContent Decoded package content
+ * @param $sessionId Session id of the sender
+ * @return $hash Hash for given package content
+ */
+ public function getHashFromContentSessionId (array $decodedContent, $sessionId) {
+ // Debug message
+ //* NOISY-DEBUG: */ $this->debugOutput('NETWORK-PACKAGE: content[md5]=' . md5($decodedContent[self::PACKAGE_CONTENT_MESSAGE]) . ',sender=' . $sessionId . ',compressor=' . $decodedContent[self::PACKAGE_CONTENT_EXTENSION]);
+
+ // Create the hash
+ // @TODO crc32() is very weak, but it needs to be fast
+ $hash = crc32(
+ $decodedContent[self::PACKAGE_CONTENT_MESSAGE] .
+ self::PACKAGE_CHECKSUM_SEPARATOR .
+ $sessionId .
+ self::PACKAGE_CHECKSUM_SEPARATOR .
+ $decodedContent[self::PACKAGE_CONTENT_EXTENSION]
+ );
+
+ // And return it
+ return $hash;
+ }
+
///////////////////////////////////////////////////////////////////////////
// Delivering packages / raw data
///////////////////////////////////////////////////////////////////////////
return $signature;
}
+ /**
+ * Checks whether the signature of given package data is 'valid', here that
+ * means it is the same or not.
+ *
+ * @param $decodedArray An array with 'decoded' (explode() was mostly called) data
+ * @return $isSignatureValid Whether the signature is valid
+ * @todo Unfinished area, signatures are currently NOT fully supported
+ */
+ private function isPackageSignatureValid (array $decodedArray) {
+ // Generate the signature of comparing it
+ $signature = $this->generatePackageSignature($decodedArray[self::INDEX_PACKAGE_CONTENT], $decodedArray[self::INDEX_PACKAGE_SENDER]);
+
+ // Is it the same?
+ //$isSignatureValid =
+ die(__METHOD__.': signature='.$signature.chr(10).',decodedArray='.print_r($decodedArray,true));
+ }
+
/**
* "Enqueues" raw content into this delivery class by reading the raw content
- * from given template instance and pushing it on the 'undeclared' stack.
+ * from given helper's template instance and pushing it on the 'undeclared'
+ * stack.
*
* @param $helperInstance An instance of a HelpableHub class
* @return void
return;
} // END - if
- // Now we know for sure there are packages to deliver, we can start
- // with the first one.
+ /*
+ * Now there are for sure packages to deliver, so start with the first
+ * one.
+ */
$packageData = $this->getStackerInstance()->getNamed(self::STACKER_NAME_UNDECLARED);
// Declare the raw package data for delivery
$this->getStackerInstance()->pushNamed(self::STACKER_NAME_DECODED_CHUNKED, $packageContent);
}
- /**
- * Checks whether a new package has arrived
- *
- * @return $hasArrived Whether a new package has arrived for processing
- */
- public function isNewPackageArrived () {
- // @TODO Add some content here
- }
-
/**
* Accepts the visitor to process the visit "request"
*
// Assert on count (should be always 3)
assert(count($decodedArray) == self::DECODED_DATA_ARRAY_SIZE);
- // Create 'decodedData' array with all assoziative array elements
+ // Generate the signature of comparing it
+ /*
+ * @todo Unsupported feature of "signed" messages commented out
+ if (!$this->isPackageSignatureValid($decodedArray)) {
+ // Is not valid, so throw an exception here
+ die('INVALID SIG! UNDER CONSTRUCTION!' . chr(10));
+ } // END - if
+ */
+
+ /*
+ * Create 'decodedData' array with all assoziative array elements,
+ * except signature.
+ */
$decodedData = array(
self::PACKAGE_DATA_SENDER => $decodedArray[self::INDEX_PACKAGE_SENDER],
self::PACKAGE_DATA_RECIPIENT => $decodedArray[self::INDEX_PACKAGE_RECIPIENT],
self::PACKAGE_DATA_CONTENT => $decodedArray[self::INDEX_PACKAGE_CONTENT],
- self::PACKAGE_DATA_STATUS => self::PACKAGE_STATUS_DECODED,
- self::PACKAGE_DATA_SIGNATURE => $this->generatePackageSignature($decodedArray[self::INDEX_PACKAGE_CONTENT], $decodedArray[self::INDEX_PACKAGE_SENDER])
+ self::PACKAGE_DATA_STATUS => self::PACKAGE_STATUS_DECODED
);
// And return it
return $decodedData;
}
+
+ /**
+ * Handles decoded data for this node by "decoding" the 'content' part of
+ * it. Again this method uses explode() for the "decoding" process.
+ *
+ * @param $decodedData An array with decoded raw package data
+ * @return void
+ * @throws InvalidDataChecksumException If the checksum doesn't match
+ */
+ public function handleDecodedData (array $decodedData) {
+ /*
+ * "Decode" the package's content by a simple explode() call, for
+ * details of the array elements, see comments for constant
+ * PACKAGE_MASK.
+ */
+ $decodedContent = explode(self::PACKAGE_MASK_SEPARATOR, $decodedData[self::PACKAGE_DATA_CONTENT]);
+
+ // Assert on array count for a very basic validation
+ assert(count($decodedContent) == self::PACKAGE_CONTENT_ARRAY_SIZE);
+
+ // Convert the indexed array into an associative array
+ $decodedContent = array(
+ // Compressor's extension used to compress the data
+ self::PACKAGE_CONTENT_EXTENSION => $decodedContent[self::INDEX_COMPRESSOR_EXTENSION],
+ // Package data (aka "message") in BASE64-decoded form
+ self::PACKAGE_CONTENT_MESSAGE => base64_decode($decodedContent[self::INDEX_PACKAGE_DATA]),
+ // Tags as an indexed array for "tagging" the message
+ self::PACKAGE_CONTENT_TAGS => explode(self::PACKAGE_TAGS_SEPARATOR, $decodedContent[self::INDEX_TAGS]),
+ // Checksum of the _decoded_ data
+ self::PACKAGE_CONTENT_CHECKSUM => $decodedContent[self::INDEX_CHECKSUM]
+ );
+
+ // Is the checksum valid?
+ if (!$this->isChecksumValid($decodedContent, $decodedData)) {
+ // Is not the same, so throw an exception here
+ throw new InvalidDataChecksumException(array($this, $decodedContent, $decodedData), BaseListener::EXCEPTION_INVALID_DATA_CHECKSUM);
+ } // END - if
+
+ /*
+ * It is the same, then decompress it, the original message is than
+ * fully decoded.
+ */
+ $decodedContent[self::PACKAGE_CONTENT_MESSAGE] = $this->getCompressorInstance()->decompressStream($decodedContent[self::PACKAGE_CONTENT_MESSAGE]);
+
+ // And push it on the next stack
+ $this->getStackerInstance()->pushNamed(self::STACKER_NAME_NEW_MESSAGE, $decodedContent);
+ }
+
+ /**
+ * Checks whether a new message has arrived
+ *
+ * @return $hasArrived Whether a new message has arrived for processing
+ */
+ public function isNewMessageArrived () {
+ // Determine if the stack is not empty
+ $hasArrived = (!$this->getStackerInstance()->isStackEmpty(self::STACKER_NAME_NEW_MESSAGE));
+
+ // Return it
+ return $hasArrived;
+ }
+
+ /**
+ * Handles newly arrived messages
+ *
+ * @return void
+ */
+ public function handleNewlyArrivedMessage () {
+ // Get it from the stacker, it is the full array with the decoded message
+ $decodedContent = $this->getStackerInstance()->popNamed(self::STACKER_NAME_NEW_MESSAGE);
+
+ die('decodedContent='.print_r($decodedContent,true));
+ }
}
// [EOF]