/// <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)); } }