mirror of
https://github.com/refraction-networking/uquic.git
synced 2025-04-04 20:57:36 +03:00
When all outstanding are acknowledged, the alarm is canceled in updateLossDetectionAlarm. This doesn't reset the timer in the session though. When OnAlarm is called, we therefore need to make sure that there are actually packets outstanding.
1083 lines
49 KiB
Go
1083 lines
49 KiB
Go
package ackhandler
|
|
|
|
import (
|
|
"time"
|
|
|
|
"github.com/golang/mock/gomock"
|
|
"github.com/lucas-clemente/quic-go/internal/congestion"
|
|
"github.com/lucas-clemente/quic-go/internal/mocks"
|
|
"github.com/lucas-clemente/quic-go/internal/protocol"
|
|
"github.com/lucas-clemente/quic-go/internal/utils"
|
|
"github.com/lucas-clemente/quic-go/internal/wire"
|
|
. "github.com/onsi/ginkgo"
|
|
. "github.com/onsi/gomega"
|
|
)
|
|
|
|
func retransmittablePacket(p *Packet) *Packet {
|
|
if p.EncryptionLevel == protocol.EncryptionUnspecified {
|
|
p.EncryptionLevel = protocol.EncryptionForwardSecure
|
|
}
|
|
if p.Length == 0 {
|
|
p.Length = 1
|
|
}
|
|
if p.SendTime.IsZero() {
|
|
p.SendTime = time.Now()
|
|
}
|
|
p.Frames = []wire.Frame{&wire.PingFrame{}}
|
|
return p
|
|
}
|
|
|
|
func nonRetransmittablePacket(p *Packet) *Packet {
|
|
p = retransmittablePacket(p)
|
|
p.Frames = []wire.Frame{
|
|
&wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 1, Largest: 1}}},
|
|
}
|
|
return p
|
|
}
|
|
|
|
func handshakePacket(p *Packet) *Packet {
|
|
p = retransmittablePacket(p)
|
|
p.EncryptionLevel = protocol.EncryptionUnencrypted
|
|
return p
|
|
}
|
|
|
|
var _ = Describe("SentPacketHandler", func() {
|
|
var (
|
|
handler *sentPacketHandler
|
|
streamFrame wire.StreamFrame
|
|
)
|
|
|
|
BeforeEach(func() {
|
|
rttStats := &congestion.RTTStats{}
|
|
handler = NewSentPacketHandler(rttStats, utils.DefaultLogger, protocol.VersionWhatever).(*sentPacketHandler)
|
|
handler.SetHandshakeComplete()
|
|
streamFrame = wire.StreamFrame{
|
|
StreamID: 5,
|
|
Data: []byte{0x13, 0x37},
|
|
}
|
|
})
|
|
|
|
getPacket := func(pn protocol.PacketNumber) *Packet {
|
|
if el, ok := handler.packetHistory.packetMap[pn]; ok {
|
|
return &el.Value
|
|
}
|
|
return nil
|
|
}
|
|
|
|
losePacket := func(pn protocol.PacketNumber) {
|
|
p := getPacket(pn)
|
|
ExpectWithOffset(1, p).ToNot(BeNil())
|
|
handler.queuePacketForRetransmission(p)
|
|
if p.includedInBytesInFlight {
|
|
p.includedInBytesInFlight = false
|
|
handler.bytesInFlight -= p.Length
|
|
}
|
|
r := handler.DequeuePacketForRetransmission()
|
|
ExpectWithOffset(1, r).ToNot(BeNil())
|
|
ExpectWithOffset(1, r.PacketNumber).To(Equal(pn))
|
|
}
|
|
|
|
expectInPacketHistory := func(expected []protocol.PacketNumber) {
|
|
ExpectWithOffset(1, handler.packetHistory.Len()).To(Equal(len(expected)))
|
|
for _, p := range expected {
|
|
ExpectWithOffset(1, handler.packetHistory.packetMap).To(HaveKey(p))
|
|
}
|
|
}
|
|
|
|
updateRTT := func(rtt time.Duration) {
|
|
handler.rttStats.UpdateRTT(rtt, 0, time.Now())
|
|
ExpectWithOffset(1, handler.rttStats.SmoothedRTT()).To(Equal(rtt))
|
|
}
|
|
|
|
It("determines the packet number length", func() {
|
|
handler.largestAcked = 0x1337
|
|
Expect(handler.GetPacketNumberLen(0x1338)).To(Equal(protocol.PacketNumberLen2))
|
|
Expect(handler.GetPacketNumberLen(0xfffffff)).To(Equal(protocol.PacketNumberLen4))
|
|
})
|
|
|
|
Context("registering sent packets", func() {
|
|
It("accepts two consecutive packets", func() {
|
|
handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 1}))
|
|
handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 2}))
|
|
Expect(handler.lastSentPacketNumber).To(Equal(protocol.PacketNumber(2)))
|
|
expectInPacketHistory([]protocol.PacketNumber{1, 2})
|
|
Expect(handler.bytesInFlight).To(Equal(protocol.ByteCount(2)))
|
|
Expect(handler.skippedPackets).To(BeEmpty())
|
|
})
|
|
|
|
It("accepts packet number 0", func() {
|
|
handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 0}))
|
|
Expect(handler.lastSentPacketNumber).To(BeZero())
|
|
handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 1}))
|
|
Expect(handler.lastSentPacketNumber).To(Equal(protocol.PacketNumber(1)))
|
|
expectInPacketHistory([]protocol.PacketNumber{0, 1})
|
|
Expect(handler.bytesInFlight).To(Equal(protocol.ByteCount(2)))
|
|
Expect(handler.skippedPackets).To(BeEmpty())
|
|
})
|
|
|
|
It("stores the sent time", func() {
|
|
sendTime := time.Now().Add(-time.Minute)
|
|
handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 1, SendTime: sendTime}))
|
|
Expect(handler.lastSentRetransmittablePacketTime).To(Equal(sendTime))
|
|
})
|
|
|
|
It("stores the sent time of handshake packets", func() {
|
|
sendTime := time.Now().Add(-time.Minute)
|
|
handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 1, SendTime: sendTime, EncryptionLevel: protocol.EncryptionUnencrypted}))
|
|
handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 2, SendTime: sendTime.Add(time.Hour), EncryptionLevel: protocol.EncryptionForwardSecure}))
|
|
Expect(handler.lastSentHandshakePacketTime).To(Equal(sendTime))
|
|
})
|
|
|
|
It("does not store non-retransmittable packets", func() {
|
|
handler.SentPacket(nonRetransmittablePacket(&Packet{PacketNumber: 1}))
|
|
Expect(handler.packetHistory.Len()).To(BeZero())
|
|
Expect(handler.lastSentRetransmittablePacketTime).To(BeZero())
|
|
Expect(handler.bytesInFlight).To(BeZero())
|
|
})
|
|
|
|
Context("skipped packet numbers", func() {
|
|
It("works with non-consecutive packet numbers", func() {
|
|
handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 1}))
|
|
handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 3}))
|
|
Expect(handler.lastSentPacketNumber).To(Equal(protocol.PacketNumber(3)))
|
|
expectInPacketHistory([]protocol.PacketNumber{1, 3})
|
|
Expect(handler.skippedPackets).To(Equal([]protocol.PacketNumber{2}))
|
|
})
|
|
|
|
It("works with non-retransmittable packets", func() {
|
|
handler.SentPacket(nonRetransmittablePacket(&Packet{PacketNumber: 1}))
|
|
handler.SentPacket(nonRetransmittablePacket(&Packet{PacketNumber: 3}))
|
|
Expect(handler.skippedPackets).To(Equal([]protocol.PacketNumber{2}))
|
|
})
|
|
|
|
It("recognizes multiple skipped packets", func() {
|
|
handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 1}))
|
|
handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 3}))
|
|
handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 5}))
|
|
Expect(handler.skippedPackets).To(Equal([]protocol.PacketNumber{2, 4}))
|
|
})
|
|
|
|
It("recognizes multiple consecutive skipped packets", func() {
|
|
handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 1}))
|
|
handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 4}))
|
|
Expect(handler.skippedPackets).To(Equal([]protocol.PacketNumber{2, 3}))
|
|
})
|
|
|
|
It("limits the lengths of the skipped packet slice", func() {
|
|
for i := protocol.PacketNumber(0); i < protocol.MaxTrackedSkippedPackets+5; i++ {
|
|
handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 2*i + 1}))
|
|
}
|
|
Expect(handler.skippedPackets).To(HaveLen(protocol.MaxUndecryptablePackets))
|
|
Expect(handler.skippedPackets[0]).To(Equal(protocol.PacketNumber(10)))
|
|
Expect(handler.skippedPackets[protocol.MaxTrackedSkippedPackets-1]).To(Equal(protocol.PacketNumber(10 + 2*(protocol.MaxTrackedSkippedPackets-1))))
|
|
})
|
|
|
|
Context("garbage collection", func() {
|
|
It("keeps all packet numbers above the LargestAcked", func() {
|
|
handler.skippedPackets = []protocol.PacketNumber{2, 5, 8, 10}
|
|
handler.largestAcked = 1
|
|
handler.garbageCollectSkippedPackets()
|
|
Expect(handler.skippedPackets).To(Equal([]protocol.PacketNumber{2, 5, 8, 10}))
|
|
})
|
|
|
|
It("doesn't keep packet numbers below the LargestAcked", func() {
|
|
handler.skippedPackets = []protocol.PacketNumber{1, 5, 8, 10}
|
|
handler.largestAcked = 5
|
|
handler.garbageCollectSkippedPackets()
|
|
Expect(handler.skippedPackets).To(Equal([]protocol.PacketNumber{8, 10}))
|
|
})
|
|
|
|
It("deletes all packet numbers if LargestAcked is sufficiently high", func() {
|
|
handler.skippedPackets = []protocol.PacketNumber{1, 5, 10}
|
|
handler.largestAcked = 15
|
|
handler.garbageCollectSkippedPackets()
|
|
Expect(handler.skippedPackets).To(BeEmpty())
|
|
})
|
|
})
|
|
|
|
Context("ACK handling", func() {
|
|
BeforeEach(func() {
|
|
handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 10}))
|
|
handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 12}))
|
|
})
|
|
|
|
It("rejects ACKs for skipped packets", func() {
|
|
ack := &wire.AckFrame{
|
|
AckRanges: []wire.AckRange{{Smallest: 10, Largest: 12}},
|
|
}
|
|
err := handler.ReceivedAck(ack, 1337, protocol.EncryptionForwardSecure, time.Now())
|
|
Expect(err).To(MatchError("InvalidAckData: Received an ACK for a skipped packet number"))
|
|
})
|
|
|
|
It("accepts an ACK that correctly nacks a skipped packet", func() {
|
|
ack := &wire.AckFrame{
|
|
AckRanges: []wire.AckRange{
|
|
{Smallest: 12, Largest: 12},
|
|
{Smallest: 10, Largest: 10},
|
|
},
|
|
}
|
|
err := handler.ReceivedAck(ack, 1337, protocol.EncryptionForwardSecure, time.Now())
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(handler.largestAcked).ToNot(BeZero())
|
|
})
|
|
})
|
|
})
|
|
})
|
|
|
|
Context("ACK processing", func() {
|
|
BeforeEach(func() {
|
|
for i := protocol.PacketNumber(0); i < 10; i++ {
|
|
handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: i}))
|
|
}
|
|
// Increase RTT, because the tests would be flaky otherwise
|
|
updateRTT(time.Hour)
|
|
Expect(handler.bytesInFlight).To(Equal(protocol.ByteCount(10)))
|
|
})
|
|
|
|
Context("ACK validation", func() {
|
|
It("accepts ACKs sent in packet 0", func() {
|
|
ack := &wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 0, Largest: 5}}}
|
|
err := handler.ReceivedAck(ack, 0, protocol.EncryptionForwardSecure, time.Now())
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(handler.largestAcked).To(Equal(protocol.PacketNumber(5)))
|
|
})
|
|
|
|
It("rejects duplicate ACKs", func() {
|
|
ack1 := &wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 0, Largest: 3}}}
|
|
ack2 := &wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 0, Largest: 4}}}
|
|
err := handler.ReceivedAck(ack1, 1337, protocol.EncryptionForwardSecure, time.Now())
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(handler.largestAcked).To(Equal(protocol.PacketNumber(3)))
|
|
// this wouldn't happen in practice
|
|
// for testing purposes, we pretend send a different ACK frame in a duplicated packet, to be able to verify that it actually doesn't get processed
|
|
err = handler.ReceivedAck(ack2, 1337, protocol.EncryptionForwardSecure, time.Now())
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(handler.largestAcked).To(Equal(protocol.PacketNumber(3)))
|
|
})
|
|
|
|
It("rejects out of order ACKs", func() {
|
|
// acks packets 0, 1, 2, 3
|
|
ack1 := &wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 0, Largest: 3}}}
|
|
ack2 := &wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 0, Largest: 4}}}
|
|
err := handler.ReceivedAck(ack1, 1337, protocol.EncryptionForwardSecure, time.Now())
|
|
Expect(err).ToNot(HaveOccurred())
|
|
// this wouldn't happen in practive
|
|
// a receiver wouldn't send an ACK for a lower largest acked in a packet sent later
|
|
err = handler.ReceivedAck(ack2, 1337-1, protocol.EncryptionForwardSecure, time.Now())
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(handler.largestAcked).To(Equal(protocol.PacketNumber(3)))
|
|
})
|
|
|
|
It("rejects ACKs with a too high LargestAcked packet number", func() {
|
|
ack := &wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 0, Largest: 9999}}}
|
|
err := handler.ReceivedAck(ack, 1, protocol.EncryptionForwardSecure, time.Now())
|
|
Expect(err).To(MatchError("InvalidAckData: Received ACK for an unsent package"))
|
|
Expect(handler.bytesInFlight).To(Equal(protocol.ByteCount(10)))
|
|
})
|
|
|
|
It("ignores repeated ACKs", func() {
|
|
ack := &wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 1, Largest: 3}}}
|
|
err := handler.ReceivedAck(ack, 1337, protocol.EncryptionForwardSecure, time.Now())
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(handler.bytesInFlight).To(Equal(protocol.ByteCount(7)))
|
|
err = handler.ReceivedAck(ack, 1337+1, protocol.EncryptionForwardSecure, time.Now())
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(handler.largestAcked).To(Equal(protocol.PacketNumber(3)))
|
|
Expect(handler.bytesInFlight).To(Equal(protocol.ByteCount(7)))
|
|
})
|
|
})
|
|
|
|
Context("acks and nacks the right packets", func() {
|
|
It("adjusts the LargestAcked, and adjusts the bytes in flight", func() {
|
|
ack := &wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 0, Largest: 5}}}
|
|
err := handler.ReceivedAck(ack, 1, protocol.EncryptionForwardSecure, time.Now())
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(handler.largestAcked).To(Equal(protocol.PacketNumber(5)))
|
|
expectInPacketHistory([]protocol.PacketNumber{6, 7, 8, 9})
|
|
Expect(handler.bytesInFlight).To(Equal(protocol.ByteCount(4)))
|
|
})
|
|
|
|
It("acks packet 0", func() {
|
|
ack := &wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 0, Largest: 0}}}
|
|
err := handler.ReceivedAck(ack, 1, protocol.EncryptionForwardSecure, time.Now())
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(getPacket(0)).To(BeNil())
|
|
expectInPacketHistory([]protocol.PacketNumber{1, 2, 3, 4, 5, 6, 7, 8, 9})
|
|
})
|
|
|
|
It("handles an ACK frame with one missing packet range", func() {
|
|
ack := &wire.AckFrame{ // lose 4 and 5
|
|
AckRanges: []wire.AckRange{
|
|
{Smallest: 6, Largest: 9},
|
|
{Smallest: 1, Largest: 3},
|
|
},
|
|
}
|
|
err := handler.ReceivedAck(ack, 1, protocol.EncryptionForwardSecure, time.Now())
|
|
Expect(err).ToNot(HaveOccurred())
|
|
expectInPacketHistory([]protocol.PacketNumber{0, 4, 5})
|
|
})
|
|
|
|
It("does not ack packets below the LowestAcked", func() {
|
|
ack := &wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 3, Largest: 8}}}
|
|
err := handler.ReceivedAck(ack, 1, protocol.EncryptionForwardSecure, time.Now())
|
|
Expect(err).ToNot(HaveOccurred())
|
|
expectInPacketHistory([]protocol.PacketNumber{0, 1, 2, 9})
|
|
})
|
|
|
|
It("handles an ACK with multiple missing packet ranges", func() {
|
|
ack := &wire.AckFrame{ // packets 2, 4 and 5, and 8 were lost
|
|
AckRanges: []wire.AckRange{
|
|
{Smallest: 9, Largest: 9},
|
|
{Smallest: 6, Largest: 7},
|
|
{Smallest: 3, Largest: 3},
|
|
{Smallest: 1, Largest: 1},
|
|
},
|
|
}
|
|
err := handler.ReceivedAck(ack, 1, protocol.EncryptionForwardSecure, time.Now())
|
|
Expect(err).ToNot(HaveOccurred())
|
|
expectInPacketHistory([]protocol.PacketNumber{0, 2, 4, 5, 8})
|
|
})
|
|
|
|
It("processes an ACK frame that would be sent after a late arrival of a packet", func() {
|
|
ack1 := &wire.AckFrame{ // 3 lost
|
|
AckRanges: []wire.AckRange{
|
|
{Smallest: 4, Largest: 6},
|
|
{Smallest: 1, Largest: 2},
|
|
},
|
|
}
|
|
err := handler.ReceivedAck(ack1, 1, protocol.EncryptionForwardSecure, time.Now())
|
|
Expect(err).ToNot(HaveOccurred())
|
|
expectInPacketHistory([]protocol.PacketNumber{0, 3, 7, 8, 9})
|
|
Expect(handler.bytesInFlight).To(Equal(protocol.ByteCount(5)))
|
|
ack2 := &wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 1, Largest: 6}}} // now ack 3
|
|
err = handler.ReceivedAck(ack2, 2, protocol.EncryptionForwardSecure, time.Now())
|
|
Expect(err).ToNot(HaveOccurred())
|
|
expectInPacketHistory([]protocol.PacketNumber{0, 7, 8, 9})
|
|
Expect(handler.bytesInFlight).To(Equal(protocol.ByteCount(4)))
|
|
})
|
|
|
|
It("processes an ACK frame that would be sent after a late arrival of a packet and another packet", func() {
|
|
ack1 := &wire.AckFrame{
|
|
AckRanges: []wire.AckRange{
|
|
{Smallest: 4, Largest: 6},
|
|
{Smallest: 0, Largest: 2},
|
|
},
|
|
}
|
|
err := handler.ReceivedAck(ack1, 1, protocol.EncryptionForwardSecure, time.Now())
|
|
Expect(err).ToNot(HaveOccurred())
|
|
expectInPacketHistory([]protocol.PacketNumber{3, 7, 8, 9})
|
|
Expect(handler.bytesInFlight).To(Equal(protocol.ByteCount(4)))
|
|
ack2 := &wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 1, Largest: 7}}}
|
|
err = handler.ReceivedAck(ack2, 2, protocol.EncryptionForwardSecure, time.Now())
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(handler.bytesInFlight).To(Equal(protocol.ByteCount(2)))
|
|
expectInPacketHistory([]protocol.PacketNumber{8, 9})
|
|
})
|
|
|
|
It("processes an ACK that contains old ACK ranges", func() {
|
|
ack1 := &wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 1, Largest: 6}}}
|
|
err := handler.ReceivedAck(ack1, 1, protocol.EncryptionForwardSecure, time.Now())
|
|
Expect(err).ToNot(HaveOccurred())
|
|
expectInPacketHistory([]protocol.PacketNumber{0, 7, 8, 9})
|
|
Expect(handler.bytesInFlight).To(Equal(protocol.ByteCount(4)))
|
|
ack2 := &wire.AckFrame{
|
|
AckRanges: []wire.AckRange{
|
|
{Smallest: 8, Largest: 8},
|
|
{Smallest: 3, Largest: 3},
|
|
{Smallest: 1, Largest: 1},
|
|
},
|
|
}
|
|
err = handler.ReceivedAck(ack2, 2, protocol.EncryptionForwardSecure, time.Now())
|
|
Expect(err).ToNot(HaveOccurred())
|
|
expectInPacketHistory([]protocol.PacketNumber{0, 7, 9})
|
|
Expect(handler.bytesInFlight).To(Equal(protocol.ByteCount(3)))
|
|
})
|
|
})
|
|
|
|
Context("calculating RTT", func() {
|
|
It("computes the RTT", func() {
|
|
now := time.Now()
|
|
// First, fake the sent times of the first, second and last packet
|
|
getPacket(1).SendTime = now.Add(-10 * time.Minute)
|
|
getPacket(2).SendTime = now.Add(-5 * time.Minute)
|
|
getPacket(6).SendTime = now.Add(-1 * time.Minute)
|
|
// Now, check that the proper times are used when calculating the deltas
|
|
ack := &wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 1, Largest: 1}}}
|
|
err := handler.ReceivedAck(ack, 1, protocol.EncryptionForwardSecure, time.Now())
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Expect(handler.rttStats.LatestRTT()).To(BeNumerically("~", 10*time.Minute, 1*time.Second))
|
|
ack = &wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 1, Largest: 2}}}
|
|
err = handler.ReceivedAck(ack, 2, protocol.EncryptionForwardSecure, time.Now())
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Expect(handler.rttStats.LatestRTT()).To(BeNumerically("~", 5*time.Minute, 1*time.Second))
|
|
ack = &wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 1, Largest: 6}}}
|
|
err = handler.ReceivedAck(ack, 3, protocol.EncryptionForwardSecure, time.Now())
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Expect(handler.rttStats.LatestRTT()).To(BeNumerically("~", 1*time.Minute, 1*time.Second))
|
|
})
|
|
|
|
It("uses the DelayTime in the ACK frame", func() {
|
|
now := time.Now()
|
|
// make sure the rttStats have a min RTT, so that the delay is used
|
|
handler.rttStats.UpdateRTT(5*time.Minute, 0, time.Now())
|
|
getPacket(1).SendTime = now.Add(-10 * time.Minute)
|
|
ack := &wire.AckFrame{
|
|
AckRanges: []wire.AckRange{{Smallest: 1, Largest: 1}},
|
|
DelayTime: 5 * time.Minute,
|
|
}
|
|
err := handler.ReceivedAck(ack, 1, protocol.EncryptionForwardSecure, time.Now())
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Expect(handler.rttStats.LatestRTT()).To(BeNumerically("~", 5*time.Minute, 1*time.Second))
|
|
})
|
|
})
|
|
|
|
Context("determining which ACKs we have received an ACK for", func() {
|
|
BeforeEach(func() {
|
|
ack1 := &wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 80, Largest: 100}}}
|
|
ack2 := &wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 50, Largest: 200}}}
|
|
morePackets := []*Packet{
|
|
{PacketNumber: 13, Frames: []wire.Frame{ack1, &streamFrame}, Length: 1},
|
|
{PacketNumber: 14, Frames: []wire.Frame{ack2, &streamFrame}, Length: 1},
|
|
{PacketNumber: 15, Frames: []wire.Frame{&streamFrame}, Length: 1},
|
|
}
|
|
for _, packet := range morePackets {
|
|
handler.SentPacket(packet)
|
|
}
|
|
})
|
|
|
|
It("determines which ACK we have received an ACK for", func() {
|
|
err := handler.ReceivedAck(&wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 13, Largest: 15}}}, 1, protocol.EncryptionForwardSecure, time.Now())
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(handler.GetLowestPacketNotConfirmedAcked()).To(Equal(protocol.PacketNumber(201)))
|
|
})
|
|
|
|
It("doesn't do anything when the acked packet didn't contain an ACK", func() {
|
|
ack := &wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 13, Largest: 13}}}
|
|
err := handler.ReceivedAck(ack, 1, protocol.EncryptionForwardSecure, time.Now())
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(handler.GetLowestPacketNotConfirmedAcked()).To(Equal(protocol.PacketNumber(101)))
|
|
ack = &wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 15, Largest: 15}}}
|
|
err = handler.ReceivedAck(ack, 2, protocol.EncryptionForwardSecure, time.Now())
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(handler.GetLowestPacketNotConfirmedAcked()).To(Equal(protocol.PacketNumber(101)))
|
|
})
|
|
|
|
It("doesn't decrease the value", func() {
|
|
err := handler.ReceivedAck(&wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 14, Largest: 14}}}, 1, protocol.EncryptionForwardSecure, time.Now())
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(handler.GetLowestPacketNotConfirmedAcked()).To(Equal(protocol.PacketNumber(201)))
|
|
err = handler.ReceivedAck(&wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 13, Largest: 13}}}, 2, protocol.EncryptionForwardSecure, time.Now())
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(handler.GetLowestPacketNotConfirmedAcked()).To(Equal(protocol.PacketNumber(201)))
|
|
})
|
|
})
|
|
})
|
|
|
|
Context("ACK processing, for retransmitted packets", func() {
|
|
It("sends a packet as retransmission", func() {
|
|
// packet 5 was retransmitted as packet 6
|
|
handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 5, Length: 10}))
|
|
Expect(handler.bytesInFlight).To(Equal(protocol.ByteCount(10)))
|
|
losePacket(5)
|
|
Expect(handler.bytesInFlight).To(BeZero())
|
|
handler.SentPacketsAsRetransmission([]*Packet{retransmittablePacket(&Packet{PacketNumber: 6, Length: 11})}, 5)
|
|
Expect(handler.bytesInFlight).To(Equal(protocol.ByteCount(11)))
|
|
})
|
|
|
|
It("removes a packet when it is acked", func() {
|
|
// packet 5 was retransmitted as packet 6
|
|
handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 5, Length: 10}))
|
|
losePacket(5)
|
|
handler.SentPacketsAsRetransmission([]*Packet{retransmittablePacket(&Packet{PacketNumber: 6, Length: 11})}, 5)
|
|
Expect(handler.bytesInFlight).To(Equal(protocol.ByteCount(11)))
|
|
// ack 5
|
|
ack := &wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 5, Largest: 5}}}
|
|
err := handler.ReceivedAck(ack, 1, protocol.EncryptionForwardSecure, time.Now())
|
|
Expect(err).ToNot(HaveOccurred())
|
|
expectInPacketHistory([]protocol.PacketNumber{6})
|
|
Expect(handler.bytesInFlight).To(Equal(protocol.ByteCount(11)))
|
|
})
|
|
|
|
It("handles ACKs that ack the original packet as well as the retransmission", func() {
|
|
// packet 5 was retransmitted as packet 7
|
|
handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 5, Length: 10}))
|
|
losePacket(5)
|
|
handler.SentPacketsAsRetransmission([]*Packet{retransmittablePacket(&Packet{PacketNumber: 7, Length: 11})}, 5)
|
|
// ack 5 and 7
|
|
ack := &wire.AckFrame{
|
|
AckRanges: []wire.AckRange{
|
|
{Smallest: 7, Largest: 7},
|
|
{Smallest: 5, Largest: 5},
|
|
},
|
|
}
|
|
err := handler.ReceivedAck(ack, 1, protocol.EncryptionForwardSecure, time.Now())
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(handler.packetHistory.Len()).To(BeZero())
|
|
Expect(handler.bytesInFlight).To(BeZero())
|
|
})
|
|
})
|
|
|
|
Context("Retransmission handling", func() {
|
|
It("does not dequeue a packet if no ack has been received", func() {
|
|
handler.SentPacket(&Packet{PacketNumber: 1})
|
|
Expect(handler.DequeuePacketForRetransmission()).To(BeNil())
|
|
})
|
|
|
|
Context("STOP_WAITINGs", func() {
|
|
It("gets a STOP_WAITING frame", func() {
|
|
handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 1}))
|
|
handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 2}))
|
|
handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 3}))
|
|
ack := &wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 3, Largest: 3}}}
|
|
err := handler.ReceivedAck(ack, 2, protocol.EncryptionForwardSecure, time.Now())
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(handler.GetStopWaitingFrame(false)).To(Equal(&wire.StopWaitingFrame{LeastUnacked: 4}))
|
|
})
|
|
|
|
It("gets a STOP_WAITING frame after queueing a retransmission", func() {
|
|
handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 5}))
|
|
handler.queuePacketForRetransmission(getPacket(5))
|
|
Expect(handler.GetStopWaitingFrame(false)).To(Equal(&wire.StopWaitingFrame{LeastUnacked: 6}))
|
|
})
|
|
})
|
|
})
|
|
|
|
Context("congestion", func() {
|
|
var cong *mocks.MockSendAlgorithm
|
|
|
|
BeforeEach(func() {
|
|
cong = mocks.NewMockSendAlgorithm(mockCtrl)
|
|
handler.congestion = cong
|
|
})
|
|
|
|
It("should call OnSent", func() {
|
|
cong.EXPECT().OnPacketSent(
|
|
gomock.Any(),
|
|
protocol.ByteCount(42),
|
|
protocol.PacketNumber(1),
|
|
protocol.ByteCount(42),
|
|
true,
|
|
)
|
|
cong.EXPECT().TimeUntilSend(gomock.Any())
|
|
p := &Packet{
|
|
PacketNumber: 1,
|
|
Length: 42,
|
|
Frames: []wire.Frame{&wire.PingFrame{}},
|
|
}
|
|
handler.SentPacket(p)
|
|
})
|
|
|
|
It("should call MaybeExitSlowStart and OnPacketAcked", func() {
|
|
rcvTime := time.Now().Add(-5 * time.Second)
|
|
cong.EXPECT().OnPacketSent(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Times(3)
|
|
cong.EXPECT().TimeUntilSend(gomock.Any()).Times(3)
|
|
gomock.InOrder(
|
|
cong.EXPECT().MaybeExitSlowStart(), // must be called before packets are acked
|
|
cong.EXPECT().OnPacketAcked(protocol.PacketNumber(1), protocol.ByteCount(1), protocol.ByteCount(3), rcvTime),
|
|
cong.EXPECT().OnPacketAcked(protocol.PacketNumber(2), protocol.ByteCount(1), protocol.ByteCount(3), rcvTime),
|
|
)
|
|
handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 1}))
|
|
handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 2}))
|
|
handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 3}))
|
|
ack := &wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 1, Largest: 2}}}
|
|
err := handler.ReceivedAck(ack, 1, protocol.EncryptionForwardSecure, rcvTime)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
})
|
|
|
|
It("doesn't call OnPacketLost and OnRetransmissionTimeout when queuing RTOs", func() {
|
|
for i := protocol.PacketNumber(1); i < 3; i++ {
|
|
cong.EXPECT().OnPacketSent(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any())
|
|
cong.EXPECT().TimeUntilSend(gomock.Any())
|
|
handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: i}))
|
|
}
|
|
handler.OnAlarm() // TLP
|
|
Expect(handler.DequeuePacketForRetransmission()).To(BeNil())
|
|
handler.OnAlarm() // TLP
|
|
Expect(handler.DequeuePacketForRetransmission()).To(BeNil())
|
|
handler.OnAlarm() // RTO
|
|
Expect(handler.DequeuePacketForRetransmission()).ToNot(BeNil())
|
|
Expect(handler.DequeuePacketForRetransmission()).ToNot(BeNil())
|
|
})
|
|
|
|
It("declares all lower packets lost and call OnRetransmissionTimeout when verifying an RTO", func() {
|
|
cong.EXPECT().OnPacketSent(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Times(5)
|
|
cong.EXPECT().TimeUntilSend(gomock.Any()).Times(5)
|
|
handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 1, SendTime: time.Now().Add(-time.Hour)}))
|
|
handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 2, SendTime: time.Now().Add(-time.Hour)}))
|
|
handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 3, SendTime: time.Now().Add(-time.Hour)}))
|
|
handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 4, SendTime: time.Now().Add(-time.Hour)}))
|
|
handler.OnAlarm() // TLP
|
|
handler.OnAlarm() // TLP
|
|
handler.OnAlarm() // RTO
|
|
Expect(handler.DequeuePacketForRetransmission()).ToNot(BeNil())
|
|
Expect(handler.DequeuePacketForRetransmission()).ToNot(BeNil())
|
|
// send one probe packet and receive an ACK for it
|
|
rcvTime := time.Now()
|
|
gomock.InOrder(
|
|
cong.EXPECT().MaybeExitSlowStart(),
|
|
cong.EXPECT().OnRetransmissionTimeout(true),
|
|
cong.EXPECT().OnPacketAcked(protocol.PacketNumber(5), protocol.ByteCount(1), protocol.ByteCount(5), rcvTime),
|
|
cong.EXPECT().OnPacketLost(protocol.PacketNumber(1), protocol.ByteCount(1), protocol.ByteCount(5)),
|
|
cong.EXPECT().OnPacketLost(protocol.PacketNumber(2), protocol.ByteCount(1), protocol.ByteCount(5)),
|
|
cong.EXPECT().OnPacketLost(protocol.PacketNumber(3), protocol.ByteCount(1), protocol.ByteCount(5)),
|
|
cong.EXPECT().OnPacketLost(protocol.PacketNumber(4), protocol.ByteCount(1), protocol.ByteCount(5)),
|
|
)
|
|
handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 5}))
|
|
ack := &wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 5, Largest: 5}}}
|
|
err := handler.ReceivedAck(ack, 1, protocol.EncryptionForwardSecure, rcvTime)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
})
|
|
|
|
It("doesn't call OnRetransmissionTimeout when a spurious RTO occurs", func() {
|
|
cong.EXPECT().OnPacketSent(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Times(3)
|
|
cong.EXPECT().TimeUntilSend(gomock.Any()).Times(3)
|
|
handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 1, SendTime: time.Now().Add(-time.Hour)}))
|
|
handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 2, SendTime: time.Now()}))
|
|
handler.OnAlarm() // TLP
|
|
handler.OnAlarm() // TLP
|
|
handler.OnAlarm() // RTO
|
|
Expect(handler.DequeuePacketForRetransmission()).ToNot(BeNil())
|
|
Expect(handler.DequeuePacketForRetransmission()).ToNot(BeNil())
|
|
// send one probe packet
|
|
|
|
handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 3}))
|
|
// receive an ACK for a packet send *before* the probe packet
|
|
// don't EXPECT any call to OnRetransmissionTimeout
|
|
gomock.InOrder(
|
|
cong.EXPECT().MaybeExitSlowStart(),
|
|
cong.EXPECT().OnPacketAcked(protocol.PacketNumber(2), protocol.ByteCount(1), protocol.ByteCount(3), gomock.Any()),
|
|
cong.EXPECT().OnPacketLost(protocol.PacketNumber(1), protocol.ByteCount(1), protocol.ByteCount(3)),
|
|
)
|
|
ack := &wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 2, Largest: 2}}}
|
|
err := handler.ReceivedAck(ack, 1, protocol.EncryptionForwardSecure, time.Now())
|
|
Expect(err).ToNot(HaveOccurred())
|
|
})
|
|
|
|
It("doesn't call OnPacketAcked when a retransmitted packet is acked", func() {
|
|
cong.EXPECT().OnPacketSent(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Times(2)
|
|
cong.EXPECT().TimeUntilSend(gomock.Any()).Times(2)
|
|
handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 1, SendTime: time.Now().Add(-time.Hour)}))
|
|
handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 2}))
|
|
// lose packet 1
|
|
gomock.InOrder(
|
|
cong.EXPECT().MaybeExitSlowStart(),
|
|
cong.EXPECT().OnPacketAcked(protocol.PacketNumber(2), protocol.ByteCount(1), protocol.ByteCount(2), gomock.Any()),
|
|
cong.EXPECT().OnPacketLost(protocol.PacketNumber(1), protocol.ByteCount(1), protocol.ByteCount(2)),
|
|
)
|
|
ack := &wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 2, Largest: 2}}}
|
|
err := handler.ReceivedAck(ack, 1, protocol.EncryptionForwardSecure, time.Now())
|
|
Expect(err).ToNot(HaveOccurred())
|
|
// don't EXPECT any further calls to the congestion controller
|
|
ack = &wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 1, Largest: 2}}}
|
|
err = handler.ReceivedAck(ack, 2, protocol.EncryptionForwardSecure, time.Now())
|
|
Expect(err).ToNot(HaveOccurred())
|
|
})
|
|
|
|
It("calls OnPacketAcked and OnPacketLost with the right bytes_in_flight value", func() {
|
|
cong.EXPECT().OnPacketSent(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Times(4)
|
|
cong.EXPECT().TimeUntilSend(gomock.Any()).Times(4)
|
|
handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 1, SendTime: time.Now().Add(-time.Hour)}))
|
|
handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 2, SendTime: time.Now().Add(-30 * time.Minute)}))
|
|
handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 3, SendTime: time.Now().Add(-30 * time.Minute)}))
|
|
handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 4, SendTime: time.Now()}))
|
|
// receive the first ACK
|
|
gomock.InOrder(
|
|
cong.EXPECT().MaybeExitSlowStart(),
|
|
cong.EXPECT().OnPacketAcked(protocol.PacketNumber(2), protocol.ByteCount(1), protocol.ByteCount(4), gomock.Any()),
|
|
cong.EXPECT().OnPacketLost(protocol.PacketNumber(1), protocol.ByteCount(1), protocol.ByteCount(4)),
|
|
)
|
|
ack := &wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 2, Largest: 2}}}
|
|
err := handler.ReceivedAck(ack, 1, protocol.EncryptionForwardSecure, time.Now().Add(-30*time.Minute))
|
|
Expect(err).ToNot(HaveOccurred())
|
|
// receive the second ACK
|
|
gomock.InOrder(
|
|
cong.EXPECT().MaybeExitSlowStart(),
|
|
cong.EXPECT().OnPacketAcked(protocol.PacketNumber(4), protocol.ByteCount(1), protocol.ByteCount(2), gomock.Any()),
|
|
cong.EXPECT().OnPacketLost(protocol.PacketNumber(3), protocol.ByteCount(1), protocol.ByteCount(2)),
|
|
)
|
|
ack = &wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 4, Largest: 4}}}
|
|
err = handler.ReceivedAck(ack, 2, protocol.EncryptionForwardSecure, time.Now())
|
|
Expect(err).ToNot(HaveOccurred())
|
|
})
|
|
|
|
It("only allows sending of ACKs when congestion limited", func() {
|
|
handler.bytesInFlight = 100
|
|
cong.EXPECT().GetCongestionWindow().Return(protocol.ByteCount(200))
|
|
Expect(handler.SendMode()).To(Equal(SendAny))
|
|
cong.EXPECT().GetCongestionWindow().Return(protocol.ByteCount(75))
|
|
Expect(handler.SendMode()).To(Equal(SendAck))
|
|
})
|
|
|
|
It("only allows sending of ACKs when we're keeping track of MaxOutstandingSentPackets packets", func() {
|
|
cong.EXPECT().GetCongestionWindow().Return(protocol.MaxByteCount).AnyTimes()
|
|
cong.EXPECT().TimeUntilSend(gomock.Any()).AnyTimes()
|
|
cong.EXPECT().OnPacketSent(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes()
|
|
for i := protocol.PacketNumber(1); i < protocol.MaxOutstandingSentPackets; i++ {
|
|
handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: i}))
|
|
Expect(handler.SendMode()).To(Equal(SendAny))
|
|
}
|
|
handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: protocol.MaxOutstandingSentPackets}))
|
|
Expect(handler.SendMode()).To(Equal(SendAck))
|
|
})
|
|
|
|
It("doesn't allow retransmission if congestion limited", func() {
|
|
handler.bytesInFlight = 100
|
|
handler.retransmissionQueue = []*Packet{{PacketNumber: 3}}
|
|
cong.EXPECT().GetCongestionWindow().Return(protocol.ByteCount(50))
|
|
Expect(handler.SendMode()).To(Equal(SendAck))
|
|
})
|
|
|
|
It("allows sending retransmissions", func() {
|
|
cong.EXPECT().GetCongestionWindow().Return(protocol.MaxByteCount)
|
|
handler.retransmissionQueue = []*Packet{{PacketNumber: 3}}
|
|
Expect(handler.SendMode()).To(Equal(SendRetransmission))
|
|
})
|
|
|
|
It("allow retransmissions, if we're keeping track of between MaxOutstandingSentPackets and MaxTrackedSentPackets packets", func() {
|
|
cong.EXPECT().GetCongestionWindow().Return(protocol.MaxByteCount)
|
|
Expect(protocol.MaxOutstandingSentPackets).To(BeNumerically("<", protocol.MaxTrackedSentPackets))
|
|
handler.retransmissionQueue = make([]*Packet, protocol.MaxOutstandingSentPackets+10)
|
|
Expect(handler.SendMode()).To(Equal(SendRetransmission))
|
|
handler.retransmissionQueue = make([]*Packet, protocol.MaxTrackedSentPackets)
|
|
Expect(handler.SendMode()).To(Equal(SendNone))
|
|
})
|
|
|
|
It("allows RTOs, even when congestion limited", func() {
|
|
// note that we don't EXPECT a call to GetCongestionWindow
|
|
// that means retransmissions are sent without considering the congestion window
|
|
handler.numRTOs = 1
|
|
handler.retransmissionQueue = []*Packet{{PacketNumber: 3}}
|
|
Expect(handler.SendMode()).To(Equal(SendRTO))
|
|
})
|
|
|
|
It("gets the pacing delay", func() {
|
|
sendTime := time.Now().Add(-time.Minute)
|
|
handler.bytesInFlight = 100
|
|
cong.EXPECT().OnPacketSent(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any())
|
|
cong.EXPECT().TimeUntilSend(protocol.ByteCount(100)).Return(time.Hour)
|
|
handler.SentPacket(&Packet{PacketNumber: 1, SendTime: sendTime})
|
|
Expect(handler.TimeUntilSend()).To(Equal(sendTime.Add(time.Hour)))
|
|
})
|
|
|
|
It("allows sending of all RTO probe packets", func() {
|
|
handler.numRTOs = 5
|
|
Expect(handler.ShouldSendNumPackets()).To(Equal(5))
|
|
})
|
|
|
|
It("allows sending of one packet, if it should be sent immediately", func() {
|
|
cong.EXPECT().TimeUntilSend(gomock.Any()).Return(time.Duration(0))
|
|
Expect(handler.ShouldSendNumPackets()).To(Equal(1))
|
|
})
|
|
|
|
It("allows sending of multiple packets, if the pacing delay is smaller than the minimum", func() {
|
|
pacingDelay := protocol.MinPacingDelay / 10
|
|
cong.EXPECT().TimeUntilSend(gomock.Any()).Return(pacingDelay)
|
|
Expect(handler.ShouldSendNumPackets()).To(Equal(10))
|
|
})
|
|
|
|
It("allows sending of multiple packets, if the pacing delay is smaller than the minimum, and not a fraction", func() {
|
|
pacingDelay := protocol.MinPacingDelay * 2 / 5
|
|
cong.EXPECT().TimeUntilSend(gomock.Any()).Return(pacingDelay)
|
|
Expect(handler.ShouldSendNumPackets()).To(Equal(3))
|
|
})
|
|
})
|
|
|
|
It("doesn't set an alarm if there are no outstanding packets", func() {
|
|
handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 10}))
|
|
handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 11}))
|
|
ack := &wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 10, Largest: 11}}}
|
|
err := handler.ReceivedAck(ack, 1, protocol.EncryptionForwardSecure, time.Now())
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(handler.GetAlarmTimeout()).To(BeZero())
|
|
})
|
|
|
|
It("does nothing on OnAlarm if there are no outstanding packets", func() {
|
|
Expect(handler.OnAlarm()).To(Succeed())
|
|
Expect(handler.SendMode()).To(Equal(SendAny))
|
|
})
|
|
|
|
Context("TLPs", func() {
|
|
It("uses the RTT from RTT stats", func() {
|
|
rtt := 2 * time.Second
|
|
updateRTT(rtt)
|
|
Expect(handler.computeTLPTimeout()).To(Equal(rtt * 3 / 2))
|
|
})
|
|
|
|
It("uses the minTLPTimeout for short RTTs", func() {
|
|
rtt := 2 * time.Microsecond
|
|
updateRTT(rtt)
|
|
Expect(handler.computeTLPTimeout()).To(Equal(minTPLTimeout))
|
|
})
|
|
|
|
It("sets the TLP send mode until one retransmittable packet is sent", func() {
|
|
handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 1, SendTime: time.Now().Add(-time.Hour)}))
|
|
handler.OnAlarm()
|
|
Expect(handler.SendMode()).To(Equal(SendTLP))
|
|
// Send a non-retransmittable packet.
|
|
// It doesn't count as a probe packet.
|
|
handler.SentPacket(nonRetransmittablePacket(&Packet{PacketNumber: 2}))
|
|
Expect(handler.SendMode()).To(Equal(SendTLP))
|
|
// Send a retransmittable packet.
|
|
handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 3}))
|
|
Expect(handler.SendMode()).ToNot(Equal(SendTLP))
|
|
})
|
|
|
|
It("sends two TLPs, then RTOs", func() {
|
|
handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 1, SendTime: time.Now().Add(-time.Hour)}))
|
|
handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 2, SendTime: time.Now().Add(-time.Hour)}))
|
|
// first TLP
|
|
handler.OnAlarm()
|
|
Expect(handler.SendMode()).To(Equal(SendTLP))
|
|
handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 3}))
|
|
// second TLP
|
|
handler.OnAlarm()
|
|
Expect(handler.SendMode()).To(Equal(SendTLP))
|
|
handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 4}))
|
|
// fire alarm a third time
|
|
handler.OnAlarm()
|
|
Expect(handler.SendMode()).To(Equal(SendRTO))
|
|
})
|
|
})
|
|
|
|
Context("RTOs", func() {
|
|
It("uses default RTO", func() {
|
|
Expect(handler.computeRTOTimeout()).To(Equal(defaultRTOTimeout))
|
|
})
|
|
|
|
It("uses RTO from rttStats", func() {
|
|
rtt := time.Second
|
|
handler.rttStats.UpdateRTT(rtt, 0, time.Now())
|
|
Expect(handler.rttStats.SmoothedRTT()).To(Equal(rtt))
|
|
Expect(handler.rttStats.MeanDeviation()).To(Equal(rtt / 2))
|
|
expected := rtt + rtt/2*4
|
|
Expect(handler.computeRTOTimeout()).To(Equal(expected))
|
|
})
|
|
|
|
It("limits RTO min", func() {
|
|
rtt := 3 * time.Millisecond
|
|
updateRTT(rtt)
|
|
Expect(handler.computeRTOTimeout()).To(Equal(minRTOTimeout))
|
|
})
|
|
|
|
It("limits RTO max", func() {
|
|
updateRTT(time.Hour)
|
|
Expect(handler.computeRTOTimeout()).To(Equal(maxRTOTimeout))
|
|
})
|
|
|
|
It("implements exponential backoff", func() {
|
|
handler.rtoCount = 0
|
|
Expect(handler.computeRTOTimeout()).To(Equal(defaultRTOTimeout))
|
|
handler.rtoCount = 1
|
|
Expect(handler.computeRTOTimeout()).To(Equal(2 * defaultRTOTimeout))
|
|
handler.rtoCount = 2
|
|
Expect(handler.computeRTOTimeout()).To(Equal(4 * defaultRTOTimeout))
|
|
})
|
|
|
|
It("queues two packets if RTO expires", func() {
|
|
handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 1}))
|
|
handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 2}))
|
|
|
|
updateRTT(time.Hour)
|
|
Expect(handler.lossTime.IsZero()).To(BeTrue())
|
|
Expect(time.Until(handler.GetAlarmTimeout())).To(BeNumerically("~", handler.computeRTOTimeout(), time.Minute))
|
|
|
|
handler.OnAlarm() // TLP
|
|
handler.OnAlarm() // TLP
|
|
handler.OnAlarm() // RTO
|
|
p := handler.DequeuePacketForRetransmission()
|
|
Expect(p).ToNot(BeNil())
|
|
Expect(p.PacketNumber).To(Equal(protocol.PacketNumber(1)))
|
|
p = handler.DequeuePacketForRetransmission()
|
|
Expect(p).ToNot(BeNil())
|
|
Expect(p.PacketNumber).To(Equal(protocol.PacketNumber(2)))
|
|
Expect(handler.bytesInFlight).To(Equal(protocol.ByteCount(2)))
|
|
|
|
Expect(handler.rtoCount).To(BeEquivalentTo(1))
|
|
})
|
|
|
|
It("doesn't delete packets transmitted as RTO from the history", func() {
|
|
handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 1, SendTime: time.Now().Add(-time.Hour)}))
|
|
handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 2, SendTime: time.Now().Add(-time.Hour)}))
|
|
handler.rttStats.UpdateRTT(time.Second, 0, time.Now())
|
|
handler.OnAlarm() // TLP
|
|
handler.OnAlarm() // TLP
|
|
handler.OnAlarm() // RTO
|
|
Expect(handler.DequeuePacketForRetransmission()).ToNot(BeNil())
|
|
Expect(handler.DequeuePacketForRetransmission()).ToNot(BeNil())
|
|
expectInPacketHistory([]protocol.PacketNumber{1, 2})
|
|
Expect(handler.bytesInFlight).To(Equal(protocol.ByteCount(2)))
|
|
// Send a probe packet and receive an ACK for it.
|
|
// This verifies the RTO.
|
|
handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 3}))
|
|
ack := &wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 3, Largest: 3}}}
|
|
err := handler.ReceivedAck(ack, 1, protocol.EncryptionForwardSecure, time.Now())
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(handler.packetHistory.Len()).To(BeZero())
|
|
Expect(handler.bytesInFlight).To(BeZero())
|
|
Expect(handler.retransmissionQueue).To(BeEmpty()) // 1 and 2 were already sent as probe packets
|
|
})
|
|
|
|
It("allows sending of two probe packets", func() {
|
|
handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 1, SendTime: time.Now().Add(-time.Hour)}))
|
|
handler.OnAlarm() // TLP
|
|
handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 2})) // send the first TLP
|
|
handler.OnAlarm() // TLP
|
|
handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 3})) // send the second TLP
|
|
handler.OnAlarm() // RTO
|
|
Expect(handler.SendMode()).To(Equal(SendRTO))
|
|
handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 4}))
|
|
Expect(handler.SendMode()).To(Equal(SendRTO))
|
|
handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 5}))
|
|
Expect(handler.SendMode()).ToNot(Equal(SendRTO))
|
|
})
|
|
|
|
It("queues packets sent before the probe packet for retransmission", func() {
|
|
handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 1, SendTime: time.Now().Add(-time.Hour)}))
|
|
handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 2, SendTime: time.Now().Add(-time.Hour)}))
|
|
handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 3, SendTime: time.Now().Add(-time.Hour)}))
|
|
handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 4, SendTime: time.Now().Add(-time.Hour)}))
|
|
handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 5, SendTime: time.Now().Add(-time.Hour)}))
|
|
handler.OnAlarm() // TLP
|
|
handler.OnAlarm() // TLP
|
|
handler.OnAlarm() // RTO
|
|
Expect(handler.DequeuePacketForRetransmission()).ToNot(BeNil())
|
|
Expect(handler.DequeuePacketForRetransmission()).ToNot(BeNil())
|
|
expectInPacketHistory([]protocol.PacketNumber{1, 2, 3, 4, 5})
|
|
// Send a probe packet and receive an ACK for it.
|
|
// This verifies the RTO.
|
|
handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 6}))
|
|
ack := &wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 6, Largest: 6}}}
|
|
err := handler.ReceivedAck(ack, 1, protocol.EncryptionForwardSecure, time.Now())
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(handler.packetHistory.Len()).To(BeZero())
|
|
Expect(handler.bytesInFlight).To(BeZero())
|
|
Expect(handler.retransmissionQueue).To(HaveLen(3)) // packets 3, 4, 5
|
|
})
|
|
|
|
It("handles ACKs for the original packet", func() {
|
|
handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 5, SendTime: time.Now().Add(-time.Hour)}))
|
|
handler.rttStats.UpdateRTT(time.Second, 0, time.Now())
|
|
handler.OnAlarm() // TLP
|
|
handler.OnAlarm() // TLP
|
|
handler.OnAlarm() // RTO
|
|
Expect(handler.DequeuePacketForRetransmission()).ToNot(BeNil())
|
|
handler.SentPacketsAsRetransmission([]*Packet{retransmittablePacket(&Packet{PacketNumber: 6})}, 5)
|
|
ack := &wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 5, Largest: 5}}}
|
|
err := handler.ReceivedAck(ack, 1, protocol.EncryptionForwardSecure, time.Now())
|
|
Expect(err).ToNot(HaveOccurred())
|
|
err = handler.OnAlarm()
|
|
Expect(err).ToNot(HaveOccurred())
|
|
})
|
|
|
|
It("handles ACKs for the original packet", func() {
|
|
handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 5, SendTime: time.Now().Add(-time.Hour)}))
|
|
handler.rttStats.UpdateRTT(time.Second, 0, time.Now())
|
|
err := handler.OnAlarm()
|
|
Expect(err).ToNot(HaveOccurred())
|
|
err = handler.OnAlarm()
|
|
Expect(err).ToNot(HaveOccurred())
|
|
})
|
|
})
|
|
|
|
Context("Delay-based loss detection", func() {
|
|
It("immediately detects old packets as lost when receiving an ACK", func() {
|
|
now := time.Now()
|
|
handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 1, SendTime: now.Add(-time.Hour)}))
|
|
handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 2, SendTime: now.Add(-time.Second)}))
|
|
Expect(handler.lossTime.IsZero()).To(BeTrue())
|
|
|
|
ack := &wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 2, Largest: 2}}}
|
|
err := handler.ReceivedAck(ack, 1, protocol.EncryptionForwardSecure, now)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Expect(handler.DequeuePacketForRetransmission()).ToNot(BeNil())
|
|
Expect(handler.DequeuePacketForRetransmission()).To(BeNil())
|
|
// no need to set an alarm, since packet 1 was already declared lost
|
|
Expect(handler.lossTime.IsZero()).To(BeTrue())
|
|
Expect(handler.bytesInFlight).To(BeZero())
|
|
})
|
|
|
|
It("sets the early retransmit alarm", func() {
|
|
now := time.Now()
|
|
handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 1, SendTime: now.Add(-2 * time.Second)}))
|
|
handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 2, SendTime: now.Add(-2 * time.Second)}))
|
|
handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 3, SendTime: now.Add(-time.Second)}))
|
|
Expect(handler.lossTime.IsZero()).To(BeTrue())
|
|
|
|
ack := &wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 2, Largest: 2}}}
|
|
err := handler.ReceivedAck(ack, 1, protocol.EncryptionForwardSecure, now.Add(-time.Second))
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Expect(handler.rttStats.SmoothedRTT()).To(Equal(time.Second))
|
|
|
|
// Packet 1 should be considered lost (1+1/8) RTTs after it was sent.
|
|
Expect(handler.lossTime.IsZero()).To(BeFalse())
|
|
Expect(handler.lossTime.Sub(getPacket(1).SendTime)).To(Equal(time.Second * 9 / 8))
|
|
|
|
err = handler.OnAlarm()
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(handler.DequeuePacketForRetransmission()).NotTo(BeNil())
|
|
// make sure this is not an RTO: only packet 1 is retransmissted
|
|
Expect(handler.DequeuePacketForRetransmission()).To(BeNil())
|
|
})
|
|
})
|
|
|
|
Context("handshake packets", func() {
|
|
BeforeEach(func() {
|
|
handler.handshakeComplete = false
|
|
})
|
|
|
|
It("detects the handshake timeout", func() {
|
|
now := time.Now()
|
|
sendTime := now.Add(-time.Minute)
|
|
lastHandshakePacketSendTime := now.Add(-30 * time.Second)
|
|
// send handshake packets: 1, 3
|
|
// send a forward-secure packet: 2
|
|
handler.SentPacket(handshakePacket(&Packet{PacketNumber: 1, SendTime: sendTime}))
|
|
handler.SentPacket(retransmittablePacket(&Packet{PacketNumber: 2, SendTime: sendTime}))
|
|
handler.SentPacket(handshakePacket(&Packet{PacketNumber: 3, SendTime: sendTime}))
|
|
|
|
ack := &wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 1, Largest: 1}}}
|
|
err := handler.ReceivedAck(ack, 1, protocol.EncryptionForwardSecure, now)
|
|
// RTT is now 1 minute
|
|
Expect(handler.rttStats.SmoothedRTT()).To(Equal(time.Minute))
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Expect(handler.lossTime.IsZero()).To(BeTrue())
|
|
Expect(handler.GetAlarmTimeout().Sub(sendTime)).To(Equal(2 * time.Minute))
|
|
|
|
err = handler.OnAlarm()
|
|
Expect(err).ToNot(HaveOccurred())
|
|
p := handler.DequeuePacketForRetransmission()
|
|
Expect(p).ToNot(BeNil())
|
|
Expect(p.PacketNumber).To(Equal(protocol.PacketNumber(3)))
|
|
Expect(handler.handshakeCount).To(BeEquivalentTo(1))
|
|
handler.SentPacket(handshakePacket(&Packet{PacketNumber: 4, SendTime: lastHandshakePacketSendTime}))
|
|
// make sure the exponential backoff is used
|
|
Expect(handler.GetAlarmTimeout().Sub(lastHandshakePacketSendTime)).To(Equal(4 * time.Minute))
|
|
})
|
|
|
|
It("rejects an ACK that acks packets with a higher encryption level", func() {
|
|
handler.SentPacket(&Packet{
|
|
PacketNumber: 13,
|
|
EncryptionLevel: protocol.EncryptionForwardSecure,
|
|
Frames: []wire.Frame{&streamFrame},
|
|
Length: 1,
|
|
})
|
|
ack := &wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 13, Largest: 13}}}
|
|
err := handler.ReceivedAck(ack, 1, protocol.EncryptionSecure, time.Now())
|
|
Expect(err).To(MatchError("Received ACK with encryption level encrypted (not forward-secure) that acks a packet 13 (encryption level forward-secure)"))
|
|
})
|
|
|
|
It("deletes non forward-secure packets when the handshake completes", func() {
|
|
for i := protocol.PacketNumber(1); i <= 6; i++ {
|
|
p := retransmittablePacket(&Packet{PacketNumber: i})
|
|
p.EncryptionLevel = protocol.EncryptionSecure
|
|
handler.SentPacket(p)
|
|
}
|
|
handler.queuePacketForRetransmission(getPacket(1))
|
|
handler.queuePacketForRetransmission(getPacket(3))
|
|
handler.SetHandshakeComplete()
|
|
Expect(handler.packetHistory.Len()).To(BeZero())
|
|
packet := handler.DequeuePacketForRetransmission()
|
|
Expect(packet).To(BeNil())
|
|
})
|
|
})
|
|
})
|