uquic/internal/ackhandler/sent_packet_handler_test.go
Marten Seemann 5358831604 don't do anything when OnAlarm is called, but no packets are outstanding
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.
2018-08-08 15:40:36 +07:00

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())
})
})
})