github.com/apernet/quic-go@v0.43.1-0.20240515053213-5e9e635fd9f0/internal/ackhandler/received_packet_tracker_test.go (about)

     1  package ackhandler
     2  
     3  import (
     4  	"time"
     5  
     6  	"github.com/apernet/quic-go/internal/protocol"
     7  	"github.com/apernet/quic-go/internal/utils"
     8  	"github.com/apernet/quic-go/internal/wire"
     9  
    10  	. "github.com/onsi/ginkgo/v2"
    11  	. "github.com/onsi/gomega"
    12  )
    13  
    14  var _ = Describe("Received Packet Tracker", func() {
    15  	var tracker *receivedPacketTracker
    16  
    17  	BeforeEach(func() {
    18  		tracker = newReceivedPacketTracker()
    19  	})
    20  
    21  	It("acknowledges packets", func() {
    22  		t := time.Now().Add(-10 * time.Second)
    23  		Expect(tracker.ReceivedPacket(protocol.PacketNumber(3), protocol.ECNNon, t, true)).To(Succeed())
    24  		ack := tracker.GetAckFrame()
    25  		Expect(ack).ToNot(BeNil())
    26  		Expect(ack.AckRanges).To(Equal([]wire.AckRange{{Smallest: 3, Largest: 3}}))
    27  		Expect(ack.DelayTime).To(BeZero())
    28  		// now receive another packet
    29  		Expect(tracker.ReceivedPacket(protocol.PacketNumber(4), protocol.ECNNon, t.Add(time.Second), true)).To(Succeed())
    30  		ack = tracker.GetAckFrame()
    31  		Expect(ack).ToNot(BeNil())
    32  		Expect(ack.AckRanges).To(Equal([]wire.AckRange{{Smallest: 3, Largest: 4}}))
    33  		Expect(ack.DelayTime).To(BeZero())
    34  	})
    35  
    36  	It("also acknowledges delayed packets", func() {
    37  		t := time.Now().Add(-10 * time.Second)
    38  		Expect(tracker.ReceivedPacket(protocol.PacketNumber(3), protocol.ECNNon, t, true)).To(Succeed())
    39  		ack := tracker.GetAckFrame()
    40  		Expect(ack).ToNot(BeNil())
    41  		Expect(ack.LargestAcked()).To(Equal(protocol.PacketNumber(3)))
    42  		Expect(ack.LowestAcked()).To(Equal(protocol.PacketNumber(3)))
    43  		Expect(ack.DelayTime).To(BeZero())
    44  		// now receive another packet
    45  		Expect(tracker.ReceivedPacket(protocol.PacketNumber(1), protocol.ECNNon, t.Add(time.Second), true)).To(Succeed())
    46  		ack = tracker.GetAckFrame()
    47  		Expect(ack).ToNot(BeNil())
    48  		Expect(ack.AckRanges).To(HaveLen(2))
    49  		Expect(ack.AckRanges).To(ContainElement(wire.AckRange{Smallest: 1, Largest: 1}))
    50  		Expect(ack.AckRanges).To(ContainElement(wire.AckRange{Smallest: 3, Largest: 3}))
    51  		Expect(ack.DelayTime).To(BeZero())
    52  	})
    53  
    54  	It("doesn't trigger ACKs for non-ack-eliciting packets", func() {
    55  		t := time.Now().Add(-10 * time.Second)
    56  		Expect(tracker.ReceivedPacket(protocol.PacketNumber(3), protocol.ECNNon, t, false)).To(Succeed())
    57  		Expect(tracker.GetAckFrame()).To(BeNil())
    58  		Expect(tracker.ReceivedPacket(protocol.PacketNumber(4), protocol.ECNNon, t.Add(5*time.Second), false)).To(Succeed())
    59  		Expect(tracker.GetAckFrame()).To(BeNil())
    60  		Expect(tracker.ReceivedPacket(protocol.PacketNumber(5), protocol.ECNNon, t.Add(10*time.Second), true)).To(Succeed())
    61  		ack := tracker.GetAckFrame()
    62  		Expect(ack).ToNot(BeNil())
    63  		Expect(ack.AckRanges).To(Equal([]wire.AckRange{{Smallest: 3, Largest: 5}}))
    64  	})
    65  })
    66  
    67  var _ = Describe("Application Data Received Packet Tracker", func() {
    68  	var tracker *appDataReceivedPacketTracker
    69  
    70  	BeforeEach(func() {
    71  		tracker = newAppDataReceivedPacketTracker(utils.DefaultLogger)
    72  	})
    73  
    74  	Context("accepting packets", func() {
    75  		It("saves the time when each packet arrived", func() {
    76  			t := time.Now()
    77  			Expect(tracker.ReceivedPacket(protocol.PacketNumber(3), protocol.ECNNon, t, true)).To(Succeed())
    78  			Expect(tracker.largestObservedRcvdTime).To(Equal(t))
    79  		})
    80  
    81  		It("updates the largestObserved and the largestObservedRcvdTime", func() {
    82  			now := time.Now()
    83  			tracker.largestObserved = 3
    84  			tracker.largestObservedRcvdTime = now.Add(-1 * time.Second)
    85  			Expect(tracker.ReceivedPacket(5, protocol.ECNNon, now, true)).To(Succeed())
    86  			Expect(tracker.largestObserved).To(Equal(protocol.PacketNumber(5)))
    87  			Expect(tracker.largestObservedRcvdTime).To(Equal(now))
    88  		})
    89  
    90  		It("doesn't update the largestObserved and the largestObservedRcvdTime for a belated packet", func() {
    91  			now := time.Now()
    92  			timestamp := now.Add(-1 * time.Second)
    93  			tracker.largestObserved = 5
    94  			tracker.largestObservedRcvdTime = timestamp
    95  			Expect(tracker.ReceivedPacket(4, protocol.ECNNon, now, true)).To(Succeed())
    96  			Expect(tracker.largestObserved).To(Equal(protocol.PacketNumber(5)))
    97  			Expect(tracker.largestObservedRcvdTime).To(Equal(timestamp))
    98  		})
    99  	})
   100  
   101  	Context("ACKs", func() {
   102  		Context("queueing ACKs", func() {
   103  			// receives and gets ACKs for packet numbers 1 to 10 (including)
   104  			receiveAndAck10Packets := func() {
   105  				for i := 1; i <= 10; i++ {
   106  					Expect(tracker.ReceivedPacket(protocol.PacketNumber(i), protocol.ECNNon, time.Time{}, true)).To(Succeed())
   107  				}
   108  				Expect(tracker.GetAckFrame(true)).ToNot(BeNil())
   109  				Expect(tracker.ackQueued).To(BeFalse())
   110  			}
   111  
   112  			It("always queues an ACK for the first packet", func() {
   113  				Expect(tracker.ReceivedPacket(1, protocol.ECNNon, time.Now(), true)).To(Succeed())
   114  				Expect(tracker.ackQueued).To(BeTrue())
   115  				Expect(tracker.GetAlarmTimeout()).To(BeZero())
   116  				Expect(tracker.GetAckFrame(true).DelayTime).To(BeNumerically("~", 0, time.Second))
   117  			})
   118  
   119  			It("works with packet number 0", func() {
   120  				Expect(tracker.ReceivedPacket(0, protocol.ECNNon, time.Now(), true)).To(Succeed())
   121  				Expect(tracker.ackQueued).To(BeTrue())
   122  				Expect(tracker.GetAlarmTimeout()).To(BeZero())
   123  				Expect(tracker.GetAckFrame(true).DelayTime).To(BeNumerically("~", 0, time.Second))
   124  			})
   125  
   126  			It("sets ECN flags", func() {
   127  				Expect(tracker.ReceivedPacket(0, protocol.ECT0, time.Now(), true)).To(Succeed())
   128  				pn := protocol.PacketNumber(1)
   129  				for i := 0; i < 2; i++ {
   130  					Expect(tracker.ReceivedPacket(pn, protocol.ECT1, time.Now(), true)).To(Succeed())
   131  					pn++
   132  				}
   133  				for i := 0; i < 3; i++ {
   134  					Expect(tracker.ReceivedPacket(pn, protocol.ECNCE, time.Now(), true)).To(Succeed())
   135  					pn++
   136  				}
   137  				ack := tracker.GetAckFrame(false)
   138  				Expect(ack.ECT0).To(BeEquivalentTo(1))
   139  				Expect(ack.ECT1).To(BeEquivalentTo(2))
   140  				Expect(ack.ECNCE).To(BeEquivalentTo(3))
   141  			})
   142  
   143  			It("queues an ACK for every second ack-eliciting packet", func() {
   144  				receiveAndAck10Packets()
   145  				p := protocol.PacketNumber(11)
   146  				for i := 0; i <= 20; i++ {
   147  					Expect(tracker.ReceivedPacket(p, protocol.ECNNon, time.Time{}, true)).To(Succeed())
   148  					Expect(tracker.ackQueued).To(BeFalse())
   149  					p++
   150  					Expect(tracker.ReceivedPacket(p, protocol.ECNNon, time.Time{}, true)).To(Succeed())
   151  					Expect(tracker.ackQueued).To(BeTrue())
   152  					p++
   153  					// dequeue the ACK frame
   154  					Expect(tracker.GetAckFrame(true)).ToNot(BeNil())
   155  				}
   156  			})
   157  
   158  			It("resets the counter when a non-queued ACK frame is generated", func() {
   159  				receiveAndAck10Packets()
   160  				rcvTime := time.Now()
   161  				Expect(tracker.ReceivedPacket(11, protocol.ECNNon, rcvTime, true)).To(Succeed())
   162  				Expect(tracker.GetAckFrame(false)).ToNot(BeNil())
   163  				Expect(tracker.ReceivedPacket(12, protocol.ECNNon, rcvTime, true)).To(Succeed())
   164  				Expect(tracker.GetAckFrame(true)).To(BeNil())
   165  				Expect(tracker.ReceivedPacket(13, protocol.ECNNon, rcvTime, true)).To(Succeed())
   166  				Expect(tracker.GetAckFrame(false)).ToNot(BeNil())
   167  			})
   168  
   169  			It("only sets the timer when receiving a ack-eliciting packets", func() {
   170  				receiveAndAck10Packets()
   171  				Expect(tracker.ReceivedPacket(11, protocol.ECNNon, time.Now(), false)).To(Succeed())
   172  				Expect(tracker.ackQueued).To(BeFalse())
   173  				Expect(tracker.GetAlarmTimeout()).To(BeZero())
   174  				rcvTime := time.Now().Add(10 * time.Millisecond)
   175  				Expect(tracker.ReceivedPacket(12, protocol.ECNNon, rcvTime, true)).To(Succeed())
   176  				Expect(tracker.ackQueued).To(BeFalse())
   177  				Expect(tracker.GetAlarmTimeout()).To(Equal(rcvTime.Add(protocol.MaxAckDelay)))
   178  			})
   179  
   180  			It("queues an ACK if the packet was ECN-CE marked", func() {
   181  				receiveAndAck10Packets()
   182  				Expect(tracker.ReceivedPacket(11, protocol.ECNCE, time.Now(), true)).To(Succeed())
   183  				ack := tracker.GetAckFrame(true)
   184  				Expect(ack).ToNot(BeNil())
   185  				Expect(ack.AckRanges).To(HaveLen(1))
   186  				Expect(ack.AckRanges[0].Largest).To(Equal(protocol.PacketNumber(11)))
   187  				Expect(ack.ECNCE).To(BeEquivalentTo(1))
   188  			})
   189  
   190  			It("queues an ACK if it was reported missing before", func() {
   191  				receiveAndAck10Packets()
   192  				Expect(tracker.ReceivedPacket(11, protocol.ECNNon, time.Now(), true)).To(Succeed())
   193  				Expect(tracker.ReceivedPacket(13, protocol.ECNNon, time.Now(), true)).To(Succeed())
   194  				ack := tracker.GetAckFrame(true) // ACK: 1-11 and 13, missing: 12
   195  				Expect(ack).ToNot(BeNil())
   196  				Expect(ack.HasMissingRanges()).To(BeTrue())
   197  				Expect(tracker.ackQueued).To(BeFalse())
   198  				Expect(tracker.ReceivedPacket(12, protocol.ECNNon, time.Now(), true)).To(Succeed())
   199  				Expect(tracker.ackQueued).To(BeTrue())
   200  			})
   201  
   202  			It("doesn't recognize in-order packets as out-of-order after raising the threshold", func() {
   203  				receiveAndAck10Packets()
   204  				Expect(tracker.lastAck.LargestAcked()).To(Equal(protocol.PacketNumber(10)))
   205  				Expect(tracker.ackQueued).To(BeFalse())
   206  				tracker.IgnoreBelow(11)
   207  				Expect(tracker.ReceivedPacket(11, protocol.ECNNon, time.Now(), true)).To(Succeed())
   208  				Expect(tracker.GetAckFrame(true)).To(BeNil())
   209  			})
   210  
   211  			It("recognizes out-of-order packets after raising the threshold", func() {
   212  				receiveAndAck10Packets()
   213  				Expect(tracker.lastAck.LargestAcked()).To(Equal(protocol.PacketNumber(10)))
   214  				Expect(tracker.ackQueued).To(BeFalse())
   215  				tracker.IgnoreBelow(11)
   216  				Expect(tracker.ReceivedPacket(12, protocol.ECNNon, time.Now(), true)).To(Succeed())
   217  				ack := tracker.GetAckFrame(true)
   218  				Expect(ack).ToNot(BeNil())
   219  				Expect(ack.AckRanges).To(Equal([]wire.AckRange{{Smallest: 12, Largest: 12}}))
   220  			})
   221  
   222  			It("doesn't queue an ACK if for non-ack-eliciting packets arriving out-of-order", func() {
   223  				receiveAndAck10Packets()
   224  				Expect(tracker.ReceivedPacket(11, protocol.ECNNon, time.Now(), true)).To(Succeed())
   225  				Expect(tracker.GetAckFrame(true)).To(BeNil())
   226  				Expect(tracker.ReceivedPacket(13, protocol.ECNNon, time.Now(), false)).To(Succeed()) // receive a non-ack-eliciting packet out-of-order
   227  				Expect(tracker.GetAckFrame(true)).To(BeNil())
   228  			})
   229  
   230  			It("doesn't queue an ACK if packets arrive out-of-order, but haven't been acknowledged yet", func() {
   231  				receiveAndAck10Packets()
   232  				Expect(tracker.lastAck).ToNot(BeNil())
   233  				Expect(tracker.ReceivedPacket(12, protocol.ECNNon, time.Now(), false)).To(Succeed())
   234  				Expect(tracker.GetAckFrame(true)).To(BeNil())
   235  				// 11 is received out-of-order, but this hasn't been reported in an ACK frame yet
   236  				Expect(tracker.ReceivedPacket(11, protocol.ECNNon, time.Now(), true)).To(Succeed())
   237  				Expect(tracker.GetAckFrame(true)).To(BeNil())
   238  			})
   239  		})
   240  
   241  		Context("ACK generation", func() {
   242  			It("generates an ACK for an ack-eliciting packet, if no ACK is queued yet", func() {
   243  				Expect(tracker.ReceivedPacket(1, protocol.ECNNon, time.Now(), true)).To(Succeed())
   244  				// The first packet is always acknowledged.
   245  				Expect(tracker.GetAckFrame(true)).ToNot(BeNil())
   246  			})
   247  
   248  			It("doesn't generate ACK for a non-ack-eliciting packet, if no ACK is queued yet", func() {
   249  				Expect(tracker.ReceivedPacket(1, protocol.ECNNon, time.Now(), true)).To(Succeed())
   250  				// The first packet is always acknowledged.
   251  				Expect(tracker.GetAckFrame(true)).ToNot(BeNil())
   252  
   253  				Expect(tracker.ReceivedPacket(2, protocol.ECNNon, time.Now(), false)).To(Succeed())
   254  				Expect(tracker.GetAckFrame(false)).To(BeNil())
   255  				Expect(tracker.ReceivedPacket(3, protocol.ECNNon, time.Now(), true)).To(Succeed())
   256  				ack := tracker.GetAckFrame(false)
   257  				Expect(ack).ToNot(BeNil())
   258  				Expect(ack.LowestAcked()).To(Equal(protocol.PacketNumber(1)))
   259  				Expect(ack.LargestAcked()).To(Equal(protocol.PacketNumber(3)))
   260  			})
   261  
   262  			Context("for queued ACKs", func() {
   263  				BeforeEach(func() {
   264  					tracker.ackQueued = true
   265  				})
   266  
   267  				It("generates a simple ACK frame", func() {
   268  					Expect(tracker.ReceivedPacket(1, protocol.ECNNon, time.Now(), true)).To(Succeed())
   269  					Expect(tracker.ReceivedPacket(2, protocol.ECNNon, time.Now(), true)).To(Succeed())
   270  					ack := tracker.GetAckFrame(true)
   271  					Expect(ack).ToNot(BeNil())
   272  					Expect(ack.LargestAcked()).To(Equal(protocol.PacketNumber(2)))
   273  					Expect(ack.LowestAcked()).To(Equal(protocol.PacketNumber(1)))
   274  					Expect(ack.HasMissingRanges()).To(BeFalse())
   275  				})
   276  
   277  				It("generates an ACK for packet number 0", func() {
   278  					Expect(tracker.ReceivedPacket(0, protocol.ECNNon, time.Now(), true)).To(Succeed())
   279  					ack := tracker.GetAckFrame(true)
   280  					Expect(ack).ToNot(BeNil())
   281  					Expect(ack.LargestAcked()).To(Equal(protocol.PacketNumber(0)))
   282  					Expect(ack.LowestAcked()).To(Equal(protocol.PacketNumber(0)))
   283  					Expect(ack.HasMissingRanges()).To(BeFalse())
   284  				})
   285  
   286  				It("sets the delay time", func() {
   287  					Expect(tracker.ReceivedPacket(1, protocol.ECNNon, time.Now(), true)).To(Succeed())
   288  					Expect(tracker.ReceivedPacket(2, protocol.ECNNon, time.Now().Add(-1337*time.Millisecond), true)).To(Succeed())
   289  					ack := tracker.GetAckFrame(true)
   290  					Expect(ack).ToNot(BeNil())
   291  					Expect(ack.DelayTime).To(BeNumerically("~", 1337*time.Millisecond, 50*time.Millisecond))
   292  				})
   293  
   294  				It("uses a 0 delay time if the delay would be negative", func() {
   295  					Expect(tracker.ReceivedPacket(0, protocol.ECNNon, time.Now().Add(time.Hour), true)).To(Succeed())
   296  					ack := tracker.GetAckFrame(true)
   297  					Expect(ack).ToNot(BeNil())
   298  					Expect(ack.DelayTime).To(BeZero())
   299  				})
   300  
   301  				It("saves the last sent ACK", func() {
   302  					Expect(tracker.ReceivedPacket(1, protocol.ECNNon, time.Now(), true)).To(Succeed())
   303  					ack := tracker.GetAckFrame(true)
   304  					Expect(ack).ToNot(BeNil())
   305  					Expect(tracker.lastAck).To(Equal(ack))
   306  					Expect(tracker.ReceivedPacket(2, protocol.ECNNon, time.Now(), true)).To(Succeed())
   307  					tracker.ackQueued = true
   308  					ack = tracker.GetAckFrame(true)
   309  					Expect(ack).ToNot(BeNil())
   310  					Expect(tracker.lastAck).To(Equal(ack))
   311  				})
   312  
   313  				It("generates an ACK frame with missing packets", func() {
   314  					Expect(tracker.ReceivedPacket(1, protocol.ECNNon, time.Now(), true)).To(Succeed())
   315  					Expect(tracker.ReceivedPacket(4, protocol.ECNNon, time.Now(), true)).To(Succeed())
   316  					ack := tracker.GetAckFrame(true)
   317  					Expect(ack).ToNot(BeNil())
   318  					Expect(ack.LargestAcked()).To(Equal(protocol.PacketNumber(4)))
   319  					Expect(ack.LowestAcked()).To(Equal(protocol.PacketNumber(1)))
   320  					Expect(ack.AckRanges).To(Equal([]wire.AckRange{
   321  						{Smallest: 4, Largest: 4},
   322  						{Smallest: 1, Largest: 1},
   323  					}))
   324  				})
   325  
   326  				It("generates an ACK for packet number 0 and other packets", func() {
   327  					Expect(tracker.ReceivedPacket(0, protocol.ECNNon, time.Now(), true)).To(Succeed())
   328  					Expect(tracker.ReceivedPacket(1, protocol.ECNNon, time.Now(), true)).To(Succeed())
   329  					Expect(tracker.ReceivedPacket(3, protocol.ECNNon, time.Now(), true)).To(Succeed())
   330  					ack := tracker.GetAckFrame(true)
   331  					Expect(ack).ToNot(BeNil())
   332  					Expect(ack.LargestAcked()).To(Equal(protocol.PacketNumber(3)))
   333  					Expect(ack.LowestAcked()).To(Equal(protocol.PacketNumber(0)))
   334  					Expect(ack.AckRanges).To(Equal([]wire.AckRange{
   335  						{Smallest: 3, Largest: 3},
   336  						{Smallest: 0, Largest: 1},
   337  					}))
   338  				})
   339  
   340  				It("errors when called with an old packet", func() {
   341  					tracker.IgnoreBelow(7)
   342  					Expect(tracker.IsPotentiallyDuplicate(4)).To(BeTrue())
   343  					Expect(tracker.ReceivedPacket(4, protocol.ECNNon, time.Now(), true)).To(MatchError("recevedPacketTracker BUG: ReceivedPacket called for old / duplicate packet 4"))
   344  				})
   345  
   346  				It("deletes packets from the packetHistory when a lower limit is set", func() {
   347  					for i := 1; i <= 12; i++ {
   348  						Expect(tracker.ReceivedPacket(protocol.PacketNumber(i), protocol.ECNNon, time.Now(), true)).To(Succeed())
   349  					}
   350  					tracker.IgnoreBelow(7)
   351  					// check that the packets were deleted from the receivedPacketHistory by checking the values in an ACK frame
   352  					ack := tracker.GetAckFrame(true)
   353  					Expect(ack).ToNot(BeNil())
   354  					Expect(ack.LargestAcked()).To(Equal(protocol.PacketNumber(12)))
   355  					Expect(ack.LowestAcked()).To(Equal(protocol.PacketNumber(7)))
   356  					Expect(ack.HasMissingRanges()).To(BeFalse())
   357  				})
   358  
   359  				It("resets all counters needed for the ACK queueing decision when sending an ACK", func() {
   360  					Expect(tracker.ReceivedPacket(1, protocol.ECNNon, time.Now(), true)).To(Succeed())
   361  					tracker.ackAlarm = time.Now().Add(-time.Minute)
   362  					Expect(tracker.GetAckFrame(true)).ToNot(BeNil())
   363  					Expect(tracker.GetAlarmTimeout()).To(BeZero())
   364  					Expect(tracker.ackElicitingPacketsReceivedSinceLastAck).To(BeZero())
   365  					Expect(tracker.ackQueued).To(BeFalse())
   366  				})
   367  
   368  				It("doesn't generate an ACK when none is queued and the timer is not set", func() {
   369  					Expect(tracker.ReceivedPacket(1, protocol.ECNNon, time.Now(), true)).To(Succeed())
   370  					tracker.ackQueued = false
   371  					tracker.ackAlarm = time.Time{}
   372  					Expect(tracker.GetAckFrame(true)).To(BeNil())
   373  				})
   374  
   375  				It("doesn't generate an ACK when none is queued and the timer has not yet expired", func() {
   376  					Expect(tracker.ReceivedPacket(1, protocol.ECNNon, time.Now(), true)).To(Succeed())
   377  					tracker.ackQueued = false
   378  					tracker.ackAlarm = time.Now().Add(time.Minute)
   379  					Expect(tracker.GetAckFrame(true)).To(BeNil())
   380  				})
   381  
   382  				It("generates an ACK when the timer has expired", func() {
   383  					Expect(tracker.ReceivedPacket(1, protocol.ECNNon, time.Now(), true)).To(Succeed())
   384  					tracker.ackQueued = false
   385  					tracker.ackAlarm = time.Now().Add(-time.Minute)
   386  					Expect(tracker.GetAckFrame(true)).ToNot(BeNil())
   387  				})
   388  			})
   389  		})
   390  	})
   391  })