xref: /openssl/ssl/quic/quic_rstream.c (revision da1c088f)
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 
ossl_quic_rstream_new(QUIC_RXFC * rxfc,OSSL_STATM * statm,size_t rbuf_size)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 
ossl_quic_rstream_free(QUIC_RSTREAM * qrs)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 
ossl_quic_rstream_queue_data(QUIC_RSTREAM * qrs,OSSL_QRX_PKT * pkt,uint64_t offset,const unsigned char * data,uint64_t data_len,int fin)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 
read_internal(QUIC_RSTREAM * qrs,unsigned char * buf,size_t size,size_t * readbytes,int * fin,int drop)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 
get_rtt(QUIC_RSTREAM * qrs)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 
ossl_quic_rstream_read(QUIC_RSTREAM * qrs,unsigned char * buf,size_t size,size_t * readbytes,int * fin)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 
ossl_quic_rstream_peek(QUIC_RSTREAM * qrs,unsigned char * buf,size_t size,size_t * readbytes,int * fin)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 
ossl_quic_rstream_available(QUIC_RSTREAM * qrs,size_t * avail,int * fin)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 
ossl_quic_rstream_get_record(QUIC_RSTREAM * qrs,const unsigned char ** record,size_t * rec_len,int * fin)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 
ossl_quic_rstream_release_record(QUIC_RSTREAM * qrs,size_t read_len)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 
write_at_ring_buf_cb(uint64_t logical_offset,const unsigned char * buf,size_t buf_len,void * cb_arg)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 
ossl_quic_rstream_move_to_rbuf(QUIC_RSTREAM * qrs)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 
ossl_quic_rstream_resize_rbuf(QUIC_RSTREAM * qrs,size_t rbuf_size)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 
ossl_quic_rstream_set_cleanse(QUIC_RSTREAM * qrs,int cleanse)292 void ossl_quic_rstream_set_cleanse(QUIC_RSTREAM *qrs, int cleanse)
293 {
294     qrs->fl.cleanse = cleanse;
295 }
296