Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/crypto/openssl/ssl/quic/quic_rstream.c
48266 views
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_sf_list.h"
14
#include "internal/ring_buf.h"
15
16
struct quic_rstream_st {
17
SFRAME_LIST fl;
18
QUIC_RXFC *rxfc;
19
OSSL_STATM *statm;
20
UINT_RANGE head_range;
21
struct ring_buf rbuf;
22
};
23
24
QUIC_RSTREAM *ossl_quic_rstream_new(QUIC_RXFC *rxfc,
25
OSSL_STATM *statm, size_t rbuf_size)
26
{
27
QUIC_RSTREAM *ret = OPENSSL_zalloc(sizeof(*ret));
28
29
if (ret == NULL)
30
return NULL;
31
32
ring_buf_init(&ret->rbuf);
33
if (!ring_buf_resize(&ret->rbuf, rbuf_size, 0)) {
34
OPENSSL_free(ret);
35
return NULL;
36
}
37
38
ossl_sframe_list_init(&ret->fl);
39
ret->rxfc = rxfc;
40
ret->statm = statm;
41
return ret;
42
}
43
44
void ossl_quic_rstream_free(QUIC_RSTREAM *qrs)
45
{
46
int cleanse;
47
48
if (qrs == NULL)
49
return;
50
51
cleanse = qrs->fl.cleanse;
52
ossl_sframe_list_destroy(&qrs->fl);
53
ring_buf_destroy(&qrs->rbuf, cleanse);
54
OPENSSL_free(qrs);
55
}
56
57
int ossl_quic_rstream_queue_data(QUIC_RSTREAM *qrs, OSSL_QRX_PKT *pkt,
58
uint64_t offset,
59
const unsigned char *data, uint64_t data_len,
60
int fin)
61
{
62
UINT_RANGE range;
63
64
if ((data == NULL && data_len != 0) || (data_len == 0 && fin == 0)) {
65
/* empty frame allowed only at the end of the stream */
66
ERR_raise(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR);
67
return 0;
68
}
69
70
range.start = offset;
71
range.end = offset + data_len;
72
73
return ossl_sframe_list_insert(&qrs->fl, &range, pkt, data, fin);
74
}
75
76
static int read_internal(QUIC_RSTREAM *qrs, unsigned char *buf, size_t size,
77
size_t *readbytes, int *fin, int drop)
78
{
79
void *iter = NULL;
80
UINT_RANGE range;
81
const unsigned char *data;
82
uint64_t offset = 0;
83
size_t readbytes_ = 0;
84
int fin_ = 0, ret = 1;
85
86
while (ossl_sframe_list_peek(&qrs->fl, &iter, &range, &data, &fin_)) {
87
size_t l = (size_t)(range.end - range.start);
88
89
if (l > size) {
90
l = size;
91
fin_ = 0;
92
}
93
offset = range.start + l;
94
if (l == 0)
95
break;
96
97
if (data == NULL) {
98
size_t max_len;
99
100
data = ring_buf_get_ptr(&qrs->rbuf, range.start, &max_len);
101
if (!ossl_assert(data != NULL))
102
return 0;
103
if (max_len < l) {
104
memcpy(buf, data, max_len);
105
size -= max_len;
106
buf += max_len;
107
readbytes_ += max_len;
108
l -= max_len;
109
data = ring_buf_get_ptr(&qrs->rbuf, range.start + max_len,
110
&max_len);
111
if (!ossl_assert(data != NULL) || !ossl_assert(max_len > l))
112
return 0;
113
}
114
}
115
116
memcpy(buf, data, l);
117
size -= l;
118
buf += l;
119
readbytes_ += l;
120
if (size == 0)
121
break;
122
}
123
124
if (drop && offset != 0) {
125
ret = ossl_sframe_list_drop_frames(&qrs->fl, offset);
126
ring_buf_cpop_range(&qrs->rbuf, 0, offset - 1, qrs->fl.cleanse);
127
}
128
129
if (ret) {
130
*readbytes = readbytes_;
131
*fin = fin_;
132
}
133
134
return ret;
135
}
136
137
static OSSL_TIME get_rtt(QUIC_RSTREAM *qrs)
138
{
139
OSSL_TIME rtt;
140
141
if (qrs->statm != NULL) {
142
OSSL_RTT_INFO rtt_info;
143
144
ossl_statm_get_rtt_info(qrs->statm, &rtt_info);
145
rtt = rtt_info.smoothed_rtt;
146
} else {
147
rtt = ossl_time_zero();
148
}
149
return rtt;
150
}
151
152
int ossl_quic_rstream_read(QUIC_RSTREAM *qrs, unsigned char *buf, size_t size,
153
size_t *readbytes, int *fin)
154
{
155
OSSL_TIME rtt = get_rtt(qrs);
156
157
if (!read_internal(qrs, buf, size, readbytes, fin, 1))
158
return 0;
159
160
if (qrs->rxfc != NULL
161
&& !ossl_quic_rxfc_on_retire(qrs->rxfc, *readbytes, rtt))
162
return 0;
163
164
return 1;
165
}
166
167
int ossl_quic_rstream_peek(QUIC_RSTREAM *qrs, unsigned char *buf, size_t size,
168
size_t *readbytes, int *fin)
169
{
170
return read_internal(qrs, buf, size, readbytes, fin, 0);
171
}
172
173
int ossl_quic_rstream_available(QUIC_RSTREAM *qrs, size_t *avail, int *fin)
174
{
175
void *iter = NULL;
176
UINT_RANGE range;
177
const unsigned char *data;
178
uint64_t avail_ = 0;
179
180
while (ossl_sframe_list_peek(&qrs->fl, &iter, &range, &data, fin))
181
avail_ += range.end - range.start;
182
183
#if SIZE_MAX < UINT64_MAX
184
*avail = avail_ > SIZE_MAX ? SIZE_MAX : (size_t)avail_;
185
#else
186
*avail = (size_t)avail_;
187
#endif
188
return 1;
189
}
190
191
int ossl_quic_rstream_get_record(QUIC_RSTREAM *qrs,
192
const unsigned char **record, size_t *rec_len,
193
int *fin)
194
{
195
const unsigned char *record_ = NULL;
196
size_t rec_len_, max_len;
197
198
if (!ossl_sframe_list_lock_head(&qrs->fl, &qrs->head_range, &record_, fin)) {
199
/* No head frame to lock and return */
200
*record = NULL;
201
*rec_len = 0;
202
return 1;
203
}
204
205
/* if final empty frame, we drop it immediately */
206
if (qrs->head_range.end == qrs->head_range.start) {
207
if (!ossl_assert(*fin))
208
return 0;
209
if (!ossl_sframe_list_drop_frames(&qrs->fl, qrs->head_range.end))
210
return 0;
211
}
212
213
rec_len_ = (size_t)(qrs->head_range.end - qrs->head_range.start);
214
215
if (record_ == NULL && rec_len_ != 0) {
216
record_ = ring_buf_get_ptr(&qrs->rbuf, qrs->head_range.start,
217
&max_len);
218
if (!ossl_assert(record_ != NULL))
219
return 0;
220
if (max_len < rec_len_) {
221
rec_len_ = max_len;
222
qrs->head_range.end = qrs->head_range.start + max_len;
223
}
224
}
225
226
*rec_len = rec_len_;
227
*record = record_;
228
return 1;
229
}
230
231
232
int ossl_quic_rstream_release_record(QUIC_RSTREAM *qrs, size_t read_len)
233
{
234
uint64_t offset;
235
236
if (!ossl_sframe_list_is_head_locked(&qrs->fl))
237
return 0;
238
239
if (read_len > qrs->head_range.end - qrs->head_range.start) {
240
if (read_len != SIZE_MAX)
241
return 0;
242
offset = qrs->head_range.end;
243
} else {
244
offset = qrs->head_range.start + read_len;
245
}
246
247
if (!ossl_sframe_list_drop_frames(&qrs->fl, offset))
248
return 0;
249
250
if (offset > 0)
251
ring_buf_cpop_range(&qrs->rbuf, 0, offset - 1, qrs->fl.cleanse);
252
253
if (qrs->rxfc != NULL) {
254
OSSL_TIME rtt = get_rtt(qrs);
255
256
if (!ossl_quic_rxfc_on_retire(qrs->rxfc, offset, rtt))
257
return 0;
258
}
259
260
return 1;
261
}
262
263
static int write_at_ring_buf_cb(uint64_t logical_offset,
264
const unsigned char *buf,
265
size_t buf_len,
266
void *cb_arg)
267
{
268
struct ring_buf *rbuf = cb_arg;
269
270
return ring_buf_write_at(rbuf, logical_offset, buf, buf_len);
271
}
272
273
int ossl_quic_rstream_move_to_rbuf(QUIC_RSTREAM *qrs)
274
{
275
if (ring_buf_avail(&qrs->rbuf) == 0)
276
return 0;
277
return ossl_sframe_list_move_data(&qrs->fl,
278
write_at_ring_buf_cb, &qrs->rbuf);
279
}
280
281
int ossl_quic_rstream_resize_rbuf(QUIC_RSTREAM *qrs, size_t rbuf_size)
282
{
283
if (ossl_sframe_list_is_head_locked(&qrs->fl))
284
return 0;
285
286
if (!ring_buf_resize(&qrs->rbuf, rbuf_size, qrs->fl.cleanse))
287
return 0;
288
289
return 1;
290
}
291
292
void ossl_quic_rstream_set_cleanse(QUIC_RSTREAM *qrs, int cleanse)
293
{
294
qrs->fl.cleanse = cleanse;
295
}
296
297