private bool TryParseLine(int maxLength, out string?line)
        {
            maxLength += NewLine.Length;

            var  data         = _receiveBuffer.AsReadOnlySequence();
            bool lineExpected = data.Length >= maxLength;

            if (lineExpected)
            {
                // Don't look at more than maxLength data.
                data = data.Slice(0, maxLength);
            }

            var reader = new SequenceReader <byte>(data);

            if (reader.TryReadTo(out ReadOnlySequence <byte> lineSequence, NewLine))
            {
                try
                {
                    line = s_utf8Encoding.GetString(lineSequence.ToArray());
                }
                catch (DecoderFallbackException)
                {
                    ThrowHelper.ThrowProtocolInvalidUtf8();
                    throw;
                }
                _receiveBuffer.Remove(reader.Consumed);
                return(true);
            }

            if (lineExpected)
            {
                throw new ProtocolException($"Line delimited by '\\r\\n' exceeds {maxLength}");
            }

            line = null;
            return(false);
        }
Beispiel #2
0
 public SequenceReader(ReadOnlySequence <byte> data)
 {
     _reader = new SequenceReader <byte>(data);
 }
Beispiel #3
0
        public bool TryDecodePacket(Sequence receiveBuffer, int maxLength, out Packet packet)
        {
            // Binary Packet Protocol: https://tools.ietf.org/html/rfc4253#section-6.

            /*
             *  uint32    packet_length
             *  byte      padding_length
             *  byte[n1]  payload; n1 = packet_length - padding_length - 1
             *  byte[n2]  random padding; n2 = padding_length
             *  byte[m]   mac (Message Authentication Code - MAC); m = mac_length
             */

            if (_decodedPacket == null)
            {
                _decodedPacket = _sequencePool.RentSequence();
            }

            // We can't decode past the packet, because the mac is not encrypted.
            // We need to know the packet length to know how much we can decrypt.
            while (_decodedPacket.Length < 4 && receiveBuffer.Length >= _decode.BlockSize)
            {
                _decode.Transform(receiveBuffer.AsReadOnlySequence().Slice(0, _decode.BlockSize), _decodedPacket);
                receiveBuffer.Remove(_decode.BlockSize);
            }

            var decodedReader = new SequenceReader(_decodedPacket);

            if (decodedReader.Length >= 4)
            {
                // Read the packet length.
                uint packet_length = decodedReader.ReadUInt32();
                if (packet_length > maxLength)
                {
                    ThrowHelper.ThrowProtocolPacketTooLong();
                }

                // Decode the entire packet.
                uint concatenated_length = 4 + packet_length;
                // TODO: verify contatenated_length is a multiple of the cipher block size or 8, whichever is larger.
                long remaining = concatenated_length - decodedReader.Length;
                if (remaining > 0 && receiveBuffer.Length >= remaining)
                {
                    _decode.Transform(receiveBuffer.AsReadOnlySequence().Slice(0, remaining), _decodedPacket);
                    receiveBuffer.Remove(remaining);
                    remaining = 0;
                }

                if (remaining == 0)
                {
                    if (_decodedPacket.Length != concatenated_length)
                    {
                        ThrowHelper.ThrowInvalidOperation("Complete packet expected.");
                    }

                    // TODO: verify mac
                    receiveBuffer.Remove(_mac.HashSize);

                    packet         = new Packet(_decodedPacket);
                    _decodedPacket = null;
                    return(true);
                }
            }

            packet = new Packet(null);
            return(false);
        }