]>
Commit | Line | Data |
---|---|---|
bbf902c3 | 1 | /* |
da1c088f | 2 | * Copyright 2022-2023 The OpenSSL Project Authors. All Rights Reserved. |
bbf902c3 TM |
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 | */ | |
2113ea58 | 9 | #include <openssl/err.h> |
bbf902c3 | 10 | #include "internal/common.h" |
e77396f6 | 11 | #include "internal/time.h" |
bbf902c3 TM |
12 | #include "internal/quic_stream.h" |
13 | #include "internal/quic_sf_list.h" | |
2113ea58 | 14 | #include "internal/ring_buf.h" |
bbf902c3 TM |
15 | |
16 | struct quic_rstream_st { | |
17 | SFRAME_LIST fl; | |
e77396f6 TM |
18 | QUIC_RXFC *rxfc; |
19 | OSSL_STATM *statm; | |
2113ea58 TM |
20 | UINT_RANGE head_range; |
21 | struct ring_buf rbuf; | |
bbf902c3 TM |
22 | }; |
23 | ||
6d5d5fc9 | 24 | QUIC_RSTREAM *ossl_quic_rstream_new(QUIC_RXFC *rxfc, |
2113ea58 | 25 | OSSL_STATM *statm, size_t rbuf_size) |
bbf902c3 | 26 | { |
2113ea58 | 27 | QUIC_RSTREAM *ret = OPENSSL_zalloc(sizeof(*ret)); |
bbf902c3 TM |
28 | |
29 | if (ret == NULL) | |
30 | return NULL; | |
31 | ||
2113ea58 | 32 | ring_buf_init(&ret->rbuf); |
292c9df2 | 33 | if (!ring_buf_resize(&ret->rbuf, rbuf_size, 0)) { |
2113ea58 TM |
34 | OPENSSL_free(ret); |
35 | return NULL; | |
36 | } | |
37 | ||
6d5d5fc9 | 38 | ossl_sframe_list_init(&ret->fl); |
e77396f6 TM |
39 | ret->rxfc = rxfc; |
40 | ret->statm = statm; | |
bbf902c3 TM |
41 | return ret; |
42 | } | |
43 | ||
44 | void ossl_quic_rstream_free(QUIC_RSTREAM *qrs) | |
45 | { | |
292c9df2 TM |
46 | int cleanse; |
47 | ||
21247795 HL |
48 | if (qrs == NULL) |
49 | return; | |
50 | ||
292c9df2 | 51 | cleanse = qrs->fl.cleanse; |
bbf902c3 | 52 | ossl_sframe_list_destroy(&qrs->fl); |
292c9df2 | 53 | ring_buf_destroy(&qrs->rbuf, cleanse); |
bbf902c3 TM |
54 | OPENSSL_free(qrs); |
55 | } | |
56 | ||
6d5d5fc9 | 57 | int ossl_quic_rstream_queue_data(QUIC_RSTREAM *qrs, OSSL_QRX_PKT *pkt, |
bbf902c3 TM |
58 | uint64_t offset, |
59 | const unsigned char *data, uint64_t data_len, | |
60 | int fin) | |
61 | { | |
62 | UINT_RANGE range; | |
63 | ||
2113ea58 TM |
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 | ||
bbf902c3 TM |
70 | range.start = offset; |
71 | range.end = offset + data_len; | |
e77396f6 | 72 | |
6d5d5fc9 | 73 | return ossl_sframe_list_insert(&qrs->fl, &range, pkt, data, fin); |
bbf902c3 TM |
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 | ||
2113ea58 | 89 | if (l > size) { |
bbf902c3 | 90 | l = size; |
2113ea58 TM |
91 | fin_ = 0; |
92 | } | |
bbf902c3 | 93 | offset = range.start + l; |
2113ea58 TM |
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); | |
bbf902c3 TM |
117 | size -= l; |
118 | buf += l; | |
119 | readbytes_ += l; | |
120 | if (size == 0) | |
121 | break; | |
122 | } | |
123 | ||
2113ea58 | 124 | if (drop && offset != 0) { |
bbf902c3 | 125 | ret = ossl_sframe_list_drop_frames(&qrs->fl, offset); |
a02571a0 | 126 | ring_buf_cpop_range(&qrs->rbuf, 0, offset - 1, qrs->fl.cleanse); |
2113ea58 | 127 | } |
bbf902c3 TM |
128 | |
129 | if (ret) { | |
130 | *readbytes = readbytes_; | |
131 | *fin = fin_; | |
132 | } | |
133 | ||
134 | return ret; | |
135 | } | |
136 | ||
2113ea58 | 137 | static OSSL_TIME get_rtt(QUIC_RSTREAM *qrs) |
bbf902c3 | 138 | { |
e77396f6 TM |
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 | } | |
2113ea58 TM |
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); | |
e77396f6 TM |
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; | |
bbf902c3 TM |
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 | } | |
2113ea58 TM |
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) | |
a02571a0 | 251 | ring_buf_cpop_range(&qrs->rbuf, 0, offset - 1, qrs->fl.cleanse); |
2113ea58 TM |
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 | { | |
2113ea58 TM |
283 | if (ossl_sframe_list_is_head_locked(&qrs->fl)) |
284 | return 0; | |
285 | ||
292c9df2 | 286 | if (!ring_buf_resize(&qrs->rbuf, rbuf_size, qrs->fl.cleanse)) |
2113ea58 TM |
287 | return 0; |
288 | ||
289 | return 1; | |
290 | } | |
a02571a0 TM |
291 | |
292 | void ossl_quic_rstream_set_cleanse(QUIC_RSTREAM *qrs, int cleanse) | |
293 | { | |
294 | qrs->fl.cleanse = cleanse; | |
295 | } |