diff --git a/internal/utils/rtt_stats.go b/internal/utils/rtt_stats.go index 527539e1..2cd9a191 100644 --- a/internal/utils/rtt_stats.go +++ b/internal/utils/rtt_stats.go @@ -103,8 +103,12 @@ func (r *RTTStats) SetMaxAckDelay(mad time.Duration) { // SetInitialRTT sets the initial RTT. // It is used during the 0-RTT handshake when restoring the RTT stats from the session state. func (r *RTTStats) SetInitialRTT(t time.Duration) { + // On the server side, by the time we get to process the session ticket, + // we might already have obtained an RTT measurement. + // This can happen if we received the ClientHello in multiple pieces, and one of those pieces was lost. + // Discard the restored value. A fresh measurement is always better. if r.hasMeasurement { - panic("initial RTT set after first measurement") + return } r.smoothedRTT = t r.latestRTT = t diff --git a/internal/utils/rtt_stats_test.go b/internal/utils/rtt_stats_test.go index 29892c6f..eae31926 100644 --- a/internal/utils/rtt_stats_test.go +++ b/internal/utils/rtt_stats_test.go @@ -154,4 +154,14 @@ var _ = Describe("RTT stats", func() { Expect(rttStats.SmoothedRTT()).To(Equal(200 * time.Millisecond)) Expect(rttStats.MeanDeviation()).To(Equal(100 * time.Millisecond)) }) + + It("doesn't restore the RTT if we already have a measurement", func() { + const rtt = 10 * time.Millisecond + rttStats.UpdateRTT(rtt, 0, time.Now()) + Expect(rttStats.LatestRTT()).To(Equal(rtt)) + Expect(rttStats.SmoothedRTT()).To(Equal(rtt)) + rttStats.SetInitialRTT(time.Minute) + Expect(rttStats.LatestRTT()).To(Equal(rtt)) + Expect(rttStats.SmoothedRTT()).To(Equal(rtt)) + }) })