Esempio n. 1
0
        public static EventStreamHeader FromBuffer(byte[] buffer, int offset, ref int newOffset)
        {
            newOffset = offset;
            byte nameLength = buffer[newOffset++];
            var  header     = new EventStreamHeader(Encoding.UTF8.GetString(buffer, newOffset, nameLength));

            newOffset += nameLength;

            header.HeaderType = (EventStreamHeaderType)buffer[newOffset++];

            Int16 valueLength = 0;

            switch (header.HeaderType)
            {
            case EventStreamHeaderType.BoolTrue:
                header.HeaderValue = true;
                break;

            case EventStreamHeaderType.BoolFalse:
                header.HeaderValue = false;
                break;

            case EventStreamHeaderType.Byte:
                header.HeaderValue = buffer[newOffset];
                newOffset         += _sizeOfByte;
                break;

            case EventStreamHeaderType.Int16:
                header.HeaderValue = IPAddress.NetworkToHostOrder(BitConverter.ToInt16(buffer, newOffset));
                newOffset         += _sizeOfInt16;
                break;

            case EventStreamHeaderType.Int32:
                header.HeaderValue = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(buffer, newOffset));
                newOffset         += _sizeOfInt32;
                break;

            case EventStreamHeaderType.Int64:
                header.HeaderValue = IPAddress.NetworkToHostOrder(BitConverter.ToInt64(buffer, newOffset));
                newOffset         += _sizeOfInt64;
                break;

            case EventStreamHeaderType.ByteBuf:
                valueLength        = IPAddress.NetworkToHostOrder(BitConverter.ToInt16(buffer, newOffset));
                newOffset         += _sizeOfInt16;
                header.HeaderValue = new byte[valueLength];
                Buffer.BlockCopy(buffer, newOffset, header.HeaderValue as byte[], 0, valueLength);
                newOffset += valueLength;
                break;

            case EventStreamHeaderType.String:
                valueLength        = IPAddress.NetworkToHostOrder(BitConverter.ToInt16(buffer, newOffset));
                newOffset         += _sizeOfInt16;
                header.HeaderValue = Encoding.UTF8.GetString(buffer, newOffset, valueLength);
                newOffset         += valueLength;
                break;

            case EventStreamHeaderType.Timestamp:
                Int64 tempValue = IPAddress.NetworkToHostOrder(BitConverter.ToInt64(buffer, newOffset));
                newOffset += _sizeOfInt64;
                //keep in mind on the windows APIs (and hence NetStandard as well) the epoch is 1/1/1900,
                //and we're using unix epoch. So we compensate here.
                header.HeaderValue = _unixEpoch.AddMilliseconds(tempValue);
                break;

            case EventStreamHeaderType.UUID:
                var guidCpy = new byte[16];
                valueLength = _sizeOfGuid;
                Buffer.BlockCopy(buffer, newOffset, guidCpy, 0, valueLength);
                newOffset         += valueLength;
                header.HeaderValue = new Guid(guidCpy);
                break;

            default:
                throw new EventStreamParseException(string.Format(CultureInfo.InvariantCulture, "Header Type: {0} is an unknown type.", header.HeaderType));
            }

            return(header);
        }
        /// <summary>
        /// Builds a message from buffer.
        /// </summary>
        /// <param name="buffer">buffer to read</param>
        /// <param name="offset">offset to start reading</param>
        /// <param name="length">buffer length.</param>
        /// <returns>
        /// parsed instance of EventStreamMessage. Doesn't return null,
        /// does throw if CRCs don't match.
        /// </returns>
        public static EventStreamMessage FromBuffer(byte[] buffer, int offset, int length)
        {
            var currentOffset = offset;

            //get the total length of the message
            var totalLength = BitConverter.ToInt32(buffer, currentOffset);

            //endianness conversion
            totalLength    = EndianConversionUtility.NetworkToHostOrder(totalLength);
            currentOffset += SizeOfInt32;

            //get the length of the headers block.
            var headersLength = BitConverter.ToInt32(buffer, currentOffset);

            //endianness conversion
            headersLength  = EndianConversionUtility.NetworkToHostOrder(headersLength);
            currentOffset += SizeOfInt32;

            //get the prelude crc
            var preludeCrc = BitConverter.ToInt32(buffer, currentOffset);

            //endianness conversion
            preludeCrc = EndianConversionUtility.NetworkToHostOrder(preludeCrc);

            var message = new EventStreamMessage();

            message.Headers = new Dictionary <string, IEventStreamHeader>(StringComparer.Ordinal);

            using (var nullStream = new NullStream())
                using (var runningChecksum = new CrcCalculatorStream(nullStream))
                {
                    //write up to the prelude crc to the checksum stream
                    runningChecksum.Write(buffer, offset, currentOffset - offset);
                    //compare the current crc to the prelude crc and make sure they match.
                    if (preludeCrc != runningChecksum.Crc32)
                    {
                        throw new EventStreamChecksumFailureException(string.Format(CultureInfo.InvariantCulture, "Message Prelude Checksum failure. Expected {0} but was {1}", preludeCrc, runningChecksum.Crc32));
                    }

                    //if the data length passed isn't enough for the total length, that's an error condition.
                    if (totalLength != length)
                    {
                        throw new EventStreamChecksumFailureException(
                                  string.Format(CultureInfo.InvariantCulture, "Message Total Length didn't match the passed in length. Expected {0} but was {1}", length, totalLength));
                    }

                    //now write the prelude crc to the checksum stream
                    runningChecksum.Write(buffer, currentOffset, SizeOfInt32);
                    currentOffset += SizeOfInt32;

                    //prelude length is total message, minus framing and headers size.
                    var payloadLength = totalLength - headersLength - FramingSize;

                    //if we have headers, then loop over each one and parse them out.
                    if (headersLength > 0)
                    {
                        int preOpOffset = currentOffset;
                        while (currentOffset - PreludeLen < headersLength)
                        {
                            EventStreamHeader header = EventStreamHeader.FromBuffer(buffer, currentOffset, ref currentOffset);
                            message.Headers.Add(header.Name, header);
                        }

                        //after parsing the header remember to write that data to the checksum stream
                        runningChecksum.Write(buffer, preOpOffset, currentOffset - preOpOffset);
                    }

                    // now we're on the payload
                    message.Payload = new byte[payloadLength];
                    Buffer.BlockCopy(buffer, currentOffset, message.Payload, 0, message.Payload.Length);
                    runningChecksum.Write(buffer, currentOffset, message.Payload.Length);
                    currentOffset += message.Payload.Length;

                    //after reading the payload, get the message crc and make sure it matches.
                    var trailingCrc = BitConverter.ToInt32(buffer, currentOffset);
                    //endianness conversion.
                    trailingCrc = EndianConversionUtility.NetworkToHostOrder(trailingCrc);

                    if (trailingCrc != runningChecksum.Crc32)
                    {
                        throw new EventStreamChecksumFailureException(
                                  string.Format(CultureInfo.InvariantCulture, "Message Checksum failure. Expected {0} but was {1}", trailingCrc, runningChecksum.Crc32));
                    }
                }

            return(message);
        }