blob: 4942f8cca18dfec49afd0497c49452175ddf4b13 [file] [log] [blame] [edit]
// Copyright 2023 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build go1.21
package quic
import (
"time"
)
type rttState struct {
minRTT time.Duration
latestRTT time.Duration
smoothedRTT time.Duration
rttvar time.Duration // RTT variation
firstSampleTime time.Time // time of first RTT sample
}
func (r *rttState) init() {
r.minRTT = -1 // -1 indicates the first sample has not been taken yet
// "[...] the initial RTT SHOULD be set to 333 milliseconds."
// https://www.rfc-editor.org/rfc/rfc9002.html#section-6.2.2-1
const initialRTT = 333 * time.Millisecond
// https://www.rfc-editor.org/rfc/rfc9002.html#section-5.3-12
r.smoothedRTT = initialRTT
r.rttvar = initialRTT / 2
}
func (r *rttState) establishPersistentCongestion() {
// "Endpoints SHOULD set the min_rtt to the newest RTT sample
// after persistent congestion is established."
// https://www.rfc-editor.org/rfc/rfc9002#section-5.2-5
r.minRTT = r.latestRTT
}
// updateRTTSample is called when we generate a new RTT sample.
// https://www.rfc-editor.org/rfc/rfc9002.html#section-5
func (r *rttState) updateSample(now time.Time, handshakeConfirmed bool, spaceID numberSpace, latestRTT, ackDelay, maxAckDelay time.Duration) {
r.latestRTT = latestRTT
if r.minRTT < 0 {
// First RTT sample.
// "min_rtt MUST be set to the latest_rtt on the first RTT sample."
// https://www.rfc-editor.org/rfc/rfc9002.html#section-5.2-2
r.minRTT = latestRTT
// https://www.rfc-editor.org/rfc/rfc9002.html#section-5.3-14
r.smoothedRTT = latestRTT
r.rttvar = latestRTT / 2
r.firstSampleTime = now
return
}
// "min_rtt MUST be set to the lesser of min_rtt and latest_rtt [...]
// on all other samples."
// https://www.rfc-editor.org/rfc/rfc9002.html#section-5.2-2
r.minRTT = min(r.minRTT, latestRTT)
// https://www.rfc-editor.org/rfc/rfc9002.html#section-5.3-16
if handshakeConfirmed {
ackDelay = min(ackDelay, maxAckDelay)
}
adjustedRTT := latestRTT - ackDelay
if adjustedRTT < r.minRTT {
adjustedRTT = latestRTT
}
rttvarSample := abs(r.smoothedRTT - adjustedRTT)
r.rttvar = (3*r.rttvar + rttvarSample) / 4
r.smoothedRTT = ((7 * r.smoothedRTT) + adjustedRTT) / 8
}