1
2
3
4
5
6
7 package quic
8
9 import (
10 "math"
11 "time"
12 )
13
14 type lossState struct {
15 side connSide
16
17
18
19 handshakeConfirmed bool
20
21
22
23 maxAckDelay time.Duration
24
25
26
27
28 timer time.Time
29
30
31 ptoTimerArmed bool
32
33
34 ptoExpired bool
35
36
37
38 ptoBackoffCount int
39
40
41
42
43
44
45
46
47
48
49
50
51 antiAmplificationLimit int
52
53
54 consecutiveNonAckElicitingPackets int
55
56 rtt rttState
57 pacer pacerState
58 cc *ccReno
59
60
61 spaces [numberSpaceCount]struct {
62 sentPacketList
63 maxAcked packetNumber
64 lastAckEliciting packetNumber
65 }
66
67
68 ackFrameRTT time.Duration
69 ackFrameContainsAckEliciting bool
70 }
71
72 const antiAmplificationUnlimited = math.MaxInt
73
74 func (c *lossState) init(side connSide, maxDatagramSize int, now time.Time) {
75 c.side = side
76 if side == clientSide {
77
78 c.antiAmplificationLimit = antiAmplificationUnlimited
79 }
80 c.rtt.init()
81 c.cc = newReno(maxDatagramSize)
82 c.pacer.init(now, c.cc.congestionWindow, timerGranularity)
83
84
85
86 c.maxAckDelay = 25 * time.Millisecond
87
88 for space := range c.spaces {
89 c.spaces[space].maxAcked = -1
90 c.spaces[space].lastAckEliciting = -1
91 }
92 }
93
94
95 func (c *lossState) setMaxAckDelay(d time.Duration) {
96 if d >= (1<<14)*time.Millisecond {
97
98
99 return
100 }
101 c.maxAckDelay = d
102 }
103
104
105 func (c *lossState) confirmHandshake() {
106 c.handshakeConfirmed = true
107 }
108
109
110
111 func (c *lossState) validateClientAddress() {
112 c.antiAmplificationLimit = antiAmplificationUnlimited
113 }
114
115
116
117
118
119
120
121 const minPacketSize = 128
122
123 type ccLimit int
124
125 const (
126 ccOK = ccLimit(iota)
127 ccBlocked
128 ccLimited
129 ccPaced
130 )
131
132
133
134 func (c *lossState) sendLimit(now time.Time) (limit ccLimit, next time.Time) {
135 if c.antiAmplificationLimit < minPacketSize {
136
137 return ccBlocked, time.Time{}
138 }
139 if c.ptoExpired {
140
141 return ccOK, time.Time{}
142 }
143 if !c.cc.canSend() {
144
145 return ccLimited, time.Time{}
146 }
147 if c.cc.bytesInFlight == 0 {
148
149 return ccOK, time.Time{}
150 }
151 canSend, next := c.pacer.canSend(now)
152 if !canSend {
153
154 return ccPaced, next
155 }
156 return ccOK, time.Time{}
157 }
158
159
160 func (c *lossState) maxSendSize() int {
161 return min(c.antiAmplificationLimit, c.cc.maxDatagramSize)
162 }
163
164
165
166 func (c *lossState) advance(now time.Time, lossf func(numberSpace, *sentPacket, packetFate)) {
167 c.pacer.advance(now, c.cc.congestionWindow, c.rtt.smoothedRTT)
168 if c.ptoTimerArmed && !c.timer.IsZero() && !c.timer.After(now) {
169 c.ptoExpired = true
170 c.timer = time.Time{}
171 c.ptoBackoffCount++
172 }
173 c.detectLoss(now, lossf)
174 }
175
176
177 func (c *lossState) nextNumber(space numberSpace) packetNumber {
178 return c.spaces[space].nextNum
179 }
180
181
182 func (c *lossState) packetSent(now time.Time, space numberSpace, sent *sentPacket) {
183 sent.time = now
184 c.spaces[space].add(sent)
185 size := sent.size
186 if c.antiAmplificationLimit != antiAmplificationUnlimited {
187 c.antiAmplificationLimit = max(0, c.antiAmplificationLimit-size)
188 }
189 if sent.inFlight {
190 c.cc.packetSent(now, space, sent)
191 c.pacer.packetSent(now, size, c.cc.congestionWindow, c.rtt.smoothedRTT)
192 if sent.ackEliciting {
193 c.spaces[space].lastAckEliciting = sent.num
194 c.ptoExpired = false
195 }
196 c.scheduleTimer(now)
197 }
198 if sent.ackEliciting {
199 c.consecutiveNonAckElicitingPackets = 0
200 } else {
201 c.consecutiveNonAckElicitingPackets++
202 }
203 }
204
205
206 func (c *lossState) datagramReceived(now time.Time, size int) {
207 if c.antiAmplificationLimit != antiAmplificationUnlimited {
208 c.antiAmplificationLimit += 3 * size
209
210
211
212 c.scheduleTimer(now)
213 if c.ptoTimerArmed && !c.timer.IsZero() && !c.timer.After(now) {
214 c.ptoExpired = true
215 c.timer = time.Time{}
216 }
217 }
218 }
219
220
221
222
223 func (c *lossState) receiveAckStart() {
224 c.ackFrameContainsAckEliciting = false
225 c.ackFrameRTT = -1
226 }
227
228
229
230 func (c *lossState) receiveAckRange(now time.Time, space numberSpace, rangeIndex int, start, end packetNumber, ackf func(numberSpace, *sentPacket, packetFate)) {
231
232
233 if s := c.spaces[space].start(); start < s {
234 start = s
235 }
236 if e := c.spaces[space].end(); end > e {
237 end = e
238 }
239 if start >= end {
240 return
241 }
242 if rangeIndex == 0 {
243
244
245 sent := c.spaces[space].num(end - 1)
246 if !sent.acked {
247 c.ackFrameRTT = max(0, now.Sub(sent.time))
248 }
249 }
250 for pnum := start; pnum < end; pnum++ {
251 sent := c.spaces[space].num(pnum)
252 if sent.acked || sent.lost {
253 continue
254 }
255
256 if pnum > c.spaces[space].maxAcked {
257 c.spaces[space].maxAcked = pnum
258 }
259 sent.acked = true
260 c.cc.packetAcked(now, sent)
261 ackf(space, sent, packetAcked)
262 if sent.ackEliciting {
263 c.ackFrameContainsAckEliciting = true
264 }
265 }
266 }
267
268
269
270 func (c *lossState) receiveAckEnd(now time.Time, space numberSpace, ackDelay time.Duration, lossf func(numberSpace, *sentPacket, packetFate)) {
271 c.spaces[space].sentPacketList.clean()
272
273
274
275 if c.ackFrameRTT >= 0 && c.ackFrameContainsAckEliciting {
276 c.rtt.updateSample(now, c.handshakeConfirmed, space, c.ackFrameRTT, ackDelay, c.maxAckDelay)
277 }
278
279
280
281 if !(c.side == clientSide && space == initialSpace) {
282 c.ptoBackoffCount = 0
283 }
284
285
286
287 c.timer = time.Time{}
288 c.detectLoss(now, lossf)
289 c.cc.packetBatchEnd(now, space, &c.rtt, c.maxAckDelay)
290 }
291
292
293
294
295 func (c *lossState) discardPackets(space numberSpace, lossf func(numberSpace, *sentPacket, packetFate)) {
296 for i := 0; i < c.spaces[space].size; i++ {
297 sent := c.spaces[space].nth(i)
298 sent.lost = true
299 c.cc.packetDiscarded(sent)
300 lossf(numberSpace(space), sent, packetLost)
301 }
302 c.spaces[space].clean()
303 }
304
305
306 func (c *lossState) discardKeys(now time.Time, space numberSpace) {
307
308 for i := 0; i < c.spaces[space].size; i++ {
309 sent := c.spaces[space].nth(i)
310 c.cc.packetDiscarded(sent)
311 }
312 c.spaces[space].discard()
313 c.spaces[space].maxAcked = -1
314 c.spaces[space].lastAckEliciting = -1
315 c.scheduleTimer(now)
316 }
317
318 func (c *lossState) lossDuration() time.Duration {
319
320 return max((9*max(c.rtt.smoothedRTT, c.rtt.latestRTT))/8, timerGranularity)
321 }
322
323 func (c *lossState) detectLoss(now time.Time, lossf func(numberSpace, *sentPacket, packetFate)) {
324
325 const lossThreshold = 3
326
327 lossTime := now.Add(-c.lossDuration())
328 for space := numberSpace(0); space < numberSpaceCount; space++ {
329 for i := 0; i < c.spaces[space].size; i++ {
330 sent := c.spaces[space].nth(i)
331 if sent.lost || sent.acked {
332 continue
333 }
334
335
336
337
338
339 switch {
340 case c.spaces[space].maxAcked-sent.num >= lossThreshold:
341
342
343 fallthrough
344 case sent.num <= c.spaces[space].maxAcked && !sent.time.After(lossTime):
345
346
347 sent.lost = true
348 lossf(space, sent, packetLost)
349 if sent.inFlight {
350 c.cc.packetLost(now, space, sent, &c.rtt)
351 }
352 }
353 if !sent.lost {
354 break
355 }
356 }
357 c.spaces[space].clean()
358 }
359 c.scheduleTimer(now)
360 }
361
362
363
364
365
366
367
368
369
370
371 func (c *lossState) scheduleTimer(now time.Time) {
372 c.ptoTimerArmed = false
373
374
375
376
377
378 var oldestPotentiallyLost time.Time
379 for space := numberSpace(0); space < numberSpaceCount; space++ {
380 if c.spaces[space].size > 0 && c.spaces[space].start() <= c.spaces[space].maxAcked {
381 firstTime := c.spaces[space].nth(0).time
382 if oldestPotentiallyLost.IsZero() || firstTime.Before(oldestPotentiallyLost) {
383 oldestPotentiallyLost = firstTime
384 }
385 }
386 }
387 if !oldestPotentiallyLost.IsZero() {
388 c.timer = oldestPotentiallyLost.Add(c.lossDuration())
389 return
390 }
391
392
393 if c.ptoExpired {
394
395 c.timer = time.Time{}
396 return
397 }
398 if c.antiAmplificationLimit >= 0 && c.antiAmplificationLimit < minPacketSize {
399
400
401 c.timer = time.Time{}
402 return
403 }
404
405
406
407 var last time.Time
408 if !c.handshakeConfirmed {
409 for space := initialSpace; space <= handshakeSpace; space++ {
410 sent := c.spaces[space].num(c.spaces[space].lastAckEliciting)
411 if sent == nil {
412 continue
413 }
414 if last.IsZero() || last.After(sent.time) {
415 last = sent.time
416 }
417 }
418 } else {
419 sent := c.spaces[appDataSpace].num(c.spaces[appDataSpace].lastAckEliciting)
420 if sent != nil {
421 last = sent.time
422 }
423 }
424 if last.IsZero() &&
425 c.side == clientSide &&
426 c.spaces[handshakeSpace].maxAcked < 0 &&
427 !c.handshakeConfirmed {
428
429
430
431 if !c.timer.IsZero() {
432
433
434 c.ptoTimerArmed = true
435 return
436 }
437 last = now
438 } else if last.IsZero() {
439 c.timer = time.Time{}
440 return
441 }
442 c.timer = last.Add(c.ptoPeriod())
443 c.ptoTimerArmed = true
444 }
445
446 func (c *lossState) ptoPeriod() time.Duration {
447
448 return c.ptoBasePeriod() << c.ptoBackoffCount
449 }
450
451 func (c *lossState) ptoBasePeriod() time.Duration {
452
453 pto := c.rtt.smoothedRTT + max(4*c.rtt.rttvar, timerGranularity)
454 if c.handshakeConfirmed {
455
456
457
458 pto += c.maxAckDelay
459 }
460 return pto
461 }
462
View as plain text