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_rstream.c
Line
Count
Source
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
#include <openssl/err.h>
10
#include "internal/common.h"
11
#include "internal/time.h"
12
#include "internal/quic_stream.h"
13
#include "internal/quic_strm_reas.h"
14
#include "internal/ring_buf.h"
15
16
struct quic_rstream_st {
17
    SFRAME_SET fs;
18
    QUIC_RXFC *rxfc;
19
    OSSL_STATM *statm;
20
    UINT_RANGE head_range;
21
};
22
23
#if !defined(NDEBUG) && defined(WITH_RSTREAM_DEBUG)
24
#include <stdio.h>
25
#define DEBUG_PRINT(...) fprintf(__VA_ARGS__)
26
#else
27
0
#define DEBUG_PRINT(...) (void)(0)
28
#endif
29
30
QUIC_RSTREAM *ossl_quic_rstream_new(QUIC_RXFC *rxfc,
31
    OSSL_STATM *statm, QUIC_RSTREAM_QPARM *rsqp)
32
0
{
33
0
    QUIC_RSTREAM *ret = OPENSSL_zalloc(sizeof(*ret));
34
35
0
    if (ret == NULL)
36
0
        return NULL;
37
38
0
    ossl_sframe_set_init(&ret->fs, rsqp);
39
0
    ret->rxfc = rxfc;
40
0
    ret->statm = statm;
41
0
    return ret;
42
0
}
43
44
void ossl_quic_rstream_free(QUIC_RSTREAM *qrs)
45
0
{
46
0
    if (qrs == NULL)
47
0
        return;
48
49
0
    ossl_sframe_set_destroy_ranges(&qrs->fs);
50
0
    OPENSSL_free(qrs);
51
0
}
52
53
int ossl_quic_rstream_queue_data(QUIC_RSTREAM *qrs, OSSL_QRX_PKT *pkt,
54
    uint64_t offset,
55
    const unsigned char *data, uint64_t data_len,
56
    int fin)
57
0
{
58
0
    UINT_RANGE range;
59
60
0
    if ((data == NULL && data_len != 0) || (data_len == 0 && fin == 0)) {
61
        /* empty frame allowed only at the end of the stream */
62
0
        ERR_raise(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR);
63
0
        return 0;
64
0
    }
65
66
0
    range.start = offset;
67
0
    range.end = offset + data_len;
68
69
0
    return ossl_sframe_set_insert(&qrs->fs, &range, pkt, data, fin);
70
0
}
71
72
static int read_internal(QUIC_RSTREAM *qrs, unsigned char *buf, size_t size,
73
    size_t *readbytes, int *fin, int drop)
74
0
{
75
0
    void *iter = NULL;
76
0
    UINT_RANGE range;
77
0
    const unsigned char *data;
78
0
    uint64_t offset = 0;
79
0
    size_t readbytes_ = 0;
80
0
    int fin_ = 0, ret = 1;
81
82
0
    DEBUG_PRINT(stderr, "%s want: %zu\n", OPENSSL_FUNC, size);
83
0
    while (ossl_sframe_set_peek(&qrs->fs, &iter, &range, &data, &fin_)) {
84
0
        size_t l = (size_t)(range.end - range.start);
85
86
0
        DEBUG_PRINT(stderr, "\t[ %llu, %llu ]\n", range.start, range.end);
87
0
        if (l > size) {
88
0
            l = size;
89
0
            fin_ = 0;
90
0
        }
91
0
        offset = range.start + l;
92
0
        if (l == 0)
93
0
            break;
94
95
0
        memcpy(buf, data, l);
96
0
        size -= l;
97
0
        buf += l;
98
0
        readbytes_ += l;
99
0
        if (size == 0)
100
0
            break;
101
0
    }
102
103
0
    if (drop && offset != 0)
104
0
        ret = ossl_sframe_set_move_offset(&qrs->fs, offset);
105
106
0
    if (ret) {
107
0
        DEBUG_PRINT(stderr, "%s got: %zu\n", OPENSSL_FUNC, readbytes_);
108
0
        *readbytes = readbytes_;
109
0
        *fin = fin_;
110
0
    } else {
111
0
        DEBUG_PRINT(stderr, "%s got: nothing\n", OPENSSL_FUNC);
112
0
    }
113
114
0
    return ret;
115
0
}
116
117
static OSSL_TIME get_rtt(QUIC_RSTREAM *qrs)
118
0
{
119
0
    OSSL_TIME rtt;
120
121
0
    if (qrs->statm != NULL) {
122
0
        OSSL_RTT_INFO rtt_info;
123
124
0
        ossl_statm_get_rtt_info(qrs->statm, &rtt_info);
125
0
        rtt = rtt_info.smoothed_rtt;
126
0
    } else {
127
0
        rtt = ossl_time_zero();
128
0
    }
129
0
    return rtt;
130
0
}
131
132
int ossl_quic_rstream_read(QUIC_RSTREAM *qrs, unsigned char *buf, size_t size,
133
    size_t *readbytes, int *fin)
134
0
{
135
0
    OSSL_TIME rtt = get_rtt(qrs);
136
137
0
    if (!read_internal(qrs, buf, size, readbytes, fin, 1))
138
0
        return 0;
139
140
0
    if (qrs->rxfc != NULL
141
0
        && !ossl_quic_rxfc_on_retire(qrs->rxfc, *readbytes, rtt))
142
0
        return 0;
143
144
0
    return 1;
145
0
}
146
147
int ossl_quic_rstream_peek(QUIC_RSTREAM *qrs, unsigned char *buf, size_t size,
148
    size_t *readbytes, int *fin)
149
0
{
150
0
    return read_internal(qrs, buf, size, readbytes, fin, 0);
151
0
}
152
153
int ossl_quic_rstream_available(QUIC_RSTREAM *qrs, size_t *avail, int *fin)
154
0
{
155
0
    uint64_t avail_ = 0;
156
157
0
    ossl_sframe_set_avail(&qrs->fs, &avail_, fin);
158
159
#if SIZE_MAX < UINT64_MAX
160
    *avail = avail_ > SIZE_MAX ? SIZE_MAX : (size_t)avail_;
161
#else
162
0
    *avail = (size_t)avail_;
163
0
#endif
164
0
    return 1;
165
0
}
166
167
int ossl_quic_rstream_get_record(QUIC_RSTREAM *qrs,
168
    const unsigned char **record, size_t *rec_len,
169
    int *fin)
170
0
{
171
0
    const unsigned char *record_ = NULL;
172
0
    void *iterator = NULL;
173
0
    size_t rec_len_;
174
0
    int ok;
175
176
0
    ok = ossl_sframe_set_peek(&qrs->fs, &iterator, &qrs->head_range, &record_,
177
0
        fin);
178
0
    if (ok == 0) {
179
0
        *record = NULL;
180
0
        *rec_len = 0;
181
0
        return 1;
182
0
    }
183
184
0
    DEBUG_PRINT(stderr, "%s head: [ %llu, %llu ]\n", OPENSSL_FUNC,
185
0
        qrs->head_range.start, qrs->head_range.end);
186
    /* if final empty frame, we drop it immediately */
187
0
    if (qrs->head_range.end == qrs->head_range.start) {
188
0
        if (!ossl_assert(*fin))
189
0
            return 0;
190
0
        if (!ossl_sframe_set_move_offset(&qrs->fs, qrs->head_range.end))
191
0
            return 0;
192
0
    }
193
194
0
    rec_len_ = (size_t)(qrs->head_range.end - qrs->head_range.start);
195
0
    *rec_len = rec_len_;
196
0
    *record = record_;
197
198
0
    return 1;
199
0
}
200
201
int ossl_quic_rstream_release_record(QUIC_RSTREAM *qrs, size_t read_len)
202
0
{
203
0
    uint64_t offset;
204
205
0
    if (read_len > qrs->head_range.end - qrs->head_range.start) {
206
0
        if (read_len != SIZE_MAX)
207
0
            return 0;
208
0
        offset = qrs->head_range.end;
209
0
    } else {
210
0
        offset = qrs->head_range.start + read_len;
211
0
    }
212
213
0
    if (!ossl_sframe_set_move_offset(&qrs->fs, offset))
214
0
        return 0;
215
216
0
    if (qrs->rxfc != NULL) {
217
0
        OSSL_TIME rtt = get_rtt(qrs);
218
219
0
        if (!ossl_quic_rxfc_on_retire(qrs->rxfc, offset, rtt))
220
0
            return 0;
221
0
    }
222
223
0
    return 1;
224
0
}
225
226
void ossl_quic_rstream_set_cleanse(QUIC_RSTREAM *qrs, int cleanse)
227
0
{
228
0
    qrs->fs.cleanse = cleanse;
229
0
}
230
231
size_t ossl_quic_rstream_get_chunk_count(QUIC_RSTREAM *qrs)
232
0
{
233
0
    return qrs->fs.stream_chunks;
234
0
}
235
236
size_t ossl_quic_rstream_get_range_count(QUIC_RSTREAM *qrs)
237
0
{
238
0
    return qrs->fs.stream_ranges;
239
0
}