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); }
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); } }
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 } }
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(); } } }
/// <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); }
/// <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); }
private static void ProcessPingFrame(PingFrame pingFrame) { _timeoutTimer.Enabled = false; _pingTimer.Enabled = true; }
/// <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); } }
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); }