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