github.com/MerlinKodo/quic-go@v0.39.2/internal/ackhandler/received_packet_tracker_test.go (about) 1 package ackhandler 2 3 import ( 4 "time" 5 6 "github.com/MerlinKodo/quic-go/internal/protocol" 7 "github.com/MerlinKodo/quic-go/internal/utils" 8 "github.com/MerlinKodo/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 ( 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.largestObservedRcvdTime).To(BeTemporally("~", time.Now(), 10*time.Millisecond)) 29 }) 30 31 It("updates the largestObserved and the largestObservedRcvdTime", func() { 32 now := time.Now() 33 tracker.largestObserved = 3 34 tracker.largestObservedRcvdTime = 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.largestObservedRcvdTime).To(Equal(now)) 38 }) 39 40 It("doesn't update the largestObserved and the largestObservedRcvdTime for a belated packet", func() { 41 now := time.Now() 42 timestamp := now.Add(-1 * time.Second) 43 tracker.largestObserved = 5 44 tracker.largestObservedRcvdTime = timestamp 45 Expect(tracker.ReceivedPacket(4, protocol.ECNNon, now, true)).To(Succeed()) 46 Expect(tracker.largestObserved).To(Equal(protocol.PacketNumber(5))) 47 Expect(tracker.largestObservedRcvdTime).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 })