Coverage Report

Created: 2026-10-28 06:28

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/openssl35/ssl/quic/quic_strm_reas.c
Line
Count
Source
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
144M
#define STDERR NULL
18
/* ARGSUSED */
19
static void print_foo(void *f, ...)
20
58.6M
{
21
58.6M
}
22
23
144M
#define DEBUG_PRINT print_foo
24
25
0
#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
53.0k
#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
186k
#define sc_data sc_data_u.u_data
70
0
#define sc_data_w sc_data_u.u_data_w
71
72
207k
#define sc_pkt sc_storage_u.u_sc_pkt
73
0
#define sc_buf sc_storage_u.u_sc_buf
74
0
#define sc_dstorage sc_storage_u.u_sc_dstorage
75
76
239M
DEFINE_LIST_OF(sc, struct stream_chunk_t);
quic_strm_reas.c:ossl_list_sc_insert_head
Line
Count
Source
76
DEFINE_LIST_OF(sc, struct stream_chunk_t);
quic_strm_reas.c:ossl_list_sc_tail
Line
Count
Source
76
DEFINE_LIST_OF(sc, struct stream_chunk_t);
quic_strm_reas.c:ossl_list_sc_insert_tail
Line
Count
Source
76
DEFINE_LIST_OF(sc, struct stream_chunk_t);
quic_strm_reas.c:ossl_list_sc_join
Line
Count
Source
76
DEFINE_LIST_OF(sc, struct stream_chunk_t);
quic_strm_reas.c:ossl_list_sc_head
Line
Count
Source
76
DEFINE_LIST_OF(sc, struct stream_chunk_t);
quic_strm_reas.c:ossl_list_sc_next
Line
Count
Source
76
DEFINE_LIST_OF(sc, struct stream_chunk_t);
quic_strm_reas.c:ossl_list_sc_remove
Line
Count
Source
76
DEFINE_LIST_OF(sc, struct stream_chunk_t);
77
239M
78
239M
#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
414k
#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
212k
#define UINT64_TO_SIZE_T(_x) ((size_t)(((_x) > SIZE_MAX) ? SIZE_MAX : (_x)))
107
108
static void rsqp_add_overhead(QUIC_RSTREAM_QPARM *rsqp, size_t sc_overhead)
109
107k
{
110
107k
    rsqp->rsqp_pkt_overhead_sz += sc_overhead;
111
107k
}
112
113
static void rsqp_sub_overhead(QUIC_RSTREAM_QPARM *rsqp, size_t sc_overhead)
114
103k
{
115
103k
    rsqp->rsqp_pkt_overhead_sz -= sc_overhead;
116
103k
}
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
 */
129
static unsigned char *deconst(const unsigned char *data)
130
0
{
131
0
    union {
132
0
        const unsigned char *u_data;
133
0
        unsigned char *u_data_w;
134
0
    } data_u;
135
136
0
    data_u.u_data = data;
137
138
0
    return data_u.u_data_w;
139
0
}
140
141
static void sc_data_trim_left(struct stream_chunk_t *sc, size_t trim_sz,
142
    int cleanse)
143
3.57k
{
144
3.57k
    if (sc->sc_st == ST_TYPE_DIRECT) {
145
0
        assert(SCHUNK_SIZE(sc) >= trim_sz);
146
0
        memmove(sc->sc_data_w, &sc->sc_data[trim_sz],
147
0
            UINT64_TO_SIZE_T((SCHUNK_SIZE(sc) - trim_sz)));
148
0
        if (cleanse && trim_sz > 0) {
149
0
            OPENSSL_cleanse(
150
0
                sc->sc_data_w + UINT64_TO_SIZE_T(SCHUNK_SIZE(sc) - trim_sz),
151
0
                UINT64_TO_SIZE_T(trim_sz));
152
0
        }
153
3.57k
    } else {
154
3.57k
        if (cleanse && trim_sz > 0) {
155
0
            OPENSSL_cleanse(sc->sc_data_w, trim_sz);
156
0
        }
157
3.57k
        sc->sc_data += trim_sz;
158
3.57k
    }
159
3.57k
}
160
161
static void sc_data_trim_right(struct stream_chunk_t *sc, size_t trim_sz,
162
    int cleanse)
163
570
{
164
570
    unsigned char *data_realloc;
165
570
    size_t w_offset;
166
167
570
    assert(SCHUNK_SIZE(sc) >= trim_sz);
168
169
570
    if (cleanse)
170
0
        OPENSSL_cleanse(
171
0
            &sc->sc_data_w[sc->sc_range.end - trim_sz - sc->sc_range.start],
172
0
            trim_sz);
173
174
570
    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
0
        assert(sc->sc_data_w >= sc->sc_buf);
181
0
        w_offset = sc->sc_data_w - sc->sc_buf;
182
0
        if (trim_sz > 0) {
183
0
            assert(SCHUNK_SIZE(sc) > trim_sz);
184
0
            data_realloc = OPENSSL_realloc(sc->sc_buf,
185
0
                w_offset + UINT64_TO_SIZE_T(SCHUNK_SIZE(sc)) - trim_sz);
186
0
            if (data_realloc != NULL) {
187
0
                sc->sc_buf = data_realloc;
188
0
                sc->sc_data_w = sc->sc_buf + w_offset;
189
0
            }
190
0
        }
191
0
    }
192
570
}
193
194
static int srange_cmp(const struct stream_range_t *a_sr,
195
    const struct stream_range_t *b_sr)
196
190k
{
197
190k
    assert(a_sr->sr_range.start < a_sr->sr_range.end);
198
190k
    assert(b_sr->sr_range.start < b_sr->sr_range.end);
199
    /*
200
     * no overlap, A precedes B
201
     */
202
190k
    if (a_sr->sr_range.end < b_sr->sr_range.start)
203
66.0k
        return -1;
204
205
    /*
206
     * no overlap, A follows B
207
     */
208
124k
    if (a_sr->sr_range.start > b_sr->sr_range.end)
209
29.1k
        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
95.2k
    return 0;
217
124k
}
218
219
static int keep_schunk_data_on_packet(SFRAME_SET *fs, OSSL_QRX_PKT *pkt,
220
    size_t overhead)
221
103k
{
222
103k
    if ((fs->rsqp->rsqp_pkt_overhead_sz + overhead) >= fs->rsqp->rsqp_pkt_overhead_treshold)
223
0
        return 0;
224
225
103k
    return 1;
226
103k
}
227
228
static struct stream_chunk_t *new_schunk(SFRAME_SET *fs, OSSL_QRX_PKT *pkt,
229
    UINT_RANGE *r, const unsigned char *data)
230
103k
{
231
103k
    struct stream_chunk_t *sc;
232
103k
    uint64_t rsize;
233
103k
    size_t overhead;
234
235
103k
    if (pkt == NULL)
236
0
        return NULL;
237
238
103k
    sc = OPENSSL_zalloc(sizeof(*sc));
239
103k
    if (sc == NULL)
240
0
        return NULL;
241
242
103k
    rsize = r->end - r->start;
243
103k
    assert(rsize <= pkt->datagram_len);
244
103k
    overhead = UINT64_TO_SIZE_T(pkt->datagram_len - rsize);
245
246
103k
    if (keep_schunk_data_on_packet(fs, pkt, overhead) == 1) {
247
103k
        sc->sc_st = ST_TYPE_PKT;
248
103k
        sc->sc_pkt = pkt;
249
103k
        ossl_qrx_pkt_up_ref(pkt);
250
103k
        rsqp_add_overhead(fs->rsqp, overhead);
251
103k
        sc->sc_data = data;
252
103k
        sc->sc_range = *r;
253
103k
        DEBUG_PRINT(STDERR,
254
103k
            "%s sc: %p sc overhead: %llu pkt_buf_overhead_sz: %llu -> %zu\n",
255
103k
            OPENSSL_FUNC, (void *)sc, SCHUNK_OVERHEAD(pkt, sc),
256
103k
            fs->rsqp->rsqp_pkt_overhead_sz - SCHUNK_OVERHEAD(pkt, sc),
257
103k
            fs->rsqp->rsqp_pkt_overhead_sz);
258
103k
    } else {
259
0
        if (rsize <= DIRECT_STORAGE_SZ) {
260
0
            DEBUG_PRINT(STDERR, "%s ST_TYPE_DIRECT sc: %p %llu\n", OPENSSL_FUNC,
261
0
                (void *)sc, rsize);
262
0
            sc->sc_st = ST_TYPE_DIRECT;
263
0
            sc->sc_data_w = sc->sc_dstorage;
264
0
        } else {
265
0
            DEBUG_PRINT(STDERR, "%s ST_TYPE_HEAP sc: %p %llu\n", OPENSSL_FUNC,
266
0
                (void *)sc, rsize);
267
0
            sc->sc_st = ST_TYPE_HEAP;
268
0
            sc->sc_buf = OPENSSL_malloc(UINT64_TO_SIZE_T(rsize));
269
0
            if (sc->sc_buf == NULL) {
270
0
                OPENSSL_free(sc);
271
0
                return NULL;
272
0
            }
273
0
            sc->sc_data_w = sc->sc_buf;
274
0
        }
275
0
        sc->sc_range = *r;
276
0
        memcpy(sc->sc_data_w, data, UINT64_TO_SIZE_T(rsize));
277
278
0
        if (fs->cleanse)
279
0
            OPENSSL_cleanse(deconst(data), UINT64_TO_SIZE_T(rsize));
280
0
    }
281
282
103k
    return sc;
283
103k
}
284
285
static void destroy_schunk(SFRAME_SET *fs, struct stream_chunk_t *sc)
286
103k
{
287
103k
    if (sc == NULL)
288
0
        return;
289
290
103k
    if (fs->cleanse)
291
0
        OPENSSL_cleanse(sc->sc_data_w,
292
0
            UINT64_TO_SIZE_T(sc->sc_st == ST_TYPE_DIRECT
293
0
                    ? DIRECT_STORAGE_SZ
294
0
                    : SCHUNK_SIZE(sc)));
295
296
103k
    switch (sc->sc_st) {
297
103k
    case ST_TYPE_PKT:
298
103k
        assert(fs->rsqp->rsqp_pkt_overhead_sz >= SCHUNK_OVERHEAD(sc->sc_pkt, sc));
299
103k
        DEBUG_PRINT(STDERR,
300
103k
            "%s sc: %p sc overhead: %llu pkt_buf_overhead_sz: %zu -> %llu\n",
301
103k
            OPENSSL_FUNC, (void *)sc, SCHUNK_OVERHEAD(sc->sc_pkt, sc),
302
103k
            fs->rsqp->rsqp_pkt_overhead_sz,
303
103k
            fs->rsqp->rsqp_pkt_overhead_sz - SCHUNK_OVERHEAD(sc->sc_pkt, sc));
304
103k
        rsqp_sub_overhead(fs->rsqp,
305
103k
            UINT64_TO_SIZE_T(SCHUNK_OVERHEAD(sc->sc_pkt, sc)));
306
103k
        ossl_qrx_pkt_release(sc->sc_pkt);
307
103k
        break;
308
0
    case ST_TYPE_HEAP:
309
0
        OPENSSL_free(sc->sc_buf);
310
0
        break;
311
0
    default:
312
0
        assert(sc->sc_st == ST_TYPE_DIRECT);
313
103k
    }
314
315
103k
    OPENSSL_free(sc);
316
103k
}
317
318
static struct stream_range_t *new_srange(void)
319
96.3k
{
320
96.3k
    struct stream_range_t *sr;
321
322
96.3k
    sr = OPENSSL_zalloc(sizeof(*sr));
323
96.3k
    if (sr != NULL) {
324
96.3k
        ossl_list_sc_init(&sr->sr_chunks);
325
96.3k
    }
326
327
96.3k
    return sr;
328
96.3k
}
329
330
static void destroy_srange(SFRAME_SET *fs, struct stream_range_t *sr)
331
96.3k
{
332
96.3k
    struct stream_chunk_t *sc;
333
334
96.3k
    if (sr == NULL)
335
0
        return;
336
337
96.3k
    assert(sr->sr_rbe.rb_parent == NULL);
338
96.3k
    assert(sr->sr_rbe.rb_left == NULL);
339
96.3k
    assert(sr->sr_rbe.rb_right == NULL);
340
341
119k
    while ((sc = ossl_list_sc_head(&sr->sr_chunks)) != NULL) {
342
23.1k
        ossl_list_sc_remove(&sr->sr_chunks, sc);
343
23.1k
        fs->stream_chunks--;
344
23.1k
        destroy_schunk(fs, sc);
345
23.1k
    }
346
347
96.3k
    OPENSSL_free(sr);
348
96.3k
}
349
350
static struct stream_range_t *create_range(SFRAME_SET *fs,
351
    struct stream_chunk_t *sc)
352
96.3k
{
353
96.3k
    struct stream_range_t *sr;
354
355
96.3k
    assert(sc != NULL);
356
357
96.3k
    sr = new_srange();
358
96.3k
    if (sr != NULL) {
359
96.3k
        ossl_list_sc_insert_head(&sr->sr_chunks, sc);
360
96.3k
        sr->sr_range = sc->sc_range;
361
96.3k
        fs->stream_chunks++;
362
96.3k
    }
363
364
96.3k
    return sr;
365
96.3k
}
366
367
void ossl_sframe_set_init(SFRAME_SET *fs, QUIC_RSTREAM_QPARM *rsqp)
368
299k
{
369
299k
    assert(rsqp != NULL);
370
371
299k
    memset(fs, 0, sizeof(*fs));
372
299k
    OSSL_RBT_INIT(srange, &fs->ranges);
373
299k
    fs->rsqp = rsqp;
374
299k
}
375
376
static uint64_t get_sc_dstorage_sz(struct stream_chunk_t *sc)
377
0
{
378
0
    uint64_t sz = 0;
379
380
0
    if (sc->sc_st == ST_TYPE_DIRECT && SCHUNK_SIZE(sc) < DIRECT_STORAGE_SZ)
381
0
        sz = DIRECT_STORAGE_SZ - SCHUNK_SIZE(sc);
382
383
0
    return sz;
384
0
}
385
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
7.30k
{
389
7.30k
    struct stream_chunk_t *head_sc, *tail_sc, *new_sc;
390
7.30k
    uint64_t rsize;
391
7.30k
    uint64_t offset;
392
7.30k
    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
7.30k
    rsize = r->end - r->start;
399
7.30k
    if (r->start < sr->sr_range.start && r->end > sr->sr_range.end
400
1.39k
        && ossl_list_sc_num(&sr->sr_chunks) > 1)
401
144
        return 0;
402
403
7.15k
    head_sc = ossl_list_sc_head(&sr->sr_chunks);
404
7.15k
    assert(head_sc != NULL);
405
7.15k
    tail_sc = ossl_list_sc_tail(&sr->sr_chunks);
406
7.15k
    assert(tail_sc != NULL);
407
408
    /*
409
     * full overlap of direct storage can be treated when range contains
410
     * exactly one chunk.
411
     */
412
7.15k
    if (head_sc == tail_sc
413
5.64k
        && head_sc->sc_range.start > r->start
414
3.78k
        && head_sc->sc_range.end < r->end) {
415
        /*
416
         * can deal with full overlap
417
         */
418
1.25k
        if (head_sc->sc_st != ST_TYPE_DIRECT)
419
1.25k
            return 0;
420
421
0
        DEBUG_PRINT(STDERR, "%s @in %p [ %llu, %llu ]\n",
422
0
            OPENSSL_FUNC, *data, r->start, r->end);
423
0
        rsize = r->end - r->start;
424
0
        if (rsize <= DIRECT_STORAGE_SZ) {
425
            /*
426
             * update existing chunk
427
             */
428
0
            DEBUG_PRINT(STDERR,
429
0
                "%s overwrite dstorage %p [ %llu, %llu ] -> [ %llu, %llu ] "
430
0
                "sr: %p [ %llu, %llu ]\n",
431
0
                OPENSSL_FUNC, (void *)head_sc,
432
0
                head_sc->sc_range.start, head_sc->sc_range.end,
433
0
                r->start, r->end,
434
0
                (void *)sr, sr->sr_range.start, sr->sr_range.end);
435
0
            memcpy(head_sc->sc_data_w, *data, UINT64_TO_SIZE_T(rsize));
436
437
0
            if (fs->cleanse)
438
0
                OPENSSL_cleanse(deconst(*data), UINT64_TO_SIZE_T(rsize));
439
440
0
            *data += rsize;
441
0
            head_sc->sc_range.start = r->start;
442
0
            head_sc->sc_range.end = r->end;
443
0
        } else {
444
            /*
445
             * try to replace existing chunk
446
             */
447
0
            new_sc = new_schunk(fs, pkt, r, *data);
448
0
            if (new_sc == NULL) {
449
0
                DEBUG_PRINT(STDERR, "%s new_chunk() alloc failed\n",
450
0
                    OPENSSL_FUNC);
451
0
                return -1;
452
0
            }
453
454
0
            DEBUG_PRINT(STDERR,
455
0
                "%s replace chunk %p [ %llu, %llu ] -> %p [ %llu, %llu ]\n",
456
0
                OPENSSL_FUNC,
457
0
                (void *)head_sc, head_sc->sc_range.start, head_sc->sc_range.end,
458
0
                (void *)new_sc, new_sc->sc_range.start, new_sc->sc_range.end);
459
0
            ossl_list_sc_remove(&sr->sr_chunks, head_sc);
460
0
            ossl_list_sc_insert_head(&sr->sr_chunks, new_sc);
461
0
            destroy_schunk(fs, head_sc);
462
0
        }
463
0
        DEBUG_PRINT(STDERR, "\trange: %p [ %llu, %llu ] -> [ %llu, %llu ]\n",
464
0
            (void *)sr, sr->sr_range.start, sr->sr_range.end, r->start, r->end);
465
0
        sr->sr_range.start = r->start;
466
0
        sr->sr_range.end = r->end;
467
        /*
468
         * indicate that while range got consumed.
469
         */
470
0
        r->start = 0;
471
0
        r->end = 0;
472
5.90k
    } else if (tail_sc->sc_range.end < r->end) {
473
        /*
474
         * append only
475
         */
476
2.76k
        if (tail_sc->sc_st != ST_TYPE_DIRECT)
477
2.76k
            return 0;
478
479
0
        dsize = get_sc_dstorage_sz(tail_sc);
480
0
        if (dsize == 0)
481
0
            return 0;
482
483
0
        DEBUG_PRINT(STDERR, "%s append: @in %p [ %llu, %llu ] dsize: %llu "
484
0
                            "tail_sc: %p [ %llu, %llu] sr: %p [ %llu, %llu ]\n",
485
0
            OPENSSL_FUNC, *data, r->start, r->end, dsize,
486
0
            (void *)tail_sc, tail_sc->sc_range.start, tail_sc->sc_range.end,
487
0
            (void *)sr, sr->sr_range.start, sr->sr_range.end);
488
489
0
        if (r->start < tail_sc->sc_range.end) {
490
0
            rsize = tail_sc->sc_range.end - r->start;
491
492
0
            if (fs->cleanse)
493
0
                OPENSSL_cleanse(deconst(*data), UINT64_TO_SIZE_T(rsize));
494
495
0
            *data += rsize;
496
497
0
            r->start = tail_sc->sc_range.end;
498
0
        }
499
500
0
        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
0
        assert(rsize > 0);
506
0
        rsize = (rsize < dsize) ? rsize : dsize;
507
0
        offset = SCHUNK_SIZE(tail_sc);
508
0
        memcpy(&tail_sc->sc_data_w[offset], *data, UINT64_TO_SIZE_T(rsize));
509
0
        DEBUG_PRINT(STDERR, "%s append tail_sc: %p [ %llu, %llu ] -> ",
510
0
            OPENSSL_FUNC, (void *)tail_sc,
511
0
            tail_sc->sc_range.start, tail_sc->sc_range.end);
512
0
        tail_sc->sc_range.end += rsize;
513
0
        DEBUG_PRINT(STDERR, "[ %llu, %llu ]\n",
514
0
            tail_sc->sc_range.start, tail_sc->sc_range.end);
515
0
        assert(SCHUNK_SIZE(tail_sc) <= DIRECT_STORAGE_SZ);
516
0
        DEBUG_PRINT(STDERR, "\trange: %p [ %llu, %llu ] -> ",
517
0
            (void *)sr, sr->sr_range.start, sr->sr_range.end);
518
0
        sr->sr_range.end = tail_sc->sc_range.end;
519
0
        DEBUG_PRINT(STDERR, "[ %llu, %llu ]\n",
520
0
            sr->sr_range.start, sr->sr_range.end);
521
522
0
        if (fs->cleanse)
523
0
            OPENSSL_cleanse(deconst(*data), UINT64_TO_SIZE_T(rsize));
524
525
0
        *data += rsize;
526
0
        r->start = tail_sc->sc_range.end;
527
3.14k
    } else if (head_sc->sc_range.start > r->start) {
528
3.14k
        const unsigned char *data_buf;
529
        /*
530
         * prepend only
531
         */
532
3.14k
        if (head_sc->sc_st != ST_TYPE_DIRECT)
533
3.14k
            return 0;
534
535
0
        dsize = get_sc_dstorage_sz(head_sc);
536
0
        if (dsize == 0)
537
0
            return 0;
538
539
0
        DEBUG_PRINT(STDERR, "%s prepend: @in %p [ %llu, %llu ] dsize: %llu "
540
0
                            "sr: %p [ %llu, %llu ]\n",
541
0
            OPENSSL_FUNC, *data, r->start, r->end, dsize,
542
0
            (void *)sr, sr->sr_range.start, sr->sr_range.end);
543
544
0
        if (r->end > head_sc->sc_range.start) {
545
0
            if (fs->cleanse)
546
0
                OPENSSL_cleanse(
547
0
                    deconst(*data + (head_sc->sc_range.start - r->start)),
548
0
                    UINT64_TO_SIZE_T(r->end - head_sc->sc_range.start));
549
0
            r->end = head_sc->sc_range.start;
550
0
        }
551
552
0
        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
0
        assert(rsize > 0);
558
0
        rsize = (rsize < dsize) ? rsize : dsize;
559
0
        memmove(&head_sc->sc_data_w[rsize], head_sc->sc_data,
560
0
            UINT64_TO_SIZE_T(SCHUNK_SIZE(head_sc)));
561
0
        offset = r->end - rsize - r->start;
562
0
        assert(offset < r->end - r->start);
563
0
        data_buf = *data;
564
0
        memcpy(head_sc->sc_data_w, &data_buf[offset], UINT64_TO_SIZE_T(rsize));
565
0
        DEBUG_PRINT(STDERR, "%s prepend head_sc: %p [ %llu, %llu ] -> ",
566
0
            OPENSSL_FUNC, (void *)head_sc,
567
0
            head_sc->sc_range.start, head_sc->sc_range.end);
568
0
        head_sc->sc_range.start -= rsize;
569
0
        DEBUG_PRINT(STDERR, "[ %llu, %llu ]\n",
570
0
            head_sc->sc_range.start, head_sc->sc_range.end);
571
0
        assert(SCHUNK_SIZE(head_sc) <= DIRECT_STORAGE_SZ);
572
0
        DEBUG_PRINT(STDERR, "\trange: %p [ %llu, %llu ] -> ",
573
0
            (void *)sr, sr->sr_range.start, sr->sr_range.end);
574
0
        sr->sr_range.start = head_sc->sc_range.start;
575
0
        DEBUG_PRINT(STDERR, "[ %llu, %llu ]\n",
576
0
            sr->sr_range.start, sr->sr_range.end);
577
0
        assert(r->end - r->start >= rsize);
578
579
0
        if (fs->cleanse)
580
0
            OPENSSL_cleanse(deconst(&data_buf[offset]),
581
0
                UINT64_TO_SIZE_T(rsize));
582
583
0
        r->end -= rsize;
584
0
    } else {
585
0
        assert(0);
586
0
        return -1;
587
0
    }
588
589
    /*
590
     * returns 1 if all data were consumed
591
     */
592
7.15k
    assert(r->end >= r->start);
593
0
    DEBUG_PRINT(STDERR, "%s @out %p [ %llu, %llu ]\n",
594
0
        OPENSSL_FUNC, *data, r->start, r->end);
595
596
0
    return ((r->end - r->start) == 0) ? 1 : 0;
597
0
}
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
 */
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
7.30k
{
614
7.30k
    uint64_t unused_sz;
615
616
7.30k
    if (!(r->start < sr->sr_range.start && r->end > sr->sr_range.end)) {
617
5.90k
        if (r->end > sr->sr_range.end && r->start < sr->sr_range.end) {
618
2.06k
            unused_sz = sr->sr_range.end - r->start;
619
2.06k
            if (fs->cleanse)
620
0
                OPENSSL_cleanse(deconst(data), UINT64_TO_SIZE_T(unused_sz));
621
622
2.06k
            DEBUG_PRINT(STDERR, "%s right overlap %p [ %llu, %llu ]:\n\t"
623
2.06k
                                "r: [ %llu, %llu ] -> [ %llu, %llu ]\n",
624
2.06k
                OPENSSL_FUNC,
625
2.06k
                (void *)sr, sr->sr_range.start, sr->sr_range.end,
626
2.06k
                r->start, r->end,
627
2.06k
                sr->sr_range.end, r->end);
628
629
2.06k
            data += unused_sz;
630
2.06k
            r->start = sr->sr_range.end;
631
3.84k
        } else if (r->start < sr->sr_range.start
632
3.14k
            && r->end > sr->sr_range.start) {
633
1.34k
            unused_sz = r->end - sr->sr_range.start;
634
1.34k
            if (fs->cleanse)
635
0
                OPENSSL_cleanse(deconst(data
636
0
                                    + (sr->sr_range.start - r->start)),
637
0
                    UINT64_TO_SIZE_T(unused_sz));
638
639
1.34k
            DEBUG_PRINT(STDERR, "%s left overlap %p [ %llu, %llu]:\n\t"
640
1.34k
                                "r: [ %llu, %llu ] -> [ %llu, %llu ]\n",
641
1.34k
                OPENSSL_FUNC,
642
1.34k
                (void *)sr, sr->sr_range.start, sr->sr_range.end,
643
1.34k
                r->start, r->end,
644
1.34k
                r->start, sr->sr_range.start);
645
1.34k
            r->end = sr->sr_range.start;
646
1.34k
        }
647
5.90k
    }
648
649
7.30k
    return data;
650
7.30k
}
651
652
/*
653
 * Inserts a newly received chunk to the head of the chunk list.
654
 */
655
static void prepend_chunk(SFRAME_SET *fs, struct stream_range_t *sr,
656
    struct stream_chunk_t *sc)
657
3.14k
{
658
3.14k
    DEBUG_PRINT(STDERR, "%s %p [ %llu, %llu ] add to head %p [ %llu, %llu ] "
659
3.14k
                        "-> [ %llu, %llu ]\n",
660
3.14k
        OPENSSL_FUNC,
661
3.14k
        (void *)sc, sc->sc_range.start, sc->sc_range.end,
662
3.14k
        (void *)sr, sr->sr_range.start, sr->sr_range.end,
663
3.14k
        sc->sc_range.start, sr->sr_range.end);
664
665
    /*
666
     * the new chunk must not be empty
667
     */
668
3.14k
    assert(sc->sc_range.end > sc->sc_range.start);
669
    /*
670
     * and must not overlap range.
671
     */
672
3.14k
    assert(sc->sc_range.end == sr->sr_range.start);
673
674
3.14k
    ossl_list_sc_insert_head(&sr->sr_chunks, sc);
675
3.14k
    sr->sr_range.start = sc->sc_range.start;
676
3.14k
    fs->stream_chunks++;
677
3.14k
}
678
679
/*
680
 * Inserts a newly received chunk to the tail of the chunk list.
681
 */
682
static void append_chunk(SFRAME_SET *fs, struct stream_range_t *sr,
683
    struct stream_chunk_t *sc)
684
2.76k
{
685
2.76k
    DEBUG_PRINT(STDERR, "%s %p [ %llu, %llu ] add to tail %p [ %llu, %llu ] "
686
2.76k
                        "-> [ %llu, %llu ]\n",
687
2.76k
        OPENSSL_FUNC,
688
2.76k
        (void *)sc, sc->sc_range.start, sc->sc_range.end,
689
2.76k
        (void *)sr, sr->sr_range.start, sr->sr_range.end,
690
2.76k
        sr->sr_range.start, sc->sc_range.end);
691
692
    /*
693
     * the new chunk must not be empty
694
     */
695
2.76k
    assert(sc->sc_range.end > sc->sc_range.start);
696
    /*
697
     * and must not overlap range
698
     */
699
2.76k
    assert(sc->sc_range.start == sr->sr_range.end);
700
701
2.76k
    ossl_list_sc_insert_tail(&sr->sr_chunks, sc);
702
2.76k
    sr->sr_range.end = sc->sc_range.end;
703
2.76k
    fs->stream_chunks++;
704
2.76k
}
705
706
static void replace_chunks_in_range(SFRAME_SET *fs, struct stream_range_t *sr,
707
    struct stream_chunk_t *sc)
708
1.39k
{
709
1.39k
    struct stream_chunk_t *destroy_sc;
710
711
3.09k
    while ((destroy_sc = ossl_list_sc_head(&sr->sr_chunks)) != NULL) {
712
1.69k
        ossl_list_sc_remove(&sr->sr_chunks, destroy_sc);
713
1.69k
        fs->stream_chunks--;
714
1.69k
        destroy_schunk(fs, destroy_sc);
715
1.69k
    }
716
717
1.39k
    ossl_list_sc_insert_head(&sr->sr_chunks, sc);
718
1.39k
    fs->stream_chunks++;
719
1.39k
    DEBUG_PRINT(STDERR, "%s range: %p [ %llu, %llu ] -> [ %llu, %llu ]\n",
720
1.39k
        OPENSSL_FUNC, (void *)sr, sr->sr_range.start, sr->sr_range.end,
721
1.39k
        sc->sc_range.start, sc->sc_range.end);
722
1.39k
    sr->sr_range.start = sc->sc_range.start;
723
1.39k
    sr->sr_range.end = sc->sc_range.end;
724
1.39k
}
725
726
static struct stream_range_t *find_range(SFRAME_SET *fs,
727
    struct stream_range_t *key)
728
189k
{
729
189k
    struct stream_range_t *sr = NULL;
730
731
189k
    if (!OSSL_RBT_EMPTY(srange, &fs->ranges))
732
101k
        sr = OSSL_RBT_FIND(srange, &fs->ranges, key);
733
734
189k
    return sr;
735
189k
}
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
 */
743
static int chop_range(SFRAME_SET *fs, struct stream_range_t *sr,
744
    uint64_t new_end)
745
1.13k
{
746
1.13k
    struct stream_chunk_t *sc;
747
1.13k
    size_t unused_sz;
748
749
1.13k
    assert(sr->sr_range.end >= new_end);
750
751
1.73k
    while ((sc = ossl_list_sc_tail(&sr->sr_chunks)) != NULL) {
752
1.73k
        if (sc->sc_range.start >= new_end) {
753
601
            ossl_list_sc_remove(&sr->sr_chunks, sc);
754
601
            fs->stream_chunks--;
755
601
            destroy_schunk(fs, sc);
756
1.13k
        } else {
757
1.13k
            break;
758
1.13k
        }
759
1.73k
    }
760
761
1.13k
    if (sc == NULL)
762
0
        return 0;
763
764
1.13k
    assert(new_end <= sc->sc_range.end);
765
1.13k
    assert(sc->sc_range.start < new_end);
766
767
1.13k
    unused_sz = UINT64_TO_SIZE_T(sc->sc_range.end - new_end);
768
1.13k
    if (unused_sz == 0) {
769
561
        sr->sr_range.end = new_end;
770
561
        return 1;
771
561
    }
772
773
570
    sc_data_trim_right(sc, unused_sz, fs->cleanse);
774
570
    sc->sc_range.end = new_end;
775
570
    sr->sr_range.end = new_end;
776
777
570
    if (sc->sc_st == ST_TYPE_PKT) {
778
570
        rsqp_add_overhead(fs->rsqp, unused_sz);
779
570
        DEBUG_PRINT(STDERR, "%s sc: %p unused_sz: %zu %zu -> %zu\n",
780
570
            OPENSSL_FUNC, (void *)sc, unused_sz,
781
570
            fs->rsqp->rsqp_pkt_overhead_sz - unused_sz,
782
570
            fs->rsqp->rsqp_pkt_overhead_sz);
783
570
    }
784
785
570
    return 1;
786
1.13k
}
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
 */
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
859
{
796
    /*
797
     * both ranges must not be empty
798
     */
799
859
    assert(super_sr->sr_range.start < super_sr->sr_range.end);
800
859
    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
859
    assert(super_sr->sr_range.start <= sub_sr->sr_range.start
806
859
        && super_sr->sr_range.end >= sub_sr->sr_range.end);
807
808
859
    DEBUG_PRINT(STDERR, "%s super: %p [ %llu, %llu ], sub: %p [ %llu, %llu]\n",
809
859
        OPENSSL_FUNC, (void *)super_sr, super_sr->sr_range.start,
810
859
        super_sr->sr_range.end, (void *)sub_sr, sub_sr->sr_range.start,
811
859
        sub_sr->sr_range.end);
812
859
    destroy_srange(fs, sub_sr);
813
814
859
    return super_sr;
815
859
}
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
 */
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
1.13k
{
828
    /*
829
     * both ranges must not be empty
830
     */
831
1.13k
    assert(left_sr->sr_range.start < left_sr->sr_range.end);
832
1.13k
    assert(right_sr->sr_range.start < right_sr->sr_range.end);
833
    /*
834
     * right range follows left range (left < right)
835
     */
836
1.13k
    assert(left_sr->sr_range.end >= right_sr->sr_range.start);
837
838
1.13k
    DEBUG_PRINT(STDERR, "%s %p [ %llu, %llu ] + %p [ %llu, %llu ] = %p "
839
1.13k
                        "[ %llu, %llu ]\n",
840
1.13k
        OPENSSL_FUNC, (void *)left_sr, left_sr->sr_range.start,
841
1.13k
        left_sr->sr_range.end, (void *)right_sr, right_sr->sr_range.start,
842
1.13k
        right_sr->sr_range.end, (void *)left_sr,
843
1.13k
        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
1.13k
    if (chop_range(fs, left_sr, right_sr->sr_range.start) == 0)
850
0
        return NULL;
851
852
1.13k
    ossl_list_sc_join(&left_sr->sr_chunks, &right_sr->sr_chunks);
853
1.13k
    left_sr->sr_range.end = right_sr->sr_range.end;
854
855
1.13k
    destroy_srange(fs, right_sr);
856
857
1.13k
    return left_sr;
858
1.13k
}
859
860
/*
861
 * receives a chunk of data from stream frame.
862
 * note there is a tri-state return value:
863
 */
864
int ossl_sframe_set_insert(SFRAME_SET *fs, UINT_RANGE *r, OSSL_QRX_PKT *pkt,
865
    const unsigned char *data, int fin)
866
215k
{
867
215k
    struct stream_range_t *sr = NULL;
868
215k
    struct stream_range_t *adjacent_sr = NULL;
869
215k
    struct stream_range_t *joined_sr = NULL;
870
215k
    struct stream_chunk_t *sc = NULL;
871
215k
    struct stream_range_t key_sr = { 0 };
872
873
215k
    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
215k
    if (fin != 0) {
881
25.2k
        if (fs->fin == 0) {
882
7.40k
            sr = OSSL_RBT_MAX(srange, &fs->ranges);
883
7.40k
            if (r->end < fs->offset
884
7.40k
                || (sr != NULL && sr->sr_range.end > r->end)) {
885
0
                ossl_quic_channel_raise_protocol_error(fs->rsqp->rsqp_ch,
886
0
                    OSSL_QUIC_ERR_FINAL_SIZE_ERROR,
887
0
                    OSSL_QUIC_FRAME_TYPE_STREAM_FIN,
888
0
                    "stream final size error");
889
0
                return 0;
890
0
            }
891
7.40k
            fs->fin = 1;
892
7.40k
            fs->fin_off = r->end;
893
17.8k
        } else if (fs->fin_off != r->end) {
894
0
            ossl_quic_channel_raise_protocol_error(fs->rsqp->rsqp_ch,
895
0
                OSSL_QUIC_ERR_FINAL_SIZE_ERROR,
896
0
                OSSL_QUIC_FRAME_TYPE_STREAM_FIN,
897
0
                "stream final size error");
898
0
            return 0;
899
0
        }
900
25.2k
    }
901
902
    /*
903
     * reject any data at or past the FIN offset (if FIN offset is set).
904
     */
905
215k
    if (fs->fin != 0) {
906
26.0k
        if (fs->fin_off < r->end) {
907
0
            ossl_quic_channel_raise_protocol_error(fs->rsqp->rsqp_ch,
908
0
                OSSL_QUIC_ERR_FINAL_SIZE_ERROR,
909
0
                (fin == 0) ? OSSL_QUIC_FRAME_TYPE_STREAM
910
0
                           : OSSL_QUIC_FRAME_TYPE_STREAM_FIN,
911
0
                "stream final size error");
912
0
            return 0;
913
0
        }
914
26.0k
    }
915
916
215k
    if (r->end <= fs->offset) {
917
        /*
918
         * retransmitted range got consumed already.
919
         */
920
26.0k
        DEBUG_PRINT(STDERR, "%s [ %llu, %llu ] <= %llu\n", OPENSSL_FUNC,
921
26.0k
            r->start, r->end, fs->offset);
922
26.0k
        if (fs->cleanse && data != NULL)
923
0
            OPENSSL_cleanse(deconst(data), UINT64_TO_SIZE_T(r->end - r->start));
924
26.0k
        return 1;
925
26.0k
    }
926
927
189k
    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
658
        DEBUG_PRINT(STDERR, "%s [ %llu, %llu ] -> [ %llu, %llu ]\n", OPENSSL_FUNC,
935
658
            r->start, r->end, fs->offset, r->end);
936
658
        if (fs->cleanse)
937
0
            OPENSSL_cleanse(deconst(data),
938
0
                UINT64_TO_SIZE_T(fs->offset - r->start));
939
658
        data += fs->offset - r->start;
940
658
        r->start = fs->offset;
941
658
    }
942
943
189k
    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
189k
    if (r->start == r->end)
950
108
        return 1;
951
952
189k
    assert(r->start < r->end);
953
954
189k
    if ((sr = find_range(fs, &key_sr)) == NULL) {
955
96.3k
        sc = new_schunk(fs, pkt, r, data);
956
96.3k
        if (sc == NULL)
957
0
            goto err;
958
959
96.3k
        sr = create_range(fs, sc);
960
96.3k
        if (sr == NULL)
961
0
            goto err;
962
96.3k
        DEBUG_PRINT(STDERR, "%s chunk: %p [ %llu, %llu ] new range: %p\n",
963
96.3k
            OPENSSL_FUNC, (void *)sc, sc->sc_range.start, sc->sc_range.end,
964
96.3k
            (void *)sr);
965
96.3k
        sc = NULL;
966
96.3k
        OSSL_RBT_INSERT(srange, &fs->ranges, sr);
967
96.3k
        fs->stream_ranges++;
968
96.3k
    } else {
969
        /*
970
         * retransmission, the whole chunk is found in existing range already
971
         */
972
93.2k
        if (r->start >= sr->sr_range.start && r->end <= sr->sr_range.end) {
973
85.9k
            DEBUG_PRINT(STDERR,
974
85.9k
                "%s [ %llu, %llu ] found in %p [ %llu, %llu ]\n", OPENSSL_FUNC,
975
85.9k
                r->start, r->end, (void *)sr, sr->sr_range.start,
976
85.9k
                sr->sr_range.end);
977
85.9k
            if (fs->cleanse)
978
0
                OPENSSL_cleanse(deconst(data),
979
0
                    UINT64_TO_SIZE_T(r->end - r->start));
980
85.9k
            goto done; /* Range is present already. */
981
85.9k
        }
982
983
7.30k
        switch (try_dstorage(fs, pkt, sr, r, &data)) {
984
7.30k
        case 0:
985
7.30k
            break;
986
0
        case 1:
987
            /*
988
             * all data were consumed, range is updated.
989
             */
990
0
            goto range_updated;
991
0
        default:
992
            /*
993
             * malloc error. forget the range we found.
994
             */
995
0
            sr = NULL;
996
0
            goto err;
997
7.30k
        }
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
7.30k
        data = trim_partial_overlap(fs, sr, r, data);
1004
1005
7.30k
        sc = new_schunk(fs, pkt, r, data);
1006
7.30k
        if (sc == NULL) {
1007
0
            sr = NULL;
1008
0
            goto err;
1009
0
        }
1010
7.30k
        DEBUG_PRINT(STDERR, "%s %p [ %llu, %llu ] -> %p [ %llu, %llu ]\n",
1011
7.30k
            OPENSSL_FUNC, (void *)sc, sc->sc_range.start, sc->sc_range.end,
1012
7.30k
            (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
7.30k
        if (sc->sc_range.start < sr->sr_range.start
1021
4.53k
            && sc->sc_range.end > sr->sr_range.end) {
1022
            /* new chunk includes the whole range */
1023
1.39k
            replace_chunks_in_range(fs, sr, sc);
1024
1.39k
            sc = NULL; /* chunk got consumed */
1025
5.90k
        } else if (sc->sc_range.end > sr->sr_range.end
1026
2.76k
            && sc->sc_range.start <= sr->sr_range.end) {
1027
2.76k
            append_chunk(fs, sr, sc);
1028
2.76k
            sc = NULL; /* chunk got consumed */
1029
3.14k
        } else if (sc->sc_range.start < sr->sr_range.start
1030
3.14k
            && sc->sc_range.end >= sr->sr_range.start) {
1031
3.14k
            prepend_chunk(fs, sr, sc);
1032
3.14k
            sc = NULL; /* chunk got consumed */
1033
3.14k
        } else {
1034
0
            assert(NULL); /* unreachable */
1035
0
            sr = NULL;
1036
0
            goto err;
1037
0
        }
1038
1039
7.30k
    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
7.30k
        OSSL_RBT_REMOVE(srange, &fs->ranges, sr);
1054
7.30k
        fs->stream_ranges--;
1055
        /*
1056
         * _INSERT() returns range where sr needs to be joined
1057
         */
1058
7.30k
        adjacent_sr = OSSL_RBT_INSERT(srange, &fs->ranges, sr);
1059
1060
9.29k
        while (adjacent_sr != NULL) {
1061
1.99k
            OSSL_RBT_REMOVE(srange, &fs->ranges, adjacent_sr);
1062
1.99k
            DEBUG_PRINT(STDERR, "%s %p [ %llu, %llu ] >< %p [ %llu, %llu ]\n",
1063
1.99k
                OPENSSL_FUNC, (void *)sr, sr->sr_range.start, sr->sr_range.end,
1064
1.99k
                (void *)adjacent_sr, adjacent_sr->sr_range.start,
1065
1.99k
                adjacent_sr->sr_range.end);
1066
1.99k
            fs->stream_ranges--;
1067
1068
1.99k
            if (sr->sr_range.start <= adjacent_sr->sr_range.start
1069
1.39k
                && sr->sr_range.end >= adjacent_sr->sr_range.end) {
1070
                /*
1071
                 *  adjacent_sr subset of sr
1072
                 */
1073
859
                joined_sr = merge_ranges(fs, sr, adjacent_sr);
1074
1.13k
            } else if (sr->sr_range.start >= adjacent_sr->sr_range.start
1075
594
                && sr->sr_range.end <= adjacent_sr->sr_range.end) {
1076
                /*
1077
                 *  sr subset of adjacent_sr
1078
                 */
1079
0
                joined_sr = merge_ranges(fs, adjacent_sr, sr);
1080
1.13k
            } else if (sr->sr_range.start < adjacent_sr->sr_range.start
1081
537
                && sr->sr_range.end >= adjacent_sr->sr_range.start) {
1082
                /*
1083
                 * adjacent_sr follows sr
1084
                 */
1085
537
                assert(sr->sr_range.end < adjacent_sr->sr_range.end);
1086
537
                joined_sr = append_range(fs, sr, adjacent_sr);
1087
594
            } else if (sr->sr_range.start <= adjacent_sr->sr_range.end
1088
594
                && sr->sr_range.end > adjacent_sr->sr_range.end) {
1089
                /*
1090
                 *  sr follows adjacent_sr
1091
                 */
1092
594
                assert(sr->sr_range.end > adjacent_sr->sr_range.end);
1093
594
                joined_sr = append_range(fs, adjacent_sr, sr);
1094
594
            } else {
1095
0
                assert(NULL); /* never happens */
1096
0
                joined_sr = NULL;
1097
0
            }
1098
1.99k
            if (joined_sr == NULL)
1099
0
                goto err;
1100
1101
1.99k
            sr = joined_sr;
1102
1.99k
            adjacent_sr = OSSL_RBT_INSERT(srange, &fs->ranges, sr);
1103
1.99k
        }
1104
7.30k
        fs->stream_ranges++;
1105
7.30k
    }
1106
1107
189k
done:
1108
189k
    return 1;
1109
1110
0
err:
1111
0
    destroy_schunk(fs, sc);
1112
0
    destroy_srange(fs, sr);
1113
0
    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
0
    return 0;
1122
189k
}
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
 */
1135
int ossl_sframe_set_peek(SFRAME_SET *fs, void **iterator,
1136
    UINT_RANGE *range, const unsigned char **data,
1137
    int *fin)
1138
114M
{
1139
114M
    uint64_t start;
1140
114M
    struct stream_range_t *sr = (struct stream_range_t *)*iterator;
1141
114M
    struct stream_chunk_t *sc = NULL;
1142
1143
114M
    if (sr == NULL) {
1144
114M
        sr = OSSL_RBT_MIN(srange, &fs->ranges);
1145
114M
        start = fs->offset;
1146
114M
        if (sr != NULL) {
1147
29.4M
            sc = ossl_list_sc_head(&sr->sr_chunks);
1148
29.4M
            sr->sr_it_sc = NULL;
1149
29.4M
            assert(sc->sc_range.start == sr->sr_range.start);
1150
29.4M
        }
1151
        /*
1152
         * no chunks are ready to be consumed, if there is a gap.
1153
         */
1154
114M
        if (sc != NULL && sc->sc_range.start > start) {
1155
29.4M
            DEBUG_PRINT(STDERR, "%s sc: %p sr: %p sc->start %llu, fs->offset: %llu\n",
1156
29.4M
                OPENSSL_FUNC, (void *)sc, (void *)sr, sc->sc_range.start, start);
1157
29.4M
            sc = NULL;
1158
29.4M
        }
1159
114M
    } 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
3.62k
        start = sr->sr_it_sc->sc_range.end;
1172
3.62k
        sc = ossl_list_sc_next(sr->sr_it_sc);
1173
3.62k
        assert(sc == NULL || sc->sc_range.start == start);
1174
3.62k
        assert(sc == NULL || sc->sc_range.start < sc->sc_range.end);
1175
3.62k
    } else {
1176
        /* iterator got invalidated by move/flatten operation on range */
1177
0
        DEBUG_PRINT(STDERR, "%s iterator got invalidated\n", OPENSSL_FUNC);
1178
0
        return 0;
1179
0
    }
1180
1181
114M
    range->start = start;
1182
1183
114M
    if (sc == NULL) {
1184
114M
        range->end = start;
1185
114M
        *data = NULL;
1186
114M
        *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
114M
        if (fs->fin && start == fs->fin_off)
1194
859
            *fin = fs->fin;
1195
114M
        else
1196
114M
            *fin = 0;
1197
1198
114M
        DEBUG_PRINT(STDERR, "%s no more chunks\n", OPENSSL_FUNC);
1199
1200
114M
        return 0;
1201
114M
    }
1202
1203
79.6k
    range->end = sc->sc_range.end;
1204
    /* chunk keeps data always attached, data dies with chunk */
1205
79.6k
    assert(sc->sc_data != NULL);
1206
79.6k
    assert(sc->sc_range.start <= start);
1207
79.6k
    *data = sc->sc_data + (start - sc->sc_range.start);
1208
79.6k
    *fin = fs->fin && sc->sc_range.end == fs->fin_off;
1209
1210
79.6k
    if (sr->sr_it_sc != NULL)
1211
146
        DEBUG_PRINT(STDERR, "%s %p [ %llu, %llu ] %p [ %llu, %llu ]\n",
1212
146
            OPENSSL_FUNC, (void *)sr->sr_it_sc,
1213
146
            sr->sr_it_sc->sc_range.start, sr->sr_it_sc->sc_range.end,
1214
146
            (void *)sc, sc->sc_range.start, sc->sc_range.end);
1215
1216
79.6k
    sr->sr_it_sc = sc;
1217
79.6k
    *iterator = sr;
1218
1219
    /*
1220
     * peek operation indicates error if there are no data to read
1221
     * in range.
1222
     */
1223
79.6k
    DEBUG_PRINT(STDERR,
1224
79.6k
        "%s peek range: [ %llu, %llu ] range: %p [ %llu, %llu ]\n", OPENSSL_FUNC,
1225
79.6k
        range->start, range->end, (void *)sr, sr->sr_range.start,
1226
79.6k
        sr->sr_range.end);
1227
1228
79.6k
    return (range->start == range->end) ? 0 : 1;
1229
79.6k
}
1230
1231
void ossl_sframe_set_destroy_ranges(SFRAME_SET *fs)
1232
299k
{
1233
299k
    struct stream_range_t *sr, *save_sr;
1234
1235
299k
    OSSL_RBT_FOREACH_SAFE (sr, srange, &fs->ranges, save_sr) {
1236
18.4k
        OSSL_RBT_REMOVE(srange, &fs->ranges, sr);
1237
18.4k
        fs->stream_ranges--;
1238
18.4k
        destroy_srange(fs, sr);
1239
18.4k
    }
1240
299k
}
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
 */
1247
int ossl_sframe_set_move_offset(SFRAME_SET *fs, uint64_t new_offset)
1248
79.5k
{
1249
79.5k
    struct stream_range_t *sr = OSSL_RBT_MIN(srange, &fs->ranges);
1250
79.5k
    struct stream_chunk_t *sc, *save_sc;
1251
79.5k
    size_t unused_sz;
1252
1253
79.5k
    if (new_offset == fs->offset)
1254
0
        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
79.5k
    if (sr == NULL || new_offset < fs->offset
1261
79.5k
        || new_offset < sr->sr_range.start || new_offset > sr->sr_range.end)
1262
0
        return 0;
1263
1264
79.5k
    fs->offset = new_offset;
1265
1266
81.7k
    OSSL_LIST_FOREACH_DELSAFE (sc, save_sc, sc, &sr->sr_chunks) {
1267
81.7k
        if (new_offset >= sc->sc_range.end) {
1268
78.1k
            ossl_list_sc_remove(&sr->sr_chunks, sc);
1269
78.1k
            fs->stream_chunks--;
1270
78.1k
            if (sr->sr_it_sc == sc)
1271
78.0k
                sr->sr_it_sc = NULL; /* invalidate iterator chunk */
1272
78.1k
            destroy_schunk(fs, sc);
1273
78.1k
        } else {
1274
3.57k
            break;
1275
3.57k
        }
1276
81.7k
    }
1277
1278
79.5k
    DEBUG_PRINT(STDERR, "%s offset: %llu -> %llu range: %p [ %llu, %llu ] -> ",
1279
79.5k
        OPENSSL_FUNC, fs->offset - new_offset, new_offset,
1280
79.5k
        (void *)sr, sr->sr_range.start, sr->sr_range.end);
1281
1282
79.5k
    if (sc == NULL) {
1283
        /*
1284
         * the whole range was consumed.
1285
         * this step invalidates iterator we use in ossl_sframe_peek()
1286
         */
1287
75.9k
        OSSL_RBT_REMOVE(srange, &fs->ranges, sr);
1288
75.9k
        destroy_srange(fs, sr);
1289
75.9k
        fs->stream_ranges--;
1290
75.9k
        DEBUG_PRINT(STDERR, "[ NULL ]\n");
1291
75.9k
    } else {
1292
3.57k
        unused_sz = UINT64_TO_SIZE_T(new_offset - sc->sc_range.start);
1293
3.57k
        sc_data_trim_left(sc, unused_sz, fs->cleanse);
1294
3.57k
        sc->sc_range.start = new_offset;
1295
3.57k
        sr->sr_range.start = new_offset;
1296
3.57k
        DEBUG_PRINT(STDERR, "[ %lli, %llu ]\n",
1297
3.57k
            sr->sr_range.start, sr->sr_range.end);
1298
1299
3.57k
        if (sc->sc_st == ST_TYPE_PKT) {
1300
3.57k
            rsqp_add_overhead(fs->rsqp, unused_sz);
1301
3.57k
            DEBUG_PRINT(STDERR, "%s sc: %p unused_sz: %zu %zu -> %zu\n",
1302
3.57k
                OPENSSL_FUNC, (void *)sc, unused_sz,
1303
3.57k
                fs->rsqp->rsqp_pkt_overhead_sz - unused_sz,
1304
3.57k
                fs->rsqp->rsqp_pkt_overhead_sz);
1305
3.57k
        }
1306
3.57k
    }
1307
1308
79.5k
    return 1;
1309
79.5k
}
1310
1311
/* Contiguous bytes available from fs->offset, in O(log n): the first range. */
1312
int ossl_sframe_set_avail(SFRAME_SET *fs, uint64_t *avail, int *fin)
1313
17.9M
{
1314
17.9M
    struct stream_range_t *sr = OSSL_RBT_MIN(srange, &fs->ranges);
1315
1316
17.9M
    if (sr != NULL && sr->sr_range.start <= fs->offset
1317
3.25k
        && sr->sr_range.end > fs->offset)
1318
3.25k
        *avail = sr->sr_range.end - fs->offset;
1319
17.9M
    else
1320
17.9M
        *avail = 0;
1321
17.9M
    *fin = (fs->fin && fs->offset + *avail == fs->fin_off) ? 1 : 0;
1322
17.9M
    return 1;
1323
17.9M
}
1324
1325
QUIC_RSTREAM_QPARM *ossl_quic_rstream_qparm_new(QUIC_CHANNEL *ch)
1326
53.0k
{
1327
53.0k
    QUIC_RSTREAM_QPARM *rsqp;
1328
1329
53.0k
    rsqp = OPENSSL_malloc(sizeof(QUIC_RSTREAM_QPARM));
1330
53.0k
    if (rsqp != NULL) {
1331
53.0k
        rsqp->rsqp_pkt_overhead_treshold = PKT_BUFFER_OVERHEAD_TRESHOLD;
1332
53.0k
        rsqp->rsqp_pkt_overhead_sz = 0;
1333
53.0k
        rsqp->rsqp_ch = ch;
1334
53.0k
    }
1335
1336
53.0k
    return rsqp;
1337
53.0k
}
1338
1339
void ossl_quic_rstream_qparm_destroy(QUIC_RSTREAM_QPARM *rsqp)
1340
53.0k
{
1341
53.0k
    if (rsqp != NULL) {
1342
53.0k
        assert(rsqp->rsqp_pkt_overhead_sz == 0);
1343
53.0k
        OPENSSL_free(rsqp);
1344
53.0k
    }
1345
53.0k
}