internal void OnPingAckReceived(long payload, Http2Connection connection) { if (_state != State.PingSent && _state != State.TerminatingMayReceivePingAck) { if (NetEventSource.Log.IsEnabled()) { connection.Trace($"[FlowControl] Unexpected PING ACK in state {_state}"); } ThrowProtocolError(); } if (_state == State.TerminatingMayReceivePingAck) { _state = State.Disabled; return; } // RTT PINGs always carry negative payload, positive values indicate a response to KeepAlive PING. Debug.Assert(payload < 0); if (_pingCounter != payload) { if (NetEventSource.Log.IsEnabled()) { connection.Trace($"[FlowControl] Unexpected RTT PING ACK payload {payload}, should be {_pingCounter}."); } ThrowProtocolError(); } RefreshRtt(connection); _state = State.Waiting; }
internal void OnDataOrHeadersReceived(Http2Connection connection) { if (_state != State.Waiting) { return; } long now = Stopwatch.GetTimestamp(); bool initial = _initialBurst > 0; if (initial || now - _pingSentTimestamp > PingIntervalInTicks) { if (initial) { _initialBurst--; } // Send a PING _pingCounter--; if (NetEventSource.Log.IsEnabled()) { connection.Trace($"[FlowControl] Sending RTT PING with payload {_pingCounter}"); } connection.LogExceptions(connection.SendPingAsync(_pingCounter, isAck: false)); _pingSentTimestamp = now; _state = State.PingSent; } }
private void RefreshRtt(Http2Connection connection) { long prevRtt = _minRtt == 0 ? long.MaxValue : _minRtt; TimeSpan currentRtt = Stopwatch.GetElapsedTime(_pingSentTimestamp); long minRtt = Math.Min(prevRtt, currentRtt.Ticks); Interlocked.Exchange(ref _minRtt, minRtt); // MinRtt is being queried from another thread if (NetEventSource.Log.IsEnabled()) { connection.Trace($"[FlowControl] Updated MinRtt: {MinRtt.TotalMilliseconds} ms"); } }