package ackhandler import ( "github.com/lucas-clemente/quic-go/frames" "github.com/lucas-clemente/quic-go/protocol" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" ) var _ = Describe("SentPacketHandler", func() { var handler *sentPacketHandler var streamFrame frames.StreamFrame BeforeEach(func() { handler = NewSentPacketHandler().(*sentPacketHandler) streamFrame = frames.StreamFrame{ StreamID: 5, Data: []byte{0x13, 0x37}, } }) Context("SentPacket", func() { It("accepts two consecutive packets", func() { entropy := EntropyAccumulator(0) packet1 := Packet{PacketNumber: 1, Frames: []frames.Frame{&streamFrame}, EntropyBit: true} packet2 := Packet{PacketNumber: 2, Frames: []frames.Frame{&streamFrame}, EntropyBit: true} err := handler.SentPacket(&packet1) Expect(err).ToNot(HaveOccurred()) err = handler.SentPacket(&packet2) Expect(err).ToNot(HaveOccurred()) Expect(handler.lastSentPacketNumber).To(Equal(protocol.PacketNumber(2))) Expect(handler.packetHistory).To(HaveKey(protocol.PacketNumber(1))) Expect(handler.packetHistory).To(HaveKey(protocol.PacketNumber(2))) entropy.Add(packet1.PacketNumber, packet1.EntropyBit) Expect(handler.packetHistory[1].PacketNumber).To(Equal(protocol.PacketNumber(1))) Expect(handler.packetHistory[1].Entropy).To(Equal(entropy)) entropy.Add(packet2.PacketNumber, packet2.EntropyBit) Expect(handler.packetHistory[2].PacketNumber).To(Equal(protocol.PacketNumber(2))) Expect(handler.packetHistory[2].Entropy).To(Equal(entropy)) }) It("rejects packets with the same packet number", func() { packet1 := Packet{PacketNumber: 1, Frames: []frames.Frame{&streamFrame}, EntropyBit: true} packet2 := Packet{PacketNumber: 1, Frames: []frames.Frame{&streamFrame}, EntropyBit: false} err := handler.SentPacket(&packet1) Expect(err).ToNot(HaveOccurred()) err = handler.SentPacket(&packet2) Expect(err).To(HaveOccurred()) Expect(handler.lastSentPacketNumber).To(Equal(protocol.PacketNumber(1))) Expect(handler.packetHistory).To(HaveKey(protocol.PacketNumber(1))) }) It("rejects non-consecutive packets", func() { packet1 := Packet{PacketNumber: 1, Frames: []frames.Frame{&streamFrame}, EntropyBit: true} packet2 := Packet{PacketNumber: 3, Frames: []frames.Frame{&streamFrame}, EntropyBit: false} err := handler.SentPacket(&packet1) Expect(err).ToNot(HaveOccurred()) err = handler.SentPacket(&packet2) Expect(err).To(HaveOccurred()) Expect(handler.lastSentPacketNumber).To(Equal(protocol.PacketNumber(1))) Expect(handler.packetHistory).To(HaveKey(protocol.PacketNumber(1))) Expect(handler.packetHistory).ToNot(HaveKey(protocol.PacketNumber(2))) Expect(handler.packetHistory).ToNot(HaveKey(protocol.PacketNumber(2))) }) It("correctly calculates the entropy, even if the last packet has already been ACKed", func() { packet1 := Packet{PacketNumber: 1, Frames: []frames.Frame{&streamFrame}, EntropyBit: true} packet2 := Packet{PacketNumber: 2, Frames: []frames.Frame{&streamFrame}, EntropyBit: true} err := handler.SentPacket(&packet1) Expect(err).ToNot(HaveOccurred()) entropy := EntropyAccumulator(0) entropy.Add(packet1.PacketNumber, packet1.EntropyBit) ack := frames.AckFrame{ LargestObserved: 1, Entropy: byte(entropy), } err = handler.ReceivedAck(&ack) Expect(err).ToNot(HaveOccurred()) err = handler.SentPacket(&packet2) Expect(err).ToNot(HaveOccurred()) Expect(handler.lastSentPacketNumber).To(Equal(protocol.PacketNumber(2))) entropy.Add(packet2.PacketNumber, packet2.EntropyBit) Expect(handler.packetHistory[2].Entropy).To(Equal(entropy)) }) }) Context("ACK entropy calculations", func() { var packets []*Packet var entropy EntropyAccumulator BeforeEach(func() { entropy = EntropyAccumulator(0) packets = []*Packet{ &Packet{PacketNumber: 1, Frames: []frames.Frame{&streamFrame}, EntropyBit: true}, &Packet{PacketNumber: 2, Frames: []frames.Frame{&streamFrame}, EntropyBit: true}, &Packet{PacketNumber: 3, Frames: []frames.Frame{&streamFrame}, EntropyBit: true}, &Packet{PacketNumber: 4, Frames: []frames.Frame{&streamFrame}, EntropyBit: true}, &Packet{PacketNumber: 5, Frames: []frames.Frame{&streamFrame}, EntropyBit: true}, &Packet{PacketNumber: 6, Frames: []frames.Frame{&streamFrame}, EntropyBit: true}, } for _, packet := range packets { handler.SentPacket(packet) } }) It("no NACK ranges", func() { largestObserved := 5 for i := 0; i < largestObserved; i++ { entropy.Add(packets[i].PacketNumber, packets[i].EntropyBit) } ack := frames.AckFrame{LargestObserved: protocol.PacketNumber(largestObserved)} calculatedEntropy, err := handler.calculateExpectedEntropy(&ack) Expect(err).ToNot(HaveOccurred()) Expect(calculatedEntropy).To(Equal(entropy)) }) It("one NACK ranges", func() { largestObserved := 5 for i := 0; i < largestObserved; i++ { if i == 2 || i == 3 { // skip Packet 3 and 4 continue } entropy.Add(packets[i].PacketNumber, packets[i].EntropyBit) } ack := frames.AckFrame{ LargestObserved: protocol.PacketNumber(largestObserved), NackRanges: []frames.NackRange{frames.NackRange{FirstPacketNumber: 3, LastPacketNumber: 4}}, } calculatedEntropy, err := handler.calculateExpectedEntropy(&ack) Expect(err).ToNot(HaveOccurred()) Expect(calculatedEntropy).To(Equal(entropy)) }) It("one NACK ranges, when some packages have already been ACKed", func() { largestObserved := 6 for i := 0; i < largestObserved; i++ { if i == 2 || i == 3 { // skip Packet 3 and 4 continue } entropy.Add(packets[i].PacketNumber, packets[i].EntropyBit) } handler.ackPacket(1) handler.ackPacket(2) handler.ackPacket(5) ack := frames.AckFrame{ LargestObserved: protocol.PacketNumber(largestObserved), NackRanges: []frames.NackRange{frames.NackRange{FirstPacketNumber: 3, LastPacketNumber: 4}}, } calculatedEntropy, err := handler.calculateExpectedEntropy(&ack) Expect(err).ToNot(HaveOccurred()) Expect(calculatedEntropy).To(Equal(entropy)) }) It("multiple NACK ranges", func() { largestObserved := 5 for i := 0; i < largestObserved; i++ { if i == 1 || i == 3 { // skip Packet 2 and 4 continue } entropy.Add(packets[i].PacketNumber, packets[i].EntropyBit) } ack := frames.AckFrame{ LargestObserved: protocol.PacketNumber(largestObserved), NackRanges: []frames.NackRange{ frames.NackRange{FirstPacketNumber: 4, LastPacketNumber: 4}, frames.NackRange{FirstPacketNumber: 2, LastPacketNumber: 2}, }, } calculatedEntropy, err := handler.calculateExpectedEntropy(&ack) Expect(err).ToNot(HaveOccurred()) Expect(calculatedEntropy).To(Equal(entropy)) }) It("actually rejects an ACK with the wrong entropy", func() { ack := frames.AckFrame{ LargestObserved: 4, Entropy: 1, } err := handler.ReceivedAck(&ack) Expect(err).To(HaveOccurred()) Expect(err).To(Equal(ErrEntropy)) }) It("completely processes an ACK without a NACK range", func() { entropy := EntropyAccumulator(0) largestObserved := 4 for i := 0; i < largestObserved; i++ { entropy.Add(packets[i].PacketNumber, packets[i].EntropyBit) } ack := frames.AckFrame{ LargestObserved: protocol.PacketNumber(largestObserved), Entropy: byte(entropy), } err := handler.ReceivedAck(&ack) Expect(err).ToNot(HaveOccurred()) Expect(handler.LargestObserved).To(Equal(protocol.PacketNumber(largestObserved))) Expect(handler.highestInOrderAckedPacketNumber).To(Equal(protocol.PacketNumber(largestObserved))) Expect(handler.packetHistory).ToNot(HaveKey(protocol.PacketNumber(largestObserved - 1))) Expect(handler.packetHistory).To(HaveKey(protocol.PacketNumber(largestObserved + 1))) }) It("completely processes an ACK with a NACK range", func() { entropy := EntropyAccumulator(0) largestObserved := 6 for i := 0; i < largestObserved; i++ { if i == 2 || i == 4 { // Packet Number 3 and 5 missing continue } entropy.Add(packets[i].PacketNumber, packets[i].EntropyBit) } ack := frames.AckFrame{ LargestObserved: protocol.PacketNumber(largestObserved), Entropy: byte(entropy), NackRanges: []frames.NackRange{ frames.NackRange{FirstPacketNumber: 5, LastPacketNumber: 5}, frames.NackRange{FirstPacketNumber: 3, LastPacketNumber: 3}, }, } err := handler.ReceivedAck(&ack) Expect(err).ToNot(HaveOccurred()) Expect(handler.LargestObserved).To(Equal(protocol.PacketNumber(largestObserved))) Expect(handler.highestInOrderAckedPacketNumber).To(Equal(protocol.PacketNumber(2))) Expect(handler.packetHistory).ToNot(HaveKey(protocol.PacketNumber(2))) Expect(handler.packetHistory).To(HaveKey(protocol.PacketNumber(3))) Expect(handler.packetHistory).ToNot(HaveKey(protocol.PacketNumber(4))) Expect(handler.packetHistory).To(HaveKey(protocol.PacketNumber(5))) Expect(handler.packetHistory).ToNot(HaveKey(protocol.PacketNumber(6))) }) }) Context("ACK processing", func() { // in all these tests, the EntropyBit of each Packet is set to false, so that the resulting EntropyByte will always be 0 var packets []*Packet BeforeEach(func() { packets = []*Packet{ &Packet{PacketNumber: 1, Frames: []frames.Frame{&streamFrame}, EntropyBit: false}, &Packet{PacketNumber: 2, Frames: []frames.Frame{&streamFrame}, EntropyBit: false}, &Packet{PacketNumber: 3, Frames: []frames.Frame{&streamFrame}, EntropyBit: false}, &Packet{PacketNumber: 4, Frames: []frames.Frame{&streamFrame}, EntropyBit: false}, &Packet{PacketNumber: 5, Frames: []frames.Frame{&streamFrame}, EntropyBit: false}, &Packet{PacketNumber: 6, Frames: []frames.Frame{&streamFrame}, EntropyBit: false}, } for _, packet := range packets { handler.SentPacket(packet) } }) Context("ACK validation", func() { It("rejects duplicate ACKs", func() { largestObserved := 3 ack := frames.AckFrame{ LargestObserved: protocol.PacketNumber(largestObserved), } err := handler.ReceivedAck(&ack) Expect(err).ToNot(HaveOccurred()) err = handler.ReceivedAck(&ack) Expect(err).To(HaveOccurred()) Expect(err).To(Equal(ErrDuplicateOrOutOfOrderAck)) }) It("rejects out of order ACKs", func() { largestObserved := 3 ack := frames.AckFrame{ LargestObserved: protocol.PacketNumber(largestObserved), } err := handler.ReceivedAck(&ack) Expect(err).ToNot(HaveOccurred()) ack.LargestObserved-- err = handler.ReceivedAck(&ack) Expect(err).To(HaveOccurred()) Expect(err).To(Equal(ErrDuplicateOrOutOfOrderAck)) Expect(handler.LargestObserved).To(Equal(protocol.PacketNumber(largestObserved))) }) It("rejects ACKs with a too high LargestObserved packet number", func() { ack := frames.AckFrame{ LargestObserved: packets[len(packets)-1].PacketNumber + 1337, } err := handler.ReceivedAck(&ack) Expect(err).To(HaveOccurred()) Expect(err).To(Equal(errAckForUnsentPacket)) Expect(handler.highestInOrderAckedPacketNumber).To(Equal(protocol.PacketNumber(0))) }) }) }) Context("Retransmission handler", func() { var packets []*Packet BeforeEach(func() { retransmissionThreshold = 1 packets = []*Packet{ &Packet{PacketNumber: 1, Frames: []frames.Frame{&streamFrame}, EntropyBit: false}, &Packet{PacketNumber: 2, Frames: []frames.Frame{&streamFrame}, EntropyBit: false}, &Packet{PacketNumber: 3, Frames: []frames.Frame{&streamFrame}, EntropyBit: false}, &Packet{PacketNumber: 4, Frames: []frames.Frame{&streamFrame}, EntropyBit: false}, &Packet{PacketNumber: 5, Frames: []frames.Frame{&streamFrame}, EntropyBit: false}, &Packet{PacketNumber: 6, Frames: []frames.Frame{&streamFrame}, EntropyBit: false}, } for _, packet := range packets { handler.SentPacket(packet) } }) It("queues a packet for retransmission", func() { handler.nackPacket(2) handler.nackPacket(2) Expect(len(handler.retransmissionQueue)).To(Equal(1)) Expect(handler.retransmissionQueue[0].PacketNumber).To(Equal(protocol.PacketNumber(2))) }) It("dequeues a packet for retransmission", func() { handler.nackPacket(3) handler.nackPacket(3) packet := handler.DequeuePacketForRetransmission() Expect(packet.PacketNumber).To(Equal(protocol.PacketNumber(3))) Expect(handler.DequeuePacketForRetransmission()).To(BeNil()) }) It("keeps the packets in the right order", func() { handler.nackPacket(2) handler.nackPacket(2) handler.nackPacket(4) handler.nackPacket(4) packet := handler.DequeuePacketForRetransmission() Expect(packet.PacketNumber).To(Equal(protocol.PacketNumber(2))) packet = handler.DequeuePacketForRetransmission() Expect(packet.PacketNumber).To(Equal(protocol.PacketNumber(4))) }) It("only queues each packet once, regardless of the number of NACKs", func() { handler.nackPacket(2) handler.nackPacket(2) handler.nackPacket(4) handler.nackPacket(4) handler.nackPacket(2) handler.nackPacket(2) _ = handler.DequeuePacketForRetransmission() _ = handler.DequeuePacketForRetransmission() Expect(handler.DequeuePacketForRetransmission()).To(BeNil()) }) It("does not change the highestInOrderAckedPacketNumber after queueing a retransmission", func() { ack := frames.AckFrame{ LargestObserved: 4, NackRanges: []frames.NackRange{frames.NackRange{FirstPacketNumber: 3, LastPacketNumber: 3}}, } err := handler.ReceivedAck(&ack) Expect(err).ToNot(HaveOccurred()) Expect(handler.highestInOrderAckedPacketNumber).To(Equal(protocol.PacketNumber(2))) handler.nackPacket(3) // this is the second NACK for this packet Expect(handler.highestInOrderAckedPacketNumber).To(Equal(protocol.PacketNumber(2))) }) }) })