github.com/tumi8/quic-go@v0.37.4-tum/noninternal/ackhandler/received_packet_tracker_test.go (about)

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