Coverage Report

Created: 2026-10-16 07:31

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