| File: | out/../deps/ngtcp2/ngtcp2/lib/ngtcp2_rtb.c |
| Warning: | line 1095, column 5 Value stored to 'rv' is never read |
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); |
Value stored to 'rv' is never read | |
| 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 | } |