File: | out/../deps/ngtcp2/ngtcp2/lib/ngtcp2_rtb.c |
Warning: | line 622, column 14 2nd function call argument is an uninitialized value |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* | |||
2 | * ngtcp2 | |||
3 | * | |||
4 | * Copyright (c) 2017 ngtcp2 contributors | |||
5 | * | |||
6 | * Permission is hereby granted, free of charge, to any person obtaining | |||
7 | * a copy of this software and associated documentation files (the | |||
8 | * "Software"), to deal in the Software without restriction, including | |||
9 | * without limitation the rights to use, copy, modify, merge, publish, | |||
10 | * distribute, sublicense, and/or sell copies of the Software, and to | |||
11 | * permit persons to whom the Software is furnished to do so, subject to | |||
12 | * the following conditions: | |||
13 | * | |||
14 | * The above copyright notice and this permission notice shall be | |||
15 | * included in all copies or substantial portions of the Software. | |||
16 | * | |||
17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | |||
18 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |||
19 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | |||
20 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE | |||
21 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION | |||
22 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION | |||
23 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |||
24 | */ | |||
25 | #include "ngtcp2_rtb.h" | |||
26 | ||||
27 | #include <assert.h> | |||
28 | #include <string.h> | |||
29 | ||||
30 | #include "ngtcp2_macro.h" | |||
31 | #include "ngtcp2_conn.h" | |||
32 | #include "ngtcp2_log.h" | |||
33 | #include "ngtcp2_vec.h" | |||
34 | #include "ngtcp2_cc.h" | |||
35 | #include "ngtcp2_rcvry.h" | |||
36 | #include "ngtcp2_rst.h" | |||
37 | ||||
38 | int ngtcp2_frame_chain_new(ngtcp2_frame_chain **pfrc, const ngtcp2_mem *mem) { | |||
39 | *pfrc = ngtcp2_mem_malloc(mem, sizeof(ngtcp2_frame_chain)); | |||
40 | if (*pfrc == NULL((void*)0)) { | |||
41 | return NGTCP2_ERR_NOMEM-501; | |||
42 | } | |||
43 | ||||
44 | ngtcp2_frame_chain_init(*pfrc); | |||
45 | ||||
46 | return 0; | |||
47 | } | |||
48 | ||||
49 | int ngtcp2_frame_chain_extralen_new(ngtcp2_frame_chain **pfrc, size_t extralen, | |||
50 | const ngtcp2_mem *mem) { | |||
51 | *pfrc = ngtcp2_mem_malloc(mem, sizeof(ngtcp2_frame_chain) + extralen); | |||
52 | if (*pfrc == NULL((void*)0)) { | |||
53 | return NGTCP2_ERR_NOMEM-501; | |||
54 | } | |||
55 | ||||
56 | ngtcp2_frame_chain_init(*pfrc); | |||
57 | ||||
58 | return 0; | |||
59 | } | |||
60 | ||||
61 | int ngtcp2_frame_chain_stream_datacnt_new(ngtcp2_frame_chain **pfrc, | |||
62 | size_t datacnt, | |||
63 | const ngtcp2_mem *mem) { | |||
64 | size_t need = sizeof(ngtcp2_vec) * (datacnt - 1); | |||
65 | size_t avail = sizeof(ngtcp2_frame) - sizeof(ngtcp2_stream); | |||
66 | ||||
67 | if (datacnt > 0 && need > avail) { | |||
68 | return ngtcp2_frame_chain_extralen_new(pfrc, need - avail, mem); | |||
69 | } | |||
70 | ||||
71 | return ngtcp2_frame_chain_new(pfrc, mem); | |||
72 | } | |||
73 | ||||
74 | int ngtcp2_frame_chain_crypto_datacnt_new(ngtcp2_frame_chain **pfrc, | |||
75 | size_t datacnt, | |||
76 | const ngtcp2_mem *mem) { | |||
77 | size_t need = sizeof(ngtcp2_vec) * (datacnt - 1); | |||
78 | size_t avail = sizeof(ngtcp2_frame) - sizeof(ngtcp2_crypto); | |||
79 | ||||
80 | if (datacnt > 0 && need > avail) { | |||
81 | return ngtcp2_frame_chain_extralen_new(pfrc, need - avail, mem); | |||
82 | } | |||
83 | ||||
84 | return ngtcp2_frame_chain_new(pfrc, mem); | |||
85 | } | |||
86 | ||||
87 | int ngtcp2_frame_chain_new_token_new(ngtcp2_frame_chain **pfrc, | |||
88 | const ngtcp2_vec *token, | |||
89 | const ngtcp2_mem *mem) { | |||
90 | size_t avail = sizeof(ngtcp2_frame) - sizeof(ngtcp2_new_token); | |||
91 | int rv; | |||
92 | uint8_t *p; | |||
93 | ngtcp2_frame *fr; | |||
94 | ||||
95 | if (token->len > avail) { | |||
96 | rv = ngtcp2_frame_chain_extralen_new(pfrc, token->len - avail, mem); | |||
97 | } else { | |||
98 | rv = ngtcp2_frame_chain_new(pfrc, mem); | |||
99 | } | |||
100 | if (rv != 0) { | |||
101 | return rv; | |||
102 | } | |||
103 | ||||
104 | fr = &(*pfrc)->fr; | |||
105 | fr->type = NGTCP2_FRAME_NEW_TOKEN; | |||
106 | ||||
107 | p = (uint8_t *)(*pfrc) + sizeof(ngtcp2_new_token); | |||
108 | memcpy(p, token->base, token->len); | |||
109 | ||||
110 | ngtcp2_vec_init(&fr->new_token.token, p, token->len); | |||
111 | ||||
112 | return 0; | |||
113 | } | |||
114 | ||||
115 | void ngtcp2_frame_chain_del(ngtcp2_frame_chain *frc, const ngtcp2_mem *mem) { | |||
116 | ngtcp2_frame_chain_binder *binder; | |||
117 | ||||
118 | if (frc == NULL((void*)0)) { | |||
119 | return; | |||
120 | } | |||
121 | ||||
122 | binder = frc->binder; | |||
123 | if (binder && --binder->refcount == 0) { | |||
124 | ngtcp2_mem_free(mem, binder); | |||
125 | } | |||
126 | ||||
127 | ngtcp2_mem_free(mem, frc); | |||
128 | } | |||
129 | ||||
130 | void ngtcp2_frame_chain_init(ngtcp2_frame_chain *frc) { | |||
131 | frc->next = NULL((void*)0); | |||
132 | frc->binder = NULL((void*)0); | |||
133 | } | |||
134 | ||||
135 | void ngtcp2_frame_chain_list_del(ngtcp2_frame_chain *frc, | |||
136 | const ngtcp2_mem *mem) { | |||
137 | ngtcp2_frame_chain *next; | |||
138 | ||||
139 | for (; frc;) { | |||
140 | next = frc->next; | |||
141 | ngtcp2_frame_chain_del(frc, mem); | |||
142 | frc = next; | |||
143 | } | |||
144 | } | |||
145 | ||||
146 | int ngtcp2_frame_chain_binder_new(ngtcp2_frame_chain_binder **pbinder, | |||
147 | const ngtcp2_mem *mem) { | |||
148 | *pbinder = ngtcp2_mem_calloc(mem, 1, sizeof(ngtcp2_frame_chain_binder)); | |||
149 | if (*pbinder == NULL((void*)0)) { | |||
150 | return NGTCP2_ERR_NOMEM-501; | |||
151 | } | |||
152 | ||||
153 | return 0; | |||
154 | } | |||
155 | ||||
156 | int ngtcp2_bind_frame_chains(ngtcp2_frame_chain *a, ngtcp2_frame_chain *b, | |||
157 | const ngtcp2_mem *mem) { | |||
158 | ngtcp2_frame_chain_binder *binder; | |||
159 | int rv; | |||
160 | ||||
161 | assert(b->binder == NULL)((void) (0)); | |||
162 | ||||
163 | if (a->binder == NULL((void*)0)) { | |||
164 | rv = ngtcp2_frame_chain_binder_new(&binder, mem); | |||
165 | if (rv != 0) { | |||
166 | return rv; | |||
167 | } | |||
168 | ||||
169 | a->binder = binder; | |||
170 | ++a->binder->refcount; | |||
171 | } | |||
172 | ||||
173 | b->binder = a->binder; | |||
174 | ++b->binder->refcount; | |||
175 | ||||
176 | return 0; | |||
177 | } | |||
178 | ||||
179 | int ngtcp2_rtb_entry_new(ngtcp2_rtb_entry **pent, const ngtcp2_pkt_hd *hd, | |||
180 | ngtcp2_frame_chain *frc, ngtcp2_tstamp ts, | |||
181 | size_t pktlen, uint8_t flags, const ngtcp2_mem *mem) { | |||
182 | (*pent) = ngtcp2_mem_calloc(mem, 1, sizeof(ngtcp2_rtb_entry)); | |||
183 | if (*pent == NULL((void*)0)) { | |||
184 | return NGTCP2_ERR_NOMEM-501; | |||
185 | } | |||
186 | ||||
187 | (*pent)->hd.pkt_num = hd->pkt_num; | |||
188 | (*pent)->hd.type = hd->type; | |||
189 | (*pent)->hd.flags = hd->flags; | |||
190 | (*pent)->frc = frc; | |||
191 | (*pent)->ts = ts; | |||
192 | (*pent)->lost_ts = UINT64_MAX(18446744073709551615UL); | |||
193 | (*pent)->pktlen = pktlen; | |||
194 | (*pent)->flags = flags; | |||
195 | (*pent)->next = NULL((void*)0); | |||
196 | ||||
197 | return 0; | |||
198 | } | |||
199 | ||||
200 | void ngtcp2_rtb_entry_del(ngtcp2_rtb_entry *ent, const ngtcp2_mem *mem) { | |||
201 | if (ent == NULL((void*)0)) { | |||
202 | return; | |||
203 | } | |||
204 | ||||
205 | ngtcp2_frame_chain_list_del(ent->frc, mem); | |||
206 | ||||
207 | ngtcp2_mem_free(mem, ent); | |||
208 | } | |||
209 | ||||
210 | static int greater(const ngtcp2_ksl_key *lhs, const ngtcp2_ksl_key *rhs) { | |||
211 | return *(int64_t *)lhs > *(int64_t *)rhs; | |||
212 | } | |||
213 | ||||
214 | void ngtcp2_rtb_init(ngtcp2_rtb *rtb, ngtcp2_pktns_id pktns_id, | |||
215 | ngtcp2_strm *crypto, ngtcp2_rst *rst, ngtcp2_cc *cc, | |||
216 | ngtcp2_log *log, ngtcp2_qlog *qlog, | |||
217 | const ngtcp2_mem *mem) { | |||
218 | ngtcp2_ksl_init(&rtb->ents, greater, sizeof(int64_t), mem); | |||
219 | rtb->crypto = crypto; | |||
220 | rtb->rst = rst; | |||
221 | rtb->cc = cc; | |||
222 | rtb->log = log; | |||
223 | rtb->qlog = qlog; | |||
224 | rtb->mem = mem; | |||
225 | rtb->largest_acked_tx_pkt_num = -1; | |||
226 | rtb->num_ack_eliciting = 0; | |||
227 | rtb->num_retransmittable = 0; | |||
228 | rtb->probe_pkt_left = 0; | |||
229 | rtb->pktns_id = pktns_id; | |||
230 | rtb->cc_pkt_num = 0; | |||
231 | rtb->cc_bytes_in_flight = 0; | |||
232 | rtb->persistent_congestion_start_ts = UINT64_MAX(18446744073709551615UL); | |||
233 | rtb->num_lost_pkts = 0; | |||
234 | } | |||
235 | ||||
236 | void ngtcp2_rtb_free(ngtcp2_rtb *rtb) { | |||
237 | ngtcp2_ksl_it it; | |||
238 | ||||
239 | if (rtb == NULL((void*)0)) { | |||
240 | return; | |||
241 | } | |||
242 | ||||
243 | it = ngtcp2_ksl_begin(&rtb->ents); | |||
244 | ||||
245 | for (; !ngtcp2_ksl_it_end(&it)((&it)->blk->n == (&it)->i && (& it)->blk->next == ((void*)0)); ngtcp2_ksl_it_next(&it)(++(&it)->i == (&it)->blk->n && (& it)->blk->next ? ((&it)->blk = (&it)->blk ->next, (&it)->i = 0) : 0)) { | |||
246 | ngtcp2_rtb_entry_del(ngtcp2_ksl_it_get(&it), rtb->mem); | |||
247 | } | |||
248 | ||||
249 | ngtcp2_ksl_free(&rtb->ents); | |||
250 | } | |||
251 | ||||
252 | static void rtb_on_add(ngtcp2_rtb *rtb, ngtcp2_rtb_entry *ent, | |||
253 | ngtcp2_conn_stat *cstat) { | |||
254 | ngtcp2_rst_on_pkt_sent(rtb->rst, ent, cstat); | |||
255 | ||||
256 | assert(rtb->cc_pkt_num <= ent->hd.pkt_num)((void) (0)); | |||
257 | ||||
258 | cstat->bytes_in_flight += ent->pktlen; | |||
259 | rtb->cc_bytes_in_flight += ent->pktlen; | |||
260 | ||||
261 | ngtcp2_rst_update_app_limited(rtb->rst, cstat); | |||
262 | ||||
263 | if (ent->flags & NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING0x04) { | |||
264 | ++rtb->num_ack_eliciting; | |||
265 | } | |||
266 | if (ent->flags & NGTCP2_RTB_ENTRY_FLAG_RETRANSMITTABLE0x02) { | |||
267 | ++rtb->num_retransmittable; | |||
268 | } | |||
269 | } | |||
270 | ||||
271 | static void rtb_on_remove(ngtcp2_rtb *rtb, ngtcp2_rtb_entry *ent, | |||
272 | ngtcp2_conn_stat *cstat) { | |||
273 | if (ent->flags & NGTCP2_RTB_ENTRY_FLAG_LOST_RETRANSMITTED0x10) { | |||
274 | assert(rtb->num_lost_pkts)((void) (0)); | |||
275 | --rtb->num_lost_pkts; | |||
276 | return; | |||
277 | } | |||
278 | ||||
279 | if (ent->flags & NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING0x04) { | |||
280 | assert(rtb->num_ack_eliciting)((void) (0)); | |||
281 | --rtb->num_ack_eliciting; | |||
282 | } | |||
283 | ||||
284 | if ((ent->flags & NGTCP2_RTB_ENTRY_FLAG_RETRANSMITTABLE0x02) && | |||
285 | !(ent->flags & NGTCP2_RTB_ENTRY_FLAG_PTO_RECLAIMED0x08)) { | |||
286 | assert(rtb->num_retransmittable)((void) (0)); | |||
287 | --rtb->num_retransmittable; | |||
288 | } | |||
289 | ||||
290 | if (rtb->cc_pkt_num <= ent->hd.pkt_num) { | |||
291 | assert(cstat->bytes_in_flight >= ent->pktlen)((void) (0)); | |||
292 | cstat->bytes_in_flight -= ent->pktlen; | |||
293 | ||||
294 | assert(rtb->cc_bytes_in_flight >= ent->pktlen)((void) (0)); | |||
295 | rtb->cc_bytes_in_flight -= ent->pktlen; | |||
296 | } | |||
297 | } | |||
298 | ||||
299 | /* | |||
300 | * rtb_reclaim_frame queues unacknowledged frames included in |ent| | |||
301 | * for retransmission. The re-queued frames are not deleted from | |||
302 | * |ent|. It returns the number of frames queued. | |||
303 | */ | |||
304 | static ngtcp2_ssize rtb_reclaim_frame(ngtcp2_rtb *rtb, ngtcp2_conn *conn, | |||
305 | ngtcp2_pktns *pktns, | |||
306 | ngtcp2_rtb_entry *ent) { | |||
307 | ngtcp2_frame_chain *frc, *nfrc, **pfrc = &pktns->tx.frq; | |||
308 | ngtcp2_frame *fr; | |||
309 | ngtcp2_strm *strm; | |||
310 | ngtcp2_range gap, range; | |||
311 | size_t num_reclaimed = 0; | |||
312 | int rv; | |||
313 | ||||
314 | /* PADDING only (or PADDING + ACK ) packets will have NULL | |||
315 | ent->frc. */ | |||
316 | /* TODO Reconsider the order of pfrc */ | |||
317 | for (frc = ent->frc; frc; frc = frc->next) { | |||
318 | fr = &frc->fr; | |||
319 | /* Check that a late ACK acknowledged this frame. */ | |||
320 | if (frc->binder && | |||
321 | (frc->binder->flags & NGTCP2_FRAME_CHAIN_BINDER_FLAG_ACK0x01)) { | |||
322 | continue; | |||
323 | } | |||
324 | switch (frc->fr.type) { | |||
325 | case NGTCP2_FRAME_STREAM: | |||
326 | strm = ngtcp2_conn_find_stream(conn, fr->stream.stream_id); | |||
327 | if (strm == NULL((void*)0)) { | |||
328 | continue; | |||
329 | } | |||
330 | ||||
331 | gap = ngtcp2_strm_get_unacked_range_after(strm, fr->stream.offset); | |||
332 | ||||
333 | range.begin = fr->stream.offset; | |||
334 | range.end = fr->stream.offset + | |||
335 | ngtcp2_vec_len(fr->stream.data, fr->stream.datacnt); | |||
336 | range = ngtcp2_range_intersect(&range, &gap); | |||
337 | if (ngtcp2_range_len(&range) == 0 && | |||
338 | (!fr->stream.fin || (strm->flags & NGTCP2_STRM_FLAG_FIN_ACKED0x40))) { | |||
339 | continue; | |||
340 | } | |||
341 | ||||
342 | rv = ngtcp2_frame_chain_stream_datacnt_new(&nfrc, fr->stream.datacnt, | |||
343 | rtb->mem); | |||
344 | if (rv != 0) { | |||
345 | return rv; | |||
346 | } | |||
347 | ||||
348 | nfrc->fr = *fr; | |||
349 | ngtcp2_vec_copy(nfrc->fr.stream.data, fr->stream.data, | |||
350 | fr->stream.datacnt); | |||
351 | ||||
352 | rv = ngtcp2_strm_streamfrq_push(strm, nfrc); | |||
353 | if (rv != 0) { | |||
354 | ngtcp2_frame_chain_del(nfrc, conn->mem); | |||
355 | return rv; | |||
356 | } | |||
357 | if (!ngtcp2_strm_is_tx_queued(strm)) { | |||
358 | strm->cycle = ngtcp2_conn_tx_strmq_first_cycle(conn); | |||
359 | rv = ngtcp2_conn_tx_strmq_push(conn, strm); | |||
360 | if (rv != 0) { | |||
361 | return rv; | |||
362 | } | |||
363 | } | |||
364 | ||||
365 | ++num_reclaimed; | |||
366 | ||||
367 | continue; | |||
368 | case NGTCP2_FRAME_CRYPTO: | |||
369 | /* Don't resend CRYPTO frame if the whole region it contains has | |||
370 | been acknowledged */ | |||
371 | gap = ngtcp2_strm_get_unacked_range_after(rtb->crypto, fr->crypto.offset); | |||
372 | ||||
373 | range.begin = fr->crypto.offset; | |||
374 | range.end = fr->crypto.offset + | |||
375 | ngtcp2_vec_len(fr->crypto.data, fr->crypto.datacnt); | |||
376 | range = ngtcp2_range_intersect(&range, &gap); | |||
377 | if (ngtcp2_range_len(&range) == 0) { | |||
378 | continue; | |||
379 | } | |||
380 | ||||
381 | rv = ngtcp2_frame_chain_crypto_datacnt_new(&nfrc, fr->crypto.datacnt, | |||
382 | rtb->mem); | |||
383 | if (rv != 0) { | |||
384 | return rv; | |||
385 | } | |||
386 | ||||
387 | nfrc->fr = *fr; | |||
388 | ngtcp2_vec_copy(nfrc->fr.crypto.data, fr->crypto.data, | |||
389 | fr->crypto.datacnt); | |||
390 | ||||
391 | rv = ngtcp2_ksl_insert(&pktns->crypto.tx.frq, NULL((void*)0), | |||
392 | &nfrc->fr.crypto.offset, nfrc); | |||
393 | if (rv != 0) { | |||
394 | assert(ngtcp2_err_is_fatal(rv))((void) (0)); | |||
395 | ngtcp2_frame_chain_del(nfrc, conn->mem); | |||
396 | return rv; | |||
397 | } | |||
398 | ||||
399 | ++num_reclaimed; | |||
400 | ||||
401 | continue; | |||
402 | case NGTCP2_FRAME_NEW_TOKEN: | |||
403 | rv = ngtcp2_frame_chain_new_token_new(&nfrc, &fr->new_token.token, | |||
404 | rtb->mem); | |||
405 | if (rv != 0) { | |||
406 | return rv; | |||
407 | } | |||
408 | ||||
409 | rv = ngtcp2_bind_frame_chains(frc, nfrc, rtb->mem); | |||
410 | if (rv != 0) { | |||
411 | return rv; | |||
412 | } | |||
413 | ||||
414 | break; | |||
415 | default: | |||
416 | rv = ngtcp2_frame_chain_new(&nfrc, rtb->mem); | |||
417 | if (rv != 0) { | |||
418 | return rv; | |||
419 | } | |||
420 | ||||
421 | nfrc->fr = *fr; | |||
422 | ||||
423 | rv = ngtcp2_bind_frame_chains(frc, nfrc, rtb->mem); | |||
424 | if (rv != 0) { | |||
425 | return rv; | |||
426 | } | |||
427 | ||||
428 | break; | |||
429 | } | |||
430 | ||||
431 | ++num_reclaimed; | |||
432 | ||||
433 | nfrc->next = *pfrc; | |||
434 | *pfrc = nfrc; | |||
435 | pfrc = &nfrc->next; | |||
436 | } | |||
437 | ||||
438 | return (ngtcp2_ssize)num_reclaimed; | |||
439 | } | |||
440 | ||||
441 | static int rtb_on_pkt_lost(ngtcp2_rtb *rtb, ngtcp2_ksl_it *it, | |||
442 | ngtcp2_rtb_entry *ent, ngtcp2_conn *conn, | |||
443 | ngtcp2_pktns *pktns, ngtcp2_tstamp ts) { | |||
444 | int rv; | |||
445 | ngtcp2_ssize reclaimed; | |||
446 | ||||
447 | ngtcp2_log_pkt_lost(rtb->log, ent->hd.pkt_num, ent->hd.type, ent->hd.flags, | |||
448 | ent->ts); | |||
449 | ||||
450 | if (rtb->qlog) { | |||
451 | ngtcp2_qlog_pkt_lost(rtb->qlog, ent); | |||
452 | } | |||
453 | ||||
454 | if (!(ent->flags & NGTCP2_RTB_ENTRY_FLAG_PROBE0x01)) { | |||
455 | if (ent->flags & NGTCP2_RTB_ENTRY_FLAG_PTO_RECLAIMED0x08) { | |||
456 | ngtcp2_log_info(rtb->log, NGTCP2_LOG_EVENT_RCV, | |||
457 | "pkn=%" PRId64"l" "d" " has already been reclaimed on PTO", | |||
458 | ent->hd.pkt_num); | |||
459 | assert(!(ent->flags & NGTCP2_RTB_ENTRY_FLAG_LOST_RETRANSMITTED))((void) (0)); | |||
460 | assert(UINT64_MAX == ent->lost_ts)((void) (0)); | |||
461 | ||||
462 | ent->flags |= NGTCP2_RTB_ENTRY_FLAG_LOST_RETRANSMITTED0x10; | |||
463 | ent->lost_ts = ts; | |||
464 | ||||
465 | ++rtb->num_lost_pkts; | |||
466 | ||||
467 | ngtcp2_ksl_it_next(it)(++(it)->i == (it)->blk->n && (it)->blk-> next ? ((it)->blk = (it)->blk->next, (it)->i = 0) : 0); | |||
468 | ||||
469 | return 0; | |||
470 | } | |||
471 | ||||
472 | if (ent->frc) { | |||
473 | assert(!(ent->flags & NGTCP2_RTB_ENTRY_FLAG_LOST_RETRANSMITTED))((void) (0)); | |||
474 | assert(UINT64_MAX == ent->lost_ts)((void) (0)); | |||
475 | ||||
476 | reclaimed = rtb_reclaim_frame(rtb, conn, pktns, ent); | |||
477 | if (reclaimed < 0) { | |||
478 | return (int)reclaimed; | |||
479 | } | |||
480 | ||||
481 | if (reclaimed) { | |||
482 | ent->flags |= NGTCP2_RTB_ENTRY_FLAG_LOST_RETRANSMITTED0x10; | |||
483 | ent->lost_ts = ts; | |||
484 | ||||
485 | ++rtb->num_lost_pkts; | |||
486 | ||||
487 | ngtcp2_ksl_it_next(it)(++(it)->i == (it)->blk->n && (it)->blk-> next ? ((it)->blk = (it)->blk->next, (it)->i = 0) : 0); | |||
488 | ||||
489 | return 0; | |||
490 | } | |||
491 | } | |||
492 | } else { | |||
493 | ngtcp2_log_info(rtb->log, NGTCP2_LOG_EVENT_RCV, | |||
494 | "pkn=%" PRId64"l" "d" | |||
495 | " is a probe packet, no retransmission is necessary", | |||
496 | ent->hd.pkt_num); | |||
497 | } | |||
498 | ||||
499 | rv = ngtcp2_ksl_remove(&rtb->ents, it, &ent->hd.pkt_num); | |||
500 | assert(0 == rv)((void) (0)); | |||
501 | ||||
502 | ngtcp2_rtb_entry_del(ent, rtb->mem); | |||
503 | ||||
504 | return 0; | |||
505 | } | |||
506 | ||||
507 | int ngtcp2_rtb_add(ngtcp2_rtb *rtb, ngtcp2_rtb_entry *ent, | |||
508 | ngtcp2_conn_stat *cstat) { | |||
509 | int rv; | |||
510 | ||||
511 | rv = ngtcp2_ksl_insert(&rtb->ents, NULL((void*)0), &ent->hd.pkt_num, ent); | |||
512 | if (rv != 0) { | |||
513 | return rv; | |||
514 | } | |||
515 | ||||
516 | rtb_on_add(rtb, ent, cstat); | |||
517 | ||||
518 | return 0; | |||
519 | } | |||
520 | ||||
521 | ngtcp2_ksl_it ngtcp2_rtb_head(ngtcp2_rtb *rtb) { | |||
522 | return ngtcp2_ksl_begin(&rtb->ents); | |||
523 | } | |||
524 | ||||
525 | static void rtb_remove(ngtcp2_rtb *rtb, ngtcp2_ksl_it *it, | |||
526 | ngtcp2_rtb_entry **pent, ngtcp2_rtb_entry *ent, | |||
527 | ngtcp2_conn_stat *cstat) { | |||
528 | int rv; | |||
529 | rv = ngtcp2_ksl_remove(&rtb->ents, it, &ent->hd.pkt_num); | |||
530 | assert(0 == rv)((void) (0)); | |||
531 | rtb_on_remove(rtb, ent, cstat); | |||
532 | ||||
533 | assert(ent->next == NULL)((void) (0)); | |||
534 | ||||
535 | ngtcp2_list_insert(ent, pent)do { (ent)->next = *(pent); *(pent) = (ent); } while (0); | |||
536 | } | |||
537 | ||||
538 | static int rtb_process_acked_pkt(ngtcp2_rtb *rtb, ngtcp2_rtb_entry *ent, | |||
539 | ngtcp2_conn *conn) { | |||
540 | ngtcp2_frame_chain *frc; | |||
541 | uint64_t prev_stream_offset, stream_offset; | |||
542 | ngtcp2_strm *strm; | |||
543 | int rv; | |||
544 | uint64_t datalen; | |||
545 | ngtcp2_strm *crypto = rtb->crypto; | |||
546 | ngtcp2_crypto_level crypto_level; | |||
| ||||
547 | ||||
548 | for (frc = ent->frc; frc; frc = frc->next) { | |||
549 | if (frc->binder) { | |||
550 | frc->binder->flags |= NGTCP2_FRAME_CHAIN_BINDER_FLAG_ACK0x01; | |||
551 | } | |||
552 | ||||
553 | switch (frc->fr.type) { | |||
554 | case NGTCP2_FRAME_STREAM: | |||
555 | strm = ngtcp2_conn_find_stream(conn, frc->fr.stream.stream_id); | |||
556 | if (strm == NULL((void*)0)) { | |||
557 | break; | |||
558 | } | |||
559 | ||||
560 | if (frc->fr.stream.fin) { | |||
561 | strm->flags |= NGTCP2_STRM_FLAG_FIN_ACKED0x40; | |||
562 | } | |||
563 | ||||
564 | prev_stream_offset = ngtcp2_strm_get_acked_offset(strm); | |||
565 | rv = ngtcp2_strm_ack_data( | |||
566 | strm, frc->fr.stream.offset, | |||
567 | ngtcp2_vec_len(frc->fr.stream.data, frc->fr.stream.datacnt)); | |||
568 | if (rv != 0) { | |||
569 | return rv; | |||
570 | } | |||
571 | ||||
572 | if (conn->callbacks.acked_stream_data_offset) { | |||
573 | stream_offset = ngtcp2_strm_get_acked_offset(strm); | |||
574 | datalen = stream_offset - prev_stream_offset; | |||
575 | if (datalen == 0 && !frc->fr.stream.fin) { | |||
576 | break; | |||
577 | } | |||
578 | ||||
579 | rv = conn->callbacks.acked_stream_data_offset( | |||
580 | conn, strm->stream_id, prev_stream_offset, datalen, conn->user_data, | |||
581 | strm->stream_user_data); | |||
582 | if (rv != 0) { | |||
583 | return NGTCP2_ERR_CALLBACK_FAILURE-502; | |||
584 | } | |||
585 | } | |||
586 | ||||
587 | rv = ngtcp2_conn_close_stream_if_shut_rdwr(conn, strm, NGTCP2_NO_ERROR0x0u); | |||
588 | if (rv != 0) { | |||
589 | return rv; | |||
590 | } | |||
591 | break; | |||
592 | case NGTCP2_FRAME_CRYPTO: | |||
593 | prev_stream_offset = ngtcp2_strm_get_acked_offset(crypto); | |||
594 | rv = ngtcp2_strm_ack_data( | |||
595 | crypto, frc->fr.crypto.offset, | |||
596 | ngtcp2_vec_len(frc->fr.crypto.data, frc->fr.crypto.datacnt)); | |||
597 | if (rv != 0) { | |||
598 | return rv; | |||
599 | } | |||
600 | ||||
601 | if (conn->callbacks.acked_crypto_offset) { | |||
602 | stream_offset = ngtcp2_strm_get_acked_offset(crypto); | |||
603 | datalen = stream_offset - prev_stream_offset; | |||
604 | if (datalen == 0) { | |||
605 | break; | |||
606 | } | |||
607 | ||||
608 | switch (rtb->pktns_id) { | |||
609 | case NGTCP2_PKTNS_ID_INITIAL: | |||
610 | crypto_level = NGTCP2_CRYPTO_LEVEL_INITIAL; | |||
611 | break; | |||
612 | case NGTCP2_PKTNS_ID_HANDSHAKE: | |||
613 | crypto_level = NGTCP2_CRYPTO_LEVEL_HANDSHAKE; | |||
614 | break; | |||
615 | case NGTCP2_PKTNS_ID_APPLICATION: | |||
616 | crypto_level = NGTCP2_CRYPTO_LEVEL_APPLICATION; | |||
617 | break; | |||
618 | default: | |||
619 | assert(0)((void) (0)); | |||
620 | } | |||
621 | ||||
622 | rv = conn->callbacks.acked_crypto_offset( | |||
| ||||
623 | conn, crypto_level, prev_stream_offset, datalen, conn->user_data); | |||
624 | if (rv != 0) { | |||
625 | return NGTCP2_ERR_CALLBACK_FAILURE-502; | |||
626 | } | |||
627 | } | |||
628 | break; | |||
629 | case NGTCP2_FRAME_RESET_STREAM: | |||
630 | strm = ngtcp2_conn_find_stream(conn, frc->fr.reset_stream.stream_id); | |||
631 | if (strm == NULL((void*)0)) { | |||
632 | break; | |||
633 | } | |||
634 | strm->flags |= NGTCP2_STRM_FLAG_RST_ACKED0x20; | |||
635 | rv = ngtcp2_conn_close_stream_if_shut_rdwr(conn, strm, NGTCP2_NO_ERROR0x0u); | |||
636 | if (rv != 0) { | |||
637 | return rv; | |||
638 | } | |||
639 | break; | |||
640 | case NGTCP2_FRAME_RETIRE_CONNECTION_ID: | |||
641 | assert(conn->dcid.num_retire_queued)((void) (0)); | |||
642 | --conn->dcid.num_retire_queued; | |||
643 | break; | |||
644 | } | |||
645 | } | |||
646 | return 0; | |||
647 | } | |||
648 | ||||
649 | static void rtb_on_pkt_acked(ngtcp2_rtb *rtb, ngtcp2_rtb_entry *ent, | |||
650 | ngtcp2_conn_stat *cstat, ngtcp2_tstamp ts) { | |||
651 | ngtcp2_cc *cc = rtb->cc; | |||
652 | ngtcp2_cc_pkt pkt; | |||
653 | ||||
654 | ngtcp2_rst_update_rate_sample(rtb->rst, ent, ts); | |||
655 | ||||
656 | cc->on_pkt_acked(cc, cstat, | |||
657 | ngtcp2_cc_pkt_init(&pkt, ent->hd.pkt_num, ent->pktlen, | |||
658 | rtb->pktns_id, ent->ts), | |||
659 | ts); | |||
660 | ||||
661 | if (!(ent->flags & NGTCP2_RTB_ENTRY_FLAG_PROBE0x01) && | |||
662 | (ent->flags & NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING0x04)) { | |||
663 | cstat->pto_count = 0; | |||
664 | } | |||
665 | } | |||
666 | ||||
667 | static void conn_verify_ecn(ngtcp2_conn *conn, ngtcp2_pktns *pktns, | |||
668 | ngtcp2_cc *cc, ngtcp2_conn_stat *cstat, | |||
669 | const ngtcp2_ack *fr, size_t ecn_acked, | |||
670 | ngtcp2_tstamp largest_acked_sent_ts, | |||
671 | ngtcp2_tstamp ts) { | |||
672 | if (conn->tx.ecn.state == NGTCP2_ECN_STATE_FAILED) { | |||
673 | return; | |||
674 | } | |||
675 | ||||
676 | if ((ecn_acked && fr->type == NGTCP2_FRAME_ACK) || | |||
677 | (fr->type == NGTCP2_FRAME_ACK_ECN && | |||
678 | (pktns->rx.ecn.ack.ect0 > fr->ecn.ect0 || | |||
679 | pktns->rx.ecn.ack.ect1 > fr->ecn.ect1 || | |||
680 | pktns->rx.ecn.ack.ce > fr->ecn.ce || | |||
681 | (fr->ecn.ect0 - pktns->rx.ecn.ack.ect0) + | |||
682 | (fr->ecn.ce - pktns->rx.ecn.ack.ce) < | |||
683 | ecn_acked || | |||
684 | fr->ecn.ect0 > pktns->tx.ecn.ect0 || fr->ecn.ect1))) { | |||
685 | ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_CON, | |||
686 | "path is not ECN capable"); | |||
687 | conn->tx.ecn.state = NGTCP2_ECN_STATE_FAILED; | |||
688 | return; | |||
689 | } | |||
690 | ||||
691 | if (conn->tx.ecn.state != NGTCP2_ECN_STATE_CAPABLE && ecn_acked) { | |||
692 | ngtcp2_log_info(&conn->log, NGTCP2_LOG_EVENT_CON, "path is ECN capable"); | |||
693 | conn->tx.ecn.state = NGTCP2_ECN_STATE_CAPABLE; | |||
694 | } | |||
695 | ||||
696 | if (fr->type == NGTCP2_FRAME_ACK_ECN) { | |||
697 | if (largest_acked_sent_ts != UINT64_MAX(18446744073709551615UL) && | |||
698 | fr->ecn.ce > pktns->rx.ecn.ack.ce) { | |||
699 | cc->congestion_event(cc, cstat, largest_acked_sent_ts, ts); | |||
700 | } | |||
701 | ||||
702 | pktns->rx.ecn.ack.ect0 = fr->ecn.ect0; | |||
703 | pktns->rx.ecn.ack.ect1 = fr->ecn.ect1; | |||
704 | pktns->rx.ecn.ack.ce = fr->ecn.ce; | |||
705 | } | |||
706 | } | |||
707 | ||||
708 | ngtcp2_ssize ngtcp2_rtb_recv_ack(ngtcp2_rtb *rtb, const ngtcp2_ack *fr, | |||
709 | ngtcp2_conn_stat *cstat, ngtcp2_conn *conn, | |||
710 | ngtcp2_pktns *pktns, ngtcp2_tstamp pkt_ts, | |||
711 | ngtcp2_tstamp ts) { | |||
712 | ngtcp2_rtb_entry *ent; | |||
713 | int64_t largest_ack = fr->largest_ack, min_ack; | |||
714 | size_t i; | |||
715 | int rv; | |||
716 | ngtcp2_ksl_it it; | |||
717 | ngtcp2_ssize num_acked = 0; | |||
718 | ngtcp2_tstamp largest_pkt_sent_ts = UINT64_MAX(18446744073709551615UL); | |||
719 | ngtcp2_tstamp largest_acked_sent_ts = UINT64_MAX(18446744073709551615UL); | |||
720 | int64_t pkt_num; | |||
721 | ngtcp2_cc *cc = rtb->cc; | |||
722 | ngtcp2_rtb_entry *acked_ent = NULL((void*)0); | |||
723 | int ack_eliciting_pkt_acked = 0; | |||
724 | size_t ecn_acked = 0; | |||
725 | int verify_ecn = 0; | |||
726 | ||||
727 | if (conn && (conn->flags & NGTCP2_CONN_FLAG_KEY_UPDATE_NOT_CONFIRMED0x0800) && | |||
728 | largest_ack >= conn->pktns.crypto.tx.ckm->pkt_num) { | |||
729 | conn->flags &= (uint16_t)~NGTCP2_CONN_FLAG_KEY_UPDATE_NOT_CONFIRMED0x0800; | |||
730 | conn->crypto.key_update.confirmed_ts = ts; | |||
731 | ||||
732 | ngtcp2_log_info(rtb->log, NGTCP2_LOG_EVENT_CRY, "key update confirmed"); | |||
733 | } | |||
734 | ||||
735 | if (rtb->largest_acked_tx_pkt_num < largest_ack) { | |||
736 | rtb->largest_acked_tx_pkt_num = largest_ack; | |||
737 | verify_ecn = 1; | |||
738 | } | |||
739 | ||||
740 | /* Assume that ngtcp2_pkt_validate_ack(fr) returns 0 */ | |||
741 | it = ngtcp2_ksl_lower_bound(&rtb->ents, &largest_ack); | |||
742 | if (ngtcp2_ksl_it_end(&it)((&it)->blk->n == (&it)->i && (& it)->blk->next == ((void*)0))) { | |||
743 | if (verify_ecn) { | |||
744 | conn_verify_ecn(conn, pktns, rtb->cc, cstat, fr, ecn_acked, | |||
745 | largest_acked_sent_ts, ts); | |||
746 | } | |||
747 | return 0; | |||
748 | } | |||
749 | ||||
750 | min_ack = largest_ack - (int64_t)fr->first_ack_blklen; | |||
751 | ||||
752 | for (; !ngtcp2_ksl_it_end(&it)((&it)->blk->n == (&it)->i && (& it)->blk->next == ((void*)0));) { | |||
753 | pkt_num = *(int64_t *)ngtcp2_ksl_it_key(&it)((ngtcp2_ksl_key *)((ngtcp2_ksl_node *)(void *)(((&it)-> blk)->nodes + ((&it)->ksl)->nodelen * ((&it) ->i)))->key); | |||
754 | ||||
755 | assert(pkt_num <= largest_ack)((void) (0)); | |||
756 | ||||
757 | if (pkt_num < min_ack) { | |||
758 | break; | |||
759 | } | |||
760 | ||||
761 | ent = ngtcp2_ksl_it_get(&it); | |||
762 | ||||
763 | if (largest_ack == pkt_num) { | |||
764 | largest_pkt_sent_ts = ent->ts; | |||
765 | } | |||
766 | ||||
767 | if (ent->flags & NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING0x04) { | |||
768 | ack_eliciting_pkt_acked = 1; | |||
769 | } | |||
770 | ||||
771 | rtb_remove(rtb, &it, &acked_ent, ent, cstat); | |||
772 | ++num_acked; | |||
773 | } | |||
774 | ||||
775 | for (i = 0; i < fr->num_blks;) { | |||
776 | largest_ack = min_ack - (int64_t)fr->blks[i].gap - 2; | |||
777 | min_ack = largest_ack - (int64_t)fr->blks[i].blklen; | |||
778 | ||||
779 | it = ngtcp2_ksl_lower_bound(&rtb->ents, &largest_ack); | |||
780 | if (ngtcp2_ksl_it_end(&it)((&it)->blk->n == (&it)->i && (& it)->blk->next == ((void*)0))) { | |||
781 | break; | |||
782 | } | |||
783 | ||||
784 | for (; !ngtcp2_ksl_it_end(&it)((&it)->blk->n == (&it)->i && (& it)->blk->next == ((void*)0));) { | |||
785 | pkt_num = *(int64_t *)ngtcp2_ksl_it_key(&it)((ngtcp2_ksl_key *)((ngtcp2_ksl_node *)(void *)(((&it)-> blk)->nodes + ((&it)->ksl)->nodelen * ((&it) ->i)))->key); | |||
786 | if (pkt_num < min_ack) { | |||
787 | break; | |||
788 | } | |||
789 | ent = ngtcp2_ksl_it_get(&it); | |||
790 | ||||
791 | if (ent->flags & NGTCP2_RTB_ENTRY_FLAG_ACK_ELICITING0x04) { | |||
792 | ack_eliciting_pkt_acked = 1; | |||
793 | } | |||
794 | ||||
795 | rtb_remove(rtb, &it, &acked_ent, ent, cstat); | |||
796 | ++num_acked; | |||
797 | } | |||
798 | ||||
799 | ++i; | |||
800 | } | |||
801 | ||||
802 | if (largest_pkt_sent_ts != UINT64_MAX(18446744073709551615UL) && ack_eliciting_pkt_acked) { | |||
803 | ngtcp2_conn_update_rtt(conn, pkt_ts - largest_pkt_sent_ts, | |||
804 | fr->ack_delay_unscaled, ts); | |||
805 | if (cc->new_rtt_sample) { | |||
806 | cc->new_rtt_sample(cc, cstat, ts); | |||
807 | } | |||
808 | } | |||
809 | ||||
810 | ngtcp2_rst_on_ack_recv(rtb->rst, cstat); | |||
811 | ||||
812 | if (conn) { | |||
813 | for (ent = acked_ent; ent; ent = acked_ent) { | |||
814 | if (ent->hd.pkt_num >= pktns->tx.ecn.start_pkt_num && | |||
815 | (ent->flags & NGTCP2_RTB_ENTRY_FLAG_ECN0x20)) { | |||
816 | ++ecn_acked; | |||
817 | } | |||
818 | ||||
819 | assert(largest_acked_sent_ts == UINT64_MAX ||((void) (0)) | |||
820 | largest_acked_sent_ts <= ent->ts)((void) (0)); | |||
821 | ||||
822 | largest_acked_sent_ts = ent->ts; | |||
823 | ||||
824 | rv = rtb_process_acked_pkt(rtb, ent, conn); | |||
825 | if (rv != 0) { | |||
826 | goto fail; | |||
827 | } | |||
828 | ||||
829 | rtb_on_pkt_acked(rtb, ent, cstat, ts); | |||
830 | acked_ent = ent->next; | |||
831 | ngtcp2_rtb_entry_del(ent, rtb->mem); | |||
832 | } | |||
833 | ||||
834 | if (verify_ecn) { | |||
835 | conn_verify_ecn(conn, pktns, rtb->cc, cstat, fr, ecn_acked, | |||
836 | largest_acked_sent_ts, ts); | |||
837 | } | |||
838 | } else { | |||
839 | /* For unit tests */ | |||
840 | for (ent = acked_ent; ent; ent = acked_ent) { | |||
841 | rtb_on_pkt_acked(rtb, ent, cstat, ts); | |||
842 | acked_ent = ent->next; | |||
843 | ngtcp2_rtb_entry_del(ent, rtb->mem); | |||
844 | } | |||
845 | } | |||
846 | ||||
847 | cc->on_ack_recv(cc, cstat, ts); | |||
848 | ||||
849 | return num_acked; | |||
850 | ||||
851 | fail: | |||
852 | for (ent = acked_ent; ent; ent = acked_ent) { | |||
853 | acked_ent = ent->next; | |||
854 | ngtcp2_rtb_entry_del(ent, rtb->mem); | |||
855 | } | |||
856 | ||||
857 | return rv; | |||
858 | } | |||
859 | ||||
860 | static int rtb_pkt_lost(ngtcp2_rtb *rtb, ngtcp2_conn_stat *cstat, | |||
861 | const ngtcp2_rtb_entry *ent, uint64_t loss_delay, | |||
862 | ngtcp2_tstamp lost_send_time, uint64_t pkt_thres) { | |||
863 | ngtcp2_tstamp loss_time; | |||
864 | ||||
865 | if (ent->ts <= lost_send_time || | |||
866 | rtb->largest_acked_tx_pkt_num >= ent->hd.pkt_num + (int64_t)pkt_thres) { | |||
867 | return 1; | |||
868 | } | |||
869 | ||||
870 | loss_time = cstat->loss_time[rtb->pktns_id]; | |||
871 | ||||
872 | if (loss_time == UINT64_MAX(18446744073709551615UL)) { | |||
873 | loss_time = ent->ts + loss_delay; | |||
874 | } else { | |||
875 | loss_time = ngtcp2_min(loss_time, ent->ts + loss_delay)((loss_time) < (ent->ts + loss_delay) ? (loss_time) : ( ent->ts + loss_delay)); | |||
876 | } | |||
877 | ||||
878 | cstat->loss_time[rtb->pktns_id] = loss_time; | |||
879 | ||||
880 | return 0; | |||
881 | } | |||
882 | ||||
883 | /* | |||
884 | * rtb_compute_pkt_loss_delay computes loss delay. | |||
885 | */ | |||
886 | static ngtcp2_duration compute_pkt_loss_delay(const ngtcp2_conn_stat *cstat) { | |||
887 | /* 9/8 is kTimeThreshold */ | |||
888 | ngtcp2_duration loss_delay = | |||
889 | ngtcp2_max(cstat->latest_rtt, cstat->smoothed_rtt)((cstat->latest_rtt) > (cstat->smoothed_rtt) ? (cstat ->latest_rtt) : (cstat->smoothed_rtt)) * 9 / 8; | |||
890 | return ngtcp2_max(loss_delay, NGTCP2_GRANULARITY)((loss_delay) > (((uint64_t)1000000ULL)) ? (loss_delay) : ( ((uint64_t)1000000ULL))); | |||
891 | } | |||
892 | ||||
893 | /* | |||
894 | * conn_all_ecn_pkt_lost returns nonzero if all ECN QUIC packets are | |||
895 | * lost during validation period. | |||
896 | */ | |||
897 | static int conn_all_ecn_pkt_lost(ngtcp2_conn *conn) { | |||
898 | ngtcp2_pktns *in_pktns = conn->in_pktns; | |||
899 | ngtcp2_pktns *hs_pktns = conn->hs_pktns; | |||
900 | ngtcp2_pktns *pktns = &conn->pktns; | |||
901 | ||||
902 | return (!in_pktns || in_pktns->tx.ecn.validation_pkt_sent == | |||
903 | in_pktns->tx.ecn.validation_pkt_lost) && | |||
904 | (!hs_pktns || hs_pktns->tx.ecn.validation_pkt_sent == | |||
905 | hs_pktns->tx.ecn.validation_pkt_lost) && | |||
906 | pktns->tx.ecn.validation_pkt_sent == pktns->tx.ecn.validation_pkt_lost; | |||
907 | } | |||
908 | ||||
909 | int ngtcp2_rtb_detect_lost_pkt(ngtcp2_rtb *rtb, ngtcp2_conn *conn, | |||
910 | ngtcp2_pktns *pktns, ngtcp2_conn_stat *cstat, | |||
911 | ngtcp2_duration pto, ngtcp2_tstamp ts) { | |||
912 | ngtcp2_rtb_entry *ent; | |||
913 | ngtcp2_duration loss_delay; | |||
914 | ngtcp2_tstamp lost_send_time; | |||
915 | ngtcp2_ksl_it it; | |||
916 | ngtcp2_tstamp latest_ts, oldest_ts; | |||
917 | int64_t last_lost_pkt_num; | |||
918 | ngtcp2_duration loss_window, congestion_period; | |||
919 | ngtcp2_cc *cc = rtb->cc; | |||
920 | int rv; | |||
921 | uint64_t pkt_thres = | |||
922 | rtb->cc_bytes_in_flight / cstat->max_udp_payload_size / 2; | |||
923 | size_t ecn_pkt_lost = 0; | |||
924 | ngtcp2_tstamp start_ts; | |||
925 | ||||
926 | pkt_thres = ngtcp2_max(pkt_thres, NGTCP2_PKT_THRESHOLD)((pkt_thres) > (3) ? (pkt_thres) : (3)); | |||
927 | cstat->loss_time[rtb->pktns_id] = UINT64_MAX(18446744073709551615UL); | |||
928 | loss_delay = compute_pkt_loss_delay(cstat); | |||
929 | lost_send_time = ts - loss_delay; | |||
930 | ||||
931 | it = ngtcp2_ksl_lower_bound(&rtb->ents, &rtb->largest_acked_tx_pkt_num); | |||
932 | for (; !ngtcp2_ksl_it_end(&it)((&it)->blk->n == (&it)->i && (& it)->blk->next == ((void*)0)); ngtcp2_ksl_it_next(&it)(++(&it)->i == (&it)->blk->n && (& it)->blk->next ? ((&it)->blk = (&it)->blk ->next, (&it)->i = 0) : 0)) { | |||
933 | ent = ngtcp2_ksl_it_get(&it); | |||
934 | ||||
935 | if (ent->flags & NGTCP2_RTB_ENTRY_FLAG_LOST_RETRANSMITTED0x10) { | |||
936 | break; | |||
937 | } | |||
938 | ||||
939 | if (rtb_pkt_lost(rtb, cstat, ent, loss_delay, lost_send_time, pkt_thres)) { | |||
940 | /* All entries from ent are considered to be lost. */ | |||
941 | latest_ts = oldest_ts = ent->ts; | |||
942 | last_lost_pkt_num = ent->hd.pkt_num; | |||
943 | ||||
944 | congestion_period = (cstat->smoothed_rtt + | |||
945 | ngtcp2_max(4 * cstat->rttvar, NGTCP2_GRANULARITY)((4 * cstat->rttvar) > (((uint64_t)1000000ULL)) ? (4 * cstat ->rttvar) : (((uint64_t)1000000ULL))) + | |||
946 | conn->remote.transport_params.max_ack_delay) * | |||
947 | NGTCP2_PERSISTENT_CONGESTION_THRESHOLD3; | |||
948 | ||||
949 | start_ts = ngtcp2_max(rtb->persistent_congestion_start_ts,((rtb->persistent_congestion_start_ts) > (cstat->first_rtt_sample_ts ) ? (rtb->persistent_congestion_start_ts) : (cstat->first_rtt_sample_ts )) | |||
950 | cstat->first_rtt_sample_ts)((rtb->persistent_congestion_start_ts) > (cstat->first_rtt_sample_ts ) ? (rtb->persistent_congestion_start_ts) : (cstat->first_rtt_sample_ts )); | |||
951 | ||||
952 | for (; !ngtcp2_ksl_it_end(&it)((&it)->blk->n == (&it)->i && (& it)->blk->next == ((void*)0));) { | |||
953 | ent = ngtcp2_ksl_it_get(&it); | |||
954 | ||||
955 | if (last_lost_pkt_num == ent->hd.pkt_num + 1 && ent->ts >= start_ts) { | |||
956 | last_lost_pkt_num = ent->hd.pkt_num; | |||
957 | oldest_ts = ent->ts; | |||
958 | } else { | |||
959 | last_lost_pkt_num = -1; | |||
960 | } | |||
961 | ||||
962 | if ((ent->flags & NGTCP2_RTB_ENTRY_FLAG_LOST_RETRANSMITTED0x10)) { | |||
963 | if (rtb->pktns_id != NGTCP2_PKTNS_ID_APPLICATION || | |||
964 | last_lost_pkt_num == -1 || | |||
965 | latest_ts - oldest_ts >= congestion_period) { | |||
966 | break; | |||
967 | } | |||
968 | ngtcp2_ksl_it_next(&it)(++(&it)->i == (&it)->blk->n && (& it)->blk->next ? ((&it)->blk = (&it)->blk ->next, (&it)->i = 0) : 0); | |||
969 | continue; | |||
970 | } | |||
971 | ||||
972 | if (ent->hd.pkt_num >= pktns->tx.ecn.start_pkt_num && | |||
973 | (ent->flags & NGTCP2_RTB_ENTRY_FLAG_ECN0x20)) { | |||
974 | ++ecn_pkt_lost; | |||
975 | } | |||
976 | ||||
977 | rtb_on_remove(rtb, ent, cstat); | |||
978 | rv = rtb_on_pkt_lost(rtb, &it, ent, conn, pktns, ts); | |||
979 | if (rv != 0) { | |||
980 | return rv; | |||
981 | } | |||
982 | } | |||
983 | ||||
984 | switch (conn->tx.ecn.state) { | |||
985 | case NGTCP2_ECN_STATE_TESTING: | |||
986 | if (conn->tx.ecn.validation_start_ts == UINT64_MAX(18446744073709551615UL)) { | |||
987 | break; | |||
988 | } | |||
989 | if (ts - conn->tx.ecn.validation_start_ts < 3 * pto) { | |||
990 | pktns->tx.ecn.validation_pkt_lost += ecn_pkt_lost; | |||
991 | assert(pktns->tx.ecn.validation_pkt_sent >=((void) (0)) | |||
992 | pktns->tx.ecn.validation_pkt_lost)((void) (0)); | |||
993 | break; | |||
994 | } | |||
995 | conn->tx.ecn.state = NGTCP2_ECN_STATE_UNKNOWN; | |||
996 | /* fall through */ | |||
997 | case NGTCP2_ECN_STATE_UNKNOWN: | |||
998 | pktns->tx.ecn.validation_pkt_lost += ecn_pkt_lost; | |||
999 | assert(pktns->tx.ecn.validation_pkt_sent >=((void) (0)) | |||
1000 | pktns->tx.ecn.validation_pkt_lost)((void) (0)); | |||
1001 | if (conn_all_ecn_pkt_lost(conn)) { | |||
1002 | conn->tx.ecn.state = NGTCP2_ECN_STATE_FAILED; | |||
1003 | } | |||
1004 | break; | |||
1005 | default: | |||
1006 | break; | |||
1007 | } | |||
1008 | ||||
1009 | cc->congestion_event(cc, cstat, latest_ts, ts); | |||
1010 | ||||
1011 | loss_window = latest_ts - oldest_ts; | |||
1012 | /* Persistent congestion situation is only evaluated for app | |||
1013 | * packet number space and for the packets sent after handshake | |||
1014 | * is confirmed. During handshake, there is not much packets | |||
1015 | * sent and also people seem to do lots of effort not to trigger | |||
1016 | * persistent congestion there, then it is a lot easier to just | |||
1017 | * not enable it during handshake. | |||
1018 | */ | |||
1019 | if (rtb->pktns_id == NGTCP2_PKTNS_ID_APPLICATION && loss_window > 0) { | |||
1020 | if (loss_window >= congestion_period) { | |||
1021 | ngtcp2_log_info(rtb->log, NGTCP2_LOG_EVENT_RCV, | |||
1022 | "persistent congestion loss_window=%" PRIu64"l" "u" | |||
1023 | " congestion_period=%" PRIu64"l" "u", | |||
1024 | loss_window, congestion_period); | |||
1025 | ||||
1026 | /* Reset min_rtt, srtt, and rttvar here. Next new RTT | |||
1027 | sample will be used to recalculate these values. */ | |||
1028 | cstat->min_rtt = UINT64_MAX(18446744073709551615UL); | |||
1029 | cstat->smoothed_rtt = conn->local.settings.initial_rtt; | |||
1030 | cstat->rttvar = conn->local.settings.initial_rtt / 2; | |||
1031 | cstat->first_rtt_sample_ts = UINT64_MAX(18446744073709551615UL); | |||
1032 | ||||
1033 | cc->on_persistent_congestion(cc, cstat, ts); | |||
1034 | } | |||
1035 | } | |||
1036 | ||||
1037 | break; | |||
1038 | } | |||
1039 | } | |||
1040 | ||||
1041 | ngtcp2_rtb_remove_excessive_lost_pkt(rtb, pkt_thres); | |||
1042 | ||||
1043 | return 0; | |||
1044 | } | |||
1045 | ||||
1046 | void ngtcp2_rtb_remove_excessive_lost_pkt(ngtcp2_rtb *rtb, size_t n) { | |||
1047 | ngtcp2_ksl_it it = ngtcp2_ksl_end(&rtb->ents); | |||
1048 | ngtcp2_rtb_entry *ent; | |||
1049 | int rv; | |||
1050 | ||||
1051 | for (; rtb->num_lost_pkts > n;) { | |||
1052 | assert(ngtcp2_ksl_it_end(&it))((void) (0)); | |||
1053 | ngtcp2_ksl_it_prev(&it); | |||
1054 | ent = ngtcp2_ksl_it_get(&it); | |||
1055 | ||||
1056 | assert(ent->flags & NGTCP2_RTB_ENTRY_FLAG_LOST_RETRANSMITTED)((void) (0)); | |||
1057 | ||||
1058 | ngtcp2_log_info(rtb->log, NGTCP2_LOG_EVENT_RCV, | |||
1059 | "removing stale lost pkn=%" PRId64"l" "d", ent->hd.pkt_num); | |||
1060 | ||||
1061 | --rtb->num_lost_pkts; | |||
1062 | rv = ngtcp2_ksl_remove(&rtb->ents, &it, &ent->hd.pkt_num); | |||
1063 | assert(0 == rv)((void) (0)); | |||
1064 | ngtcp2_rtb_entry_del(ent, rtb->mem); | |||
1065 | } | |||
1066 | } | |||
1067 | ||||
1068 | void ngtcp2_rtb_remove_expired_lost_pkt(ngtcp2_rtb *rtb, ngtcp2_duration pto, | |||
1069 | ngtcp2_tstamp ts) { | |||
1070 | ngtcp2_ksl_it it; | |||
1071 | ngtcp2_rtb_entry *ent; | |||
1072 | int rv; | |||
1073 | ||||
1074 | if (ngtcp2_ksl_len(&rtb->ents) == 0) { | |||
1075 | return; | |||
1076 | } | |||
1077 | ||||
1078 | it = ngtcp2_ksl_end(&rtb->ents); | |||
1079 | ||||
1080 | for (;;) { | |||
1081 | assert(ngtcp2_ksl_it_end(&it))((void) (0)); | |||
1082 | ||||
1083 | ngtcp2_ksl_it_prev(&it); | |||
1084 | ent = ngtcp2_ksl_it_get(&it); | |||
1085 | ||||
1086 | if (!(ent->flags & NGTCP2_RTB_ENTRY_FLAG_LOST_RETRANSMITTED0x10) || | |||
1087 | ts - ent->lost_ts < pto) { | |||
1088 | return; | |||
1089 | } | |||
1090 | ||||
1091 | ngtcp2_log_info(rtb->log, NGTCP2_LOG_EVENT_RCV, | |||
1092 | "removing stale lost pkn=%" PRId64"l" "d", ent->hd.pkt_num); | |||
1093 | ||||
1094 | --rtb->num_lost_pkts; | |||
1095 | rv = ngtcp2_ksl_remove(&rtb->ents, &it, &ent->hd.pkt_num); | |||
1096 | assert(0 == rv)((void) (0)); | |||
1097 | ngtcp2_rtb_entry_del(ent, rtb->mem); | |||
1098 | ||||
1099 | if (ngtcp2_ksl_len(&rtb->ents) == 0) { | |||
1100 | return; | |||
1101 | } | |||
1102 | } | |||
1103 | } | |||
1104 | ||||
1105 | ngtcp2_tstamp ngtcp2_rtb_lost_pkt_ts(ngtcp2_rtb *rtb) { | |||
1106 | ngtcp2_ksl_it it; | |||
1107 | ngtcp2_rtb_entry *ent; | |||
1108 | ||||
1109 | if (ngtcp2_ksl_len(&rtb->ents) == 0) { | |||
1110 | return UINT64_MAX(18446744073709551615UL); | |||
1111 | } | |||
1112 | ||||
1113 | it = ngtcp2_ksl_end(&rtb->ents); | |||
1114 | ngtcp2_ksl_it_prev(&it); | |||
1115 | ent = ngtcp2_ksl_it_get(&it); | |||
1116 | ||||
1117 | if (!(ent->flags & NGTCP2_RTB_ENTRY_FLAG_LOST_RETRANSMITTED0x10)) { | |||
1118 | return UINT64_MAX(18446744073709551615UL); | |||
1119 | } | |||
1120 | ||||
1121 | return ent->lost_ts; | |||
1122 | } | |||
1123 | ||||
1124 | static int rtb_on_pkt_lost_resched_move(ngtcp2_rtb *rtb, ngtcp2_conn *conn, | |||
1125 | ngtcp2_pktns *pktns, | |||
1126 | ngtcp2_rtb_entry *ent) { | |||
1127 | ngtcp2_frame_chain **pfrc, *frc; | |||
1128 | ngtcp2_stream *sfr; | |||
1129 | ngtcp2_strm *strm; | |||
1130 | int rv; | |||
1131 | ||||
1132 | ngtcp2_log_pkt_lost(rtb->log, ent->hd.pkt_num, ent->hd.type, ent->hd.flags, | |||
1133 | ent->ts); | |||
1134 | ||||
1135 | if (rtb->qlog) { | |||
1136 | ngtcp2_qlog_pkt_lost(rtb->qlog, ent); | |||
1137 | } | |||
1138 | ||||
1139 | if (ent->flags & NGTCP2_RTB_ENTRY_FLAG_PROBE0x01) { | |||
1140 | ngtcp2_log_info(rtb->log, NGTCP2_LOG_EVENT_RCV, | |||
1141 | "pkn=%" PRId64"l" "d" | |||
1142 | " is a probe packet, no retransmission is necessary", | |||
1143 | ent->hd.pkt_num); | |||
1144 | return 0; | |||
1145 | } | |||
1146 | ||||
1147 | if (!ent->frc) { | |||
1148 | /* PADDING only (or PADDING + ACK ) packets will have NULL | |||
1149 | ent->frc. */ | |||
1150 | assert(!(ent->flags & NGTCP2_RTB_ENTRY_FLAG_LOST_RETRANSMITTED))((void) (0)); | |||
1151 | assert(!(ent->flags & NGTCP2_RTB_ENTRY_FLAG_PTO_RECLAIMED))((void) (0)); | |||
1152 | return 0; | |||
1153 | } | |||
1154 | ||||
1155 | if (ent->flags & NGTCP2_RTB_ENTRY_FLAG_LOST_RETRANSMITTED0x10) { | |||
1156 | --rtb->num_lost_pkts; | |||
1157 | } | |||
1158 | ||||
1159 | if (ent->flags & NGTCP2_RTB_ENTRY_FLAG_LOST_RETRANSMITTED0x10) { | |||
1160 | ngtcp2_log_info(rtb->log, NGTCP2_LOG_EVENT_RCV, | |||
1161 | "pkn=%" PRId64"l" "d" | |||
1162 | " was declared lost and has already been retransmitted", | |||
1163 | ent->hd.pkt_num); | |||
1164 | return 0; | |||
1165 | } | |||
1166 | ||||
1167 | if (ent->flags & NGTCP2_RTB_ENTRY_FLAG_PTO_RECLAIMED0x08) { | |||
1168 | ngtcp2_log_info(rtb->log, NGTCP2_LOG_EVENT_RCV, | |||
1169 | "pkn=%" PRId64"l" "d" " has already been reclaimed on PTO", | |||
1170 | ent->hd.pkt_num); | |||
1171 | return 0; | |||
1172 | } | |||
1173 | ||||
1174 | pfrc = &ent->frc; | |||
1175 | ||||
1176 | for (; *pfrc;) { | |||
1177 | switch ((*pfrc)->fr.type) { | |||
1178 | case NGTCP2_FRAME_STREAM: | |||
1179 | frc = *pfrc; | |||
1180 | ||||
1181 | *pfrc = frc->next; | |||
1182 | frc->next = NULL((void*)0); | |||
1183 | sfr = &frc->fr.stream; | |||
1184 | ||||
1185 | strm = ngtcp2_conn_find_stream(conn, sfr->stream_id); | |||
1186 | if (!strm) { | |||
1187 | ngtcp2_frame_chain_del(frc, conn->mem); | |||
1188 | break; | |||
1189 | } | |||
1190 | rv = ngtcp2_strm_streamfrq_push(strm, frc); | |||
1191 | if (rv != 0) { | |||
1192 | ngtcp2_frame_chain_del(frc, conn->mem); | |||
1193 | return rv; | |||
1194 | } | |||
1195 | if (!ngtcp2_strm_is_tx_queued(strm)) { | |||
1196 | strm->cycle = ngtcp2_conn_tx_strmq_first_cycle(conn); | |||
1197 | rv = ngtcp2_conn_tx_strmq_push(conn, strm); | |||
1198 | if (rv != 0) { | |||
1199 | return rv; | |||
1200 | } | |||
1201 | } | |||
1202 | break; | |||
1203 | case NGTCP2_FRAME_CRYPTO: | |||
1204 | frc = *pfrc; | |||
1205 | ||||
1206 | *pfrc = frc->next; | |||
1207 | frc->next = NULL((void*)0); | |||
1208 | ||||
1209 | rv = ngtcp2_ksl_insert(&pktns->crypto.tx.frq, NULL((void*)0), | |||
1210 | &frc->fr.crypto.offset, frc); | |||
1211 | if (rv != 0) { | |||
1212 | assert(ngtcp2_err_is_fatal(rv))((void) (0)); | |||
1213 | ngtcp2_frame_chain_del(frc, conn->mem); | |||
1214 | return rv; | |||
1215 | } | |||
1216 | break; | |||
1217 | default: | |||
1218 | pfrc = &(*pfrc)->next; | |||
1219 | } | |||
1220 | } | |||
1221 | ||||
1222 | *pfrc = pktns->tx.frq; | |||
1223 | pktns->tx.frq = ent->frc; | |||
1224 | ent->frc = NULL((void*)0); | |||
1225 | ||||
1226 | return 0; | |||
1227 | } | |||
1228 | ||||
1229 | int ngtcp2_rtb_remove_all(ngtcp2_rtb *rtb, ngtcp2_conn *conn, | |||
1230 | ngtcp2_pktns *pktns, ngtcp2_conn_stat *cstat) { | |||
1231 | ngtcp2_rtb_entry *ent; | |||
1232 | ngtcp2_ksl_it it; | |||
1233 | int rv; | |||
1234 | ||||
1235 | it = ngtcp2_ksl_begin(&rtb->ents); | |||
1236 | ||||
1237 | for (; !ngtcp2_ksl_it_end(&it)((&it)->blk->n == (&it)->i && (& it)->blk->next == ((void*)0));) { | |||
1238 | ent = ngtcp2_ksl_it_get(&it); | |||
1239 | ||||
1240 | rtb_on_remove(rtb, ent, cstat); | |||
1241 | rv = ngtcp2_ksl_remove(&rtb->ents, &it, &ent->hd.pkt_num); | |||
1242 | assert(0 == rv)((void) (0)); | |||
1243 | ||||
1244 | rv = rtb_on_pkt_lost_resched_move(rtb, conn, pktns, ent); | |||
1245 | ngtcp2_rtb_entry_del(ent, rtb->mem); | |||
1246 | if (rv != 0) { | |||
1247 | return rv; | |||
1248 | } | |||
1249 | } | |||
1250 | ||||
1251 | return 0; | |||
1252 | } | |||
1253 | ||||
1254 | int ngtcp2_rtb_empty(ngtcp2_rtb *rtb) { | |||
1255 | return ngtcp2_ksl_len(&rtb->ents) == 0; | |||
1256 | } | |||
1257 | ||||
1258 | void ngtcp2_rtb_reset_cc_state(ngtcp2_rtb *rtb, int64_t cc_pkt_num) { | |||
1259 | rtb->cc_pkt_num = cc_pkt_num; | |||
1260 | rtb->cc_bytes_in_flight = 0; | |||
1261 | } | |||
1262 | ||||
1263 | ngtcp2_ssize ngtcp2_rtb_reclaim_on_pto(ngtcp2_rtb *rtb, ngtcp2_conn *conn, | |||
1264 | ngtcp2_pktns *pktns, size_t num_pkts) { | |||
1265 | ngtcp2_ksl_it it; | |||
1266 | ngtcp2_rtb_entry *ent; | |||
1267 | ngtcp2_ssize reclaimed; | |||
1268 | size_t atmost = num_pkts; | |||
1269 | ||||
1270 | it = ngtcp2_ksl_end(&rtb->ents); | |||
1271 | for (; !ngtcp2_ksl_it_begin(&it) && num_pkts >= 1;) { | |||
1272 | ngtcp2_ksl_it_prev(&it); | |||
1273 | ent = ngtcp2_ksl_it_get(&it); | |||
1274 | ||||
1275 | if ((ent->flags & (NGTCP2_RTB_ENTRY_FLAG_LOST_RETRANSMITTED0x10 | | |||
1276 | NGTCP2_RTB_ENTRY_FLAG_PTO_RECLAIMED0x08)) || | |||
1277 | !(ent->flags & NGTCP2_RTB_ENTRY_FLAG_RETRANSMITTABLE0x02)) { | |||
1278 | continue; | |||
1279 | } | |||
1280 | ||||
1281 | assert(ent->frc)((void) (0)); | |||
1282 | ||||
1283 | reclaimed = rtb_reclaim_frame(rtb, conn, pktns, ent); | |||
1284 | if (reclaimed < 0) { | |||
1285 | return reclaimed; | |||
1286 | } | |||
1287 | ||||
1288 | /* Mark reclaimed even if reclaimed == 0 so that we can skip it in | |||
1289 | the next run. */ | |||
1290 | ent->flags |= NGTCP2_RTB_ENTRY_FLAG_PTO_RECLAIMED0x08; | |||
1291 | ||||
1292 | assert(rtb->num_retransmittable)((void) (0)); | |||
1293 | --rtb->num_retransmittable; | |||
1294 | ||||
1295 | if (reclaimed) { | |||
1296 | --num_pkts; | |||
1297 | } | |||
1298 | } | |||
1299 | ||||
1300 | return (ngtcp2_ssize)(atmost - num_pkts); | |||
1301 | } |