public Task BadRttPingResponse_RequestShouldFail(int mode)
        {
            return(Http2LoopbackServer.CreateClientAndServerAsync(async uri =>
            {
                using var handler = CreateHttpClientHandler();
                using HttpClient client = CreateHttpClient(handler);
                HttpRequestException exception = await Assert.ThrowsAsync <HttpRequestException>(() => client.GetAsync(uri));
                _output.WriteLine(exception.Message + exception.StatusCode);
            },
                                                                  async server =>
            {
                Http2LoopbackConnection connection = await server.EstablishConnectionAsync();
                (int streamId, _) = await connection.ReadAndParseRequestHeaderAsync();
                await connection.SendDefaultResponseHeadersAsync(streamId);
                PingFrame pingFrame = await connection.ReadPingAsync(); // expect an RTT PING

                if (mode == 0)
                {
                    // Invalid PING payload
                    await connection.SendPingAckAsync(-6666); // send an invalid PING response
                }
                else
                {
                    // Unexpected PING response
                    await connection.SendPingAckAsync(pingFrame.Data);     // send an valid PING response
                    await connection.SendPingAckAsync(pingFrame.Data - 1); // send a second unexpected PING response
                }

                await connection.SendResponseDataAsync(streamId, new byte[] { 1, 2, 3 }, true); // otherwise fine response
            },
                                                                  NoAutoPingResponseHttp2Options));
        }
        public void Read_Protected_ResultBytesAreExpected()
        {
            //Arrange
            var messageBytes        = Utils.ParseHexString(GetProtectedMessageHex());
            var destConnectionId    = PacketConnectionId.Empty;
            var packetNumbers       = GetPacketNumbersHex();
            var currentPacketNumber = PacketNumber.Parse(Utils.ParseHexString(packetNumbers.Current));
            var largestPacketNumber = PacketNumber.Parse(Utils.ParseHexString(packetNumbers.Largest));
            var secrets             = GetSecrets();
            var aead   = Cipher.TLS_CHACHA20_POLY1305_SHA256.CreateAead(Utils.ParseHexString(secrets.Iv), Utils.ParseHexString(secrets.Key));
            var cipher = Cipher.TLS_CHACHA20_POLY1305_SHA256.CreateCipher(Utils.ParseHexString(secrets.Hp));

            //Act
            var cursor = new MemoryCursor(messageBytes);

            var result = ShortPacket.TryParseProtectedByConnectionId(aead, cipher, cursor, destConnectionId, largestPacketNumber, out var packet);

            using (packet.Payload.SetCursor(cursor))
            {
                result &= PingFrame.TryParse(cursor);

                result &= cursor.IsEnd();
            }

            result &= cursor.IsEnd();

            //Assert
            Assert.True(result);
            Assert.Equal(destConnectionId, packet.DestinationConnectionId);
            Assert.Equal(currentPacketNumber, packet.Number);
        }
예제 #3
0
        private void HandlePingFrame(PingFrame pingFrame)
        {
            Http2Logger.LogDebug("PING frame: stream id={0}, payload={1}", pingFrame.StreamId,
                                 pingFrame.Payload.Count);

            /* 12 -> 6.7
             * PING frames are not associated with any individual stream.  If a PING
             * frame is received with a stream identifier field value other than
             * 0x0, the recipient MUST respond with a connection error of type PROTOCOL_ERROR. */
            if (pingFrame.StreamId != 0)
            {
                throw new ProtocolError(ResetStatusCode.ProtocolError,
                                        "Incoming ping frame with stream id != 0");
            }

            if (pingFrame.PayloadLength != PingFrame.DefPayloadLength)
            {
                throw new ProtocolError(ResetStatusCode.FrameSizeError, "Ping payload size is not equal to 8");
            }

            if (pingFrame.IsAck)
            {
                _pingReceived.Set();
            }
            else
            {
                var pingAckFrame = new PingFrame(true, pingFrame.Payload.ToArray());
                _writeQueue.WriteFrame(pingAckFrame);
            }
        }
예제 #4
0
        public async Task SendPingFrame(string receiverAddress, int timeOut)
        {
            PingFrame pingFrame = new PingFrame(GetNextFrameId(), _address, receiverAddress, timeOut);

            try
            {
                await SubmitLoRaFrameAsync(pingFrame, timeOut).ConfigureAwait(false);
            }
            catch (AckNotReceivedTimeoutException)
            {
                //TimeOut are handle via Event
            }
        }
예제 #5
0
        private void OnKeepAlive()
        {
            if (_keepAliveLocker.Wait(0))
            {
                try
                {
                    if (!Active)
                    {
                        return;
                    }

                    if (!KeepAliveEnabled)
                    {
                        return;
                    }

                    if (_localActor.Type == _remoteActor.Type &&
                        _localActor.Name == _remoteActor.Name)
                    {
                        return;
                    }

                    if (_keepAliveTracker.ShouldSendKeepAlive())
                    {
                        var actorKeepAliveRequest       = new PingFrame();
                        var actorKeepAliveRequestBuffer = _channelConfiguration.FrameBuilder.EncodeFrame(actorKeepAliveRequest);

                        _log.DebugFormat("KeepAlive send request from local actor [{0}] to remote actor [{1}].", _localActor, _remoteActor);

                        _innerSession.Send(actorKeepAliveRequestBuffer);
                        StartKeepAliveTimeoutTimer();

                        _keepAliveTracker.ResetTimer();
                    }
                }
                catch (Exception ex)
                {
                    _log.Error(ex.Message, ex);
                    Close();
                }
                finally
                {
                    _keepAliveLocker.Release();
                }
            }
        }
예제 #6
0
        /// <summary>
        /// Pings session.
        /// </summary>
        /// <returns></returns>
        public TimeSpan Ping()
        {
            var pingFrame = new PingFrame(false);

            _writeQueue.WriteFrame(pingFrame);
            var now = DateTime.UtcNow;

            if (!_pingReceived.WaitOne(3000))
            {
                //Remote endpoint was not answer at time.
                Dispose();
            }
            _pingReceived.Reset();

            var newNow = DateTime.UtcNow;

            Http2Logger.LogDebug("Ping: " + (newNow - now).Milliseconds);
            return(newNow - now);
        }
예제 #7
0
        /// <summary>
        /// Process a ping frame request.
        /// </summary>
        /// <param name="httpContext">The current http context.</param>
        /// <param name="pingFrame">The ping frame.</param>
        private static void ProcessPingFrameRequest(Nequeo.Net.Http2.HttpContext httpContext, PingFrame pingFrame)
        {
            /*  PING frames are not associated with any individual stream.  If a PING
             *  frame is received with a stream identifier field value other than
             *  0x0, the recipient MUST respond with a connection error of type PROTOCOL_ERROR. */
            if (pingFrame.StreamId != 0)
            {
                throw new ProtocolError(ErrorCodeRegistry.Protocol_Error, "Incoming ping frame with stream id not equal to 0.");
            }

            // If the payload length is incorrect.
            if (pingFrame.PayloadLength != PingFrame.DefPayloadLength)
            {
                throw new ProtocolError(ErrorCodeRegistry.Frame_Size_Error, "Ping payload size is not equal to " + PingFrame.DefPayloadLength.ToString());
            }

            // Create the ping frame response.
            var frame = new PingFrame(true, pingFrame.Payload.ToArray());

            // Write the frame.
            httpContext.ResponseWrite(frame.Buffer);
        }
        public void Write_Protected_ResultBytesAreExpected()
        {
            //Arrange
            var expectedBytes       = GetProtectedMessageHex();
            var buffer              = new byte[PacketBuffer.MaxPacketSize];
            var destConnectionId    = PacketConnectionId.Empty;
            var packetNumbers       = GetPacketNumbersHex();
            var currentPacketNumber = PacketNumber.Parse(Utils.ParseHexString(packetNumbers.Current));
            var largestPacketNumber = PacketNumber.Parse(Utils.ParseHexString(packetNumbers.Largest));
            var secrets             = GetSecrets();
            var aead   = Cipher.TLS_CHACHA20_POLY1305_SHA256.CreateAead(Utils.ParseHexString(secrets.Iv), Utils.ParseHexString(secrets.Key));
            var cipher = Cipher.TLS_CHACHA20_POLY1305_SHA256.CreateCipher(Utils.ParseHexString(secrets.Hp));

            //Act
            var cursor = new MemoryCursor(buffer);

            using (ShortPacket.StartProtectedWriting(aead, cipher, cursor, destConnectionId, currentPacketNumber, largestPacketNumber))
            {
                PingFrame.Write(cursor);
            }

            //Assert
            Assert.Equal(expectedBytes, Utils.ToHexString(cursor.PeekStart().ToArray()), true);
        }
예제 #9
0
 private static void ProcessPingFrame(PingFrame pingFrame)
 {
     _timeoutTimer.Enabled = false;
     _pingTimer.Enabled    = true;
 }
예제 #10
0
        /// <summary>
        /// Dispatches the incoming frame.
        /// </summary>
        /// <param name="frame">The frame.</param>
        /// <exception cref="System.NotImplementedException"></exception>
        private void DispatchIncomingFrame(Frame frame)
        {
            Http2Stream stream = null;

            //Spec 03 tells that frame with continues flag MUST be followed by a frame with the same type
            //and the same stread id.
            if (_toBeContinuedHeaders != null)
            {
                if (_toBeContinuedFrame.FrameType != frame.FrameType ||
                    _toBeContinuedFrame.StreamId != frame.StreamId)
                {
                    //If not, we must close the session.
                    Dispose();
                    return;
                }
            }

            try
            {
                switch (frame.FrameType)
                {
                case FrameType.Headers:
                    Http2Logger.LogDebug("New headers with id = " + frame.StreamId);
                    var headersFrame      = (HeadersFrame)frame;
                    var serializedHeaders = new byte[headersFrame.CompressedHeaders.Count];

                    Buffer.BlockCopy(headersFrame.CompressedHeaders.Array,
                                     headersFrame.CompressedHeaders.Offset,
                                     serializedHeaders, 0, serializedHeaders.Length);

                    var decompressedHeaders = _comprProc.Decompress(serializedHeaders);
                    var headers             = new HeadersList(decompressedHeaders);

                    if (!headersFrame.IsEndHeaders)
                    {
                        _toBeContinuedHeaders = decompressedHeaders;
                        _toBeContinuedFrame   = headersFrame;
                        break;
                    }

                    if (_toBeContinuedHeaders != null)
                    {
                        headers.AddRange(_toBeContinuedHeaders);
                    }

                    headersFrame.Headers.AddRange(headers);
                    foreach (var header in headers)
                    {
                        Http2Logger.LogDebug("Stream {0} header: {1}={2}", frame.StreamId, header.Key, header.Value);
                    }

                    stream = GetStream(headersFrame.StreamId);

                    if (stream == null)
                    {
                        // new stream
                        if (ActiveStreams.GetOpenedStreamsBy(_remoteEnd) + 1 > OurMaxConcurrentStreams)
                        {
                            //Remote side tries to open more streams than allowed
                            Dispose();
                            return;
                        }

                        string path = headers.GetValue(":path");

                        if (path == null)
                        {
                            path = _handshakeHeaders.ContainsKey(":path") ? _handshakeHeaders[":path"] : @"\index.html";
                            headers.Add(new KeyValuePair <string, string>(":path", path));
                        }

                        stream = new Http2Stream(headers, headersFrame.StreamId,
                                                 _writeQueue, _flowControlManager,
                                                 _comprProc);

                        ActiveStreams[stream.Id] = stream;

                        stream.OnClose += (o, args) =>
                        {
                            if (!ActiveStreams.Remove(ActiveStreams[args.Id]))
                            {
                                throw new ArgumentException("Cant remove stream from ActiveStreams");
                            }
                        };

                        _toBeContinuedFrame   = null;
                        _toBeContinuedHeaders = null;
                    }

                    break;

                case FrameType.Priority:
                    var priorityFrame = (PriorityFrame)frame;
                    Http2Logger.LogDebug("Priority frame. StreamId: {0} Priority: {1}", priorityFrame.StreamId, priorityFrame.Priority);
                    stream = GetStream(priorityFrame.StreamId);
                    if (_usePriorities)
                    {
                        stream.Priority = priorityFrame.Priority;
                    }
                    break;

                case FrameType.RstStream:
                    var resetFrame = (RstStreamFrame)frame;
                    stream = GetStream(resetFrame.StreamId);

                    if (stream != null)
                    {
                        Http2Logger.LogDebug("RST frame with code " + resetFrame.StatusCode);
                        stream.Dispose();
                    }
                    break;

                case FrameType.Data:
                    var dataFrame = (DataFrame)frame;
                    Http2Logger.LogDebug("Data frame. StreamId:{0} Length:{1}", dataFrame.StreamId, dataFrame.FrameLength);
                    stream = GetStream(dataFrame.StreamId);

                    //Aggressive window update
                    if (stream.IsFlowControlEnabled)
                    {
                        stream.WriteWindowUpdate(2000000);
                    }
                    break;

                case FrameType.Ping:
                    var pingFrame = (PingFrame)frame;
                    Http2Logger.LogDebug("Ping frame with StreamId:{0} Payload:{1}", pingFrame.StreamId, pingFrame.Payload.Count);

                    if (pingFrame.FrameLength != PingFrame.PayloadLength)
                    {
                        throw new ProtocolError(ResetStatusCode.ProtocolError, "Ping payload size is not equal to 8");
                    }

                    if (pingFrame.IsPong)
                    {
                        _wasPingReceived = true;
                        _pingReceived.Set();
                    }
                    else
                    {
                        var pongFrame = new PingFrame(true, pingFrame.Payload.ToArray());
                        _writeQueue.WriteFrame(pongFrame);
                    }
                    break;

                case FrameType.Settings:
                    //Not first frame in the session.
                    //Client initiates connection and sends settings before request.
                    //It means that if server sent settings before it will not be a first frame,
                    //because client initiates connection.
                    if (_ourEnd == ConnectionEnd.Server && !_wasSettingsReceived && ActiveStreams.Count != 0)
                    {
                        Dispose();
                        return;
                    }

                    var settingFrame = (SettingsFrame)frame;
                    Http2Logger.LogDebug("Settings frame. Entry count: {0} StreamId: {1}", settingFrame.EntryCount, settingFrame.StreamId);
                    _wasSettingsReceived = true;
                    _settingsManager.ProcessSettings(settingFrame, this, _flowControlManager);
                    break;

                case FrameType.WindowUpdate:
                    if (_useFlowControl)
                    {
                        var windowFrame = (WindowUpdateFrame)frame;
                        Http2Logger.LogDebug("WindowUpdate frame. Delta: {0} StreamId: {1}", windowFrame.Delta, windowFrame.StreamId);
                        stream = GetStream(windowFrame.StreamId);

                        if (stream != null)
                        {
                            stream.UpdateWindowSize(windowFrame.Delta);
                            stream.PumpUnshippedFrames();
                        }
                    }
                    break;

                case FrameType.GoAway:
                    _goAwayReceived = true;
                    Http2Logger.LogDebug("GoAway frame received");
                    Dispose();
                    break;

                default:
                    throw new NotImplementedException(frame.FrameType.ToString());
                }

                if (stream != null && frame is IEndStreamFrame && ((IEndStreamFrame)frame).IsEndStream)
                {
                    //Tell the stream that it was the last frame
                    Http2Logger.LogDebug("Final frame received for stream with id = " + stream.Id);
                    stream.EndStreamReceived = true;
                }

                if (stream != null && OnFrameReceived != null)
                {
                    OnFrameReceived(this, new FrameReceivedEventArgs(stream, frame));
                }
            }

            //Frame came for already closed stream. Ignore it.
            //Spec:
            //An endpoint that sends RST_STREAM MUST ignore
            //frames that it receives on closed streams if it sends RST_STREAM.
            //
            //An endpoint MUST NOT send frames on a closed stream.  An endpoint
            //that receives a frame after receiving a RST_STREAM or a frame
            //containing a END_STREAM flag on that stream MUST treat that as a
            //stream error (Section 5.4.2) of type PROTOCOL_ERROR.
            catch (Http2StreamNotFoundException)
            {
                if (stream != null)
                {
                    stream.WriteRst(ResetStatusCode.ProtocolError);
                }
                else
                {
                    //GoAway?
                }
            }
            catch (CompressionError ex)
            {
                //The endpoint is unable to maintain the compression context for the connection.
                Http2Logger.LogError("Compression error occured: " + ex.Message);
                Close(ResetStatusCode.CompressionError);
            }
            catch (ProtocolError pEx)
            {
                Http2Logger.LogError("Protocol error occured: " + pEx.Message);
                Close(pEx.Code);
            }
        }
예제 #11
0
        public Frame GetFrame()
        {
            Frame result;
            var   frameType = _array.PeekByte();

            switch (frameType)
            {
            case 0x00:
                result = new PaddingFrame();
                break;

            case 0x01:
                result = new PingFrame();
                break;

            case 0x02:
                result = new AckFrame();
                break;

            case 0x03:
                result = new AckFrame();
                break;

            case 0x04:
                result = new ResetStreamFrame();
                break;

            case 0x05:
                result = new StopSendingFrame();
                break;

            case 0x06:
                result = new CryptoFrame();
                break;

            case 0x07:
                result = new NewTokenFrame();
                break;

            case 0x08:
                result = new StreamFrame();
                break;

            case 0x09:
                result = new StreamFrame();
                break;

            case 0x0a:
                result = new StreamFrame();
                break;

            case 0x0b:
                result = new StreamFrame();
                break;

            case 0x0c:
                result = new StreamFrame();
                break;

            case 0x0d:
                result = new StreamFrame();
                break;

            case 0x0e:
                result = new StreamFrame();
                break;

            case 0x0f:
                result = new StreamFrame();
                break;

            case 0x10:
                result = new MaxDataFrame();
                break;

            case 0x11:
                result = new MaxStreamDataFrame();
                break;

            case 0x12:
                result = new MaxStreamsFrame();
                break;

            case 0x13:
                result = new MaxStreamsFrame();
                break;

            case 0x14:
                result = new DataBlockedFrame();
                break;

            case 0x15:
                result = new StreamDataBlockedFrame();
                break;

            case 0x16:
                result = new StreamsBlockedFrame();
                break;

            case 0x17:
                result = new StreamsBlockedFrame();
                break;

            case 0x18:
                result = new NewConnectionIdFrame();
                break;

            case 0x19:
                result = new RetireConnectionIdFrame();
                break;

            case 0x1a:
                result = new PathChallengeFrame();
                break;

            case 0x1b:
                result = new PathResponseFrame();
                break;

            case 0x1c:
                result = new ConnectionCloseFrame();
                break;

            case 0x1d:
                result = new ConnectionCloseFrame();
                break;

            default:
                result = null;
                break;
            }

            if (result != null)
            {
                result.Decode(_array);
            }

            return(result);
        }