/// <summary>
        /// Returns the number of bytes to read from the stream.
        /// </summary>
        /// <param name="state">Instance of <see cref="T:NavtelecomProtocol.SessionState" />.</param>
        /// <param name="reader"><see cref="T:SharpStructures.BinaryListReader" /> linked to a FLEX message body.</param>
        /// <param name="writer"><see cref="T:SharpStructures.MemoryBufferWriter" /> with data to be sent to the client.</param>
        /// <param name="token">The token to monitor for cancellation requests.</param>
        /// <returns>A task that represents the asynchronous operation. Contains the total number of bytes to read from the socket. Zero bytes to stop reading and send the response.</returns>
        public async Task <int> GetPendingBytesAsync(SessionState state, BinaryListReader reader, MemoryBufferWriter writer, CancellationToken token)
        {
            switch (reader.ByteList.Count)
            {
            case 2:
                return(13);

            case 15:
                reader.SetPosition(13);

                return(reader.ReadUInt16() + 1);

            default:
                if (reader.ByteList.Last() != BinaryUtilities.GetCrc8(reader.ByteList.Take(reader.ByteList.Count - 1)))
                {
                    throw new ArgumentException("Invalid FLEX message CRC.");
                }

                reader.SetPosition(4);

                var result    = reader.ReadByte();
                var crashTime = reader.ReadUInt32();
                var offset    = reader.ReadUInt32();
                var sizeRead  = reader.ReadUInt16();

                if (state.CrashInfo != null && result == 0x00 && state.CrashInfo.Timestamp == crashTime)
                {
                    for (var i = 0; i < sizeRead; ++i)
                    {
                        state.CrashInfo.Data[offset + i] = reader.ByteList[15 + i];
                    }

                    state.CrashInfo.Offset = offset + sizeRead;

                    var bytesLeft = state.CrashInfo.Data.Length - state.CrashInfo.Offset;

                    writer.Write(CrashInformation.CrashDataQuery);
                    writer.Write(crashTime);
                    writer.Write(state.CrashInfo.Offset);
                    writer.Write(bytesLeft > ushort.MaxValue ? ushort.MaxValue : (ushort)bytesLeft);
                    writer.Write(BinaryUtilities.GetCrc8(writer.Buffer));

                    if (bytesLeft == 0)
                    {
                        if (_onReadyCrash != null)
                        {
                            await _onReadyCrash(state, token).ConfigureAwait(false);
                        }

                        state.CrashInfo = null;
                    }
                }

                return(0);
            }
        }
예제 #2
0
        /// <summary>
        /// Returns the number of bytes to read from the stream.
        /// </summary>
        /// <param name="state">Instance of <see cref="T:NavtelecomProtocol.SessionState" />.</param>
        /// <param name="reader"><see cref="T:SharpStructures.BinaryListReader" /> linked to a FLEX message body.</param>
        /// <param name="writer"><see cref="T:SharpStructures.MemoryBufferWriter" /> with data to be sent to the client.</param>
        /// <param name="token">The token to monitor for cancellation requests.</param>
        /// <returns>A task that represents the asynchronous operation. Contains the total number of bytes to read from the socket. Zero bytes to stop reading and send the response.</returns>
        public Task <int> GetPendingBytesAsync(SessionState state, BinaryListReader reader, MemoryBufferWriter writer,
                                               CancellationToken token)
        {
            switch (reader.ByteList.Count)
            {
            case 2:
                return(Task.FromResult(12));

            case 14:
                return(Task.FromResult(reader.ByteList[13] + 1));

            default:
                if (reader.ByteList.Last() != BinaryUtilities.GetCrc8(reader.ByteList.Take(reader.ByteList.Count - 1)))
                {
                    throw new ArgumentException("Invalid FLEX message CRC.");
                }

                reader.SetPosition(2);

                reader.ReadByte();
                reader.ReadByte();

                var crashTime   = reader.ReadUInt32();
                var crashLength = reader.ReadUInt32();

                var flags = reader.ReadByte();

                var nameLength = reader.ReadByte();
                var crashName  = new string(reader.ReadBytes(nameLength).Select(x => (char)x).ToArray());

                if (crashTime > 0 && crashLength > 0 && flags == 0xFF)
                {
                    state.CrashInfo = new CrashInformation
                    {
                        Data      = new byte[crashLength],
                        Name      = crashName,
                        Timestamp = crashTime
                    };

                    writer.Write(CrashInformation.CrashDataQuery);
                    writer.Write(crashTime);
                    writer.Write(0U);
                    writer.Write(crashLength > ushort.MaxValue ? ushort.MaxValue : (ushort)crashLength);
                    writer.Write(BinaryUtilities.GetCrc8(writer.Buffer));
                }

                return(Task.FromResult(0));
            }
        }
예제 #3
0
        public void CopyToWithSomeFullSegmentsWorks_CopyTo()
        {
            var inputSize = (MinimumSegmentSize * 2) + 1;
            var input     = Enumerable.Range(0, inputSize).Select(i => (byte)i).ToArray();

            using (var bufferWriter = new MemoryBufferWriter(MinimumSegmentSize))
            {
                bufferWriter.Write(input, 0, input.Length);
                Assert.Equal(input.Length, bufferWriter.Length);

                using (var destination = new MemoryBufferWriter())
                {
                    bufferWriter.CopyTo(destination);
                    var data = new byte[bufferWriter.Length];
                    bufferWriter.CopyTo(data);

                    Assert.Equal(input, data);

                    Array.Clear(data, 0, data.Length);

                    destination.CopyTo(data);
                    Assert.Equal(input, data);
                }
            }
        }
예제 #4
0
        public void WriteMultipleMessages()
        {
            var expectedEncoding = new byte[]
            {
                /* length: */ 0x00,
                /* body: <empty> */
                /* length: */ 0x0E,
                /* body: */ 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x2C, 0x0D, 0x0A, 0x57, 0x6F, 0x72, 0x6C, 0x64, 0x21,
            };

            var messages = new[]
            {
                new byte[0],
                Encoding.UTF8.GetBytes("Hello,\r\nWorld!")
            };

            using (var writer = new MemoryBufferWriter()) // Use small chunks to test Advance/Enlarge and partial payload writing
            {
                foreach (var message in messages)
                {
                    BinaryMessageFormatter.WriteLengthPrefix(message.Length, writer);
                    writer.Write(message);
                }

                Assert.Equal(expectedEncoding, writer.ToArray());
            }
        }
        public void MemoryBufferWriter()
        {
            var array  = new byte[WriteCount * WritePerSize];
            var writer = new MemoryBufferWriter <byte>(array);

            for (var i = 0; i < WriteCount; i++)
            {
                writer.Write(this.filedValue);
            }
        }
예제 #6
0
        public void WriteBinaryMessage(byte[] encoded, byte[] payload)
        {
            using (var writer = new MemoryBufferWriter())
            {
                BinaryMessageFormatter.WriteLengthPrefix(payload.Length, writer);
                writer.Write(payload);

                Assert.Equal(encoded, writer.ToArray());
            }
        }
        /// <summary>
        /// Processes the body of the message.
        /// </summary>
        /// <param name="state">Instance of <see cref="T:NavtelecomProtocol.SessionState" />.</param>
        /// <param name="reader"><see cref="T:SharpStructures.BinaryListReader" /> linked to an NTCB message body.</param>
        /// <param name="writer"><see cref="T:SharpStructures.MemoryBufferWriter" /> with data to be sent to the client.</param>
        public void ProcessBody(SessionState state, BinaryListReader reader, MemoryBufferWriter writer)
        {
            if (!reader.ReadBytes(Prefix.Length).Select(x => (char)x).SequenceEqual(Prefix))
            {
                throw new ArgumentException("NTCB identity message prefix does not match.");
            }

            state.DeviceIdentifier = new string(reader.ReadBytes(15).Select(x => (char)x).ToArray());

            writer.Write(Response);
        }
예제 #8
0
 public void RoundTrippingTest(byte[] payload)
 {
     using (var writer = new MemoryBufferWriter())
     {
         BinaryMessageFormatter.WriteLengthPrefix(payload.Length, writer);
         writer.Write(payload);
         var buffer = new ReadOnlySequence <byte>(writer.ToArray());
         Assert.True(BinaryMessageParser.TryParseMessage(ref buffer, out var roundtripped));
         Assert.Equal(payload, roundtripped.ToArray());
     }
 }
예제 #9
0
        public void WriteTextMessage(byte[] encoded, string payload)
        {
            var message = Encoding.UTF8.GetBytes(payload);

            using (var writer = new MemoryBufferWriter())
            {
                BinaryMessageFormatter.WriteLengthPrefix(message.Length, writer);
                writer.Write(message);

                Assert.Equal(encoded, writer.ToArray());
            }
        }
예제 #10
0
        public void ToArrayWithSomeFullSegmentsWorks()
        {
            var inputSize = (MinimumSegmentSize * 2) + 1;
            var input     = Enumerable.Range(0, inputSize).Select(i => (byte)i).ToArray();

            using (var bufferWriter = new MemoryBufferWriter(MinimumSegmentSize))
            {
                bufferWriter.Write(input, 0, input.Length);
                Assert.Equal(input.Length, bufferWriter.Length);

                var data = bufferWriter.ToArray();
                Assert.Equal(input, data);
            }
        }
예제 #11
0
        public void ToArrayWithExactlyFullSegmentsWorks_CopyTo()
        {
            var inputSize = MinimumSegmentSize * 2;
            var input     = Enumerable.Range(0, inputSize).Select(i => (byte)i).ToArray();

            using (var bufferWriter = new MemoryBufferWriter(MinimumSegmentSize))
            {
                bufferWriter.Write(input, 0, input.Length);
                Assert.Equal(input.Length, bufferWriter.Length);

                var data = new byte[bufferWriter.Length];

                bufferWriter.CopyTo(data);
                Assert.Equal(input, data);
            }
        }
예제 #12
0
        public void WriteByteWorksIfFirstByteInNewSegment()
        {
            var inputSize = MinimumSegmentSize;
            var input     = Enumerable.Range(0, inputSize).Select(i => (byte)i).ToArray();

            using (var bufferWriter = new MemoryBufferWriter(MinimumSegmentSize))
            {
                bufferWriter.Write(input, 0, input.Length);
                Assert.Equal(16, bufferWriter.Length);
                bufferWriter.WriteByte(16);
                Assert.Equal(17, bufferWriter.Length);

                var data = bufferWriter.ToArray();
                Assert.Equal(input, data.Take(16));
                Assert.Equal(16, data[16]);
            }
        }
예제 #13
0
        public void WriteSpanWorksAtNonZeroOffset_CopyTo()
        {
            using (var bufferWriter = new MemoryBufferWriter())
            {
                bufferWriter.WriteByte(1);
                bufferWriter.Write(new byte[] { 2, 3, 4 }.AsSpan());

                Assert.Equal(4, bufferWriter.Length);

                var data = new byte[bufferWriter.Length];
                bufferWriter.CopyTo(data);
                Assert.Equal(1, data[0]);
                Assert.Equal(2, data[1]);
                Assert.Equal(3, data[2]);
                Assert.Equal(4, data[3]);
            }
        }
예제 #14
0
        public async Task CopyToAsyncWithExactlyFullSegmentsWorks()
        {
            var inputSize = MinimumSegmentSize * 2;
            var input     = Enumerable.Range(0, inputSize).Select(i => (byte)i).ToArray();

            using (var bufferWriter = new MemoryBufferWriter(MinimumSegmentSize))
            {
                bufferWriter.Write(input, 0, input.Length);
                Assert.Equal(input.Length, bufferWriter.Length);

                var ms = new MemoryStream();
                await bufferWriter.CopyToAsync(ms);

                var data = ms.ToArray();
                Assert.Equal(input, data);
            }
        }
예제 #15
0
        public void WriteByteWorksIfSegmentHasSpace()
        {
            var input = new byte[] { 11, 12, 13 };

            using (var bufferWriter = new MemoryBufferWriter())
            {
                bufferWriter.Write(input, 0, input.Length);
                bufferWriter.WriteByte(14);

                Assert.Equal(4, bufferWriter.Length);

                var data = bufferWriter.ToArray();
                Assert.Equal(4, data.Length);
                Assert.Equal(11, data[0]);
                Assert.Equal(12, data[1]);
                Assert.Equal(13, data[2]);
                Assert.Equal(14, data[3]);
            }
        }
예제 #16
0
        public void Setup()
        {
            var buffer = new byte[MessageLength];

            Random.NextBytes(buffer);
            using (var writer = new MemoryBufferWriter())
            {
                BinaryMessageFormatter.WriteLengthPrefix(buffer.Length, writer);
                writer.Write(buffer);
                _binaryInput = writer.ToArray();
            }

            buffer = new byte[MessageLength];
            Random.NextBytes(buffer);
            using (var writer = new MemoryBufferWriter())
            {
                writer.Write(buffer);
                TextMessageFormatter.WriteRecordSeparator(writer);

                _textInput = writer.ToArray();
            }
        }
        /// <summary>
        /// Returns the number of bytes to read from the stream.
        /// </summary>
        /// <param name="sessionState">Instance of <see cref="T:NavtelecomProtocol.SessionState" />.</param>
        /// <param name="receiveBuffer">A read-only collection of bytes received from a stream.</param>
        /// <param name="sendBuffer"><see cref="T:SharpStructures.MemoryBuffer" /> with data to be sent to the client.</param>
        /// <param name="token">The token to monitor for cancellation requests.</param>
        /// <returns>A task that represents the asynchronous operation. Contains the total number of bytes to read from the socket. Zero bytes to stop reading and send the response.</returns>
        public Task <int> GetPendingBytesAsync(SessionState sessionState, IReadOnlyList <byte> receiveBuffer, MemoryBuffer sendBuffer, CancellationToken token)
        {
            switch (receiveBuffer.Count)
            {
            case 1:
                return(Task.FromResult(HeaderLength - 1));

            case HeaderLength:
                var reader = new BinaryListReader(receiveBuffer, true);

                if (!reader.ReadBytes(HeaderPreamble.Length).Select(x => (char)x).SequenceEqual(HeaderPreamble))
                {
                    throw new ArgumentException("NTCB header preamble does not match.");
                }

                sessionState.ReceiverId = reader.ReadUInt32();
                sessionState.SenderId   = reader.ReadUInt32();

                var payloadLength = reader.ReadUInt16();

                reader.ReadByte();

                var headerChecksum = reader.ReadByte();

                if (BinaryUtilities.GetXorSum(receiveBuffer.Take(HeaderLength - 1)) != headerChecksum)
                {
                    throw new ArgumentException("NTCB header checksum does not match.");
                }

                return(Task.FromResult((int)payloadLength));

            default:
                if (BinaryUtilities.GetXorSum(receiveBuffer.Skip(HeaderLength)) != receiveBuffer[14])
                {
                    throw new ArgumentException("NTCB body checksum does not match.");
                }

                var bodyProcessor =
                    _bodyProcessors.GetValueOrDefault(receiveBuffer.Skip(HeaderLength).Select(x => (char)x));

                if (bodyProcessor == null)
                {
                    throw new ArgumentException("Unknown NTCB message type.");
                }

                var bodyReader = new BinaryListReader(receiveBuffer, true);

                bodyReader.SetPosition(HeaderLength);

                sendBuffer.AllocateSpace(HeaderLength);

                var writer = new MemoryBufferWriter(sendBuffer, true);

                bodyProcessor.ProcessBody(sessionState, bodyReader, writer);

                var responseLength = sendBuffer.Position - HeaderLength;

                sendBuffer.SetPosition(0);

                writer.Write(HeaderPreamble.Select(x => (byte)x).ToArray());
                writer.Write(sessionState.SenderId);
                writer.Write(sessionState.ReceiverId);
                writer.Write((ushort)responseLength);
                writer.Write(BinaryUtilities.GetXorSum(sendBuffer.Array.Skip(HeaderLength).Take(responseLength)));
                writer.Write(BinaryUtilities.GetXorSum(sendBuffer.Array.Take(HeaderLength - 1)));

                sendBuffer.SetPosition(responseLength + HeaderLength);

                return(Task.FromResult(0));
            }
        }