diff --git a/ackhandler/sent_packet_handler.go b/ackhandler/sent_packet_handler.go index 236f08f15..116022dc4 100644 --- a/ackhandler/sent_packet_handler.go +++ b/ackhandler/sent_packet_handler.go @@ -42,6 +42,8 @@ type sentPacketHandler struct { rttStats *congestion.RTTStats congestion congestion.SendAlgorithm + + consecutiveRTOCount uint32 } // NewSentPacketHandler creates a new sentPacketHandler @@ -227,6 +229,11 @@ func (h *sentPacketHandler) ReceivedAck(ackFrame *frames.AckFrame, withPacketNum } } + if rttUpdated { + // Reset counter if a new packet was acked + h.consecutiveRTOCount = 0 + } + h.garbageCollectSkippedPackets() h.stopWaitingManager.ReceivedAck(ackFrame) @@ -300,6 +307,7 @@ func (h *sentPacketHandler) MaybeQueueRTOs() { h.queuePacketForRetransmission(el) // Reset the RTO timer here, since it's not clear that this packet contained any retransmittable frames h.lastSentPacketTime = time.Now() + h.consecutiveRTOCount++ return } } @@ -309,7 +317,10 @@ func (h *sentPacketHandler) getRTO() time.Duration { if rto == 0 { rto = protocol.DefaultRetransmissionTime } - return utils.MaxDuration(rto, protocol.MinRetransmissionTime) + rto = utils.MaxDuration(rto, protocol.MinRetransmissionTime) + // Exponential backoff + rto *= 1 << h.consecutiveRTOCount + return utils.MinDuration(rto, protocol.MaxRetransmissionTime) } func (h *sentPacketHandler) TimeOfFirstRTO() time.Time { diff --git a/ackhandler/sent_packet_handler_test.go b/ackhandler/sent_packet_handler_test.go index f507531a5..86058f0a6 100644 --- a/ackhandler/sent_packet_handler_test.go +++ b/ackhandler/sent_packet_handler_test.go @@ -786,6 +786,21 @@ var _ = Describe("SentPacketHandler", func() { handler.rttStats.UpdateRTT(rtt, 0, time.Now()) Expect(handler.getRTO()).To(Equal(protocol.MinRetransmissionTime)) }) + + It("limits RTO max", func() { + rtt := time.Hour + handler.rttStats.UpdateRTT(rtt, 0, time.Now()) + Expect(handler.getRTO()).To(Equal(protocol.MaxRetransmissionTime)) + }) + + It("implements exponential backoff", func() { + handler.consecutiveRTOCount = 0 + Expect(handler.getRTO()).To(Equal(protocol.DefaultRetransmissionTime)) + handler.consecutiveRTOCount = 1 + Expect(handler.getRTO()).To(Equal(2 * protocol.DefaultRetransmissionTime)) + handler.consecutiveRTOCount = 2 + Expect(handler.getRTO()).To(Equal(4 * protocol.DefaultRetransmissionTime)) + }) }) Context("RTO retransmission", func() { diff --git a/protocol/protocol.go b/protocol/protocol.go index bd912452d..aae2e0a85 100644 --- a/protocol/protocol.go +++ b/protocol/protocol.go @@ -59,5 +59,8 @@ const DefaultRetransmissionTime = 500 * time.Millisecond // MinRetransmissionTime is the minimum RTO time const MinRetransmissionTime = 200 * time.Millisecond +// MaxRetransmissionTime is the maximum RTO time +const MaxRetransmissionTime = 60 * time.Second + // ClientHelloMinimumSize is the minimum size the server expects an inchoate CHLO to have. const ClientHelloMinimumSize = 1024