Coverage Report

Created: 2024-07-24 06:31

/src/openssl/ssl/quic/quic_sstream.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright 2022-2023 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/quic_stream.h"
11
#include "internal/uint_set.h"
12
#include "internal/common.h"
13
#include "internal/ring_buf.h"
14
15
/*
16
 * ==================================================================
17
 * QUIC Send Stream
18
 */
19
struct quic_sstream_st {
20
    struct ring_buf ring_buf;
21
22
    /*
23
     * Any logical byte in the stream is in one of these states:
24
     *
25
     *   - NEW: The byte has not yet been transmitted, or has been lost and is
26
     *     in need of retransmission.
27
     *
28
     *   - IN_FLIGHT: The byte has been transmitted but is awaiting
29
     *     acknowledgement. We continue to store the data in case we return
30
     *     to the NEW state.
31
     *
32
     *   - ACKED: The byte has been acknowledged and we can cease storing it.
33
     *     We do not necessarily cull it immediately, so there may be a delay
34
     *     between reaching the ACKED state and the buffer space actually being
35
     *     recycled.
36
     *
37
     * A logical byte in the stream is
38
     *
39
     *   - in the NEW state if it is in new_set;
40
     *   - is in the ACKED state if it is in acked_set
41
     *       (and may or may not have been culled);
42
     *   - is in the IN_FLIGHT state otherwise.
43
     *
44
     * Invariant: No logical byte is ever in both new_set and acked_set.
45
     */
46
    UINT_SET        new_set, acked_set;
47
48
    /*
49
     * The current size of the stream is ring_buf.head_offset. If
50
     * have_final_size is true, this is also the final size of the stream.
51
     */
52
    unsigned int    have_final_size     : 1;
53
    unsigned int    sent_final_size     : 1;
54
    unsigned int    acked_final_size    : 1;
55
    unsigned int    cleanse             : 1;
56
};
57
58
static void qss_cull(QUIC_SSTREAM *qss);
59
60
QUIC_SSTREAM *ossl_quic_sstream_new(size_t init_buf_size)
61
0
{
62
0
    QUIC_SSTREAM *qss;
63
64
0
    qss = OPENSSL_zalloc(sizeof(QUIC_SSTREAM));
65
0
    if (qss == NULL)
66
0
        return NULL;
67
68
0
    ring_buf_init(&qss->ring_buf);
69
0
    if (!ring_buf_resize(&qss->ring_buf, init_buf_size, 0)) {
70
0
        ring_buf_destroy(&qss->ring_buf, 0);
71
0
        OPENSSL_free(qss);
72
0
        return NULL;
73
0
    }
74
75
0
    ossl_uint_set_init(&qss->new_set);
76
0
    ossl_uint_set_init(&qss->acked_set);
77
0
    return qss;
78
0
}
79
80
void ossl_quic_sstream_free(QUIC_SSTREAM *qss)
81
0
{
82
0
    if (qss == NULL)
83
0
        return;
84
85
0
    ossl_uint_set_destroy(&qss->new_set);
86
0
    ossl_uint_set_destroy(&qss->acked_set);
87
0
    ring_buf_destroy(&qss->ring_buf, qss->cleanse);
88
0
    OPENSSL_free(qss);
89
0
}
90
91
int ossl_quic_sstream_get_stream_frame(QUIC_SSTREAM *qss,
92
                                       size_t skip,
93
                                       OSSL_QUIC_FRAME_STREAM *hdr,
94
                                       OSSL_QTX_IOVEC *iov,
95
                                       size_t *num_iov)
96
0
{
97
0
    size_t num_iov_ = 0, src_len = 0, total_len = 0, i;
98
0
    uint64_t max_len;
99
0
    const unsigned char *src = NULL;
100
0
    UINT_SET_ITEM *range = ossl_list_uint_set_head(&qss->new_set);
101
102
0
    if (*num_iov < 2)
103
0
        return 0;
104
105
0
    for (i = 0; i < skip && range != NULL; ++i)
106
0
        range = ossl_list_uint_set_next(range);
107
108
0
    if (range == NULL) {
109
0
        if (i < skip)
110
            /* Don't return FIN for infinitely increasing skip */
111
0
            return 0;
112
113
        /* No new bytes to send, but we might have a FIN */
114
0
        if (!qss->have_final_size || qss->sent_final_size)
115
0
            return 0;
116
117
0
        hdr->offset = qss->ring_buf.head_offset;
118
0
        hdr->len    = 0;
119
0
        hdr->is_fin = 1;
120
0
        *num_iov    = 0;
121
0
        return 1;
122
0
    }
123
124
    /*
125
     * We can only send a contiguous range of logical bytes in a single
126
     * stream frame, so limit ourselves to the range of the first set entry.
127
     *
128
     * Set entries never have 'adjacent' entries so we don't have to worry
129
     * about them here.
130
     */
131
0
    max_len = range->range.end - range->range.start + 1;
132
133
0
    for (i = 0;; ++i) {
134
0
        if (total_len >= max_len)
135
0
            break;
136
137
0
        if (!ring_buf_get_buf_at(&qss->ring_buf,
138
0
                                 range->range.start + total_len,
139
0
                                 &src, &src_len))
140
0
            return 0;
141
142
0
        if (src_len == 0)
143
0
            break;
144
145
0
        assert(i < 2);
146
147
0
        if (total_len + src_len > max_len)
148
0
            src_len = (size_t)(max_len - total_len);
149
150
0
        iov[num_iov_].buf       = src;
151
0
        iov[num_iov_].buf_len   = src_len;
152
153
0
        total_len += src_len;
154
0
        ++num_iov_;
155
0
    }
156
157
0
    hdr->offset = range->range.start;
158
0
    hdr->len    = total_len;
159
0
    hdr->is_fin = qss->have_final_size
160
0
        && hdr->offset + hdr->len == qss->ring_buf.head_offset;
161
162
0
    *num_iov    = num_iov_;
163
0
    return 1;
164
0
}
165
166
int ossl_quic_sstream_has_pending(QUIC_SSTREAM *qss)
167
0
{
168
0
    OSSL_QUIC_FRAME_STREAM shdr;
169
0
    OSSL_QTX_IOVEC iov[2];
170
0
    size_t num_iov = OSSL_NELEM(iov);
171
172
0
    return ossl_quic_sstream_get_stream_frame(qss, 0, &shdr, iov, &num_iov);
173
0
}
174
175
uint64_t ossl_quic_sstream_get_cur_size(QUIC_SSTREAM *qss)
176
0
{
177
0
    return qss->ring_buf.head_offset;
178
0
}
179
180
int ossl_quic_sstream_mark_transmitted(QUIC_SSTREAM *qss,
181
                                       uint64_t start,
182
                                       uint64_t end)
183
0
{
184
0
    UINT_RANGE r;
185
186
0
    r.start = start;
187
0
    r.end   = end;
188
189
0
    if (!ossl_uint_set_remove(&qss->new_set, &r))
190
0
        return 0;
191
192
0
    return 1;
193
0
}
194
195
int ossl_quic_sstream_mark_transmitted_fin(QUIC_SSTREAM *qss,
196
                                           uint64_t final_size)
197
0
{
198
    /*
199
     * We do not really need final_size since we already know the size of the
200
     * stream, but this serves as a sanity check.
201
     */
202
0
    if (!qss->have_final_size || final_size != qss->ring_buf.head_offset)
203
0
        return 0;
204
205
0
    qss->sent_final_size = 1;
206
0
    return 1;
207
0
}
208
209
int ossl_quic_sstream_mark_lost(QUIC_SSTREAM *qss,
210
                                uint64_t start,
211
                                uint64_t end)
212
0
{
213
0
    UINT_RANGE r;
214
0
    r.start = start;
215
0
    r.end   = end;
216
217
    /*
218
     * We lost a range of stream data bytes, so reinsert them into the new set,
219
     * so that they are returned once more by ossl_quic_sstream_get_stream_frame.
220
     */
221
0
    if (!ossl_uint_set_insert(&qss->new_set, &r))
222
0
        return 0;
223
224
0
    return 1;
225
0
}
226
227
int ossl_quic_sstream_mark_lost_fin(QUIC_SSTREAM *qss)
228
0
{
229
0
    if (qss->acked_final_size)
230
        /* Does not make sense to lose a FIN after it has been ACKed */
231
0
        return 0;
232
233
    /* FIN was lost, so we need to transmit it again. */
234
0
    qss->sent_final_size = 0;
235
0
    return 1;
236
0
}
237
238
int ossl_quic_sstream_mark_acked(QUIC_SSTREAM *qss,
239
                                 uint64_t start,
240
                                 uint64_t end)
241
0
{
242
0
    UINT_RANGE r;
243
0
    r.start = start;
244
0
    r.end   = end;
245
246
0
    if (!ossl_uint_set_insert(&qss->acked_set, &r))
247
0
        return 0;
248
249
0
    qss_cull(qss);
250
0
    return 1;
251
0
}
252
253
int ossl_quic_sstream_mark_acked_fin(QUIC_SSTREAM *qss)
254
0
{
255
0
    if (!qss->have_final_size)
256
        /* Cannot ack final size before we have a final size */
257
0
        return 0;
258
259
0
    qss->acked_final_size = 1;
260
0
    return 1;
261
0
}
262
263
void ossl_quic_sstream_fin(QUIC_SSTREAM *qss)
264
0
{
265
0
    if (qss->have_final_size)
266
0
        return;
267
268
0
    qss->have_final_size = 1;
269
0
}
270
271
int ossl_quic_sstream_get_final_size(QUIC_SSTREAM *qss, uint64_t *final_size)
272
0
{
273
0
    if (!qss->have_final_size)
274
0
        return 0;
275
276
0
    if (final_size != NULL)
277
0
        *final_size = qss->ring_buf.head_offset;
278
279
0
    return 1;
280
0
}
281
282
int ossl_quic_sstream_append(QUIC_SSTREAM *qss,
283
                             const unsigned char *buf,
284
                             size_t buf_len,
285
                             size_t *consumed)
286
0
{
287
0
    size_t l, consumed_ = 0;
288
0
    UINT_RANGE r;
289
0
    struct ring_buf old_ring_buf = qss->ring_buf;
290
291
0
    if (qss->have_final_size) {
292
0
        *consumed = 0;
293
0
        return 0;
294
0
    }
295
296
    /*
297
     * Note: It is assumed that ossl_quic_sstream_append will be called during a
298
     * call to e.g. SSL_write and this function is therefore designed to support
299
     * such semantics. In particular, the buffer pointed to by buf is only
300
     * assumed to be valid for the duration of this call, therefore we must copy
301
     * the data here. We will later copy-and-encrypt the data during packet
302
     * encryption, so this is a two-copy design. Supporting a one-copy design in
303
     * the future will require applications to use a different kind of API.
304
     * Supporting such changes in future will require corresponding enhancements
305
     * to this code.
306
     */
307
0
    while (buf_len > 0) {
308
0
        l = ring_buf_push(&qss->ring_buf, buf, buf_len);
309
0
        if (l == 0)
310
0
            break;
311
312
0
        buf         += l;
313
0
        buf_len     -= l;
314
0
        consumed_   += l;
315
0
    }
316
317
0
    if (consumed_ > 0) {
318
0
        r.start = old_ring_buf.head_offset;
319
0
        r.end   = r.start + consumed_ - 1;
320
0
        assert(r.end + 1 == qss->ring_buf.head_offset);
321
0
        if (!ossl_uint_set_insert(&qss->new_set, &r)) {
322
0
            qss->ring_buf = old_ring_buf;
323
0
            *consumed = 0;
324
0
            return 0;
325
0
        }
326
0
    }
327
328
0
    *consumed = consumed_;
329
0
    return 1;
330
0
}
331
332
static void qss_cull(QUIC_SSTREAM *qss)
333
0
{
334
0
    UINT_SET_ITEM *h = ossl_list_uint_set_head(&qss->acked_set);
335
336
    /*
337
     * Potentially cull data from our ring buffer. This can happen once data has
338
     * been ACKed and we know we are never going to have to transmit it again.
339
     *
340
     * Since we use a ring buffer design for simplicity, we cannot cull byte n +
341
     * k (for k > 0) from the ring buffer until byte n has also been culled.
342
     * This means if parts of the stream get acknowledged out of order we might
343
     * keep around some data we technically don't need to for a while. The
344
     * impact of this is likely to be small and limited to quite a short
345
     * duration, and doesn't justify the use of a more complex design.
346
     */
347
348
    /*
349
     * We only need to check the first range entry in the integer set because we
350
     * can only cull contiguous areas at the start of the ring buffer anyway.
351
     */
352
0
    if (h != NULL)
353
0
        ring_buf_cpop_range(&qss->ring_buf, h->range.start, h->range.end,
354
0
                            qss->cleanse);
355
0
}
356
357
int ossl_quic_sstream_set_buffer_size(QUIC_SSTREAM *qss, size_t num_bytes)
358
0
{
359
0
    return ring_buf_resize(&qss->ring_buf, num_bytes, qss->cleanse);
360
0
}
361
362
size_t ossl_quic_sstream_get_buffer_size(QUIC_SSTREAM *qss)
363
0
{
364
0
    return qss->ring_buf.alloc;
365
0
}
366
367
size_t ossl_quic_sstream_get_buffer_used(QUIC_SSTREAM *qss)
368
0
{
369
0
    return ring_buf_used(&qss->ring_buf);
370
0
}
371
372
size_t ossl_quic_sstream_get_buffer_avail(QUIC_SSTREAM *qss)
373
0
{
374
0
    return ring_buf_avail(&qss->ring_buf);
375
0
}
376
377
int ossl_quic_sstream_is_totally_acked(QUIC_SSTREAM *qss)
378
0
{
379
0
    UINT_RANGE r;
380
0
    uint64_t cur_size;
381
382
0
    if (qss->have_final_size && !qss->acked_final_size)
383
0
        return 0;
384
385
0
    if (ossl_quic_sstream_get_cur_size(qss) == 0)
386
0
        return 1;
387
388
0
    if (ossl_list_uint_set_num(&qss->acked_set) != 1)
389
0
        return 0;
390
391
0
    r = ossl_list_uint_set_head(&qss->acked_set)->range;
392
0
    cur_size = qss->ring_buf.head_offset;
393
394
    /*
395
     * The invariants of UINT_SET guarantee a single list element if we have a
396
     * single contiguous range, which is what we should have if everything has
397
     * been acked.
398
     */
399
0
    assert(r.end + 1 <= cur_size);
400
0
    return r.start == 0 && r.end + 1 == cur_size;
401
0
}
402
403
void ossl_quic_sstream_adjust_iov(size_t len,
404
                                  OSSL_QTX_IOVEC *iov,
405
                                  size_t num_iov)
406
0
{
407
0
    size_t running = 0, i, iovlen;
408
409
0
    for (i = 0, running = 0; i < num_iov; ++i) {
410
0
        iovlen = iov[i].buf_len;
411
412
0
        if (running >= len)
413
0
            iov[i].buf_len = 0;
414
0
        else if (running + iovlen > len)
415
0
            iov[i].buf_len = len - running;
416
417
0
        running += iovlen;
418
0
    }
419
0
}
420
421
void ossl_quic_sstream_set_cleanse(QUIC_SSTREAM *qss, int cleanse)
422
0
{
423
0
    qss->cleanse = cleanse;
424
0
}