diff --git a/QuicNet.Infrastructure/ErrorCodes.cs b/QuicNet.Infrastructure/ErrorCodes.cs index 163febe..bcd57a3 100644 --- a/QuicNet.Infrastructure/ErrorCodes.cs +++ b/QuicNet.Infrastructure/ErrorCodes.cs @@ -10,15 +10,20 @@ public enum ErrorCode : UInt16 { NO_ERROR = 0x0, INTERNAL_ERROR = 0x1, - SERVER_BUSY = 0x2, + CONNECTION_REFUSED = 0x2, FLOW_CONTROL_ERROR = 0x3, STREAM_LIMIT_ERROR = 0x4, STREAM_STATE_ERROR = 0x5, - FINAL_OFFSET_ERROR = 0x6, + FINAL_SIZE_ERROR = 0x6, FRAME_ENCODING_ERROR = 0x7, TRANSPORT_PARAMETER_ERROR = 0x8, - VERSION_NEGOTIATION_ERROR = 0x9, + CONNECTION_ID_LIMIT_ERROR = 0x9, PROTOCOL_VIOLATION = 0xA, - INVALID_MIGRATION = 0xC + INVALID_TOKEN = 0xB, + APPLICATION_ERROR = 0xC, + CRYPTO_BUFFER_EXCEEDED = 0xD, + KEY_UPDATE_ERROR = 0xE, + AEAD_LIMIT_REACHED = 0xF, + CRYPTO_ERROR = 0x100 } } diff --git a/QuicNet.Infrastructure/Frames/ConnectionCloseFrame.cs b/QuicNet.Infrastructure/Frames/ConnectionCloseFrame.cs index 8fff599..2fe9317 100644 --- a/QuicNet.Infrastructure/Frames/ConnectionCloseFrame.cs +++ b/QuicNet.Infrastructure/Frames/ConnectionCloseFrame.cs @@ -9,8 +9,10 @@ namespace QuicNet.Infrastructure.Frames { public class ConnectionCloseFrame : Frame { + public byte ActualType { get; set; } public override byte Type => 0x1c; - public UInt16 ErrorCode { get; set; } + public VariableInteger ErrorCode { get; set; } + public VariableInteger FrameType { get; set; } public VariableInteger ReasonPhraseLength { get; set; } public string ReasonPhrase { get; set; } @@ -20,19 +22,36 @@ public ConnectionCloseFrame() ReasonPhraseLength = new VariableInteger(0); } - public ConnectionCloseFrame(ErrorCode error, string reason) + /// + /// 0x1d not yet supported (Application Protocol Error) + /// + public ConnectionCloseFrame(ErrorCode error, byte frameType, string reason) { - ReasonPhraseLength = new VariableInteger(0); + ActualType = 0x1c; + + ErrorCode = (UInt64)error; + FrameType = new VariableInteger((UInt64)frameType); + if (!string.IsNullOrWhiteSpace(reason)) + { + ReasonPhraseLength = new VariableInteger((UInt64)reason.Length); + } + else + { + ReasonPhraseLength = new VariableInteger(0); + } - ErrorCode = (UInt16)error; ReasonPhrase = reason; } public override void Decode(ByteArray array) { - byte type = array.ReadByte(); + ActualType = array.ReadByte(); + ErrorCode = array.ReadVariableInteger(); + if (ActualType == 0x1c) + { + FrameType = array.ReadVariableInteger(); + } - ErrorCode = array.ReadUInt16(); ReasonPhraseLength = array.ReadVariableInteger(); byte[] rp = array.ReadBytes((int)ReasonPhraseLength.Value); @@ -42,16 +61,19 @@ public override void Decode(ByteArray array) public override byte[] Encode() { List result = new List(); - result.Add(Type); - - byte[] errorCode = ByteUtilities.GetBytes(ErrorCode); - result.AddRange(errorCode); + result.Add(ActualType); + result.AddRange(ErrorCode.ToByteArray()); + if (ActualType == 0x1c) + { + result.AddRange(FrameType.ToByteArray()); + } if (string.IsNullOrWhiteSpace(ReasonPhrase) == false) { - byte[] reasonPhrase = ByteUtilities.GetBytes(ReasonPhrase); byte[] rpl = new VariableInteger((UInt64)ReasonPhrase.Length); result.AddRange(rpl); + + byte[] reasonPhrase = ByteUtilities.GetBytes(ReasonPhrase); result.AddRange(reasonPhrase); } diff --git a/QuicNet.Infrastructure/Frames/DataBlockedFrame.cs b/QuicNet.Infrastructure/Frames/DataBlockedFrame.cs index 9bccea7..3f95179 100644 --- a/QuicNet.Infrastructure/Frames/DataBlockedFrame.cs +++ b/QuicNet.Infrastructure/Frames/DataBlockedFrame.cs @@ -10,7 +10,7 @@ namespace QuicNet.Infrastructure.Frames public class DataBlockedFrame : Frame { public override byte Type => 0x14; - public VariableInteger DataLimit { get; set; } + public VariableInteger MaximumData { get; set; } public DataBlockedFrame() { @@ -19,22 +19,20 @@ public DataBlockedFrame() public DataBlockedFrame(UInt64 dataLimit) { - DataLimit = dataLimit; + MaximumData = dataLimit; } public override void Decode(ByteArray array) { byte type = array.ReadByte(); - DataLimit = array.ReadVariableInteger(); + MaximumData = array.ReadVariableInteger(); } public override byte[] Encode() { List result = new List(); result.Add(Type); - byte[] dataLimit = DataLimit; - - result.AddRange(dataLimit); + result.AddRange(MaximumData.ToByteArray()); return result.ToArray(); } diff --git a/QuicNet.Infrastructure/Frames/MaxDataFrame.cs b/QuicNet.Infrastructure/Frames/MaxDataFrame.cs index cccfce6..142cc40 100644 --- a/QuicNet.Infrastructure/Frames/MaxDataFrame.cs +++ b/QuicNet.Infrastructure/Frames/MaxDataFrame.cs @@ -21,10 +21,9 @@ public override void Decode(ByteArray array) public override byte[] Encode() { List result = new List(); - byte[] maxData = MaximumData; result.Add(Type); - result.AddRange(maxData); + result.AddRange(MaximumData.ToByteArray()); return result.ToArray(); } diff --git a/QuicNet.Infrastructure/Frames/MaxStreamDataFrame.cs b/QuicNet.Infrastructure/Frames/MaxStreamDataFrame.cs index dc5d69b..3edda71 100644 --- a/QuicNet.Infrastructure/Frames/MaxStreamDataFrame.cs +++ b/QuicNet.Infrastructure/Frames/MaxStreamDataFrame.cs @@ -36,13 +36,10 @@ public override void Decode(ByteArray array) public override byte[] Encode() { List result = new List(); - result.Add(Type); - - byte[] streamId = StreamId; - result.AddRange(streamId); - byte[] maximumStreamData = MaximumStreamData; - result.AddRange(maximumStreamData); + result.Add(Type); + result.AddRange(StreamId.ToByteArray()); + result.AddRange(MaximumStreamData.ToByteArray()); return result.ToArray(); } diff --git a/QuicNet.Infrastructure/Frames/MaxStreamsFrame.cs b/QuicNet.Infrastructure/Frames/MaxStreamsFrame.cs index 9729a93..fbf39f1 100644 --- a/QuicNet.Infrastructure/Frames/MaxStreamsFrame.cs +++ b/QuicNet.Infrastructure/Frames/MaxStreamsFrame.cs @@ -31,10 +31,9 @@ public override void Decode(ByteArray array) public override byte[] Encode() { List result = new List(); - result.Add(Type); - byte[] streamId = MaximumStreams; - result.AddRange(streamId); + result.Add(Type); + result.AddRange(MaximumStreams.ToByteArray()); return result.ToArray(); } diff --git a/QuicNet.Infrastructure/Frames/PingFrame.cs b/QuicNet.Infrastructure/Frames/PingFrame.cs index c758af8..5819801 100644 --- a/QuicNet.Infrastructure/Frames/PingFrame.cs +++ b/QuicNet.Infrastructure/Frames/PingFrame.cs @@ -13,12 +13,15 @@ public class PingFrame : Frame public override void Decode(ByteArray array) { - throw new NotImplementedException(); + byte type = array.ReadByte(); } public override byte[] Encode() { - throw new NotImplementedException(); + List data = new List(); + data.Add(Type); + + return data.ToArray(); } } } diff --git a/QuicNet.Infrastructure/Frames/ResetStreamFrame.cs b/QuicNet.Infrastructure/Frames/ResetStreamFrame.cs index b8715eb..0bfc640 100644 --- a/QuicNet.Infrastructure/Frames/ResetStreamFrame.cs +++ b/QuicNet.Infrastructure/Frames/ResetStreamFrame.cs @@ -11,15 +11,15 @@ public class ResetStreamFrame : Frame { public override byte Type => 0x04; public VariableInteger StreamId { get; set; } - public UInt16 ApplicationErrorCode { get; set; } - public VariableInteger FinalOffset { get; set; } + public VariableInteger ApplicationProtocolErrorCode { get; set; } + public VariableInteger FinalSize { get; set; } public override void Decode(ByteArray array) { byte type = array.ReadByte(); StreamId = array.ReadVariableInteger(); - ApplicationErrorCode = array.ReadUInt16(); - FinalOffset = array.ReadVariableInteger(); + ApplicationProtocolErrorCode = array.ReadVariableInteger(); + FinalSize = array.ReadVariableInteger(); } public override byte[] Encode() @@ -27,13 +27,9 @@ public override byte[] Encode() List result = new List(); result.Add(Type); - byte[] streamId = StreamId; - result.AddRange(streamId); - - result.AddRange(ByteUtilities.GetBytes(ApplicationErrorCode)); - - byte[] offset = FinalOffset; - result.AddRange(offset); + result.AddRange(StreamId.ToByteArray()); + result.AddRange(ApplicationProtocolErrorCode.ToByteArray()); + result.AddRange(FinalSize.ToByteArray()); return result.ToArray(); } diff --git a/QuicNet.Infrastructure/Frames/StreamDataBlockedFrame.cs b/QuicNet.Infrastructure/Frames/StreamDataBlockedFrame.cs index 3a34d04..b3d5b7d 100644 --- a/QuicNet.Infrastructure/Frames/StreamDataBlockedFrame.cs +++ b/QuicNet.Infrastructure/Frames/StreamDataBlockedFrame.cs @@ -11,9 +11,7 @@ public class StreamDataBlockedFrame : Frame { public override byte Type => 0x15; public VariableInteger StreamId { get; set; } - public VariableInteger StreamDataLimit { get; set; } - - public StreamId ConvertedStreamId { get; set; } + public VariableInteger MaximumStreamData { get; set; } public StreamDataBlockedFrame() { @@ -23,26 +21,23 @@ public StreamDataBlockedFrame() public StreamDataBlockedFrame(UInt64 streamId, UInt64 streamDataLimit) { StreamId = streamId; - StreamDataLimit = streamDataLimit; + MaximumStreamData = streamDataLimit; } public override void Decode(ByteArray array) { byte type = array.ReadByte(); StreamId = array.ReadVariableInteger(); - StreamDataLimit = array.ReadVariableInteger(); + MaximumStreamData = array.ReadVariableInteger(); } public override byte[] Encode() { List result = new List(); - result.Add(Type); - byte[] streamId = StreamId; - byte[] streamDataLimit = StreamDataLimit; - - result.AddRange(streamId); - result.AddRange(streamDataLimit); + result.Add(Type); + result.AddRange(StreamId.ToByteArray()); + result.AddRange(MaximumStreamData.ToByteArray()); return result.ToArray(); } diff --git a/QuicNet.Infrastructure/Frames/StreamFrame.cs b/QuicNet.Infrastructure/Frames/StreamFrame.cs index 7e7bbf6..4175e2d 100644 --- a/QuicNet.Infrastructure/Frames/StreamFrame.cs +++ b/QuicNet.Infrastructure/Frames/StreamFrame.cs @@ -9,14 +9,13 @@ namespace QuicNet.Infrastructure.Frames { public class StreamFrame : Frame { - private byte ActualType = 0x08; + public byte ActualType = 0x08; public override byte Type => 0x08; public VariableInteger StreamId { get; set; } public VariableInteger Offset { get; set; } public VariableInteger Length { get; set; } public byte[] StreamData { get; set; } - public StreamId ConvertedStreamId { get; set; } public bool EndOfStream { get; set; } public StreamFrame() @@ -28,8 +27,8 @@ public StreamFrame(UInt64 streamId, byte[] data, UInt64 offset, bool eos) { StreamId = streamId; StreamData = data; - Length = (UInt64)data.Length; Offset = offset; + Length = (UInt64)data.Length; EndOfStream = eos; } @@ -50,7 +49,6 @@ public override void Decode(ByteArray array) EndOfStream = true; StreamData = array.ReadBytes((int)Length.Value); - ConvertedStreamId = QuickNet.Utilities.StreamId.Decode(ByteUtilities.GetBytes(StreamId.Value)); } public override byte[] Encode() @@ -72,16 +70,10 @@ public override byte[] Encode() result.AddRange(streamId); if (OFF_BIT > 0) - { - byte[] offset = Offset; - result.AddRange(offset); - } + result.AddRange(Offset.ToByteArray()); if (LEN_BIT > 0) - { - byte[] length = Length; - result.AddRange(length); - } + result.AddRange(Length.ToByteArray()); result.AddRange(StreamData); diff --git a/QuicNet.Infrastructure/PacketProcessing/PacketCreator.cs b/QuicNet.Infrastructure/PacketProcessing/PacketCreator.cs index b5cfbea..b57545e 100644 --- a/QuicNet.Infrastructure/PacketProcessing/PacketCreator.cs +++ b/QuicNet.Infrastructure/PacketProcessing/PacketCreator.cs @@ -24,12 +24,12 @@ public PacketCreator(UInt32 connectionId, UInt32 peerConnectionId) _peerConnectionId = peerConnectionId; } - public ShortHeaderPacket CreateConnectionClosePacket(ErrorCode code, string reason) + public ShortHeaderPacket CreateConnectionClosePacket(ErrorCode code, byte frameType, string reason) { ShortHeaderPacket packet = new ShortHeaderPacket(); packet.PacketNumber = _ns.Get(); packet.DestinationConnectionId = (byte)_peerConnectionId; - packet.AttachFrame(new ConnectionCloseFrame(code, reason)); + packet.AttachFrame(new ConnectionCloseFrame(code, frameType, reason)); return packet; } diff --git a/QuicNet.Infrastructure/Packets/LongHeaderPacket.cs b/QuicNet.Infrastructure/Packets/LongHeaderPacket.cs index 22b33f6..bfd281a 100644 --- a/QuicNet.Infrastructure/Packets/LongHeaderPacket.cs +++ b/QuicNet.Infrastructure/Packets/LongHeaderPacket.cs @@ -7,34 +7,46 @@ namespace QuicNet.Infrastructure.Packets { public class LongHeaderPacket : Packet { - public override byte Type => 0xC0; // 1100 0000 + public override byte Type => 0b1100_0000; // 1100 0000 - public byte DCID { get; set; } - public byte DestinationConnectionId { get; set; } - public byte SCID { get; set; } - public byte SourceConnectionId { get; set; } + public byte DestinationConnectionIdLength { get; set; } + public GranularInteger DestinationConnectionId { get; set; } + public byte SourceConnectionIdLength { get; set; } + public GranularInteger SourceConnectionId { get; set; } public PacketType PacketType { get; set; } - public LongHeaderPacket(PacketType packetType) + + public LongHeaderPacket() + { + + } + + public LongHeaderPacket(PacketType packetType, GranularInteger destinationConnectionId, GranularInteger sourceConnectionId) { PacketType = packetType; + DestinationConnectionIdLength = destinationConnectionId.Size; + DestinationConnectionId = destinationConnectionId; + + SourceConnectionIdLength = sourceConnectionId.Size; + SourceConnectionId = sourceConnectionId; } public override void Decode(byte[] packet) { ByteArray array = new ByteArray(packet); + byte type = array.ReadByte(); - PacketType = (PacketType)(type & 0x30); + PacketType = DecodeTypeFiled(type); Version = array.ReadUInt32(); - DCID = array.ReadByte(); - if (DCID > 0) - DestinationConnectionId = array.ReadByte(); + DestinationConnectionIdLength = array.ReadByte(); + if (DestinationConnectionIdLength > 0) + DestinationConnectionId = array.ReadGranularInteger(DestinationConnectionIdLength); - SCID = array.ReadByte(); - if (SCID > 0) - SourceConnectionId = array.ReadByte(); + SourceConnectionIdLength = array.ReadByte(); + if (SourceConnectionIdLength > 0) + SourceConnectionId = array.ReadGranularInteger(SourceConnectionIdLength); this.DecodeFrames(array); } @@ -48,12 +60,13 @@ public override byte[] Encode() result.Add(EncodeTypeField()); result.AddRange(ByteUtilities.GetBytes(Version)); - result.Add(DCID); - if (DCID > 0) - result.Add(DestinationConnectionId); - result.Add(SCID); - if (SCID > 0) - result.Add(SourceConnectionId); + result.Add(DestinationConnectionId.Size); + if (DestinationConnectionId.Size > 0) + result.AddRange(DestinationConnectionId.ToByteArray()); + + result.Add(SourceConnectionId.Size); + if (SourceConnectionId.Size > 0) + result.AddRange(SourceConnectionId.ToByteArray()); result.AddRange(frames); @@ -62,9 +75,16 @@ public override byte[] Encode() private byte EncodeTypeField() { - byte type = (byte)(Type | (byte)PacketType | 0x03); + byte type = (byte)(Type | ((byte)PacketType << 4) & 0b0011_0000); return type; } + + private PacketType DecodeTypeFiled(byte type) + { + PacketType result = (PacketType)((type & 0b0011_0000) >> 4); + + return result; + } } } diff --git a/QuicNet.Infrastructure/Packets/ShortHeaderPacket.cs b/QuicNet.Infrastructure/Packets/ShortHeaderPacket.cs index 1c6eaf9..18a86e2 100644 --- a/QuicNet.Infrastructure/Packets/ShortHeaderPacket.cs +++ b/QuicNet.Infrastructure/Packets/ShortHeaderPacket.cs @@ -7,7 +7,9 @@ namespace QuicNet.Infrastructure.Packets { public class ShortHeaderPacket : Packet { - public override byte Type => 0x40; // 0100 0000; + public byte ActualType = 0b01000000; + public override byte Type => 0b01000000; + public byte DestinationConnectionId { get; set; } public GranularInteger PacketNumber { get; set; } diff --git a/QuicNet.Tests.Unit/FrameTests.cs b/QuicNet.Tests.Unit/FrameTests.cs new file mode 100644 index 0000000..5d4dbe2 --- /dev/null +++ b/QuicNet.Tests.Unit/FrameTests.cs @@ -0,0 +1,28 @@ +using System; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using QuickNet.Utilities; +using QuicNet.Constants; +using QuicNet.Infrastructure; +using QuicNet.Infrastructure.Frames; + +namespace QuicNet.Tests.Unit +{ + [TestClass] + public class FrameTests + { + [TestMethod] + public void ConnectionCloseFrameTest() + { + var ccf = new ConnectionCloseFrame(ErrorCode.PROTOCOL_VIOLATION, 0x00, ErrorConstants.PMTUNotReached); + byte[] data = ccf.Encode(); + + var nccf = new ConnectionCloseFrame(); + nccf.Decode(new ByteArray(data)); + + Assert.AreEqual(ccf.ActualType, nccf.ActualType); + Assert.AreEqual(ccf.FrameType.Value, nccf.FrameType.Value); + Assert.AreEqual(ccf.ReasonPhraseLength.Value, nccf.ReasonPhraseLength.Value); + Assert.AreEqual(ccf.ReasonPhrase, nccf.ReasonPhrase); + } + } +} diff --git a/QuicNet.Tests.Unit/PacketTests.cs b/QuicNet.Tests.Unit/PacketTests.cs new file mode 100644 index 0000000..c88115c --- /dev/null +++ b/QuicNet.Tests.Unit/PacketTests.cs @@ -0,0 +1,37 @@ +using System; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using QuicNet.Infrastructure.Frames; +using QuicNet.Infrastructure.Packets; + +namespace QuicNet.Tests.Unit +{ + [TestClass] + public class PacketTests + { + [TestMethod] + public void LongeHeaderPacketTest() + { + LongHeaderPacket packet = new LongHeaderPacket(Infrastructure.PacketType.Handshake, 123415332, 1); + packet.Version = 32; + + for (int i = 0; i < 123; i++) + { + packet.AttachFrame(new PaddingFrame()); + } + + byte[] data = packet.Encode(); + + LongHeaderPacket result = new LongHeaderPacket(); + result.Decode(data); + + Assert.AreEqual(packet.Type, result.Type); + Assert.AreEqual(packet.Version, result.Version); + Assert.AreEqual(packet.DestinationConnectionIdLength, result.DestinationConnectionIdLength); + Assert.AreEqual(packet.DestinationConnectionId.Value, result.DestinationConnectionId.Value); + Assert.AreEqual(packet.SourceConnectionIdLength, result.SourceConnectionIdLength); + Assert.AreEqual(packet.SourceConnectionId.Value, result.SourceConnectionId.Value); + Assert.AreEqual(packet.PacketType, result.PacketType); + Assert.AreEqual(packet.GetFrames().Count, result.GetFrames().Count); + } + } +} diff --git a/QuicNet.Tests.Unit/QuicNet.Tests.Unit.csproj b/QuicNet.Tests.Unit/QuicNet.Tests.Unit.csproj index 43339e8..de88d6f 100644 --- a/QuicNet.Tests.Unit/QuicNet.Tests.Unit.csproj +++ b/QuicNet.Tests.Unit/QuicNet.Tests.Unit.csproj @@ -51,6 +51,8 @@ + + diff --git a/QuicNet.Tests.Unit/StreamIdTests.cs b/QuicNet.Tests.Unit/StreamIdTests.cs index b47a26a..36894df 100644 --- a/QuicNet.Tests.Unit/StreamIdTests.cs +++ b/QuicNet.Tests.Unit/StreamIdTests.cs @@ -58,5 +58,17 @@ public void ServerUnidirectional() Assert.AreEqual(data[6], 1); Assert.AreEqual(data[7], 239); } + + [TestMethod] + public void VariableIntegerTest() + { + StreamId id = new StreamId(123, StreamType.ClientBidirectional); + + VariableInteger integer = id; + + StreamId converted = integer; + + Assert.AreEqual(id.Id, converted.Id); + } } } diff --git a/QuicNet/Connections/QuicConnection.cs b/QuicNet/Connections/QuicConnection.cs index 67333bd..9d658b0 100644 --- a/QuicNet/Connections/QuicConnection.cs +++ b/QuicNet/Connections/QuicConnection.cs @@ -1,4 +1,5 @@ using QuickNet.Utilities; +using QuicNet.Constants; using QuicNet.Context; using QuicNet.Exceptions; using QuicNet.Infrastructure; @@ -69,7 +70,7 @@ public void ProcessFrames(List frames) OnMaxStreamFrame(frame); if (frame.Type == 0x14) OnDataBlockedFrame(frame); - if (frame.Type == 0x1c) + if (frame.Type >= 0x1c && frame.Type <= 0x1d) OnConnectionCloseFrame(frame); } } @@ -111,19 +112,21 @@ private void OnRstStreamFrame(Frame frame) private void OnStreamFrame(Frame frame) { StreamFrame sf = (StreamFrame)frame; - if (_streams.ContainsKey(sf.ConvertedStreamId.Id) == false) + StreamId streamId = sf.StreamId; + + if (_streams.ContainsKey(streamId.Id) == false) { - QuicStream stream = new QuicStream(this, sf.ConvertedStreamId); + QuicStream stream = new QuicStream(this, streamId); stream.ProcessData(sf); if ((UInt64)_streams.Count < MaxStreams) - _streams.Add(sf.ConvertedStreamId.Id, stream); + _streams.Add(streamId.Id, stream); else SendMaximumStreamReachedError(); } else { - QuicStream stream = _streams[sf.ConvertedStreamId.Id]; + QuicStream stream = _streams[streamId.Id]; stream.ProcessData(sf); } } @@ -165,15 +168,16 @@ private void OnDataBlockedFrame(Frame frame) private void OnStreamDataBlockedFrame(Frame frame) { StreamDataBlockedFrame sdbf = (StreamDataBlockedFrame)frame; + StreamId streamId = sdbf.StreamId; - if (_streams.ContainsKey(sdbf.ConvertedStreamId.Id) == false) + if (_streams.ContainsKey(streamId.Id) == false) return; - QuicStream stream = _streams[sdbf.ConvertedStreamId.Id]; + QuicStream stream = _streams[streamId.Id]; stream.ProcessStreamDataBlocked(sdbf); // Remove the stream from the connection - _streams.Remove(sdbf.ConvertedStreamId.Id); + _streams.Remove(streamId.Id); } #region Internal @@ -241,7 +245,7 @@ internal void TerminateConnection() internal void SendMaximumStreamReachedError() { - ShortHeaderPacket packet = PacketCreator.CreateConnectionClosePacket(Infrastructure.ErrorCode.STREAM_LIMIT_ERROR, "Maximum number of streams reached."); + ShortHeaderPacket packet = PacketCreator.CreateConnectionClosePacket(Infrastructure.ErrorCode.STREAM_LIMIT_ERROR, 0x00, ErrorConstants.MaxNumberOfStreams); Send(packet); } @@ -261,7 +265,7 @@ internal bool Send(Packet packet) // If the maximum transfer rate is reached, send FLOW_CONTROL_ERROR if (MaximumReached()) { - packet = PacketCreator.CreateConnectionClosePacket(Infrastructure.ErrorCode.FLOW_CONTROL_ERROR, "Maximum data transfer reached."); + packet = PacketCreator.CreateConnectionClosePacket(Infrastructure.ErrorCode.FLOW_CONTROL_ERROR, 0x00, ErrorConstants.MaxDataTransfer); TerminateConnection(); } diff --git a/QuicNet/Constants/ErrorConstants.cs b/QuicNet/Constants/ErrorConstants.cs new file mode 100644 index 0000000..b84ef67 --- /dev/null +++ b/QuicNet/Constants/ErrorConstants.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace QuicNet.Constants +{ + public class ErrorConstants + { + public const string ServerTooBusy = "The server is too busy to process your request."; + public const string MaxDataTransfer = "Maximum data transfer reached."; + public const string MaxNumberOfStreams = "Maximum number of streams reached."; + public const string PMTUNotReached = "PMTU have not been reached."; + } +} diff --git a/QuicNet/QuicListener.cs b/QuicNet/QuicListener.cs index c7d233c..b45a5e2 100644 --- a/QuicNet/QuicListener.cs +++ b/QuicNet/QuicListener.cs @@ -1,5 +1,6 @@ using QuickNet.Utilities; using QuicNet.Connections; +using QuicNet.Constants; using QuicNet.Context; using QuicNet.Exceptions; using QuicNet.Infrastructure; @@ -147,7 +148,7 @@ private QuicConnection ProcessInitialPacket(Packet packet, IPEndPoint endPoint) // Protocol violation if the initial packet is smaller than the PMTU. (pt. 14 / 16th draft) if (cast.Encode().Length < QuicSettings.PMTU) { - ip.AttachFrame(new ConnectionCloseFrame(ErrorCode.PROTOCOL_VIOLATION, "PMTU have not been reached.")); + ip.AttachFrame(new ConnectionCloseFrame(ErrorCode.PROTOCOL_VIOLATION, 0x00, ErrorConstants.PMTUNotReached)); } else if (ConnectionPool.AddConnection(new ConnectionData(_pwt, cast.SourceConnectionId, 0), out availableConnectionId) == true) { @@ -165,7 +166,7 @@ private QuicConnection ProcessInitialPacket(Packet packet, IPEndPoint endPoint) // Not accepting connections. Send initial packet with CONNECTION_CLOSE frame. // TODO: Buffering. The server might buffer incomming 0-RTT packets in anticipation of late delivery InitialPacket. // Maximum buffer size should be set in QuicSettings. - ip.AttachFrame(new ConnectionCloseFrame(ErrorCode.SERVER_BUSY, "The server is too busy to process your request.")); + ip.AttachFrame(new ConnectionCloseFrame(ErrorCode.CONNECTION_REFUSED, 0x00, ErrorConstants.ServerTooBusy)); } data = ip.Encode(); diff --git a/QuicNet/Streams/QuicStream.cs b/QuicNet/Streams/QuicStream.cs index f882ef8..3053f12 100644 --- a/QuicNet/Streams/QuicStream.cs +++ b/QuicNet/Streams/QuicStream.cs @@ -1,5 +1,6 @@ using QuickNet.Utilities; using QuicNet.Connections; +using QuicNet.Constants; using QuicNet.Context; using QuicNet.Exceptions; using QuicNet.Infrastructure.Frames; @@ -131,7 +132,7 @@ public void ProcessData(StreamFrame frame) // Terminate connection if maximum stream data is reached if (_currentTransferRate >= _maximumStreamData) { - ShortHeaderPacket errorPacket = _connection.PacketCreator.CreateConnectionClosePacket(Infrastructure.ErrorCode.FLOW_CONTROL_ERROR, "Maximum stream data transfer reached."); + ShortHeaderPacket errorPacket = _connection.PacketCreator.CreateConnectionClosePacket(Infrastructure.ErrorCode.FLOW_CONTROL_ERROR, frame.ActualType, ErrorConstants.MaxDataTransfer); _connection.SendData(errorPacket); _connection.TerminateConnection(); diff --git a/QuickNet.Tests.ConsoleServer/Program.cs b/QuickNet.Tests.ConsoleServer/Program.cs index 2518f49..07a0a95 100644 --- a/QuickNet.Tests.ConsoleServer/Program.cs +++ b/QuickNet.Tests.ConsoleServer/Program.cs @@ -60,7 +60,7 @@ static void Main(string[] args) packet = new InitialPacketCreator().CreateInitialPacket(124, 0); - ConnectionCloseFrame frame = new ConnectionCloseFrame(ErrorCode.SERVER_BUSY, "The server is too busy to process your request."); + ConnectionCloseFrame frame = new ConnectionCloseFrame(ErrorCode.CONNECTION_REFUSED, 0x00, "The server is too busy to process your request."); MaxStreamsFrame msidframe = new MaxStreamsFrame(144123, StreamType.ClientUnidirectional); //packet.AttachFrame(frame); packet.AttachFrame(msidframe); diff --git a/QuickNet.Utilities/ByteArray.cs b/QuickNet.Utilities/ByteArray.cs index 6253941..cbad4fa 100644 --- a/QuickNet.Utilities/ByteArray.cs +++ b/QuickNet.Utilities/ByteArray.cs @@ -80,6 +80,14 @@ public VariableInteger ReadVariableInteger() return bytes; } + public GranularInteger ReadGranularInteger(int size) + { + byte[] data = ReadBytes(size); + GranularInteger result = data; + + return result; + } + public StreamId ReadStreamId() { byte[] streamId = ReadBytes(8); diff --git a/QuickNet.Utilities/GranularInteger.cs b/QuickNet.Utilities/GranularInteger.cs index 22a3ef1..7c9e41f 100644 --- a/QuickNet.Utilities/GranularInteger.cs +++ b/QuickNet.Utilities/GranularInteger.cs @@ -19,6 +19,11 @@ public GranularInteger(UInt64 integer) _integer = integer; } + public byte[] ToByteArray() + { + return Encode(this._integer); + } + public static implicit operator byte[] (GranularInteger integer) { return Encode(integer._integer); diff --git a/QuickNet.Utilities/StreamId.cs b/QuickNet.Utilities/StreamId.cs index 67c734d..3301b18 100644 --- a/QuickNet.Utilities/StreamId.cs +++ b/QuickNet.Utilities/StreamId.cs @@ -42,6 +42,11 @@ public static implicit operator UInt64(StreamId streamId) return streamId.Id; } + public static implicit operator StreamId(VariableInteger integer) + { + return Decode(ByteUtilities.GetBytes(integer.Value)); + } + public static byte[] Encode(UInt64 id, StreamType type) { UInt64 identifier = id << 2 | (UInt64)type; diff --git a/QuickNet.Utilities/VariableInteger.cs b/QuickNet.Utilities/VariableInteger.cs index ffd019b..2e8c4f7 100644 --- a/QuickNet.Utilities/VariableInteger.cs +++ b/QuickNet.Utilities/VariableInteger.cs @@ -38,6 +38,11 @@ public static implicit operator UInt64(VariableInteger integer) return integer._integer; } + public static implicit operator VariableInteger(StreamId streamId) + { + return new VariableInteger(streamId.IntegerValue); + } + public static int Size(byte firstByte) { int result = (int)Math.Pow(2, (firstByte >> 6)); @@ -45,6 +50,11 @@ public static int Size(byte firstByte) return result; } + public byte[] ToByteArray() + { + return Encode(this._integer); + } + public static byte[] Encode(UInt64 integer) { int requiredBytes = 0;