xref: /freebsd/crypto/openssl/ssl/quic/quic_strm_reas.c (revision f9bc005b8ef3b507a5ecbc2d7fe4411ef70eff38)
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