/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 | } |