Coverage Report

Created: 2026-06-07 07:07

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/samba/third_party/ngtcp2/lib/ngtcp2_strm.c
Line
Count
Source
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_strm.h"
26
27
#include <string.h>
28
#include <assert.h>
29
30
#include "ngtcp2_rtb.h"
31
#include "ngtcp2_pkt.h"
32
#include "ngtcp2_vec.h"
33
#include "ngtcp2_frame_chain.h"
34
35
void ngtcp2_strm_init(ngtcp2_strm *strm, int64_t stream_id, uint32_t flags,
36
                      uint64_t max_rx_offset, uint64_t max_tx_offset,
37
                      void *stream_user_data, ngtcp2_objalloc *frc_objalloc,
38
0
                      const ngtcp2_mem *mem) {
39
0
  *strm = (ngtcp2_strm){
40
0
    .pe.index = NGTCP2_PQ_BAD_INDEX,
41
0
    .frc_objalloc = frc_objalloc,
42
0
    .tx =
43
0
      {
44
0
        .max_offset = max_tx_offset,
45
0
        .last_blocked_offset = UINT64_MAX,
46
0
        .last_max_stream_data_ts = UINT64_MAX,
47
0
        .last_lost_pkt_num = -1,
48
0
      },
49
0
    .rx =
50
0
      {
51
0
        .max_offset = max_rx_offset,
52
0
        .unsent_max_offset = max_rx_offset,
53
0
        .window = max_rx_offset,
54
0
      },
55
0
    .mem = mem,
56
0
    .stream_id = stream_id,
57
0
    .stream_user_data = stream_user_data,
58
0
    .flags = flags,
59
0
  };
60
0
}
61
62
0
void ngtcp2_strm_free(ngtcp2_strm *strm) {
63
0
  ngtcp2_ksl_it it;
64
65
0
  if (strm == NULL) {
66
0
    return;
67
0
  }
68
69
0
  if (strm->tx.streamfrq) {
70
0
    for (it = ngtcp2_ksl_begin(strm->tx.streamfrq); !ngtcp2_ksl_it_end(&it);
71
0
         ngtcp2_ksl_it_next(&it)) {
72
0
      ngtcp2_frame_chain_objalloc_del(ngtcp2_ksl_it_get(&it),
73
0
                                      strm->frc_objalloc, strm->mem);
74
0
    }
75
76
0
    ngtcp2_ksl_free(strm->tx.streamfrq);
77
0
    ngtcp2_mem_free(strm->mem, strm->tx.streamfrq);
78
0
  }
79
80
0
  if (strm->rx.rob) {
81
0
    ngtcp2_rob_free(strm->rx.rob);
82
0
    ngtcp2_mem_free(strm->mem, strm->rx.rob);
83
0
  }
84
85
0
  if (strm->tx.acked_offset) {
86
0
    ngtcp2_gaptr_free(strm->tx.acked_offset);
87
0
    ngtcp2_mem_free(strm->mem, strm->tx.acked_offset);
88
0
  }
89
0
}
90
91
0
static int strm_rob_init(ngtcp2_strm *strm) {
92
0
  int rv;
93
0
  ngtcp2_rob *rob = ngtcp2_mem_malloc(strm->mem, sizeof(*rob));
94
95
0
  if (rob == NULL) {
96
0
    return NGTCP2_ERR_NOMEM;
97
0
  }
98
99
0
  rv = ngtcp2_rob_init(rob, 8 * 1024, strm->mem);
100
0
  if (rv != 0) {
101
0
    ngtcp2_mem_free(strm->mem, rob);
102
0
    return rv;
103
0
  }
104
105
0
  strm->rx.rob = rob;
106
107
0
  return 0;
108
0
}
109
110
0
uint64_t ngtcp2_strm_rx_offset(const ngtcp2_strm *strm) {
111
0
  if (strm->rx.rob == NULL) {
112
0
    return strm->rx.cont_offset;
113
0
  }
114
0
  return ngtcp2_rob_first_gap_offset(strm->rx.rob);
115
0
}
116
117
/* strm_rob_heavily_fragmented returns nonzero if the number of gaps
118
   in |rob| exceeds the limit. */
119
0
static int strm_rob_heavily_fragmented(const ngtcp2_rob *rob) {
120
0
  return ngtcp2_ksl_len(&rob->gapksl) >= 4000;
121
0
}
122
123
ngtcp2_ssize ngtcp2_strm_recv_reordering(ngtcp2_strm *strm, const uint8_t *data,
124
0
                                         size_t datalen, uint64_t offset) {
125
0
  int rv;
126
0
  ngtcp2_ssize nwrite;
127
128
0
  if (strm->rx.rob == NULL) {
129
0
    rv = strm_rob_init(strm);
130
0
    if (rv != 0) {
131
0
      return rv;
132
0
    }
133
134
0
    if (strm->rx.cont_offset) {
135
0
      ngtcp2_rob_remove_prefix(strm->rx.rob, strm->rx.cont_offset);
136
0
    }
137
0
  }
138
139
0
  nwrite = ngtcp2_rob_push(strm->rx.rob, offset, data, datalen);
140
0
  if (nwrite < 0) {
141
0
    return nwrite;
142
0
  }
143
144
0
  if (strm_rob_heavily_fragmented(strm->rx.rob)) {
145
0
    return NGTCP2_ERR_INTERNAL;
146
0
  }
147
148
0
  return nwrite;
149
0
}
150
151
0
void ngtcp2_strm_update_rx_offset(ngtcp2_strm *strm, uint64_t offset) {
152
0
  if (strm->rx.rob == NULL) {
153
0
    strm->rx.cont_offset = offset;
154
0
    return;
155
0
  }
156
157
0
  ngtcp2_rob_remove_prefix(strm->rx.rob, offset);
158
0
}
159
160
0
void ngtcp2_strm_discard_reordered_data(ngtcp2_strm *strm) {
161
0
  if (strm->rx.rob == NULL) {
162
0
    return;
163
0
  }
164
165
0
  strm->rx.cont_offset = ngtcp2_strm_rx_offset(strm);
166
167
0
  ngtcp2_rob_free(strm->rx.rob);
168
0
  ngtcp2_mem_free(strm->mem, strm->rx.rob);
169
0
  strm->rx.rob = NULL;
170
0
}
171
172
0
void ngtcp2_strm_shutdown(ngtcp2_strm *strm, uint32_t flags) {
173
0
  strm->flags |= flags & NGTCP2_STRM_FLAG_SHUT_RDWR;
174
0
}
175
176
0
static int strm_streamfrq_init(ngtcp2_strm *strm) {
177
0
  ngtcp2_ksl *streamfrq = ngtcp2_mem_malloc(strm->mem, sizeof(*streamfrq));
178
0
  if (streamfrq == NULL) {
179
0
    return NGTCP2_ERR_NOMEM;
180
0
  }
181
182
0
  ngtcp2_ksl_init(streamfrq, ngtcp2_ksl_uint64_less,
183
0
                  ngtcp2_ksl_uint64_less_search, sizeof(uint64_t), strm->mem);
184
185
0
  strm->tx.streamfrq = streamfrq;
186
187
0
  return 0;
188
0
}
189
190
0
int ngtcp2_strm_streamfrq_push(ngtcp2_strm *strm, ngtcp2_frame_chain *frc) {
191
0
  int rv;
192
193
0
  assert(frc->fr.hd.type == NGTCP2_FRAME_STREAM ||
194
0
         frc->fr.hd.type == NGTCP2_FRAME_CRYPTO);
195
0
  assert(frc->next == NULL);
196
197
0
  if (strm->tx.streamfrq == NULL) {
198
0
    rv = strm_streamfrq_init(strm);
199
0
    if (rv != 0) {
200
0
      return rv;
201
0
    }
202
0
  } else if (ngtcp2_ksl_len(strm->tx.streamfrq) >= 8000) {
203
0
    return NGTCP2_ERR_INTERNAL;
204
0
  }
205
206
0
  return ngtcp2_ksl_insert(strm->tx.streamfrq, NULL, &frc->fr.stream.offset,
207
0
                           frc);
208
0
}
209
210
static int strm_streamfrq_unacked_pop(ngtcp2_strm *strm,
211
0
                                      ngtcp2_frame_chain **pfrc) {
212
0
  ngtcp2_frame_chain *frc, *nfrc;
213
0
  ngtcp2_stream *fr, *nfr;
214
0
  uint64_t offset, end_offset;
215
0
  size_t idx, end_idx;
216
0
  uint64_t base_offset, end_base_offset;
217
0
  ngtcp2_range gap;
218
0
  ngtcp2_vec *v;
219
0
  int rv;
220
0
  ngtcp2_ksl_it it;
221
222
0
  *pfrc = NULL;
223
224
0
  assert(strm->tx.streamfrq);
225
0
  assert(ngtcp2_ksl_len(strm->tx.streamfrq));
226
227
0
  for (it = ngtcp2_ksl_begin(strm->tx.streamfrq); !ngtcp2_ksl_it_end(&it);) {
228
0
    frc = ngtcp2_ksl_it_get(&it);
229
0
    fr = &frc->fr.stream;
230
231
0
    ngtcp2_ksl_remove_hint(strm->tx.streamfrq, &it, &it, &fr->offset);
232
233
0
    idx = 0;
234
0
    offset = fr->offset;
235
0
    base_offset = 0;
236
237
0
    gap = ngtcp2_strm_get_unacked_range_after(strm, offset);
238
0
    if (gap.begin < offset) {
239
0
      gap.begin = offset;
240
0
    }
241
242
0
    for (; idx < fr->datacnt && offset < gap.begin; ++idx) {
243
0
      v = &fr->data[idx];
244
0
      if (offset + v->len > gap.begin) {
245
0
        base_offset = gap.begin - offset;
246
0
        break;
247
0
      }
248
249
0
      offset += v->len;
250
0
    }
251
252
0
    if (idx == fr->datacnt) {
253
0
      if (fr->fin) {
254
0
        if (strm->flags & NGTCP2_STRM_FLAG_FIN_ACKED) {
255
0
          ngtcp2_frame_chain_objalloc_del(frc, strm->frc_objalloc, strm->mem);
256
0
          assert(ngtcp2_ksl_len(strm->tx.streamfrq) == 0);
257
0
          return 0;
258
0
        }
259
260
0
        fr->offset += ngtcp2_vec_len(fr->data, fr->datacnt);
261
0
        fr->datacnt = 0;
262
263
0
        *pfrc = frc;
264
265
0
        return 0;
266
0
      }
267
268
0
      if (fr->offset == 0 && fr->datacnt == 0 && strm->tx.offset == 0 &&
269
0
          !(strm->flags & NGTCP2_STRM_FLAG_ANY_ACKED)) {
270
0
        *pfrc = frc;
271
272
0
        return 0;
273
0
      }
274
275
0
      ngtcp2_frame_chain_objalloc_del(frc, strm->frc_objalloc, strm->mem);
276
277
0
      continue;
278
0
    }
279
280
0
    assert(gap.begin == offset + base_offset);
281
282
0
    end_idx = idx;
283
0
    end_offset = offset;
284
0
    end_base_offset = 0;
285
286
0
    for (; end_idx < fr->datacnt; ++end_idx) {
287
0
      v = &fr->data[end_idx];
288
0
      if (end_offset + v->len > gap.end) {
289
0
        end_base_offset = gap.end - end_offset;
290
0
        break;
291
0
      }
292
293
0
      end_offset += v->len;
294
0
    }
295
296
0
    if (fr->offset == offset && base_offset == 0 && fr->datacnt == end_idx) {
297
0
      *pfrc = frc;
298
0
      return 0;
299
0
    }
300
301
0
    if (fr->datacnt == end_idx) {
302
0
      memmove(fr->data, fr->data + idx, sizeof(fr->data[0]) * (end_idx - idx));
303
304
0
      assert(fr->data[0].len > base_offset);
305
306
0
      fr->offset = offset + base_offset;
307
0
      fr->datacnt = end_idx - idx;
308
0
      ngtcp2_vec_drop(&fr->data[0], (size_t)base_offset);
309
310
0
      *pfrc = frc;
311
312
0
      return 0;
313
0
    }
314
315
0
    rv = ngtcp2_frame_chain_stream_datacnt_objalloc_new(
316
0
      &nfrc, fr->datacnt - end_idx, strm->frc_objalloc, strm->mem);
317
0
    if (rv != 0) {
318
0
      ngtcp2_frame_chain_objalloc_del(frc, strm->frc_objalloc, strm->mem);
319
0
      return rv;
320
0
    }
321
322
0
    nfr = &nfrc->fr.stream;
323
0
    memcpy(nfr->data, fr->data + end_idx,
324
0
           sizeof(nfr->data[0]) * (fr->datacnt - end_idx));
325
326
0
    assert(nfr->data[0].len > end_base_offset);
327
328
0
    nfr->type = fr->type;
329
0
    nfr->flags = 0;
330
0
    nfr->fin = fr->fin;
331
0
    nfr->stream_id = fr->stream_id;
332
0
    nfr->offset = end_offset + end_base_offset;
333
0
    nfr->datacnt = fr->datacnt - end_idx;
334
0
    ngtcp2_vec_drop(&nfr->data[0], (size_t)end_base_offset);
335
336
0
    rv = ngtcp2_ksl_insert(strm->tx.streamfrq, NULL, &nfr->offset, nfrc);
337
0
    if (rv != 0) {
338
0
      assert(ngtcp2_err_is_fatal(rv));
339
0
      ngtcp2_frame_chain_objalloc_del(nfrc, strm->frc_objalloc, strm->mem);
340
0
      ngtcp2_frame_chain_objalloc_del(frc, strm->frc_objalloc, strm->mem);
341
342
0
      return rv;
343
0
    }
344
345
0
    if (end_base_offset) {
346
0
      ++end_idx;
347
0
    }
348
349
0
    memmove(fr->data, fr->data + idx, sizeof(fr->data[0]) * (end_idx - idx));
350
351
0
    assert(fr->data[0].len > base_offset);
352
353
0
    fr->fin = 0;
354
0
    fr->offset = offset + base_offset;
355
0
    fr->datacnt = end_idx - idx;
356
357
0
    if (end_base_offset) {
358
0
      assert(fr->data[fr->datacnt - 1].len > end_base_offset);
359
0
      fr->data[fr->datacnt - 1].len = (size_t)end_base_offset;
360
0
    }
361
362
0
    ngtcp2_vec_drop(&fr->data[0], (size_t)base_offset);
363
364
0
    *pfrc = frc;
365
366
0
    return 0;
367
0
  }
368
369
0
  return 0;
370
0
}
371
372
int ngtcp2_strm_streamfrq_pop(ngtcp2_strm *strm, ngtcp2_frame_chain **pfrc,
373
0
                              size_t left) {
374
0
  ngtcp2_stream *fr, *nfr;
375
0
  ngtcp2_frame_chain *frc, *nfrc;
376
0
  int rv;
377
0
  size_t nmerged;
378
0
  uint64_t datalen;
379
0
  ngtcp2_vec data[NGTCP2_MAX_STREAM_DATACNT];
380
0
  size_t datacnt;
381
0
  uint64_t unacked_offset;
382
383
0
  if (strm->tx.streamfrq == NULL || ngtcp2_ksl_len(strm->tx.streamfrq) == 0) {
384
0
    *pfrc = NULL;
385
0
    return 0;
386
0
  }
387
388
0
  rv = strm_streamfrq_unacked_pop(strm, &frc);
389
0
  if (rv != 0) {
390
0
    return rv;
391
0
  }
392
393
0
  if (frc == NULL) {
394
0
    *pfrc = NULL;
395
0
    return 0;
396
0
  }
397
398
0
  fr = &frc->fr.stream;
399
0
  datalen = ngtcp2_vec_len(fr->data, fr->datacnt);
400
401
  /* datalen could be zero if 0 length STREAM has been sent */
402
  /* We might see more data in the queue, then left < datalen could be
403
     true.  We only see the first one for now. */
404
0
  if ((fr->type == NGTCP2_FRAME_STREAM &&
405
0
       (left < datalen && left < NGTCP2_MIN_STREAM_DATALEN)) ||
406
0
      (left == 0 && datalen)) {
407
0
    rv = ngtcp2_ksl_insert(strm->tx.streamfrq, NULL, &fr->offset, frc);
408
0
    if (rv != 0) {
409
0
      assert(ngtcp2_err_is_fatal(rv));
410
0
      ngtcp2_frame_chain_objalloc_del(frc, strm->frc_objalloc, strm->mem);
411
0
      return rv;
412
0
    }
413
414
0
    *pfrc = NULL;
415
416
0
    return 0;
417
0
  }
418
419
0
  if (datalen > left) {
420
0
    datacnt = 0;
421
0
    ngtcp2_vec_split(data, &datacnt, fr->data, &fr->datacnt, left,
422
0
                     NGTCP2_MAX_STREAM_DATACNT);
423
424
0
    assert(fr->datacnt > 0);
425
0
    assert(datacnt > 0);
426
427
0
    rv = ngtcp2_frame_chain_stream_datacnt_objalloc_new(
428
0
      &nfrc, datacnt, strm->frc_objalloc, strm->mem);
429
0
    if (rv != 0) {
430
0
      assert(ngtcp2_err_is_fatal(rv));
431
0
      ngtcp2_frame_chain_objalloc_del(frc, strm->frc_objalloc, strm->mem);
432
0
      return rv;
433
0
    }
434
435
0
    nfr = &nfrc->fr.stream;
436
0
    nfr->type = fr->type;
437
0
    nfr->flags = 0;
438
0
    nfr->fin = fr->fin;
439
0
    nfr->stream_id = fr->stream_id;
440
0
    nfr->offset = fr->offset + left;
441
0
    nfr->datacnt = datacnt;
442
0
    ngtcp2_vec_copy(nfr->data, data, datacnt);
443
444
0
    rv = ngtcp2_ksl_insert(strm->tx.streamfrq, NULL, &nfr->offset, nfrc);
445
0
    if (rv != 0) {
446
0
      assert(ngtcp2_err_is_fatal(rv));
447
0
      ngtcp2_frame_chain_objalloc_del(nfrc, strm->frc_objalloc, strm->mem);
448
0
      ngtcp2_frame_chain_objalloc_del(frc, strm->frc_objalloc, strm->mem);
449
450
0
      return rv;
451
0
    }
452
453
0
    fr->fin = 0;
454
455
0
    *pfrc = frc;
456
457
0
    return 0;
458
0
  }
459
460
0
  left -= (size_t)datalen;
461
462
0
  ngtcp2_vec_copy(data, fr->data, fr->datacnt);
463
0
  datacnt = fr->datacnt;
464
465
0
  for (; left && ngtcp2_ksl_len(strm->tx.streamfrq);) {
466
0
    unacked_offset = ngtcp2_strm_streamfrq_unacked_offset(strm);
467
0
    if (unacked_offset != fr->offset + datalen) {
468
0
      assert(fr->offset + datalen < unacked_offset);
469
0
      break;
470
0
    }
471
472
0
    rv = strm_streamfrq_unacked_pop(strm, &nfrc);
473
0
    if (rv != 0) {
474
0
      assert(ngtcp2_err_is_fatal(rv));
475
0
      ngtcp2_frame_chain_objalloc_del(frc, strm->frc_objalloc, strm->mem);
476
0
      return rv;
477
0
    }
478
0
    if (nfrc == NULL) {
479
0
      break;
480
0
    }
481
482
0
    nfr = &nfrc->fr.stream;
483
484
0
    if (nfr->fin && nfr->datacnt == 0) {
485
0
      fr->fin = 1;
486
0
      ngtcp2_frame_chain_objalloc_del(nfrc, strm->frc_objalloc, strm->mem);
487
0
      break;
488
0
    }
489
490
0
    nmerged = ngtcp2_vec_merge(data, &datacnt, nfr->data, &nfr->datacnt, left,
491
0
                               NGTCP2_MAX_STREAM_DATACNT);
492
0
    if (nmerged == 0) {
493
0
      rv = ngtcp2_ksl_insert(strm->tx.streamfrq, NULL, &nfr->offset, nfrc);
494
0
      if (rv != 0) {
495
0
        assert(ngtcp2_err_is_fatal(rv));
496
0
        ngtcp2_frame_chain_objalloc_del(nfrc, strm->frc_objalloc, strm->mem);
497
0
        ngtcp2_frame_chain_objalloc_del(frc, strm->frc_objalloc, strm->mem);
498
499
0
        return rv;
500
0
      }
501
502
0
      break;
503
0
    }
504
505
0
    datalen += nmerged;
506
0
    left -= nmerged;
507
508
0
    if (nfr->datacnt == 0) {
509
0
      fr->fin = nfr->fin;
510
0
      ngtcp2_frame_chain_objalloc_del(nfrc, strm->frc_objalloc, strm->mem);
511
0
      continue;
512
0
    }
513
514
0
    nfr->offset += nmerged;
515
516
0
    rv = ngtcp2_ksl_insert(strm->tx.streamfrq, NULL, &nfr->offset, nfrc);
517
0
    if (rv != 0) {
518
0
      ngtcp2_frame_chain_objalloc_del(nfrc, strm->frc_objalloc, strm->mem);
519
0
      ngtcp2_frame_chain_objalloc_del(frc, strm->frc_objalloc, strm->mem);
520
0
      return rv;
521
0
    }
522
523
0
    break;
524
0
  }
525
526
0
  if (datacnt == fr->datacnt) {
527
0
    if (datacnt > 0) {
528
0
      fr->data[datacnt - 1] = data[datacnt - 1];
529
0
    }
530
531
0
    *pfrc = frc;
532
533
0
    return 0;
534
0
  }
535
536
0
  assert(datacnt > fr->datacnt);
537
538
0
  rv = ngtcp2_frame_chain_stream_datacnt_objalloc_new(
539
0
    &nfrc, datacnt, strm->frc_objalloc, strm->mem);
540
0
  if (rv != 0) {
541
0
    ngtcp2_frame_chain_objalloc_del(frc, strm->frc_objalloc, strm->mem);
542
0
    return rv;
543
0
  }
544
545
0
  nfr = &nfrc->fr.stream;
546
0
  nfr->type = fr->type;
547
0
  nfr->flags = fr->flags;
548
0
  nfr->fin = fr->fin;
549
0
  nfr->stream_id = fr->stream_id;
550
0
  nfr->offset = fr->offset;
551
0
  nfr->datacnt = datacnt;
552
0
  ngtcp2_vec_copy(nfr->data, data, datacnt);
553
554
0
  ngtcp2_frame_chain_objalloc_del(frc, strm->frc_objalloc, strm->mem);
555
556
0
  *pfrc = nfrc;
557
558
0
  return 0;
559
0
}
560
561
0
uint64_t ngtcp2_strm_streamfrq_unacked_offset(const ngtcp2_strm *strm) {
562
0
  ngtcp2_frame_chain *frc;
563
0
  ngtcp2_stream *fr;
564
0
  ngtcp2_range gap;
565
0
  ngtcp2_ksl_it it;
566
0
  uint64_t datalen;
567
568
0
  assert(strm->tx.streamfrq);
569
0
  assert(ngtcp2_ksl_len(strm->tx.streamfrq));
570
571
0
  for (it = ngtcp2_ksl_begin(strm->tx.streamfrq); !ngtcp2_ksl_it_end(&it);
572
0
       ngtcp2_ksl_it_next(&it)) {
573
0
    frc = ngtcp2_ksl_it_get(&it);
574
0
    fr = &frc->fr.stream;
575
576
0
    gap = ngtcp2_strm_get_unacked_range_after(strm, fr->offset);
577
578
0
    datalen = ngtcp2_vec_len(fr->data, fr->datacnt);
579
580
0
    if (gap.begin <= fr->offset) {
581
0
      return fr->offset;
582
0
    }
583
584
0
    if (gap.begin < fr->offset + datalen) {
585
0
      return gap.begin;
586
0
    }
587
588
0
    if (fr->offset + datalen == gap.begin && fr->fin &&
589
0
        !(strm->flags & NGTCP2_STRM_FLAG_FIN_ACKED)) {
590
0
      return fr->offset + datalen;
591
0
    }
592
0
  }
593
594
0
  return (uint64_t)-1;
595
0
}
596
597
0
ngtcp2_frame_chain *ngtcp2_strm_streamfrq_top(const ngtcp2_strm *strm) {
598
0
  ngtcp2_ksl_it it;
599
600
0
  assert(strm->tx.streamfrq);
601
0
  assert(ngtcp2_ksl_len(strm->tx.streamfrq));
602
603
0
  it = ngtcp2_ksl_begin(strm->tx.streamfrq);
604
605
0
  return ngtcp2_ksl_it_get(&it);
606
0
}
607
608
0
int ngtcp2_strm_streamfrq_empty(const ngtcp2_strm *strm) {
609
0
  return strm->tx.streamfrq == NULL || ngtcp2_ksl_len(strm->tx.streamfrq) == 0;
610
0
}
611
612
0
void ngtcp2_strm_streamfrq_clear(ngtcp2_strm *strm) {
613
0
  ngtcp2_frame_chain *frc;
614
0
  ngtcp2_ksl_it it;
615
616
0
  if (strm->tx.streamfrq == NULL) {
617
0
    return;
618
0
  }
619
620
0
  for (it = ngtcp2_ksl_begin(strm->tx.streamfrq); !ngtcp2_ksl_it_end(&it);
621
0
       ngtcp2_ksl_it_next(&it)) {
622
0
    frc = ngtcp2_ksl_it_get(&it);
623
0
    ngtcp2_frame_chain_objalloc_del(frc, strm->frc_objalloc, strm->mem);
624
0
  }
625
626
0
  ngtcp2_ksl_clear(strm->tx.streamfrq);
627
0
}
628
629
0
int ngtcp2_strm_is_tx_queued(const ngtcp2_strm *strm) {
630
0
  return strm->pe.index != NGTCP2_PQ_BAD_INDEX;
631
0
}
632
633
0
int ngtcp2_strm_is_all_tx_data_acked(const ngtcp2_strm *strm) {
634
0
  if (strm->tx.acked_offset == NULL) {
635
0
    return strm->tx.cont_acked_offset == strm->tx.offset;
636
0
  }
637
638
0
  return ngtcp2_gaptr_first_gap_offset(strm->tx.acked_offset) ==
639
0
         strm->tx.offset;
640
0
}
641
642
0
int ngtcp2_strm_is_all_tx_data_fin_acked(const ngtcp2_strm *strm) {
643
0
  return (strm->flags & NGTCP2_STRM_FLAG_FIN_ACKED) &&
644
0
         ngtcp2_strm_is_all_tx_data_acked(strm);
645
0
}
646
647
ngtcp2_range ngtcp2_strm_get_unacked_range_after(const ngtcp2_strm *strm,
648
0
                                                 uint64_t offset) {
649
0
  if (strm->tx.acked_offset == NULL) {
650
0
    return (ngtcp2_range){
651
0
      .begin = strm->tx.cont_acked_offset,
652
0
      .end = UINT64_MAX,
653
0
    };
654
0
  }
655
656
0
  return ngtcp2_gaptr_get_first_gap_after(strm->tx.acked_offset, offset);
657
0
}
658
659
0
uint64_t ngtcp2_strm_get_acked_offset(const ngtcp2_strm *strm) {
660
0
  if (strm->tx.acked_offset == NULL) {
661
0
    return strm->tx.cont_acked_offset;
662
0
  }
663
664
0
  return ngtcp2_gaptr_first_gap_offset(strm->tx.acked_offset);
665
0
}
666
667
0
static int strm_acked_offset_init(ngtcp2_strm *strm) {
668
0
  ngtcp2_gaptr *acked_offset =
669
0
    ngtcp2_mem_malloc(strm->mem, sizeof(*acked_offset));
670
671
0
  if (acked_offset == NULL) {
672
0
    return NGTCP2_ERR_NOMEM;
673
0
  }
674
675
0
  ngtcp2_gaptr_init(acked_offset, strm->mem);
676
677
0
  strm->tx.acked_offset = acked_offset;
678
679
0
  return 0;
680
0
}
681
682
0
int ngtcp2_strm_ack_data(ngtcp2_strm *strm, uint64_t offset, uint64_t len) {
683
0
  int rv;
684
685
0
  if (strm->tx.acked_offset == NULL) {
686
0
    if (strm->tx.cont_acked_offset == offset) {
687
0
      strm->tx.cont_acked_offset += len;
688
0
      return 0;
689
0
    }
690
691
0
    rv = strm_acked_offset_init(strm);
692
0
    if (rv != 0) {
693
0
      return rv;
694
0
    }
695
696
0
    rv =
697
0
      ngtcp2_gaptr_push(strm->tx.acked_offset, 0, strm->tx.cont_acked_offset);
698
0
    if (rv != 0) {
699
0
      return rv;
700
0
    }
701
0
  }
702
703
0
  rv = ngtcp2_gaptr_push(strm->tx.acked_offset, offset, len);
704
0
  if (rv != 0) {
705
0
    return rv;
706
0
  }
707
708
0
  if (ngtcp2_ksl_len(&strm->tx.acked_offset->gap) >= 4000) {
709
0
    return NGTCP2_ERR_INTERNAL;
710
0
  }
711
712
0
  return 0;
713
0
}
714
715
void ngtcp2_strm_set_app_error_code(ngtcp2_strm *strm,
716
0
                                    uint64_t app_error_code) {
717
0
  if (strm->flags & NGTCP2_STRM_FLAG_APP_ERROR_CODE_SET) {
718
0
    return;
719
0
  }
720
721
0
  assert(0 == strm->app_error_code);
722
723
0
  strm->flags |= NGTCP2_STRM_FLAG_APP_ERROR_CODE_SET;
724
0
  strm->app_error_code = app_error_code;
725
0
}
726
727
0
int ngtcp2_strm_require_retransmit_reset_stream(const ngtcp2_strm *strm) {
728
0
  return !ngtcp2_strm_is_all_tx_data_fin_acked(strm);
729
0
}
730
731
0
int ngtcp2_strm_require_retransmit_stop_sending(const ngtcp2_strm *strm) {
732
0
  return !(strm->flags & NGTCP2_STRM_FLAG_SHUT_RD) ||
733
0
         ngtcp2_strm_rx_offset(strm) != strm->rx.last_offset;
734
0
}
735
736
int ngtcp2_strm_require_retransmit_max_stream_data(
737
0
  const ngtcp2_strm *strm, const ngtcp2_max_stream_data *fr) {
738
0
  return fr->max_stream_data == strm->rx.max_offset &&
739
0
         !(strm->flags &
740
0
           (NGTCP2_STRM_FLAG_SHUT_RD | NGTCP2_STRM_FLAG_STOP_SENDING));
741
0
}
742
743
int ngtcp2_strm_require_retransmit_stream_data_blocked(
744
0
  const ngtcp2_strm *strm, const ngtcp2_stream_data_blocked *fr) {
745
0
  return fr->offset == strm->tx.max_offset &&
746
0
         !(strm->flags & NGTCP2_STRM_FLAG_SHUT_WR);
747
0
}