1 /*
2 * Copyright 2022-2026 The OpenSSL Project Authors. All Rights Reserved.
3 *
4 * Licensed under the Apache License 2.0 (the "License"). You may not use
5 * this file except in compliance with the License. You can obtain a copy
6 * in the file LICENSE in the source distribution or at
7 * https://www.openssl.org/source/license.html
8 */
9
10 #include "internal/uint_set.h"
11 #include "internal/common.h"
12 #include "internal/quic_stream.h"
13 #include "internal/quic_strm_reas.h"
14 #include "internal/list.h"
15 #include "internal/quic_channel.h"
16
17 #define STDERR NULL
18 /* ARGSUSED */
print_foo(void * f,...)19 static void print_foo(void *f, ...)
20 {
21 }
22
23 #define DEBUG_PRINT print_foo
24
25 #define DIRECT_STORAGE_SZ (2 * sizeof(void *))
26
27 /*
28 * Maximal allocation overhead in packet buffers is ~64kB for
29 * connection. If ~64kB limit is exceeded, then the newly received
30 * chunks are moved from the packet to the stream buffer.
31 */
32 #define PKT_BUFFER_OVERHEAD_TRESHOLD (65535)
33
34 /*
35 * storage type indicates where stream data bytes
36 * are stored.
37 */
38 enum {
39 ST_TYPE_DIRECT, /* in chunk structure itself (sc_dstorage) */
40 ST_TYPE_PKT, /* bytes are stored in attached pkt (sc_pkt) */
41 ST_TYPE_HEAP /* data are stored on memory heap buffer */
42 };
43
44 /*
45 * Stream chunk keeps stream bytes as received from QUIC STREAM_FRAME.
46 * Each chunk of stream data by [start, end).
47 */
48 struct stream_chunk_t {
49 OSSL_LIST_MEMBER(sc, struct stream_chunk_t);
50 UINT_RANGE sc_range;
51 int sc_st; /* storage type */
52 union {
53 const unsigned char *u_data;
54 unsigned char *u_data_w;
55 } sc_data_u;
56 union {
57 OSSL_QRX_PKT *u_sc_pkt;
58 unsigned char *u_sc_buf;
59 unsigned char u_sc_dstorage[DIRECT_STORAGE_SZ];
60 } sc_storage_u;
61 };
62
63 struct quic_rstream_qparm_st {
64 size_t rsqp_pkt_overhead_treshold;
65 size_t rsqp_pkt_overhead_sz;
66 QUIC_CHANNEL *rsqp_ch;
67 };
68
69 #define sc_data sc_data_u.u_data
70 #define sc_data_w sc_data_u.u_data_w
71
72 #define sc_pkt sc_storage_u.u_sc_pkt
73 #define sc_buf sc_storage_u.u_sc_buf
74 #define sc_dstorage sc_storage_u.u_sc_dstorage
75
76 DEFINE_LIST_OF(sc, struct stream_chunk_t);
77
78 #define SCHUNK_SIZE(_sc) ((_sc)->sc_range.end - (_sc)->sc_range.start)
79 #define SRANGE_SIZE(_sr) ((_sr)->sr_range.end - (_sr)->sr_range.start)
80 #define SCHUNK_OVERHEAD(_pkt, _sc) ((_pkt)->datagram_len - SCHUNK_SIZE(_sc))
81
82 /*
83 * Stream range keeps list of continuous stream chunks. The range
84 * is also defined by [start, end) interval. For every chunk
85 * in range this assertion must hold:
86 * sc->sc_range.end == sc->sc_next->sc_range.start
87 *
88 * If newly arriving stream chunk can not be inserted to existing
89 * stream range, then new range must be created.
90 */
91 struct stream_range_t {
92 OSSL_LIST(sc)
93 sr_chunks;
94 OSSL_RBT_ENTRY(stream_range_t)
95 sr_rbe;
96 UINT_RANGE sr_range;
97 struct stream_chunk_t *sr_it_sc; /* iterator */
98 };
99
100 static int srange_cmp(const struct stream_range_t *, const struct stream_range_t *);
101
102 OSSL_RBT_PROTOTYPE(srange, stream_range_t, sr_rbe, srange_cmp)
103
104 OSSL_RBT_GENERATE(srange, stream_range_t, sr_rbe, srange_cmp);
105
106 #define UINT64_TO_SIZE_T(_x) ((size_t)(((_x) > SIZE_MAX) ? SIZE_MAX : (_x)))
107
rsqp_add_overhead(QUIC_RSTREAM_QPARM * rsqp,size_t sc_overhead)108 static void rsqp_add_overhead(QUIC_RSTREAM_QPARM *rsqp, size_t sc_overhead)
109 {
110 rsqp->rsqp_pkt_overhead_sz += sc_overhead;
111 }
112
rsqp_sub_overhead(QUIC_RSTREAM_QPARM * rsqp,size_t sc_overhead)113 static void rsqp_sub_overhead(QUIC_RSTREAM_QPARM *rsqp, size_t sc_overhead)
114 {
115 rsqp->rsqp_pkt_overhead_sz -= sc_overhead;
116 }
117
118 /*
119 * Cleansing (SSL_OP_CLEANSE_PLAINTEXT) must write through the const
120 * data pointers received from ossl_sframe_set_insert(), which may
121 * point into a shared packet buffer. That is safe: each chunk
122 * references the disjoint payload slice of its own frame and a
123 * processed packet is kept alive only by the chunks stored on it,
124 * so nobody else reads the wiped bytes.
125 *
126 * The const should eventually be dropped from the prototypes
127 * instead; until then deconst() is used.
128 */
deconst(const unsigned char * data)129 static unsigned char *deconst(const unsigned char *data)
130 {
131 union {
132 const unsigned char *u_data;
133 unsigned char *u_data_w;
134 } data_u;
135
136 data_u.u_data = data;
137
138 return data_u.u_data_w;
139 }
140
sc_data_trim_left(struct stream_chunk_t * sc,size_t trim_sz,int cleanse)141 static void sc_data_trim_left(struct stream_chunk_t *sc, size_t trim_sz,
142 int cleanse)
143 {
144 if (sc->sc_st == ST_TYPE_DIRECT) {
145 assert(SCHUNK_SIZE(sc) >= trim_sz);
146 memmove(sc->sc_data_w, &sc->sc_data[trim_sz],
147 UINT64_TO_SIZE_T((SCHUNK_SIZE(sc) - trim_sz)));
148 if (cleanse && trim_sz > 0) {
149 OPENSSL_cleanse(
150 sc->sc_data_w + UINT64_TO_SIZE_T(SCHUNK_SIZE(sc) - trim_sz),
151 UINT64_TO_SIZE_T(trim_sz));
152 }
153 } else {
154 if (cleanse && trim_sz > 0) {
155 OPENSSL_cleanse(sc->sc_data_w, trim_sz);
156 }
157 sc->sc_data += trim_sz;
158 }
159 }
160
sc_data_trim_right(struct stream_chunk_t * sc,size_t trim_sz,int cleanse)161 static void sc_data_trim_right(struct stream_chunk_t *sc, size_t trim_sz,
162 int cleanse)
163 {
164 unsigned char *data_realloc;
165 size_t w_offset;
166
167 assert(SCHUNK_SIZE(sc) >= trim_sz);
168
169 if (cleanse)
170 OPENSSL_cleanse(
171 &sc->sc_data_w[sc->sc_range.end - trim_sz - sc->sc_range.start],
172 trim_sz);
173
174 if (sc->sc_st == ST_TYPE_HEAP) {
175 /*
176 * this is a shrinking realloc() here, so it should not fail.
177 * even if it fails, we still don't care, the worst outcome
178 * of such failure is waste of memory.
179 */
180 assert(sc->sc_data_w >= sc->sc_buf);
181 w_offset = sc->sc_data_w - sc->sc_buf;
182 if (trim_sz > 0) {
183 assert(SCHUNK_SIZE(sc) > trim_sz);
184 data_realloc = OPENSSL_realloc(sc->sc_buf,
185 w_offset + UINT64_TO_SIZE_T(SCHUNK_SIZE(sc)) - trim_sz);
186 if (data_realloc != NULL) {
187 sc->sc_buf = data_realloc;
188 sc->sc_data_w = sc->sc_buf + w_offset;
189 }
190 }
191 }
192 }
193
srange_cmp(const struct stream_range_t * a_sr,const struct stream_range_t * b_sr)194 static int srange_cmp(const struct stream_range_t *a_sr,
195 const struct stream_range_t *b_sr)
196 {
197 assert(a_sr->sr_range.start < a_sr->sr_range.end);
198 assert(b_sr->sr_range.start < b_sr->sr_range.end);
199 /*
200 * no overlap, A precedes B
201 */
202 if (a_sr->sr_range.end < b_sr->sr_range.start)
203 return -1;
204
205 /*
206 * no overlap, A follows B
207 */
208 if (a_sr->sr_range.start > b_sr->sr_range.end)
209 return 1;
210
211 /*
212 * partial or full overlap or ranges are adjacent.
213 * the program needs to do close examination on
214 * how to add new chunk to existing stream range.
215 */
216 return 0;
217 }
218
keep_schunk_data_on_packet(SFRAME_SET * fs,OSSL_QRX_PKT * pkt,size_t overhead)219 static int keep_schunk_data_on_packet(SFRAME_SET *fs, OSSL_QRX_PKT *pkt,
220 size_t overhead)
221 {
222 if ((fs->rsqp->rsqp_pkt_overhead_sz + overhead) >= fs->rsqp->rsqp_pkt_overhead_treshold)
223 return 0;
224
225 return 1;
226 }
227
new_schunk(SFRAME_SET * fs,OSSL_QRX_PKT * pkt,UINT_RANGE * r,const unsigned char * data)228 static struct stream_chunk_t *new_schunk(SFRAME_SET *fs, OSSL_QRX_PKT *pkt,
229 UINT_RANGE *r, const unsigned char *data)
230 {
231 struct stream_chunk_t *sc;
232 uint64_t rsize;
233 size_t overhead;
234
235 if (pkt == NULL)
236 return NULL;
237
238 sc = OPENSSL_zalloc(sizeof(*sc));
239 if (sc == NULL)
240 return NULL;
241
242 rsize = r->end - r->start;
243 assert(rsize <= pkt->datagram_len);
244 overhead = UINT64_TO_SIZE_T(pkt->datagram_len - rsize);
245
246 if (keep_schunk_data_on_packet(fs, pkt, overhead) == 1) {
247 sc->sc_st = ST_TYPE_PKT;
248 sc->sc_pkt = pkt;
249 ossl_qrx_pkt_up_ref(pkt);
250 rsqp_add_overhead(fs->rsqp, overhead);
251 sc->sc_data = data;
252 sc->sc_range = *r;
253 DEBUG_PRINT(STDERR,
254 "%s sc: %p sc overhead: %llu pkt_buf_overhead_sz: %llu -> %zu\n",
255 OPENSSL_FUNC, (void *)sc, SCHUNK_OVERHEAD(pkt, sc),
256 fs->rsqp->rsqp_pkt_overhead_sz - SCHUNK_OVERHEAD(pkt, sc),
257 fs->rsqp->rsqp_pkt_overhead_sz);
258 } else {
259 if (rsize <= DIRECT_STORAGE_SZ) {
260 DEBUG_PRINT(STDERR, "%s ST_TYPE_DIRECT sc: %p %llu\n", OPENSSL_FUNC,
261 (void *)sc, rsize);
262 sc->sc_st = ST_TYPE_DIRECT;
263 sc->sc_data_w = sc->sc_dstorage;
264 } else {
265 DEBUG_PRINT(STDERR, "%s ST_TYPE_HEAP sc: %p %llu\n", OPENSSL_FUNC,
266 (void *)sc, rsize);
267 sc->sc_st = ST_TYPE_HEAP;
268 sc->sc_buf = OPENSSL_malloc(UINT64_TO_SIZE_T(rsize));
269 if (sc->sc_buf == NULL) {
270 OPENSSL_free(sc);
271 return NULL;
272 }
273 sc->sc_data_w = sc->sc_buf;
274 }
275 sc->sc_range = *r;
276 memcpy(sc->sc_data_w, data, UINT64_TO_SIZE_T(rsize));
277
278 if (fs->cleanse)
279 OPENSSL_cleanse(deconst(data), UINT64_TO_SIZE_T(rsize));
280 }
281
282 return sc;
283 }
284
destroy_schunk(SFRAME_SET * fs,struct stream_chunk_t * sc)285 static void destroy_schunk(SFRAME_SET *fs, struct stream_chunk_t *sc)
286 {
287 if (sc == NULL)
288 return;
289
290 if (fs->cleanse)
291 OPENSSL_cleanse(sc->sc_data_w,
292 UINT64_TO_SIZE_T(sc->sc_st == ST_TYPE_DIRECT
293 ? DIRECT_STORAGE_SZ
294 : SCHUNK_SIZE(sc)));
295
296 switch (sc->sc_st) {
297 case ST_TYPE_PKT:
298 assert(fs->rsqp->rsqp_pkt_overhead_sz >= SCHUNK_OVERHEAD(sc->sc_pkt, sc));
299 DEBUG_PRINT(STDERR,
300 "%s sc: %p sc overhead: %llu pkt_buf_overhead_sz: %zu -> %llu\n",
301 OPENSSL_FUNC, (void *)sc, SCHUNK_OVERHEAD(sc->sc_pkt, sc),
302 fs->rsqp->rsqp_pkt_overhead_sz,
303 fs->rsqp->rsqp_pkt_overhead_sz - SCHUNK_OVERHEAD(sc->sc_pkt, sc));
304 rsqp_sub_overhead(fs->rsqp,
305 UINT64_TO_SIZE_T(SCHUNK_OVERHEAD(sc->sc_pkt, sc)));
306 ossl_qrx_pkt_release(sc->sc_pkt);
307 break;
308 case ST_TYPE_HEAP:
309 OPENSSL_free(sc->sc_buf);
310 break;
311 default:
312 assert(sc->sc_st == ST_TYPE_DIRECT);
313 }
314
315 OPENSSL_free(sc);
316 }
317
new_srange(void)318 static struct stream_range_t *new_srange(void)
319 {
320 struct stream_range_t *sr;
321
322 sr = OPENSSL_zalloc(sizeof(*sr));
323 if (sr != NULL) {
324 ossl_list_sc_init(&sr->sr_chunks);
325 }
326
327 return sr;
328 }
329
destroy_srange(SFRAME_SET * fs,struct stream_range_t * sr)330 static void destroy_srange(SFRAME_SET *fs, struct stream_range_t *sr)
331 {
332 struct stream_chunk_t *sc;
333
334 if (sr == NULL)
335 return;
336
337 assert(sr->sr_rbe.rb_parent == NULL);
338 assert(sr->sr_rbe.rb_left == NULL);
339 assert(sr->sr_rbe.rb_right == NULL);
340
341 while ((sc = ossl_list_sc_head(&sr->sr_chunks)) != NULL) {
342 ossl_list_sc_remove(&sr->sr_chunks, sc);
343 fs->stream_chunks--;
344 destroy_schunk(fs, sc);
345 }
346
347 OPENSSL_free(sr);
348 }
349
create_range(SFRAME_SET * fs,struct stream_chunk_t * sc)350 static struct stream_range_t *create_range(SFRAME_SET *fs,
351 struct stream_chunk_t *sc)
352 {
353 struct stream_range_t *sr;
354
355 assert(sc != NULL);
356
357 sr = new_srange();
358 if (sr != NULL) {
359 ossl_list_sc_insert_head(&sr->sr_chunks, sc);
360 sr->sr_range = sc->sc_range;
361 fs->stream_chunks++;
362 }
363
364 return sr;
365 }
366
ossl_sframe_set_init(SFRAME_SET * fs,QUIC_RSTREAM_QPARM * rsqp)367 void ossl_sframe_set_init(SFRAME_SET *fs, QUIC_RSTREAM_QPARM *rsqp)
368 {
369 assert(rsqp != NULL);
370
371 memset(fs, 0, sizeof(*fs));
372 OSSL_RBT_INIT(srange, &fs->ranges);
373 fs->rsqp = rsqp;
374 }
375
get_sc_dstorage_sz(struct stream_chunk_t * sc)376 static uint64_t get_sc_dstorage_sz(struct stream_chunk_t *sc)
377 {
378 uint64_t sz = 0;
379
380 if (sc->sc_st == ST_TYPE_DIRECT && SCHUNK_SIZE(sc) < DIRECT_STORAGE_SZ)
381 sz = DIRECT_STORAGE_SZ - SCHUNK_SIZE(sc);
382
383 return sz;
384 }
385
try_dstorage(SFRAME_SET * fs,OSSL_QRX_PKT * pkt,struct stream_range_t * sr,UINT_RANGE * r,const unsigned char ** data)386 static int try_dstorage(SFRAME_SET *fs, OSSL_QRX_PKT *pkt,
387 struct stream_range_t *sr, UINT_RANGE *r, const unsigned char **data)
388 {
389 struct stream_chunk_t *head_sc, *tail_sc, *new_sc;
390 uint64_t rsize;
391 uint64_t offset;
392 uint64_t dsize;
393
394 /*
395 * full overlap which spans over more range with more than 1 chunk,
396 * nothing to be done here, caller will handle that.
397 */
398 rsize = r->end - r->start;
399 if (r->start < sr->sr_range.start && r->end > sr->sr_range.end
400 && ossl_list_sc_num(&sr->sr_chunks) > 1)
401 return 0;
402
403 head_sc = ossl_list_sc_head(&sr->sr_chunks);
404 assert(head_sc != NULL);
405 tail_sc = ossl_list_sc_tail(&sr->sr_chunks);
406 assert(tail_sc != NULL);
407
408 /*
409 * full overlap of direct storage can be treated when range contains
410 * exactly one chunk.
411 */
412 if (head_sc == tail_sc
413 && head_sc->sc_range.start > r->start
414 && head_sc->sc_range.end < r->end) {
415 /*
416 * can deal with full overlap
417 */
418 if (head_sc->sc_st != ST_TYPE_DIRECT)
419 return 0;
420
421 DEBUG_PRINT(STDERR, "%s @in %p [ %llu, %llu ]\n",
422 OPENSSL_FUNC, *data, r->start, r->end);
423 rsize = r->end - r->start;
424 if (rsize <= DIRECT_STORAGE_SZ) {
425 /*
426 * update existing chunk
427 */
428 DEBUG_PRINT(STDERR,
429 "%s overwrite dstorage %p [ %llu, %llu ] -> [ %llu, %llu ] "
430 "sr: %p [ %llu, %llu ]\n",
431 OPENSSL_FUNC, (void *)head_sc,
432 head_sc->sc_range.start, head_sc->sc_range.end,
433 r->start, r->end,
434 (void *)sr, sr->sr_range.start, sr->sr_range.end);
435 memcpy(head_sc->sc_data_w, *data, UINT64_TO_SIZE_T(rsize));
436
437 if (fs->cleanse)
438 OPENSSL_cleanse(deconst(*data), UINT64_TO_SIZE_T(rsize));
439
440 *data += rsize;
441 head_sc->sc_range.start = r->start;
442 head_sc->sc_range.end = r->end;
443 } else {
444 /*
445 * try to replace existing chunk
446 */
447 new_sc = new_schunk(fs, pkt, r, *data);
448 if (new_sc == NULL) {
449 DEBUG_PRINT(STDERR, "%s new_chunk() alloc failed\n",
450 OPENSSL_FUNC);
451 return -1;
452 }
453
454 DEBUG_PRINT(STDERR,
455 "%s replace chunk %p [ %llu, %llu ] -> %p [ %llu, %llu ]\n",
456 OPENSSL_FUNC,
457 (void *)head_sc, head_sc->sc_range.start, head_sc->sc_range.end,
458 (void *)new_sc, new_sc->sc_range.start, new_sc->sc_range.end);
459 ossl_list_sc_remove(&sr->sr_chunks, head_sc);
460 ossl_list_sc_insert_head(&sr->sr_chunks, new_sc);
461 destroy_schunk(fs, head_sc);
462 }
463 DEBUG_PRINT(STDERR, "\trange: %p [ %llu, %llu ] -> [ %llu, %llu ]\n",
464 (void *)sr, sr->sr_range.start, sr->sr_range.end, r->start, r->end);
465 sr->sr_range.start = r->start;
466 sr->sr_range.end = r->end;
467 /*
468 * indicate that while range got consumed.
469 */
470 r->start = 0;
471 r->end = 0;
472 } else if (tail_sc->sc_range.end < r->end) {
473 /*
474 * append only
475 */
476 if (tail_sc->sc_st != ST_TYPE_DIRECT)
477 return 0;
478
479 dsize = get_sc_dstorage_sz(tail_sc);
480 if (dsize == 0)
481 return 0;
482
483 DEBUG_PRINT(STDERR, "%s append: @in %p [ %llu, %llu ] dsize: %llu "
484 "tail_sc: %p [ %llu, %llu] sr: %p [ %llu, %llu ]\n",
485 OPENSSL_FUNC, *data, r->start, r->end, dsize,
486 (void *)tail_sc, tail_sc->sc_range.start, tail_sc->sc_range.end,
487 (void *)sr, sr->sr_range.start, sr->sr_range.end);
488
489 if (r->start < tail_sc->sc_range.end) {
490 rsize = tail_sc->sc_range.end - r->start;
491
492 if (fs->cleanse)
493 OPENSSL_cleanse(deconst(*data), UINT64_TO_SIZE_T(rsize));
494
495 *data += rsize;
496
497 r->start = tail_sc->sc_range.end;
498 }
499
500 rsize = r->end - r->start;
501 /*
502 * earlier check done in ossl_sframe_set_insert() ensures
503 * there is at least some data to append.
504 */
505 assert(rsize > 0);
506 rsize = (rsize < dsize) ? rsize : dsize;
507 offset = SCHUNK_SIZE(tail_sc);
508 memcpy(&tail_sc->sc_data_w[offset], *data, UINT64_TO_SIZE_T(rsize));
509 DEBUG_PRINT(STDERR, "%s append tail_sc: %p [ %llu, %llu ] -> ",
510 OPENSSL_FUNC, (void *)tail_sc,
511 tail_sc->sc_range.start, tail_sc->sc_range.end);
512 tail_sc->sc_range.end += rsize;
513 DEBUG_PRINT(STDERR, "[ %llu, %llu ]\n",
514 tail_sc->sc_range.start, tail_sc->sc_range.end);
515 assert(SCHUNK_SIZE(tail_sc) <= DIRECT_STORAGE_SZ);
516 DEBUG_PRINT(STDERR, "\trange: %p [ %llu, %llu ] -> ",
517 (void *)sr, sr->sr_range.start, sr->sr_range.end);
518 sr->sr_range.end = tail_sc->sc_range.end;
519 DEBUG_PRINT(STDERR, "[ %llu, %llu ]\n",
520 sr->sr_range.start, sr->sr_range.end);
521
522 if (fs->cleanse)
523 OPENSSL_cleanse(deconst(*data), UINT64_TO_SIZE_T(rsize));
524
525 *data += rsize;
526 r->start = tail_sc->sc_range.end;
527 } else if (head_sc->sc_range.start > r->start) {
528 const unsigned char *data_buf;
529 /*
530 * prepend only
531 */
532 if (head_sc->sc_st != ST_TYPE_DIRECT)
533 return 0;
534
535 dsize = get_sc_dstorage_sz(head_sc);
536 if (dsize == 0)
537 return 0;
538
539 DEBUG_PRINT(STDERR, "%s prepend: @in %p [ %llu, %llu ] dsize: %llu "
540 "sr: %p [ %llu, %llu ]\n",
541 OPENSSL_FUNC, *data, r->start, r->end, dsize,
542 (void *)sr, sr->sr_range.start, sr->sr_range.end);
543
544 if (r->end > head_sc->sc_range.start) {
545 if (fs->cleanse)
546 OPENSSL_cleanse(
547 deconst(*data + (head_sc->sc_range.start - r->start)),
548 UINT64_TO_SIZE_T(r->end - head_sc->sc_range.start));
549 r->end = head_sc->sc_range.start;
550 }
551
552 rsize = r->end - r->start;
553 /*
554 * earlier check done in ossl_sframe_set_insert() ensures
555 * there is at least some data to append.
556 */
557 assert(rsize > 0);
558 rsize = (rsize < dsize) ? rsize : dsize;
559 memmove(&head_sc->sc_data_w[rsize], head_sc->sc_data,
560 UINT64_TO_SIZE_T(SCHUNK_SIZE(head_sc)));
561 offset = r->end - rsize - r->start;
562 assert(offset < r->end - r->start);
563 data_buf = *data;
564 memcpy(head_sc->sc_data_w, &data_buf[offset], UINT64_TO_SIZE_T(rsize));
565 DEBUG_PRINT(STDERR, "%s prepend head_sc: %p [ %llu, %llu ] -> ",
566 OPENSSL_FUNC, (void *)head_sc,
567 head_sc->sc_range.start, head_sc->sc_range.end);
568 head_sc->sc_range.start -= rsize;
569 DEBUG_PRINT(STDERR, "[ %llu, %llu ]\n",
570 head_sc->sc_range.start, head_sc->sc_range.end);
571 assert(SCHUNK_SIZE(head_sc) <= DIRECT_STORAGE_SZ);
572 DEBUG_PRINT(STDERR, "\trange: %p [ %llu, %llu ] -> ",
573 (void *)sr, sr->sr_range.start, sr->sr_range.end);
574 sr->sr_range.start = head_sc->sc_range.start;
575 DEBUG_PRINT(STDERR, "[ %llu, %llu ]\n",
576 sr->sr_range.start, sr->sr_range.end);
577 assert(r->end - r->start >= rsize);
578
579 if (fs->cleanse)
580 OPENSSL_cleanse(deconst(&data_buf[offset]),
581 UINT64_TO_SIZE_T(rsize));
582
583 r->end -= rsize;
584 } else {
585 assert(0);
586 return -1;
587 }
588
589 /*
590 * returns 1 if all data were consumed
591 */
592 assert(r->end >= r->start);
593 DEBUG_PRINT(STDERR, "%s @out %p [ %llu, %llu ]\n",
594 OPENSSL_FUNC, *data, r->start, r->end);
595
596 return ((r->end - r->start) == 0) ? 1 : 0;
597 }
598
599 /*
600 * If there is partial overlap between newly received data `r` and
601 * existing stream range `sr`, then this function trims overlapping
602 * bytes from `r`.
603 * sr - pointer to stream range
604 * r - pointer to range of bytes received in stream frame
605 * data - pointer to data bytes delivered in stream frame
606 * function updates r so there is no partial overlap between and sr
607 * after function returns. Function returns pointer to the first
608 * data byte in stream after `r` is adjusted. Function returns `data`
609 * when no trimming happened.
610 */
trim_partial_overlap(SFRAME_SET * fs,struct stream_range_t * sr,UINT_RANGE * r,const unsigned char * data)611 static const unsigned char *trim_partial_overlap(SFRAME_SET *fs,
612 struct stream_range_t *sr, UINT_RANGE *r, const unsigned char *data)
613 {
614 uint64_t unused_sz;
615
616 if (!(r->start < sr->sr_range.start && r->end > sr->sr_range.end)) {
617 if (r->end > sr->sr_range.end && r->start < sr->sr_range.end) {
618 unused_sz = sr->sr_range.end - r->start;
619 if (fs->cleanse)
620 OPENSSL_cleanse(deconst(data), UINT64_TO_SIZE_T(unused_sz));
621
622 DEBUG_PRINT(STDERR, "%s right overlap %p [ %llu, %llu ]:\n\t"
623 "r: [ %llu, %llu ] -> [ %llu, %llu ]\n",
624 OPENSSL_FUNC,
625 (void *)sr, sr->sr_range.start, sr->sr_range.end,
626 r->start, r->end,
627 sr->sr_range.end, r->end);
628
629 data += unused_sz;
630 r->start = sr->sr_range.end;
631 } else if (r->start < sr->sr_range.start
632 && r->end > sr->sr_range.start) {
633 unused_sz = r->end - sr->sr_range.start;
634 if (fs->cleanse)
635 OPENSSL_cleanse(deconst(data
636 + (sr->sr_range.start - r->start)),
637 UINT64_TO_SIZE_T(unused_sz));
638
639 DEBUG_PRINT(STDERR, "%s left overlap %p [ %llu, %llu]:\n\t"
640 "r: [ %llu, %llu ] -> [ %llu, %llu ]\n",
641 OPENSSL_FUNC,
642 (void *)sr, sr->sr_range.start, sr->sr_range.end,
643 r->start, r->end,
644 r->start, sr->sr_range.start);
645 r->end = sr->sr_range.start;
646 }
647 }
648
649 return data;
650 }
651
652 /*
653 * Inserts a newly received chunk to the head of the chunk list.
654 */
prepend_chunk(SFRAME_SET * fs,struct stream_range_t * sr,struct stream_chunk_t * sc)655 static void prepend_chunk(SFRAME_SET *fs, struct stream_range_t *sr,
656 struct stream_chunk_t *sc)
657 {
658 DEBUG_PRINT(STDERR, "%s %p [ %llu, %llu ] add to head %p [ %llu, %llu ] "
659 "-> [ %llu, %llu ]\n",
660 OPENSSL_FUNC,
661 (void *)sc, sc->sc_range.start, sc->sc_range.end,
662 (void *)sr, sr->sr_range.start, sr->sr_range.end,
663 sc->sc_range.start, sr->sr_range.end);
664
665 /*
666 * the new chunk must not be empty
667 */
668 assert(sc->sc_range.end > sc->sc_range.start);
669 /*
670 * and must not overlap range.
671 */
672 assert(sc->sc_range.end == sr->sr_range.start);
673
674 ossl_list_sc_insert_head(&sr->sr_chunks, sc);
675 sr->sr_range.start = sc->sc_range.start;
676 fs->stream_chunks++;
677 }
678
679 /*
680 * Inserts a newly received chunk to the tail of the chunk list.
681 */
append_chunk(SFRAME_SET * fs,struct stream_range_t * sr,struct stream_chunk_t * sc)682 static void append_chunk(SFRAME_SET *fs, struct stream_range_t *sr,
683 struct stream_chunk_t *sc)
684 {
685 DEBUG_PRINT(STDERR, "%s %p [ %llu, %llu ] add to tail %p [ %llu, %llu ] "
686 "-> [ %llu, %llu ]\n",
687 OPENSSL_FUNC,
688 (void *)sc, sc->sc_range.start, sc->sc_range.end,
689 (void *)sr, sr->sr_range.start, sr->sr_range.end,
690 sr->sr_range.start, sc->sc_range.end);
691
692 /*
693 * the new chunk must not be empty
694 */
695 assert(sc->sc_range.end > sc->sc_range.start);
696 /*
697 * and must not overlap range
698 */
699 assert(sc->sc_range.start == sr->sr_range.end);
700
701 ossl_list_sc_insert_tail(&sr->sr_chunks, sc);
702 sr->sr_range.end = sc->sc_range.end;
703 fs->stream_chunks++;
704 }
705
replace_chunks_in_range(SFRAME_SET * fs,struct stream_range_t * sr,struct stream_chunk_t * sc)706 static void replace_chunks_in_range(SFRAME_SET *fs, struct stream_range_t *sr,
707 struct stream_chunk_t *sc)
708 {
709 struct stream_chunk_t *destroy_sc;
710
711 while ((destroy_sc = ossl_list_sc_head(&sr->sr_chunks)) != NULL) {
712 ossl_list_sc_remove(&sr->sr_chunks, destroy_sc);
713 fs->stream_chunks--;
714 destroy_schunk(fs, destroy_sc);
715 }
716
717 ossl_list_sc_insert_head(&sr->sr_chunks, sc);
718 fs->stream_chunks++;
719 DEBUG_PRINT(STDERR, "%s range: %p [ %llu, %llu ] -> [ %llu, %llu ]\n",
720 OPENSSL_FUNC, (void *)sr, sr->sr_range.start, sr->sr_range.end,
721 sc->sc_range.start, sc->sc_range.end);
722 sr->sr_range.start = sc->sc_range.start;
723 sr->sr_range.end = sc->sc_range.end;
724 }
725
find_range(SFRAME_SET * fs,struct stream_range_t * key)726 static struct stream_range_t *find_range(SFRAME_SET *fs,
727 struct stream_range_t *key)
728 {
729 struct stream_range_t *sr = NULL;
730
731 if (!OSSL_RBT_EMPTY(srange, &fs->ranges))
732 sr = OSSL_RBT_FIND(srange, &fs->ranges, key);
733
734 return sr;
735 }
736
737 /*
738 * This function help us to merge two ranges (list of chunks)
739 * into single range. Function moves the end of the range
740 * towards start. It effectively chops n last chunks until
741 * new_end is found.
742 */
chop_range(SFRAME_SET * fs,struct stream_range_t * sr,uint64_t new_end)743 static int chop_range(SFRAME_SET *fs, struct stream_range_t *sr,
744 uint64_t new_end)
745 {
746 struct stream_chunk_t *sc;
747 size_t unused_sz;
748
749 assert(sr->sr_range.end >= new_end);
750
751 while ((sc = ossl_list_sc_tail(&sr->sr_chunks)) != NULL) {
752 if (sc->sc_range.start >= new_end) {
753 ossl_list_sc_remove(&sr->sr_chunks, sc);
754 fs->stream_chunks--;
755 destroy_schunk(fs, sc);
756 } else {
757 break;
758 }
759 }
760
761 if (sc == NULL)
762 return 0;
763
764 assert(new_end <= sc->sc_range.end);
765 assert(sc->sc_range.start < new_end);
766
767 unused_sz = UINT64_TO_SIZE_T(sc->sc_range.end - new_end);
768 if (unused_sz == 0) {
769 sr->sr_range.end = new_end;
770 return 1;
771 }
772
773 sc_data_trim_right(sc, unused_sz, fs->cleanse);
774 sc->sc_range.end = new_end;
775 sr->sr_range.end = new_end;
776
777 if (sc->sc_st == ST_TYPE_PKT) {
778 rsqp_add_overhead(fs->rsqp, unused_sz);
779 DEBUG_PRINT(STDERR, "%s sc: %p unused_sz: %zu %zu -> %zu\n",
780 OPENSSL_FUNC, (void *)sc, unused_sz,
781 fs->rsqp->rsqp_pkt_overhead_sz - unused_sz,
782 fs->rsqp->rsqp_pkt_overhead_sz);
783 }
784
785 return 1;
786 }
787
788 /*
789 * function merges two with full overlap. The super_sr range
790 * contains the whole sub_sr range. The function destroys
791 * sub_sr and returns super_sr.
792 */
merge_ranges(SFRAME_SET * fs,struct stream_range_t * super_sr,struct stream_range_t * sub_sr)793 static struct stream_range_t *merge_ranges(SFRAME_SET *fs,
794 struct stream_range_t *super_sr, struct stream_range_t *sub_sr)
795 {
796 /*
797 * both ranges must not be empty
798 */
799 assert(super_sr->sr_range.start < super_sr->sr_range.end);
800 assert(sub_sr->sr_range.start < sub_sr->sr_range.end);
801 /*
802 * sub_sr and super_sr are equal ranges (sets) super_sr
803 * sub_sr is subset of super_sr (super_sr includes sub_sr).
804 */
805 assert(super_sr->sr_range.start <= sub_sr->sr_range.start
806 && super_sr->sr_range.end >= sub_sr->sr_range.end);
807
808 DEBUG_PRINT(STDERR, "%s super: %p [ %llu, %llu ], sub: %p [ %llu, %llu]\n",
809 OPENSSL_FUNC, (void *)super_sr, super_sr->sr_range.start,
810 super_sr->sr_range.end, (void *)sub_sr, sub_sr->sr_range.start,
811 sub_sr->sr_range.end);
812 destroy_srange(fs, sub_sr);
813
814 return super_sr;
815 }
816
817 /*
818 * The ranges are either adjacent
819 * (left_sr->sr_range.end == right_sr->sr_range.end) or there
820 * is partial overlap between left_sr and right_sr(
821 * (left_sr->sr_range.end >= right_sr->sr_range.start).
822 * If there is partial overlap, then the left range is chopped
823 * so its end is aligned with start of right_sr.
824 */
append_range(SFRAME_SET * fs,struct stream_range_t * left_sr,struct stream_range_t * right_sr)825 static struct stream_range_t *append_range(SFRAME_SET *fs,
826 struct stream_range_t *left_sr, struct stream_range_t *right_sr)
827 {
828 /*
829 * both ranges must not be empty
830 */
831 assert(left_sr->sr_range.start < left_sr->sr_range.end);
832 assert(right_sr->sr_range.start < right_sr->sr_range.end);
833 /*
834 * right range follows left range (left < right)
835 */
836 assert(left_sr->sr_range.end >= right_sr->sr_range.start);
837
838 DEBUG_PRINT(STDERR, "%s %p [ %llu, %llu ] + %p [ %llu, %llu ] = %p "
839 "[ %llu, %llu ]\n",
840 OPENSSL_FUNC, (void *)left_sr, left_sr->sr_range.start,
841 left_sr->sr_range.end, (void *)right_sr, right_sr->sr_range.start,
842 right_sr->sr_range.end, (void *)left_sr,
843 left_sr->sr_range.start, right_sr->sr_range.end);
844
845 /*
846 * make sure there is no overlap between ranges
847 * (right_sr->sr_range.start == left_sr->sr_range.end)
848 */
849 if (chop_range(fs, left_sr, right_sr->sr_range.start) == 0)
850 return NULL;
851
852 ossl_list_sc_join(&left_sr->sr_chunks, &right_sr->sr_chunks);
853 left_sr->sr_range.end = right_sr->sr_range.end;
854
855 destroy_srange(fs, right_sr);
856
857 return left_sr;
858 }
859
860 /*
861 * receives a chunk of data from stream frame.
862 * note there is a tri-state return value:
863 */
ossl_sframe_set_insert(SFRAME_SET * fs,UINT_RANGE * r,OSSL_QRX_PKT * pkt,const unsigned char * data,int fin)864 int ossl_sframe_set_insert(SFRAME_SET *fs, UINT_RANGE *r, OSSL_QRX_PKT *pkt,
865 const unsigned char *data, int fin)
866 {
867 struct stream_range_t *sr = NULL;
868 struct stream_range_t *adjacent_sr = NULL;
869 struct stream_range_t *joined_sr = NULL;
870 struct stream_chunk_t *sc = NULL;
871 struct stream_range_t key_sr = { 0 };
872
873 assert(r->start <= r->end);
874
875 /*
876 * receive the FIN frame. If FIN was not seen yet, then record
877 * FIN's offset (r->end). If FIN was received then verify FIN's
878 * offset match, error out on mismatch.
879 */
880 if (fin != 0) {
881 if (fs->fin == 0) {
882 sr = OSSL_RBT_MAX(srange, &fs->ranges);
883 if (r->end < fs->offset
884 || (sr != NULL && sr->sr_range.end > r->end)) {
885 ossl_quic_channel_raise_protocol_error(fs->rsqp->rsqp_ch,
886 OSSL_QUIC_ERR_FINAL_SIZE_ERROR,
887 OSSL_QUIC_FRAME_TYPE_STREAM_FIN,
888 "stream final size error");
889 return 0;
890 }
891 fs->fin = 1;
892 fs->fin_off = r->end;
893 } else if (fs->fin_off != r->end) {
894 ossl_quic_channel_raise_protocol_error(fs->rsqp->rsqp_ch,
895 OSSL_QUIC_ERR_FINAL_SIZE_ERROR,
896 OSSL_QUIC_FRAME_TYPE_STREAM_FIN,
897 "stream final size error");
898 return 0;
899 }
900 }
901
902 /*
903 * reject any data at or past the FIN offset (if FIN offset is set).
904 */
905 if (fs->fin != 0) {
906 if (fs->fin_off < r->end) {
907 ossl_quic_channel_raise_protocol_error(fs->rsqp->rsqp_ch,
908 OSSL_QUIC_ERR_FINAL_SIZE_ERROR,
909 (fin == 0) ? OSSL_QUIC_FRAME_TYPE_STREAM
910 : OSSL_QUIC_FRAME_TYPE_STREAM_FIN,
911 "stream final size error");
912 return 0;
913 }
914 }
915
916 if (r->end <= fs->offset) {
917 /*
918 * retransmitted range got consumed already.
919 */
920 DEBUG_PRINT(STDERR, "%s [ %llu, %llu ] <= %llu\n", OPENSSL_FUNC,
921 r->start, r->end, fs->offset);
922 if (fs->cleanse && data != NULL)
923 OPENSSL_cleanse(deconst(data), UINT64_TO_SIZE_T(r->end - r->start));
924 return 1;
925 }
926
927 if (r->start < fs->offset) {
928 /*
929 * Make sure retransmitted chunk does not reintroduce
930 * bytes which were consumed already.
931 * Make sure retransmitted chunk does not reintroduce
932 * bytes which were consumed already.
933 */
934 DEBUG_PRINT(STDERR, "%s [ %llu, %llu ] -> [ %llu, %llu ]\n", OPENSSL_FUNC,
935 r->start, r->end, fs->offset, r->end);
936 if (fs->cleanse)
937 OPENSSL_cleanse(deconst(data),
938 UINT64_TO_SIZE_T(fs->offset - r->start));
939 data += fs->offset - r->start;
940 r->start = fs->offset;
941 }
942
943 key_sr.sr_range = *r;
944
945 /*
946 * Empty, 0 size chunk can carry the FIN bit only,
947 * and that has been just handled above.
948 */
949 if (r->start == r->end)
950 return 1;
951
952 assert(r->start < r->end);
953
954 if ((sr = find_range(fs, &key_sr)) == NULL) {
955 sc = new_schunk(fs, pkt, r, data);
956 if (sc == NULL)
957 goto err;
958
959 sr = create_range(fs, sc);
960 if (sr == NULL)
961 goto err;
962 DEBUG_PRINT(STDERR, "%s chunk: %p [ %llu, %llu ] new range: %p\n",
963 OPENSSL_FUNC, (void *)sc, sc->sc_range.start, sc->sc_range.end,
964 (void *)sr);
965 sc = NULL;
966 OSSL_RBT_INSERT(srange, &fs->ranges, sr);
967 fs->stream_ranges++;
968 } else {
969 /*
970 * retransmission, the whole chunk is found in existing range already
971 */
972 if (r->start >= sr->sr_range.start && r->end <= sr->sr_range.end) {
973 DEBUG_PRINT(STDERR,
974 "%s [ %llu, %llu ] found in %p [ %llu, %llu ]\n", OPENSSL_FUNC,
975 r->start, r->end, (void *)sr, sr->sr_range.start,
976 sr->sr_range.end);
977 if (fs->cleanse)
978 OPENSSL_cleanse(deconst(data),
979 UINT64_TO_SIZE_T(r->end - r->start));
980 goto done; /* Range is present already. */
981 }
982
983 switch (try_dstorage(fs, pkt, sr, r, &data)) {
984 case 0:
985 break;
986 case 1:
987 /*
988 * all data were consumed, range is updated.
989 */
990 goto range_updated;
991 default:
992 /*
993 * malloc error. forget the range we found.
994 */
995 sr = NULL;
996 goto err;
997 }
998
999 /*
1000 * full overlap between sr and r is handled by replace_chunks_in_range()
1001 * we call after we allocate stream chunk sc for newly received range r.
1002 */
1003 data = trim_partial_overlap(fs, sr, r, data);
1004
1005 sc = new_schunk(fs, pkt, r, data);
1006 if (sc == NULL) {
1007 sr = NULL;
1008 goto err;
1009 }
1010 DEBUG_PRINT(STDERR, "%s %p [ %llu, %llu ] -> %p [ %llu, %llu ]\n",
1011 OPENSSL_FUNC, (void *)sc, sc->sc_range.start, sc->sc_range.end,
1012 (void *)sr, sr->sr_range.start, sr->sr_range.end);
1013
1014 /*
1015 * Following calls can still be improved to handle
1016 * chunks with direct storage better, but I don't think it's
1017 * worth the effort. out of order short data chunks (less
1018 * than DIRECT_STORAGE_SZ) should be considered exceptional.
1019 */
1020 if (sc->sc_range.start < sr->sr_range.start
1021 && sc->sc_range.end > sr->sr_range.end) {
1022 /* new chunk includes the whole range */
1023 replace_chunks_in_range(fs, sr, sc);
1024 sc = NULL; /* chunk got consumed */
1025 } else if (sc->sc_range.end > sr->sr_range.end
1026 && sc->sc_range.start <= sr->sr_range.end) {
1027 append_chunk(fs, sr, sc);
1028 sc = NULL; /* chunk got consumed */
1029 } else if (sc->sc_range.start < sr->sr_range.start
1030 && sc->sc_range.end >= sr->sr_range.start) {
1031 prepend_chunk(fs, sr, sc);
1032 sc = NULL; /* chunk got consumed */
1033 } else {
1034 assert(NULL); /* unreachable */
1035 sr = NULL;
1036 goto err;
1037 }
1038
1039 range_updated:
1040 /*
1041 * Range got updated we may need to join updated range with
1042 * another ranges which exist in tree. The current range
1043 * is removed here and used as a search key. If nothing is found
1044 * range is inserted back to tree.
1045 *
1046 * If another range is found the ranges are merged to single
1047 * range. The process repeats (merging ranges may be cascade effect,
1048 * where more ranges collapse to single range). The merge result is
1049 * removed from tree and used as a search key to find another range.
1050 * If nothing is found then update is done. otherwise the ranges
1051 * are merged again.
1052 */
1053 OSSL_RBT_REMOVE(srange, &fs->ranges, sr);
1054 fs->stream_ranges--;
1055 /*
1056 * _INSERT() returns range where sr needs to be joined
1057 */
1058 adjacent_sr = OSSL_RBT_INSERT(srange, &fs->ranges, sr);
1059
1060 while (adjacent_sr != NULL) {
1061 OSSL_RBT_REMOVE(srange, &fs->ranges, adjacent_sr);
1062 DEBUG_PRINT(STDERR, "%s %p [ %llu, %llu ] >< %p [ %llu, %llu ]\n",
1063 OPENSSL_FUNC, (void *)sr, sr->sr_range.start, sr->sr_range.end,
1064 (void *)adjacent_sr, adjacent_sr->sr_range.start,
1065 adjacent_sr->sr_range.end);
1066 fs->stream_ranges--;
1067
1068 if (sr->sr_range.start <= adjacent_sr->sr_range.start
1069 && sr->sr_range.end >= adjacent_sr->sr_range.end) {
1070 /*
1071 * adjacent_sr subset of sr
1072 */
1073 joined_sr = merge_ranges(fs, sr, adjacent_sr);
1074 } else if (sr->sr_range.start >= adjacent_sr->sr_range.start
1075 && sr->sr_range.end <= adjacent_sr->sr_range.end) {
1076 /*
1077 * sr subset of adjacent_sr
1078 */
1079 joined_sr = merge_ranges(fs, adjacent_sr, sr);
1080 } else if (sr->sr_range.start < adjacent_sr->sr_range.start
1081 && sr->sr_range.end >= adjacent_sr->sr_range.start) {
1082 /*
1083 * adjacent_sr follows sr
1084 */
1085 assert(sr->sr_range.end < adjacent_sr->sr_range.end);
1086 joined_sr = append_range(fs, sr, adjacent_sr);
1087 } else if (sr->sr_range.start <= adjacent_sr->sr_range.end
1088 && sr->sr_range.end > adjacent_sr->sr_range.end) {
1089 /*
1090 * sr follows adjacent_sr
1091 */
1092 assert(sr->sr_range.end > adjacent_sr->sr_range.end);
1093 joined_sr = append_range(fs, adjacent_sr, sr);
1094 } else {
1095 assert(NULL); /* never happens */
1096 joined_sr = NULL;
1097 }
1098 if (joined_sr == NULL)
1099 goto err;
1100
1101 sr = joined_sr;
1102 adjacent_sr = OSSL_RBT_INSERT(srange, &fs->ranges, sr);
1103 }
1104 fs->stream_ranges++;
1105 }
1106
1107 done:
1108 return 1;
1109
1110 err:
1111 destroy_schunk(fs, sc);
1112 destroy_srange(fs, sr);
1113 destroy_srange(fs, adjacent_sr);
1114 /*
1115 * not enough memory (or another serious error) has occurred,
1116 * any error here is fatal as some stream chunks could be ACKed
1117 * already (RFC 9000, 31.1 Packet processing). At least stream
1118 * needs to be reset. Preferred action is to close connection.
1119 */
1120
1121 return 0;
1122 }
1123
1124 /*
1125 * peeks over the continuous range which is ready to
1126 * read. ready to read means the fs->offset must be
1127 * found in range. Also fs->offset can not reach past
1128 * the first gap in stream data received so far, thus
1129 * the only range we can use for peek operation is
1130 * OSSL_RBT_MIN(&fs->ranges).
1131 *
1132 * NOTE: it is unsafe to carry more _peek() operations
1133 * over single SFRMAE_SET.
1134 */
ossl_sframe_set_peek(SFRAME_SET * fs,void ** iterator,UINT_RANGE * range,const unsigned char ** data,int * fin)1135 int ossl_sframe_set_peek(SFRAME_SET *fs, void **iterator,
1136 UINT_RANGE *range, const unsigned char **data,
1137 int *fin)
1138 {
1139 uint64_t start;
1140 struct stream_range_t *sr = (struct stream_range_t *)*iterator;
1141 struct stream_chunk_t *sc = NULL;
1142
1143 if (sr == NULL) {
1144 sr = OSSL_RBT_MIN(srange, &fs->ranges);
1145 start = fs->offset;
1146 if (sr != NULL) {
1147 sc = ossl_list_sc_head(&sr->sr_chunks);
1148 sr->sr_it_sc = NULL;
1149 assert(sc->sc_range.start == sr->sr_range.start);
1150 }
1151 /*
1152 * no chunks are ready to be consumed, if there is a gap.
1153 */
1154 if (sc != NULL && sc->sc_range.start > start) {
1155 DEBUG_PRINT(STDERR, "%s sc: %p sr: %p sc->start %llu, fs->offset: %llu\n",
1156 OPENSSL_FUNC, (void *)sc, (void *)sr, sc->sc_range.start, start);
1157 sc = NULL;
1158 }
1159 } else if (sr == OSSL_RBT_MIN(srange, &fs->ranges) && sr->sr_it_sc != NULL) {
1160 /*
1161 * sr == _RB_MIN(), revalidates iterator in case the range we
1162 * work with disappears because it's got joined with other range
1163 * after new chunk arrival. perhaps not issue now as those operations
1164 * are mutually exclusive now.
1165 *
1166 * sr->sr_it_sc becomes NULL on _move() or _flatten() operation.
1167 *
1168 * We may need to revisit iterator implementation as current
1169 * iterator supports one caller only.
1170 */
1171 start = sr->sr_it_sc->sc_range.end;
1172 sc = ossl_list_sc_next(sr->sr_it_sc);
1173 assert(sc == NULL || sc->sc_range.start == start);
1174 assert(sc == NULL || sc->sc_range.start < sc->sc_range.end);
1175 } else {
1176 /* iterator got invalidated by move/flatten operation on range */
1177 DEBUG_PRINT(STDERR, "%s iterator got invalidated\n", OPENSSL_FUNC);
1178 return 0;
1179 }
1180
1181 range->start = start;
1182
1183 if (sc == NULL) {
1184 range->end = start;
1185 *data = NULL;
1186 *iterator = NULL;
1187
1188 /*
1189 * set fin only if we are at the end of the stream and application
1190 * can read from the stream. In other words: there must be no gap
1191 * between FIN offset and offset where application reads from stream.
1192 */
1193 if (fs->fin && start == fs->fin_off)
1194 *fin = fs->fin;
1195 else
1196 *fin = 0;
1197
1198 DEBUG_PRINT(STDERR, "%s no more chunks\n", OPENSSL_FUNC);
1199
1200 return 0;
1201 }
1202
1203 range->end = sc->sc_range.end;
1204 /* chunk keeps data always attached, data dies with chunk */
1205 assert(sc->sc_data != NULL);
1206 assert(sc->sc_range.start <= start);
1207 *data = sc->sc_data + (start - sc->sc_range.start);
1208 *fin = fs->fin && sc->sc_range.end == fs->fin_off;
1209
1210 if (sr->sr_it_sc != NULL)
1211 DEBUG_PRINT(STDERR, "%s %p [ %llu, %llu ] %p [ %llu, %llu ]\n",
1212 OPENSSL_FUNC, (void *)sr->sr_it_sc,
1213 sr->sr_it_sc->sc_range.start, sr->sr_it_sc->sc_range.end,
1214 (void *)sc, sc->sc_range.start, sc->sc_range.end);
1215
1216 sr->sr_it_sc = sc;
1217 *iterator = sr;
1218
1219 /*
1220 * peek operation indicates error if there are no data to read
1221 * in range.
1222 */
1223 DEBUG_PRINT(STDERR,
1224 "%s peek range: [ %llu, %llu ] range: %p [ %llu, %llu ]\n", OPENSSL_FUNC,
1225 range->start, range->end, (void *)sr, sr->sr_range.start,
1226 sr->sr_range.end);
1227
1228 return (range->start == range->end) ? 0 : 1;
1229 }
1230
ossl_sframe_set_destroy_ranges(SFRAME_SET * fs)1231 void ossl_sframe_set_destroy_ranges(SFRAME_SET *fs)
1232 {
1233 struct stream_range_t *sr, *save_sr;
1234
1235 OSSL_RBT_FOREACH_SAFE (sr, srange, &fs->ranges, save_sr) {
1236 OSSL_RBT_REMOVE(srange, &fs->ranges, sr);
1237 fs->stream_ranges--;
1238 destroy_srange(fs, sr);
1239 }
1240 }
1241
1242 /*
1243 * moves the read offset, freeing all chunks which end offset
1244 * is less than new_offset
1245 * sc->sc_range.end < new_offset
1246 */
ossl_sframe_set_move_offset(SFRAME_SET * fs,uint64_t new_offset)1247 int ossl_sframe_set_move_offset(SFRAME_SET *fs, uint64_t new_offset)
1248 {
1249 struct stream_range_t *sr = OSSL_RBT_MIN(srange, &fs->ranges);
1250 struct stream_chunk_t *sc, *save_sc;
1251 size_t unused_sz;
1252
1253 if (new_offset == fs->offset)
1254 return 1;
1255
1256 /*
1257 * Offset can move forward within the continuous head range only.
1258 * It can not move backward, into a gap or past the head range end.
1259 */
1260 if (sr == NULL || new_offset < fs->offset
1261 || new_offset < sr->sr_range.start || new_offset > sr->sr_range.end)
1262 return 0;
1263
1264 fs->offset = new_offset;
1265
1266 OSSL_LIST_FOREACH_DELSAFE (sc, save_sc, sc, &sr->sr_chunks) {
1267 if (new_offset >= sc->sc_range.end) {
1268 ossl_list_sc_remove(&sr->sr_chunks, sc);
1269 fs->stream_chunks--;
1270 if (sr->sr_it_sc == sc)
1271 sr->sr_it_sc = NULL; /* invalidate iterator chunk */
1272 destroy_schunk(fs, sc);
1273 } else {
1274 break;
1275 }
1276 }
1277
1278 DEBUG_PRINT(STDERR, "%s offset: %llu -> %llu range: %p [ %llu, %llu ] -> ",
1279 OPENSSL_FUNC, fs->offset - new_offset, new_offset,
1280 (void *)sr, sr->sr_range.start, sr->sr_range.end);
1281
1282 if (sc == NULL) {
1283 /*
1284 * the whole range was consumed.
1285 * this step invalidates iterator we use in ossl_sframe_peek()
1286 */
1287 OSSL_RBT_REMOVE(srange, &fs->ranges, sr);
1288 destroy_srange(fs, sr);
1289 fs->stream_ranges--;
1290 DEBUG_PRINT(STDERR, "[ NULL ]\n");
1291 } else {
1292 unused_sz = UINT64_TO_SIZE_T(new_offset - sc->sc_range.start);
1293 sc_data_trim_left(sc, unused_sz, fs->cleanse);
1294 sc->sc_range.start = new_offset;
1295 sr->sr_range.start = new_offset;
1296 DEBUG_PRINT(STDERR, "[ %lli, %llu ]\n",
1297 sr->sr_range.start, sr->sr_range.end);
1298
1299 if (sc->sc_st == ST_TYPE_PKT) {
1300 rsqp_add_overhead(fs->rsqp, unused_sz);
1301 DEBUG_PRINT(STDERR, "%s sc: %p unused_sz: %zu %zu -> %zu\n",
1302 OPENSSL_FUNC, (void *)sc, unused_sz,
1303 fs->rsqp->rsqp_pkt_overhead_sz - unused_sz,
1304 fs->rsqp->rsqp_pkt_overhead_sz);
1305 }
1306 }
1307
1308 return 1;
1309 }
1310
1311 /* Contiguous bytes available from fs->offset, in O(log n): the first range. */
ossl_sframe_set_avail(SFRAME_SET * fs,uint64_t * avail,int * fin)1312 int ossl_sframe_set_avail(SFRAME_SET *fs, uint64_t *avail, int *fin)
1313 {
1314 struct stream_range_t *sr = OSSL_RBT_MIN(srange, &fs->ranges);
1315
1316 if (sr != NULL && sr->sr_range.start <= fs->offset
1317 && sr->sr_range.end > fs->offset)
1318 *avail = sr->sr_range.end - fs->offset;
1319 else
1320 *avail = 0;
1321 *fin = (fs->fin && fs->offset + *avail == fs->fin_off) ? 1 : 0;
1322 return 1;
1323 }
1324
ossl_quic_rstream_qparm_new(QUIC_CHANNEL * ch)1325 QUIC_RSTREAM_QPARM *ossl_quic_rstream_qparm_new(QUIC_CHANNEL *ch)
1326 {
1327 QUIC_RSTREAM_QPARM *rsqp;
1328
1329 rsqp = OPENSSL_malloc(sizeof(QUIC_RSTREAM_QPARM));
1330 if (rsqp != NULL) {
1331 rsqp->rsqp_pkt_overhead_treshold = PKT_BUFFER_OVERHEAD_TRESHOLD;
1332 rsqp->rsqp_pkt_overhead_sz = 0;
1333 rsqp->rsqp_ch = ch;
1334 }
1335
1336 return rsqp;
1337 }
1338
ossl_quic_rstream_qparm_destroy(QUIC_RSTREAM_QPARM * rsqp)1339 void ossl_quic_rstream_qparm_destroy(QUIC_RSTREAM_QPARM *rsqp)
1340 {
1341 if (rsqp != NULL) {
1342 assert(rsqp->rsqp_pkt_overhead_sz == 0);
1343 OPENSSL_free(rsqp);
1344 }
1345 }
1346