From dc4a9b1d86d856ba58a9cc046fdbd6dab5ca4fff Mon Sep 17 00:00:00 2001 From: Marten Seemann Date: Tue, 13 Mar 2018 22:17:00 +0100 Subject: [PATCH] refactor sent packet handler tests --- .../ackhandler/sent_packet_handler_test.go | 647 +++++++----------- 1 file changed, 246 insertions(+), 401 deletions(-) diff --git a/internal/ackhandler/sent_packet_handler_test.go b/internal/ackhandler/sent_packet_handler_test.go index 44a8875cb..033578953 100644 --- a/internal/ackhandler/sent_packet_handler_test.go +++ b/internal/ackhandler/sent_packet_handler_test.go @@ -1,6 +1,7 @@ package ackhandler import ( + "sort" "time" "github.com/golang/mock/gomock" @@ -34,6 +35,20 @@ func handshakePacket(num protocol.PacketNumber) *Packet { } } +func createAck(ranges []wire.AckRange) *wire.AckFrame { + sort.Slice(ranges, func(i, j int) bool { + return ranges[i].First > ranges[j].First + }) + ack := &wire.AckFrame{ + LowestAcked: ranges[len(ranges)-1].First, + LargestAcked: ranges[0].Last, + } + if len(ranges) > 1 { + ack.AckRanges = ranges + } + return ack +} + var _ = Describe("SentPacketHandler", func() { var ( handler *sentPacketHandler @@ -72,76 +87,65 @@ var _ = Describe("SentPacketHandler", func() { Context("registering sent packets", func() { It("accepts two consecutive packets", func() { - packet1 := Packet{PacketNumber: 1, Frames: []wire.Frame{&streamFrame}, Length: 1} - packet2 := Packet{PacketNumber: 2, Frames: []wire.Frame{&streamFrame}, Length: 2} - handler.SentPacket(&packet1) - handler.SentPacket(&packet2) + handler.SentPacket(retransmittablePacket(1)) + handler.SentPacket(retransmittablePacket(2)) Expect(handler.lastSentPacketNumber).To(Equal(protocol.PacketNumber(2))) expectInPacketHistory([]protocol.PacketNumber{1, 2}) - Expect(handler.bytesInFlight).To(Equal(protocol.ByteCount(3))) + Expect(handler.bytesInFlight).To(Equal(protocol.ByteCount(2))) Expect(handler.skippedPackets).To(BeEmpty()) }) It("accepts packet number 0", func() { - packet1 := Packet{PacketNumber: 0, Frames: []wire.Frame{&streamFrame}, Length: 1} - packet2 := Packet{PacketNumber: 1, Frames: []wire.Frame{&streamFrame}, Length: 2} - handler.SentPacket(&packet1) + handler.SentPacket(retransmittablePacket(0)) Expect(handler.lastSentPacketNumber).To(BeZero()) - handler.SentPacket(&packet2) + handler.SentPacket(retransmittablePacket(1)) Expect(handler.lastSentPacketNumber).To(Equal(protocol.PacketNumber(1))) expectInPacketHistory([]protocol.PacketNumber{0, 1}) - Expect(handler.bytesInFlight).To(Equal(protocol.ByteCount(3))) + Expect(handler.bytesInFlight).To(Equal(protocol.ByteCount(2))) Expect(handler.skippedPackets).To(BeEmpty()) }) It("stores the sent time", func() { - packet := Packet{PacketNumber: 1, Frames: []wire.Frame{&streamFrame}, Length: 1} - handler.SentPacket(&packet) + handler.SentPacket(retransmittablePacket(1)) Expect(getPacket(1).sendTime.Unix()).To(BeNumerically("~", time.Now().Unix(), 1)) }) It("does not store non-retransmittable packets", func() { - handler.SentPacket(&Packet{PacketNumber: 1, Length: 1}) + handler.SentPacket(nonRetransmittablePacket(1)) Expect(handler.packetHistory.Len()).To(BeZero()) }) Context("skipped packet numbers", func() { It("works with non-consecutive packet numbers", func() { - packet1 := Packet{PacketNumber: 1, Frames: []wire.Frame{&streamFrame}, Length: 1} - packet2 := Packet{PacketNumber: 3, Frames: []wire.Frame{&streamFrame}, Length: 2} - handler.SentPacket(&packet1) - handler.SentPacket(&packet2) + handler.SentPacket(retransmittablePacket(1)) + handler.SentPacket(retransmittablePacket(3)) Expect(handler.lastSentPacketNumber).To(Equal(protocol.PacketNumber(3))) expectInPacketHistory([]protocol.PacketNumber{1, 3}) - Expect(handler.bytesInFlight).To(Equal(protocol.ByteCount(3))) - Expect(handler.skippedPackets).To(HaveLen(1)) - Expect(handler.skippedPackets[0]).To(Equal(protocol.PacketNumber(2))) + Expect(handler.skippedPackets).To(Equal([]protocol.PacketNumber{2})) + }) + + It("works with non-retransmittable packets", func() { + handler.SentPacket(nonRetransmittablePacket(1)) + handler.SentPacket(nonRetransmittablePacket(3)) + Expect(handler.skippedPackets).To(Equal([]protocol.PacketNumber{2})) }) It("recognizes multiple skipped packets", func() { - packet1 := Packet{PacketNumber: 1, Frames: []wire.Frame{&streamFrame}, Length: 1} - packet2 := Packet{PacketNumber: 3, Frames: []wire.Frame{&streamFrame}, Length: 2} - packet3 := Packet{PacketNumber: 5, Frames: []wire.Frame{&streamFrame}, Length: 2} - handler.SentPacket(&packet1) - handler.SentPacket(&packet2) - handler.SentPacket(&packet3) - Expect(handler.skippedPackets).To(HaveLen(2)) + handler.SentPacket(retransmittablePacket(1)) + handler.SentPacket(retransmittablePacket(3)) + handler.SentPacket(retransmittablePacket(5)) Expect(handler.skippedPackets).To(Equal([]protocol.PacketNumber{2, 4})) }) It("recognizes multiple consecutive skipped packets", func() { - packet1 := Packet{PacketNumber: 1, Frames: []wire.Frame{&streamFrame}, Length: 1} - packet2 := Packet{PacketNumber: 4, Frames: []wire.Frame{&streamFrame}, Length: 2} - handler.SentPacket(&packet1) - handler.SentPacket(&packet2) - Expect(handler.skippedPackets).To(HaveLen(2)) + handler.SentPacket(retransmittablePacket(1)) + handler.SentPacket(retransmittablePacket(4)) Expect(handler.skippedPackets).To(Equal([]protocol.PacketNumber{2, 3})) }) It("limits the lengths of the skipped packet slice", func() { for i := 0; i < protocol.MaxTrackedSkippedPackets+5; i++ { - packet := Packet{PacketNumber: protocol.PacketNumber(2*i + 1), Frames: []wire.Frame{&streamFrame}, Length: 1} - handler.SentPacket(&packet) + handler.SentPacket(retransmittablePacket(protocol.PacketNumber(2*i + 1))) } Expect(handler.skippedPackets).To(HaveLen(protocol.MaxUndecryptablePackets)) Expect(handler.skippedPackets[0]).To(Equal(protocol.PacketNumber(10))) @@ -170,284 +174,176 @@ var _ = Describe("SentPacketHandler", func() { Expect(handler.skippedPackets).To(BeEmpty()) }) }) + + Context("ACK handling", func() { + BeforeEach(func() { + handler.SentPacket(retransmittablePacket(10)) + handler.SentPacket(retransmittablePacket(12)) + }) + + It("rejects ACKs for skipped packets", func() { + ack := createAck([]wire.AckRange{{First: 10, Last: 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 := createAck([]wire.AckRange{{First: 10, Last: 10}, {First: 12, Last: 12}}) + err := handler.ReceivedAck(ack, 1337, protocol.EncryptionForwardSecure, time.Now()) + Expect(err).ToNot(HaveOccurred()) + Expect(handler.largestAcked).ToNot(BeZero()) + }) + }) }) }) Context("ACK processing", func() { - var packets []*Packet - BeforeEach(func() { - packets = []*Packet{ - {PacketNumber: 0, Frames: []wire.Frame{&streamFrame}, Length: 1}, - {PacketNumber: 1, Frames: []wire.Frame{&streamFrame}, Length: 1}, - {PacketNumber: 2, Frames: []wire.Frame{&streamFrame}, Length: 1}, - {PacketNumber: 3, Frames: []wire.Frame{&streamFrame}, Length: 1}, - {PacketNumber: 4, Frames: []wire.Frame{&streamFrame}, Length: 1}, - {PacketNumber: 5, Frames: []wire.Frame{&streamFrame}, Length: 1}, - {PacketNumber: 6, Frames: []wire.Frame{&streamFrame}, Length: 1}, - {PacketNumber: 7, Frames: []wire.Frame{&streamFrame}, Length: 1}, - {PacketNumber: 8, Frames: []wire.Frame{&streamFrame}, Length: 1}, - {PacketNumber: 9, Frames: []wire.Frame{&streamFrame}, Length: 1}, - {PacketNumber: 10, Frames: []wire.Frame{&streamFrame}, Length: 1}, - {PacketNumber: 12, Frames: []wire.Frame{&streamFrame}, Length: 1}, - } - for _, packet := range packets { - handler.SentPacket(packet) + for i := protocol.PacketNumber(0); i < 10; i++ { + handler.SentPacket(retransmittablePacket(i)) } // Increase RTT, because the tests would be flaky otherwise handler.rttStats.UpdateRTT(time.Hour, 0, time.Now()) - Expect(handler.bytesInFlight).To(Equal(protocol.ByteCount(len(packets)))) + Expect(handler.bytesInFlight).To(Equal(protocol.ByteCount(10))) }) Context("ACK validation", func() { It("accepts ACKs sent in packet 0", func() { - ack := wire.AckFrame{ - LargestAcked: 5, - LowestAcked: 1, - } - err := handler.ReceivedAck(&ack, 0, protocol.EncryptionUnencrypted, time.Now()) + ack := createAck([]wire.AckRange{{First: 0, Last: 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{LargestAcked: 3} - ack2 := wire.AckFrame{LargestAcked: 4} - err := handler.ReceivedAck(&ack1, 1337, protocol.EncryptionUnencrypted, time.Now()) + ack1 := createAck([]wire.AckRange{{First: 0, Last: 3}}) + ack2 := createAck([]wire.AckRange{{First: 0, Last: 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.EncryptionUnencrypted, time.Now()) + 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{LargestAcked: 3} - ack2 := wire.AckFrame{LargestAcked: 4} - err := handler.ReceivedAck(&ack1, 1337, protocol.EncryptionUnencrypted, time.Now()) + ack1 := createAck([]wire.AckRange{{First: 0, Last: 3}}) + ack2 := createAck([]wire.AckRange{{First: 0, Last: 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.EncryptionUnencrypted, time.Now()) + 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{ - LargestAcked: packets[len(packets)-1].PacketNumber + 1337, - } - err := handler.ReceivedAck(&ack, 1, protocol.EncryptionUnencrypted, time.Now()) + ack := createAck([]wire.AckRange{{First: 0, Last: 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(len(packets)))) + Expect(handler.bytesInFlight).To(Equal(protocol.ByteCount(10))) }) It("ignores repeated ACKs", func() { - ack := wire.AckFrame{ - LargestAcked: 3, - LowestAcked: 1, - } - err := handler.ReceivedAck(&ack, 1337, protocol.EncryptionUnencrypted, time.Now()) + ack := createAck([]wire.AckRange{{First: 1, Last: 3}}) + err := handler.ReceivedAck(ack, 1337, protocol.EncryptionForwardSecure, time.Now()) Expect(err).ToNot(HaveOccurred()) - Expect(handler.bytesInFlight).To(Equal(protocol.ByteCount(len(packets) - 3))) - err = handler.ReceivedAck(&ack, 1337+1, protocol.EncryptionUnencrypted, time.Now()) + 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(len(packets) - 3))) - }) - - It("rejects ACKs for skipped packets", func() { - ack := wire.AckFrame{ - LargestAcked: 12, - LowestAcked: 5, - } - err := handler.ReceivedAck(&ack, 1337, protocol.EncryptionUnencrypted, 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{ - LargestAcked: 12, - LowestAcked: 5, - AckRanges: []wire.AckRange{ - {First: 12, Last: 12}, - {First: 5, Last: 10}, - }, - } - err := handler.ReceivedAck(&ack, 1337, protocol.EncryptionUnencrypted, time.Now()) - Expect(err).ToNot(HaveOccurred()) - Expect(handler.largestAcked).ToNot(BeZero()) + Expect(handler.bytesInFlight).To(Equal(protocol.ByteCount(7))) }) }) Context("acks and nacks the right packets", func() { It("adjusts the LargestAcked", func() { - ack := wire.AckFrame{ - LargestAcked: 5, - LowestAcked: 0, - } - err := handler.ReceivedAck(&ack, 1, protocol.EncryptionUnencrypted, time.Now()) + ack := createAck([]wire.AckRange{{First: 0, Last: 5}}) + err := handler.ReceivedAck(ack, 1, protocol.EncryptionForwardSecure, time.Now()) Expect(err).ToNot(HaveOccurred()) Expect(handler.largestAcked).To(Equal(protocol.PacketNumber(5))) - Expect(handler.packetHistory.Len()).To(Equal(6)) // 6, 7, 8, 9, 10, 12 - for i := protocol.PacketNumber(6); i <= 10; i++ { - Expect(getPacket(i)).ToNot(BeNil()) - } - Expect(getPacket(12)).ToNot(BeNil()) - }) - - 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{ - LargestAcked: 13, - LowestAcked: 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("acks all packets for an ACK frame with no missing packets", func() { - ack := wire.AckFrame{ - LargestAcked: 8, - LowestAcked: 1, - } - err := handler.ReceivedAck(&ack, 1, protocol.EncryptionUnencrypted, time.Now()) - Expect(err).ToNot(HaveOccurred()) - Expect(handler.packetHistory.Len()).To(Equal(4)) // 0, 9, 10, 12 - Expect(getPacket(0)).ToNot(BeNil()) - Expect(getPacket(9)).ToNot(BeNil()) - Expect(getPacket(10)).ToNot(BeNil()) - Expect(getPacket(12)).ToNot(BeNil()) + expectInPacketHistory([]protocol.PacketNumber{6, 7, 8, 9}) }) It("acks packet 0", func() { - ack := wire.AckFrame{ - LargestAcked: 0, - LowestAcked: 0, - } - err := handler.ReceivedAck(&ack, 1, protocol.EncryptionUnencrypted, time.Now()) + ack := createAck([]wire.AckRange{{First: 0, Last: 0}}) + err := handler.ReceivedAck(ack, 1, protocol.EncryptionForwardSecure, time.Now()) Expect(err).ToNot(HaveOccurred()) Expect(getPacket(0)).To(BeNil()) - Expect(handler.packetHistory.Len()).To(Equal(11)) // 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12 + 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{ - LargestAcked: 9, - LowestAcked: 1, - AckRanges: []wire.AckRange{ // packets 4 and 5 were lost - {First: 6, Last: 9}, - {First: 1, Last: 3}, - }, - } - err := handler.ReceivedAck(&ack, 1, protocol.EncryptionUnencrypted, time.Now()) + ack := createAck([]wire.AckRange{{First: 1, Last: 3}, {First: 6, Last: 9}}) // lose 4 and 5 + err := handler.ReceivedAck(ack, 1, protocol.EncryptionForwardSecure, time.Now()) Expect(err).ToNot(HaveOccurred()) - expectInPacketHistory([]protocol.PacketNumber{0, 4, 5, 10, 12}) + expectInPacketHistory([]protocol.PacketNumber{0, 4, 5}) }) It("does not ack packets below the LowestAcked", func() { - ack := wire.AckFrame{ - LargestAcked: 8, - LowestAcked: 3, - } - err := handler.ReceivedAck(&ack, 1, protocol.EncryptionUnencrypted, time.Now()) + ack := createAck([]wire.AckRange{{First: 3, Last: 8}}) + err := handler.ReceivedAck(ack, 1, protocol.EncryptionForwardSecure, time.Now()) Expect(err).ToNot(HaveOccurred()) - expectInPacketHistory([]protocol.PacketNumber{0, 1, 2, 9, 10, 12}) + expectInPacketHistory([]protocol.PacketNumber{0, 1, 2, 9}) }) It("handles an ACK with multiple missing packet ranges", func() { - ack := wire.AckFrame{ - LargestAcked: 9, - LowestAcked: 1, - AckRanges: []wire.AckRange{ // packets 2, 4 and 5, and 8 were lost - {First: 9, Last: 9}, - {First: 6, Last: 7}, - {First: 3, Last: 3}, - {First: 1, Last: 1}, - }, - } - err := handler.ReceivedAck(&ack, 1, protocol.EncryptionUnencrypted, time.Now()) + ack := createAck([]wire.AckRange{ // packets 2, 4 and 5, and 8 were lost + {First: 9, Last: 9}, + {First: 6, Last: 7}, + {First: 3, Last: 3}, + {First: 1, Last: 1}, + }) + err := handler.ReceivedAck(ack, 1, protocol.EncryptionForwardSecure, time.Now()) Expect(err).ToNot(HaveOccurred()) - expectInPacketHistory([]protocol.PacketNumber{0, 2, 4, 5, 8, 10, 12}) + 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() { - largestObserved := 6 - ack1 := wire.AckFrame{ - LargestAcked: protocol.PacketNumber(largestObserved), - LowestAcked: 1, - AckRanges: []wire.AckRange{ - {First: 4, Last: protocol.PacketNumber(largestObserved)}, - {First: 1, Last: 2}, - }, - } - err := handler.ReceivedAck(&ack1, 1, protocol.EncryptionUnencrypted, time.Now()) + ack1 := createAck([]wire.AckRange{{First: 1, Last: 2}, {First: 4, Last: 6}}) // 3 lost + err := handler.ReceivedAck(ack1, 1, protocol.EncryptionForwardSecure, time.Now()) Expect(err).ToNot(HaveOccurred()) - Expect(handler.bytesInFlight).To(Equal(protocol.ByteCount(len(packets) - 5))) - expectInPacketHistory([]protocol.PacketNumber{0, 3, 7, 8, 9, 10, 12}) - ack2 := wire.AckFrame{ - LargestAcked: protocol.PacketNumber(largestObserved), - LowestAcked: 1, - } - err = handler.ReceivedAck(&ack2, 2, protocol.EncryptionUnencrypted, time.Now()) + expectInPacketHistory([]protocol.PacketNumber{0, 3, 7, 8, 9}) + Expect(handler.bytesInFlight).To(Equal(protocol.ByteCount(5))) + ack2 := createAck([]wire.AckRange{{First: 1, Last: 6}}) // now ack 3 + err = handler.ReceivedAck(ack2, 2, protocol.EncryptionForwardSecure, time.Now()) Expect(err).ToNot(HaveOccurred()) - Expect(handler.bytesInFlight).To(Equal(protocol.ByteCount(len(packets) - 6))) - expectInPacketHistory([]protocol.PacketNumber{0, 7, 8, 9, 10, 12}) + 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{ - LargestAcked: 6, - LowestAcked: 0, - AckRanges: []wire.AckRange{ - {First: 4, Last: 6}, - {First: 0, Last: 2}, - }, - } - err := handler.ReceivedAck(&ack1, 1, protocol.EncryptionUnencrypted, time.Now()) + ack1 := createAck([]wire.AckRange{{First: 0, Last: 2}, {First: 4, Last: 6}}) + err := handler.ReceivedAck(ack1, 1, protocol.EncryptionForwardSecure, time.Now()) Expect(err).ToNot(HaveOccurred()) - Expect(handler.bytesInFlight).To(Equal(protocol.ByteCount(len(packets) - 6))) - expectInPacketHistory([]protocol.PacketNumber{3, 7, 8, 9, 10, 12}) - ack2 := wire.AckFrame{ - LargestAcked: 7, - LowestAcked: 1, - } - err = handler.ReceivedAck(&ack2, 2, protocol.EncryptionUnencrypted, time.Now()) + expectInPacketHistory([]protocol.PacketNumber{3, 7, 8, 9}) + Expect(handler.bytesInFlight).To(Equal(protocol.ByteCount(4))) + ack2 := createAck([]wire.AckRange{{First: 1, Last: 7}}) + err = handler.ReceivedAck(ack2, 2, protocol.EncryptionForwardSecure, time.Now()) Expect(err).ToNot(HaveOccurred()) - Expect(handler.bytesInFlight).To(Equal(protocol.ByteCount(len(packets) - 8))) - expectInPacketHistory([]protocol.PacketNumber{8, 9, 10, 12}) + 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{ - LargestAcked: 6, - LowestAcked: 1, - } - err := handler.ReceivedAck(&ack1, 1, protocol.EncryptionUnencrypted, time.Now()) + ack1 := createAck([]wire.AckRange{{First: 1, Last: 6}}) + err := handler.ReceivedAck(ack1, 1, protocol.EncryptionForwardSecure, time.Now()) Expect(err).ToNot(HaveOccurred()) - expectInPacketHistory([]protocol.PacketNumber{0, 7, 8, 9, 10, 12}) - Expect(handler.bytesInFlight).To(Equal(protocol.ByteCount(len(packets) - 6))) - ack2 := wire.AckFrame{ - LargestAcked: 10, - LowestAcked: 1, - AckRanges: []wire.AckRange{ - {First: 8, Last: 10}, - {First: 3, Last: 3}, - {First: 1, Last: 1}, - }, - } - err = handler.ReceivedAck(&ack2, 2, protocol.EncryptionUnencrypted, time.Now()) + expectInPacketHistory([]protocol.PacketNumber{0, 7, 8, 9}) + Expect(handler.bytesInFlight).To(Equal(protocol.ByteCount(4))) + ack2 := createAck([]wire.AckRange{ + {First: 1, Last: 1}, + {First: 3, Last: 3}, + {First: 8, Last: 8}, + }) + err = handler.ReceivedAck(ack2, 2, protocol.EncryptionForwardSecure, time.Now()) Expect(err).ToNot(HaveOccurred()) - Expect(handler.bytesInFlight).To(Equal(protocol.ByteCount(len(packets) - 6 - 3))) - expectInPacketHistory([]protocol.PacketNumber{0, 7, 12}) + expectInPacketHistory([]protocol.PacketNumber{0, 7, 9}) + Expect(handler.bytesInFlight).To(Equal(protocol.ByteCount(3))) }) }) @@ -459,13 +355,13 @@ var _ = Describe("SentPacketHandler", func() { 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 - err := handler.ReceivedAck(&wire.AckFrame{LargestAcked: 1}, 1, protocol.EncryptionUnencrypted, time.Now()) + err := handler.ReceivedAck(&wire.AckFrame{LargestAcked: 1}, 1, protocol.EncryptionForwardSecure, time.Now()) Expect(err).NotTo(HaveOccurred()) Expect(handler.rttStats.LatestRTT()).To(BeNumerically("~", 10*time.Minute, 1*time.Second)) - err = handler.ReceivedAck(&wire.AckFrame{LargestAcked: 2}, 2, protocol.EncryptionUnencrypted, time.Now()) + err = handler.ReceivedAck(&wire.AckFrame{LargestAcked: 2}, 2, protocol.EncryptionForwardSecure, time.Now()) Expect(err).NotTo(HaveOccurred()) Expect(handler.rttStats.LatestRTT()).To(BeNumerically("~", 5*time.Minute, 1*time.Second)) - err = handler.ReceivedAck(&wire.AckFrame{LargestAcked: 6}, 3, protocol.EncryptionUnencrypted, time.Now()) + err = handler.ReceivedAck(&wire.AckFrame{LargestAcked: 6}, 3, protocol.EncryptionForwardSecure, time.Now()) Expect(err).NotTo(HaveOccurred()) Expect(handler.rttStats.LatestRTT()).To(BeNumerically("~", 1*time.Minute, 1*time.Second)) }) @@ -475,7 +371,7 @@ var _ = Describe("SentPacketHandler", func() { // 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) - err := handler.ReceivedAck(&wire.AckFrame{LargestAcked: 1, DelayTime: 5 * time.Minute}, 1, protocol.EncryptionUnencrypted, time.Now()) + err := handler.ReceivedAck(&wire.AckFrame{LargestAcked: 1, DelayTime: 5 * time.Minute}, 1, protocol.EncryptionForwardSecure, time.Now()) Expect(err).NotTo(HaveOccurred()) Expect(handler.rttStats.LatestRTT()).To(BeNumerically("~", 5*time.Minute, 1*time.Second)) }) @@ -494,25 +390,25 @@ var _ = Describe("SentPacketHandler", func() { }) It("determines which ACK we have received an ACK for", func() { - err := handler.ReceivedAck(&wire.AckFrame{LargestAcked: 15, LowestAcked: 12}, 1, protocol.EncryptionUnencrypted, time.Now()) + err := handler.ReceivedAck(createAck([]wire.AckRange{{First: 13, Last: 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() { - err := handler.ReceivedAck(&wire.AckFrame{LargestAcked: 13, LowestAcked: 13}, 1, protocol.EncryptionUnencrypted, time.Now()) + err := handler.ReceivedAck(createAck([]wire.AckRange{{First: 13, Last: 13}}), 1, protocol.EncryptionForwardSecure, time.Now()) Expect(err).ToNot(HaveOccurred()) Expect(handler.GetLowestPacketNotConfirmedAcked()).To(Equal(protocol.PacketNumber(101))) - err = handler.ReceivedAck(&wire.AckFrame{LargestAcked: 15, LowestAcked: 15}, 2, protocol.EncryptionUnencrypted, time.Now()) + err = handler.ReceivedAck(createAck([]wire.AckRange{{First: 15, Last: 15}}), 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{LargestAcked: 14, LowestAcked: 14}, 1, protocol.EncryptionUnencrypted, time.Now()) + err := handler.ReceivedAck(createAck([]wire.AckRange{{First: 14, Last: 14}}), 1, protocol.EncryptionForwardSecure, time.Now()) Expect(err).ToNot(HaveOccurred()) Expect(handler.GetLowestPacketNotConfirmedAcked()).To(Equal(protocol.PacketNumber(201))) - err = handler.ReceivedAck(&wire.AckFrame{LargestAcked: 13, LowestAcked: 13}, 2, protocol.EncryptionUnencrypted, time.Now()) + err = handler.ReceivedAck(createAck([]wire.AckRange{{First: 13, Last: 13}}), 2, protocol.EncryptionForwardSecure, time.Now()) Expect(err).ToNot(HaveOccurred()) Expect(handler.GetLowestPacketNotConfirmedAcked()).To(Equal(protocol.PacketNumber(201))) }) @@ -520,107 +416,30 @@ var _ = Describe("SentPacketHandler", func() { }) Context("Retransmission handling", func() { - var packets []*Packet - - BeforeEach(func() { - packets = []*Packet{ - {PacketNumber: 1, Frames: []wire.Frame{&streamFrame}, Length: 1, EncryptionLevel: protocol.EncryptionUnencrypted}, - {PacketNumber: 2, Frames: []wire.Frame{&streamFrame}, Length: 1, EncryptionLevel: protocol.EncryptionUnencrypted}, - {PacketNumber: 3, Frames: []wire.Frame{&streamFrame}, Length: 1, EncryptionLevel: protocol.EncryptionUnencrypted}, - {PacketNumber: 4, Frames: []wire.Frame{&streamFrame}, Length: 1, EncryptionLevel: protocol.EncryptionSecure}, - {PacketNumber: 5, Frames: []wire.Frame{&streamFrame}, Length: 1, EncryptionLevel: protocol.EncryptionSecure}, - {PacketNumber: 6, Frames: []wire.Frame{&streamFrame}, Length: 1, EncryptionLevel: protocol.EncryptionForwardSecure}, - {PacketNumber: 7, Frames: []wire.Frame{&streamFrame}, Length: 1, EncryptionLevel: protocol.EncryptionForwardSecure}, - } - for _, packet := range packets { - handler.SentPacket(packet) - } - // Increase RTT, because the tests would be flaky otherwise - handler.rttStats.UpdateRTT(time.Minute, 0, time.Now()) - // Ack a single packet so that we have non-RTO timings - handler.ReceivedAck(&wire.AckFrame{LargestAcked: 2, LowestAcked: 2}, 1, protocol.EncryptionForwardSecure, time.Now()) - Expect(handler.bytesInFlight).To(Equal(protocol.ByteCount(6))) - }) - It("does not dequeue a packet if no ack has been received", func() { - Expect(handler.DequeuePacketForRetransmission()).To(BeNil()) - }) - - It("dequeues a packet for retransmission", func() { - getPacket(1).sendTime = time.Now().Add(-time.Hour) - handler.OnAlarm() - Expect(getPacket(1)).To(BeNil()) - Expect(handler.retransmissionQueue).To(HaveLen(1)) - Expect(handler.retransmissionQueue[0].PacketNumber).To(Equal(protocol.PacketNumber(1))) - packet := handler.DequeuePacketForRetransmission() - Expect(packet).ToNot(BeNil()) - Expect(packet.PacketNumber).To(Equal(protocol.PacketNumber(1))) - Expect(handler.DequeuePacketForRetransmission()).To(BeNil()) - }) - - It("deletes non forward-secure packets when the handshake completes", func() { - for i := protocol.PacketNumber(1); i <= 7; i++ { - if i == 2 { // packet 2 was already acked in BeforeEach - continue - } - handler.queuePacketForRetransmission(getPacket(i)) - } - Expect(handler.retransmissionQueue).To(HaveLen(6)) - handler.SetHandshakeComplete() - packet := handler.DequeuePacketForRetransmission() - Expect(packet).ToNot(BeNil()) - Expect(packet.PacketNumber).To(Equal(protocol.PacketNumber(6))) - packet = handler.DequeuePacketForRetransmission() - Expect(packet).ToNot(BeNil()) - Expect(packet.PacketNumber).To(Equal(protocol.PacketNumber(7))) + handler.SentPacket(retransmittablePacket(1)) Expect(handler.DequeuePacketForRetransmission()).To(BeNil()) }) Context("STOP_WAITINGs", func() { It("gets a STOP_WAITING frame", func() { - ack := wire.AckFrame{LargestAcked: 5, LowestAcked: 5} + handler.SentPacket(retransmittablePacket(1)) + handler.SentPacket(retransmittablePacket(2)) + handler.SentPacket(retransmittablePacket(3)) + ack := wire.AckFrame{LargestAcked: 3, LowestAcked: 3} err := handler.ReceivedAck(&ack, 2, protocol.EncryptionForwardSecure, time.Now()) Expect(err).ToNot(HaveOccurred()) - Expect(handler.GetStopWaitingFrame(false)).To(Equal(&wire.StopWaitingFrame{LeastUnacked: 6})) + Expect(handler.GetStopWaitingFrame(false)).To(Equal(&wire.StopWaitingFrame{LeastUnacked: 4})) }) It("gets a STOP_WAITING frame after queueing a retransmission", func() { + handler.SentPacket(retransmittablePacket(5)) handler.queuePacketForRetransmission(getPacket(5)) Expect(handler.GetStopWaitingFrame(false)).To(Equal(&wire.StopWaitingFrame{LeastUnacked: 6})) }) }) }) - It("calculates bytes in flight", func() { - packet1 := Packet{PacketNumber: 1, Frames: []wire.Frame{&streamFrame}, Length: 1} - packet2 := Packet{PacketNumber: 2, Frames: []wire.Frame{&streamFrame}, Length: 2} - packet3 := Packet{PacketNumber: 3, Frames: []wire.Frame{&streamFrame}, Length: 3} - handler.SentPacket(&packet1) - Expect(handler.bytesInFlight).To(Equal(protocol.ByteCount(1))) - handler.SentPacket(&packet2) - Expect(handler.bytesInFlight).To(Equal(protocol.ByteCount(1 + 2))) - handler.SentPacket(&packet3) - Expect(handler.bytesInFlight).To(Equal(protocol.ByteCount(1 + 2 + 3))) - - // Increase RTT, because the tests would be flaky otherwise - handler.rttStats.UpdateRTT(time.Minute, 0, time.Now()) - - // ACK 1 and 3, NACK 2 - ack := wire.AckFrame{ - LargestAcked: 3, - LowestAcked: 1, - AckRanges: []wire.AckRange{ - {First: 3, Last: 3}, - {First: 1, Last: 1}, - }, - } - handler.ReceivedAck(&ack, 1, protocol.EncryptionUnencrypted, time.Now()) - Expect(handler.bytesInFlight).To(Equal(protocol.ByteCount(2))) - getPacket(2).sendTime = time.Now().Add(-time.Hour) - handler.OnAlarm() - Expect(handler.bytesInFlight).To(Equal(protocol.ByteCount(0))) - }) - Context("congestion", func() { var cong *mocks.MockSendAlgorithm @@ -743,7 +562,7 @@ var _ = Describe("SentPacketHandler", func() { }) }) - Context("calculating RTO", func() { + Context("RTOs", func() { It("uses default RTO", func() { Expect(handler.computeRTOTimeout()).To(Equal(defaultRTOTimeout)) }) @@ -775,83 +594,7 @@ var _ = Describe("SentPacketHandler", func() { handler.rtoCount = 2 Expect(handler.computeRTOTimeout()).To(Equal(4 * defaultRTOTimeout)) }) - }) - Context("Delay-based loss detection", func() { - It("detects a packet as lost", func() { - handler.SentPacket(retransmittablePacket(1)) - handler.SentPacket(retransmittablePacket(2)) - Expect(handler.lossTime.IsZero()).To(BeTrue()) - - err := handler.ReceivedAck(&wire.AckFrame{LargestAcked: 2, LowestAcked: 2}, 1, protocol.EncryptionForwardSecure, time.Now().Add(time.Hour)) - Expect(err).NotTo(HaveOccurred()) - Expect(handler.lossTime.IsZero()).To(BeFalse()) - - // RTT is around 1h now. - // The formula is (1+1/8) * RTT, so this should be around that number - Expect(time.Until(handler.lossTime)).To(BeNumerically("~", time.Hour*9/8, time.Minute)) - Expect(time.Until(handler.GetAlarmTimeout())).To(BeNumerically("~", time.Hour*9/8, time.Minute)) - - getPacket(1).sendTime = time.Now().Add(-2 * time.Hour) - handler.OnAlarm() - Expect(handler.DequeuePacketForRetransmission()).NotTo(BeNil()) - }) - - It("does not detect packets as lost without ACKs", func() { - handler.SentPacket(nonRetransmittablePacket(1)) - handler.SentPacket(retransmittablePacket(2)) - handler.SentPacket(retransmittablePacket(3)) - Expect(handler.lossTime.IsZero()).To(BeTrue()) - - now := time.Now().Add(time.Hour) - err := handler.ReceivedAck(&wire.AckFrame{LargestAcked: 1, LowestAcked: 1}, 1, protocol.EncryptionUnencrypted, now) - Expect(err).NotTo(HaveOccurred()) - Expect(handler.lossTime.IsZero()).To(BeTrue()) - Expect(handler.GetAlarmTimeout().Sub(now)).To(BeNumerically("~", handler.computeRTOTimeout(), time.Minute)) - - // This means RTO, so both packets should be lost - handler.OnAlarm() - Expect(handler.DequeuePacketForRetransmission()).ToNot(BeNil()) - Expect(handler.DequeuePacketForRetransmission()).ToNot(BeNil()) - Expect(handler.DequeuePacketForRetransmission()).To(BeNil()) - }) - }) - - Context("retransmission for handshake packets", func() { - BeforeEach(func() { - handler.handshakeComplete = false - }) - - It("detects the handshake timeout", func() { - // send handshake packets: 1, 2, 4 - // send a forward-secure packet: 3 - handler.SentPacket(handshakePacket(1)) - handler.SentPacket(handshakePacket(2)) - handler.SentPacket(retransmittablePacket(3)) - handler.SentPacket(handshakePacket(4)) - - err := handler.ReceivedAck(&wire.AckFrame{LargestAcked: 1, LowestAcked: 1}, 1, protocol.EncryptionSecure, time.Now()) - Expect(err).NotTo(HaveOccurred()) - Expect(handler.lossTime.IsZero()).To(BeTrue()) - handshakeTimeout := handler.computeHandshakeTimeout() - Expect(time.Until(handler.GetAlarmTimeout())).To(BeNumerically("~", handshakeTimeout, time.Minute)) - - handler.OnAlarm() - p := handler.DequeuePacketForRetransmission() - Expect(p).ToNot(BeNil()) - Expect(p.PacketNumber).To(Equal(protocol.PacketNumber(2))) - p = handler.DequeuePacketForRetransmission() - Expect(p).ToNot(BeNil()) - Expect(p.PacketNumber).To(Equal(protocol.PacketNumber(4))) - Expect(handler.packetHistory.Len()).To(Equal(1)) - Expect(getPacket(3)).ToNot(BeNil()) - Expect(handler.handshakeCount).To(BeEquivalentTo(1)) - // make sure the exponential backoff is used - Expect(handler.computeHandshakeTimeout()).To(BeNumerically("~", 2*handshakeTimeout, time.Minute)) - }) - }) - - Context("RTO retransmission", func() { It("queues two packets if RTO expires", func() { handler.SentPacket(retransmittablePacket(1)) handler.SentPacket(retransmittablePacket(2)) @@ -871,4 +614,106 @@ var _ = Describe("SentPacketHandler", func() { Expect(handler.rtoCount).To(BeEquivalentTo(1)) }) }) + + Context("Delay-based loss detection", func() { + It("immediately detects old packets as lost when receiving an ACK", func() { + now := time.Now() + handler.SentPacket(retransmittablePacket(1)) + getPacket(1).sendTime = now.Add(-time.Hour) + handler.SentPacket(retransmittablePacket(2)) + getPacket(2).sendTime = now.Add(-time.Second) + Expect(handler.lossTime.IsZero()).To(BeTrue()) + + err := handler.ReceivedAck(&wire.AckFrame{LargestAcked: 2, LowestAcked: 2}, 1, protocol.EncryptionForwardSecure, now) + Expect(err).NotTo(HaveOccurred()) + Expect(handler.DequeuePacketForRetransmission()).ToNot(BeNil()) + // no need to set an alarm, since packet 1 was already declared lost + Expect(handler.lossTime.IsZero()).To(BeTrue()) + }) + + It("sets the early retransmit alarm", func() { + now := time.Now() + handler.SentPacket(retransmittablePacket(1)) + getPacket(1).sendTime = now.Add(-2 * time.Second) + handler.SentPacket(retransmittablePacket(2)) + getPacket(2).sendTime = now.Add(-2 * time.Second) + handler.SentPacket(retransmittablePacket(3)) + getPacket(3).sendTime = now.Add(-time.Second) + Expect(handler.lossTime.IsZero()).To(BeTrue()) + + err := handler.ReceivedAck(&wire.AckFrame{LargestAcked: 2, LowestAcked: 2}, 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)) + // Expect(time.Until(handler.GetAlarmTimeout())).To(BeNumerically("~", time.Hour*9/8, time.Minute)) + + handler.OnAlarm() + 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() { + // send handshake packets: 1, 2, 4 + // send a forward-secure packet: 3 + handler.SentPacket(handshakePacket(1)) + handler.SentPacket(handshakePacket(2)) + handler.SentPacket(retransmittablePacket(3)) + handler.SentPacket(handshakePacket(4)) + + err := handler.ReceivedAck(createAck([]wire.AckRange{{First: 1, Last: 1}}), 1, protocol.EncryptionForwardSecure, time.Now()) + Expect(err).NotTo(HaveOccurred()) + Expect(handler.lossTime.IsZero()).To(BeTrue()) + handshakeTimeout := handler.computeHandshakeTimeout() + Expect(time.Until(handler.GetAlarmTimeout())).To(BeNumerically("~", handshakeTimeout, time.Minute)) + + handler.OnAlarm() + p := handler.DequeuePacketForRetransmission() + Expect(p).ToNot(BeNil()) + Expect(p.PacketNumber).To(Equal(protocol.PacketNumber(2))) + p = handler.DequeuePacketForRetransmission() + Expect(p).ToNot(BeNil()) + Expect(p.PacketNumber).To(Equal(protocol.PacketNumber(4))) + Expect(handler.packetHistory.Len()).To(Equal(1)) + Expect(getPacket(3)).ToNot(BeNil()) + Expect(handler.handshakeCount).To(BeEquivalentTo(1)) + // make sure the exponential backoff is used + Expect(handler.computeHandshakeTimeout()).To(BeNumerically("~", 2*handshakeTimeout, 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 := createAck([]wire.AckRange{{First: 13, Last: 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(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()) + }) + }) })