VirtualBox

source: vbox/trunk/src/libs/openssl-3.3.2/ssl/quic/quic_sstream.c@ 108358

最後變更 在這個檔案從108358是 108206,由 vboxsync 提交於 5 週 前

openssl-3.3.2: Exported all files to OSE and removed .scm-settings ​bugref:10757

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 11.7 KB
 
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 */
19struct 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
58static void qss_cull(QUIC_SSTREAM *qss);
59
60QUIC_SSTREAM *ossl_quic_sstream_new(size_t init_buf_size)
61{
62 QUIC_SSTREAM *qss;
63
64 qss = OPENSSL_zalloc(sizeof(QUIC_SSTREAM));
65 if (qss == NULL)
66 return NULL;
67
68 ring_buf_init(&qss->ring_buf);
69 if (!ring_buf_resize(&qss->ring_buf, init_buf_size, 0)) {
70 ring_buf_destroy(&qss->ring_buf, 0);
71 OPENSSL_free(qss);
72 return NULL;
73 }
74
75 ossl_uint_set_init(&qss->new_set);
76 ossl_uint_set_init(&qss->acked_set);
77 return qss;
78}
79
80void ossl_quic_sstream_free(QUIC_SSTREAM *qss)
81{
82 if (qss == NULL)
83 return;
84
85 ossl_uint_set_destroy(&qss->new_set);
86 ossl_uint_set_destroy(&qss->acked_set);
87 ring_buf_destroy(&qss->ring_buf, qss->cleanse);
88 OPENSSL_free(qss);
89}
90
91int 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{
97 size_t num_iov_ = 0, src_len = 0, total_len = 0, i;
98 uint64_t max_len;
99 const unsigned char *src = NULL;
100 UINT_SET_ITEM *range = ossl_list_uint_set_head(&qss->new_set);
101
102 if (*num_iov < 2)
103 return 0;
104
105 for (i = 0; i < skip && range != NULL; ++i)
106 range = ossl_list_uint_set_next(range);
107
108 if (range == NULL) {
109 if (i < skip)
110 /* Don't return FIN for infinitely increasing skip */
111 return 0;
112
113 /* No new bytes to send, but we might have a FIN */
114 if (!qss->have_final_size || qss->sent_final_size)
115 return 0;
116
117 hdr->offset = qss->ring_buf.head_offset;
118 hdr->len = 0;
119 hdr->is_fin = 1;
120 *num_iov = 0;
121 return 1;
122 }
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 max_len = range->range.end - range->range.start + 1;
132
133 for (i = 0;; ++i) {
134 if (total_len >= max_len)
135 break;
136
137 if (!ring_buf_get_buf_at(&qss->ring_buf,
138 range->range.start + total_len,
139 &src, &src_len))
140 return 0;
141
142 if (src_len == 0)
143 break;
144
145 assert(i < 2);
146
147 if (total_len + src_len > max_len)
148 src_len = (size_t)(max_len - total_len);
149
150 iov[num_iov_].buf = src;
151 iov[num_iov_].buf_len = src_len;
152
153 total_len += src_len;
154 ++num_iov_;
155 }
156
157 hdr->offset = range->range.start;
158 hdr->len = total_len;
159 hdr->is_fin = qss->have_final_size
160 && hdr->offset + hdr->len == qss->ring_buf.head_offset;
161
162 *num_iov = num_iov_;
163 return 1;
164}
165
166int ossl_quic_sstream_has_pending(QUIC_SSTREAM *qss)
167{
168 OSSL_QUIC_FRAME_STREAM shdr;
169 OSSL_QTX_IOVEC iov[2];
170 size_t num_iov = OSSL_NELEM(iov);
171
172 return ossl_quic_sstream_get_stream_frame(qss, 0, &shdr, iov, &num_iov);
173}
174
175uint64_t ossl_quic_sstream_get_cur_size(QUIC_SSTREAM *qss)
176{
177 return qss->ring_buf.head_offset;
178}
179
180int ossl_quic_sstream_mark_transmitted(QUIC_SSTREAM *qss,
181 uint64_t start,
182 uint64_t end)
183{
184 UINT_RANGE r;
185
186 r.start = start;
187 r.end = end;
188
189 if (!ossl_uint_set_remove(&qss->new_set, &r))
190 return 0;
191
192 return 1;
193}
194
195int ossl_quic_sstream_mark_transmitted_fin(QUIC_SSTREAM *qss,
196 uint64_t final_size)
197{
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 if (!qss->have_final_size || final_size != qss->ring_buf.head_offset)
203 return 0;
204
205 qss->sent_final_size = 1;
206 return 1;
207}
208
209int ossl_quic_sstream_mark_lost(QUIC_SSTREAM *qss,
210 uint64_t start,
211 uint64_t end)
212{
213 UINT_RANGE r;
214 r.start = start;
215 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 if (!ossl_uint_set_insert(&qss->new_set, &r))
222 return 0;
223
224 return 1;
225}
226
227int ossl_quic_sstream_mark_lost_fin(QUIC_SSTREAM *qss)
228{
229 if (qss->acked_final_size)
230 /* Does not make sense to lose a FIN after it has been ACKed */
231 return 0;
232
233 /* FIN was lost, so we need to transmit it again. */
234 qss->sent_final_size = 0;
235 return 1;
236}
237
238int ossl_quic_sstream_mark_acked(QUIC_SSTREAM *qss,
239 uint64_t start,
240 uint64_t end)
241{
242 UINT_RANGE r;
243 r.start = start;
244 r.end = end;
245
246 if (!ossl_uint_set_insert(&qss->acked_set, &r))
247 return 0;
248
249 qss_cull(qss);
250 return 1;
251}
252
253int ossl_quic_sstream_mark_acked_fin(QUIC_SSTREAM *qss)
254{
255 if (!qss->have_final_size)
256 /* Cannot ack final size before we have a final size */
257 return 0;
258
259 qss->acked_final_size = 1;
260 return 1;
261}
262
263void ossl_quic_sstream_fin(QUIC_SSTREAM *qss)
264{
265 if (qss->have_final_size)
266 return;
267
268 qss->have_final_size = 1;
269}
270
271int ossl_quic_sstream_get_final_size(QUIC_SSTREAM *qss, uint64_t *final_size)
272{
273 if (!qss->have_final_size)
274 return 0;
275
276 if (final_size != NULL)
277 *final_size = qss->ring_buf.head_offset;
278
279 return 1;
280}
281
282int ossl_quic_sstream_append(QUIC_SSTREAM *qss,
283 const unsigned char *buf,
284 size_t buf_len,
285 size_t *consumed)
286{
287 size_t l, consumed_ = 0;
288 UINT_RANGE r;
289 struct ring_buf old_ring_buf = qss->ring_buf;
290
291 if (qss->have_final_size) {
292 *consumed = 0;
293 return 0;
294 }
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 while (buf_len > 0) {
308 l = ring_buf_push(&qss->ring_buf, buf, buf_len);
309 if (l == 0)
310 break;
311
312 buf += l;
313 buf_len -= l;
314 consumed_ += l;
315 }
316
317 if (consumed_ > 0) {
318 r.start = old_ring_buf.head_offset;
319 r.end = r.start + consumed_ - 1;
320 assert(r.end + 1 == qss->ring_buf.head_offset);
321 if (!ossl_uint_set_insert(&qss->new_set, &r)) {
322 qss->ring_buf = old_ring_buf;
323 *consumed = 0;
324 return 0;
325 }
326 }
327
328 *consumed = consumed_;
329 return 1;
330}
331
332static void qss_cull(QUIC_SSTREAM *qss)
333{
334 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 if (h != NULL)
353 ring_buf_cpop_range(&qss->ring_buf, h->range.start, h->range.end,
354 qss->cleanse);
355}
356
357int ossl_quic_sstream_set_buffer_size(QUIC_SSTREAM *qss, size_t num_bytes)
358{
359 return ring_buf_resize(&qss->ring_buf, num_bytes, qss->cleanse);
360}
361
362size_t ossl_quic_sstream_get_buffer_size(QUIC_SSTREAM *qss)
363{
364 return qss->ring_buf.alloc;
365}
366
367size_t ossl_quic_sstream_get_buffer_used(QUIC_SSTREAM *qss)
368{
369 return ring_buf_used(&qss->ring_buf);
370}
371
372size_t ossl_quic_sstream_get_buffer_avail(QUIC_SSTREAM *qss)
373{
374 return ring_buf_avail(&qss->ring_buf);
375}
376
377int ossl_quic_sstream_is_totally_acked(QUIC_SSTREAM *qss)
378{
379 UINT_RANGE r;
380 uint64_t cur_size;
381
382 if (qss->have_final_size && !qss->acked_final_size)
383 return 0;
384
385 if (ossl_quic_sstream_get_cur_size(qss) == 0)
386 return 1;
387
388 if (ossl_list_uint_set_num(&qss->acked_set) != 1)
389 return 0;
390
391 r = ossl_list_uint_set_head(&qss->acked_set)->range;
392 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 assert(r.end + 1 <= cur_size);
400 return r.start == 0 && r.end + 1 == cur_size;
401}
402
403void ossl_quic_sstream_adjust_iov(size_t len,
404 OSSL_QTX_IOVEC *iov,
405 size_t num_iov)
406{
407 size_t running = 0, i, iovlen;
408
409 for (i = 0, running = 0; i < num_iov; ++i) {
410 iovlen = iov[i].buf_len;
411
412 if (running >= len)
413 iov[i].buf_len = 0;
414 else if (running + iovlen > len)
415 iov[i].buf_len = len - running;
416
417 running += iovlen;
418 }
419}
420
421void ossl_quic_sstream_set_cleanse(QUIC_SSTREAM *qss, int cleanse)
422{
423 qss->cleanse = cleanse;
424}
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette