]>
Commit | Line | Data |
---|---|---|
a73078b7 HL |
1 | /* |
2 | * Copyright 2022 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 | #ifndef OSSL_INTERNAL_QUIC_STREAM_MAP_H | |
11 | # define OSSL_INTERNAL_QUIC_STREAM_MAP_H | |
12 | # pragma once | |
13 | ||
cbe7f586 HL |
14 | # include "internal/e_os.h" |
15 | # include "internal/time.h" | |
16 | # include "internal/quic_types.h" | |
17 | # include "internal/quic_stream.h" | |
18 | # include "internal/quic_fc.h" | |
19 | # include <openssl/lhash.h> | |
20 | ||
21 | # ifndef OPENSSL_NO_QUIC | |
a73078b7 HL |
22 | |
23 | /* | |
24 | * QUIC Stream | |
25 | * =========== | |
26 | * | |
27 | * Logical QUIC stream composing all relevant send and receive components. | |
28 | */ | |
29 | typedef struct quic_stream_st QUIC_STREAM; | |
30 | ||
31 | typedef struct quic_stream_list_node_st QUIC_STREAM_LIST_NODE; | |
32 | ||
33 | struct quic_stream_list_node_st { | |
34 | QUIC_STREAM_LIST_NODE *prev, *next; | |
35 | }; | |
36 | ||
37 | struct quic_stream_st { | |
38 | QUIC_STREAM_LIST_NODE active_node; /* for use by QUIC_STREAM_MAP */ | |
f20fdd16 | 39 | QUIC_STREAM_LIST_NODE accept_node; /* accept queue of remotely-created streams */ |
a73078b7 HL |
40 | |
41 | /* Temporary link used by TXP. */ | |
42 | QUIC_STREAM *txp_next; | |
43 | ||
44 | /* | |
45 | * QUIC Stream ID. Do not assume that this encodes a type as this is a | |
46 | * version-specific property and may change between QUIC versions; instead, | |
47 | * use the type field. | |
48 | */ | |
49 | uint64_t id; | |
50 | ||
51 | /* | |
52 | * Application Error Code (AEC) used for STOP_SENDING frame. | |
53 | * This is only valid if stop_sending is 1. | |
54 | */ | |
55 | uint64_t stop_sending_aec; | |
56 | ||
57 | /* | |
58 | * Application Error Code (AEC) used for RESET_STREAM frame. | |
59 | * This is only valid if reset_stream is 1. | |
60 | */ | |
61 | uint64_t reset_stream_aec; | |
62 | ||
b6fc2294 HL |
63 | /* |
64 | * Application Error Code (AEC) for incoming STOP_SENDING frame. | |
65 | * This is only valid if peer_stop_sending is 1. | |
66 | */ | |
67 | uint64_t peer_stop_sending_aec; | |
68 | ||
69 | /* | |
70 | * Application Error Code (AEC) for incoming RESET_STREAM frame. | |
71 | * This is only valid if peer_reset_stream is 1. | |
72 | */ | |
73 | uint64_t peer_reset_stream_aec; | |
74 | ||
a73078b7 HL |
75 | /* Temporary value used by TXP. */ |
76 | uint64_t txp_txfc_new_credit_consumed; | |
77 | ||
78 | QUIC_SSTREAM *sstream; /* NULL if RX-only */ | |
56a1a0ad | 79 | QUIC_RSTREAM *rstream; /* NULL if TX only */ |
a73078b7 HL |
80 | QUIC_TXFC txfc; /* NULL if RX-only */ |
81 | QUIC_RXFC rxfc; /* NULL if TX-only */ | |
82 | unsigned int type : 8; /* QUIC_STREAM_INITIATOR_*, QUIC_STREAM_DIR_* */ | |
83 | unsigned int active : 1; | |
84 | ||
85 | /* | |
cbe7f586 HL |
86 | * Has STOP_SENDING been requested (by us)? Note that this is not the same |
87 | * as want_stop_sending below, as a STOP_SENDING frame may already have been | |
a73078b7 HL |
88 | * sent and fully acknowledged. |
89 | */ | |
90 | unsigned int stop_sending : 1; | |
91 | ||
92 | /* | |
cbe7f586 HL |
93 | * Has RESET_STREAM been requested (by us)? Works identically to |
94 | * STOP_SENDING for transmission purposes. | |
a73078b7 HL |
95 | */ |
96 | unsigned int reset_stream : 1; | |
97 | ||
cbe7f586 HL |
98 | /* Has our peer sent a STOP_SENDING frame? */ |
99 | unsigned int peer_stop_sending : 1; | |
100 | /* Has our peer sent a RESET_STREAM frame? */ | |
101 | unsigned int peer_reset_stream : 1; | |
102 | ||
a73078b7 HL |
103 | /* Temporary flags used by TXP. */ |
104 | unsigned int txp_sent_fc : 1; | |
105 | unsigned int txp_sent_stop_sending : 1; | |
106 | unsigned int txp_sent_reset_stream : 1; | |
107 | unsigned int txp_drained : 1; | |
108 | unsigned int txp_blocked : 1; | |
109 | ||
110 | /* Frame regeneration flags. */ | |
111 | unsigned int want_max_stream_data : 1; /* used for regen only */ | |
112 | unsigned int want_stop_sending : 1; /* used for gen or regen */ | |
113 | unsigned int want_reset_stream : 1; /* used for gen or regen */ | |
cbe7f586 HL |
114 | |
115 | /* A FIN has been retired from the rstream buffer. */ | |
116 | unsigned int recv_fin_retired : 1; | |
2dbc39de HL |
117 | |
118 | /* The stream's XSO has been deleted. Pending GC. */ | |
119 | unsigned int deleted : 1; | |
a73078b7 HL |
120 | }; |
121 | ||
a73078b7 HL |
122 | /* |
123 | * QUIC Stream Map | |
124 | * =============== | |
125 | * | |
126 | * The QUIC stream map: | |
127 | * | |
128 | * - maps stream IDs to QUIC_STREAM objects; | |
129 | * - tracks which streams are 'active' (currently have data for transmission); | |
130 | * - allows iteration over the active streams only. | |
131 | * | |
132 | */ | |
133 | typedef struct quic_stream_map_st { | |
134 | LHASH_OF(QUIC_STREAM) *map; | |
135 | QUIC_STREAM_LIST_NODE active_list; | |
f20fdd16 HL |
136 | QUIC_STREAM_LIST_NODE accept_list; |
137 | size_t rr_stepping, rr_counter, num_accept; | |
a73078b7 | 138 | QUIC_STREAM *rr_cur; |
cbe7f586 HL |
139 | uint64_t (*get_stream_limit_cb)(int uni, void *arg); |
140 | void *get_stream_limit_cb_arg; | |
90cecc40 HL |
141 | QUIC_RXFC *max_streams_bidi_rxfc; |
142 | QUIC_RXFC *max_streams_uni_rxfc; | |
a73078b7 HL |
143 | } QUIC_STREAM_MAP; |
144 | ||
cbe7f586 HL |
145 | /* |
146 | * get_stream_limit is a callback which is called to retrieve the current stream | |
147 | * limit for streams created by us. This mechanism is not used for | |
148 | * peer-initiated streams. If a stream's stream ID is x, a stream is allowed if | |
149 | * (x >> 2) < returned limit value; i.e., the returned value is exclusive. | |
150 | * | |
151 | * If uni is 1, get the limit for locally-initiated unidirectional streams, else | |
152 | * get the limit for locally-initiated bidirectional streams. | |
153 | * | |
154 | * If the callback is NULL, stream limiting is not applied. | |
155 | * Stream limiting is used to determine if frames can currently be produced for | |
156 | * a stream. | |
157 | */ | |
158 | int ossl_quic_stream_map_init(QUIC_STREAM_MAP *qsm, | |
159 | uint64_t (*get_stream_limit_cb)(int uni, void *arg), | |
90cecc40 HL |
160 | void *get_stream_limit_cb_arg, |
161 | QUIC_RXFC *max_streams_bidi_rxfc, | |
162 | QUIC_RXFC *max_streams_uni_rxfc); | |
a73078b7 HL |
163 | |
164 | /* | |
165 | * Any streams still in the map will be released as though | |
166 | * ossl_quic_stream_map_release was called on them. | |
167 | */ | |
168 | void ossl_quic_stream_map_cleanup(QUIC_STREAM_MAP *qsm); | |
169 | ||
170 | #define QUIC_STREAM_INITIATOR_CLIENT 0 | |
171 | #define QUIC_STREAM_INITIATOR_SERVER 1 | |
172 | #define QUIC_STREAM_INITIATOR_MASK 1 | |
173 | ||
174 | #define QUIC_STREAM_DIR_BIDI 0 | |
175 | #define QUIC_STREAM_DIR_UNI 2 | |
176 | #define QUIC_STREAM_DIR_MASK 2 | |
177 | ||
26ad16ea HL |
178 | static ossl_inline ossl_unused int ossl_quic_stream_is_server_init(QUIC_STREAM *s) |
179 | { | |
180 | return (s->type & QUIC_STREAM_INITIATOR_MASK) == QUIC_STREAM_INITIATOR_SERVER; | |
181 | } | |
182 | ||
183 | static ossl_inline ossl_unused int ossl_quic_stream_is_bidi(QUIC_STREAM *s) | |
184 | { | |
185 | return (s->type & QUIC_STREAM_DIR_MASK) == QUIC_STREAM_DIR_BIDI; | |
186 | } | |
187 | ||
a73078b7 HL |
188 | /* |
189 | * Allocate a new stream. type is a combination of one QUIC_STREAM_INITIATOR_* | |
190 | * value and one QUIC_STREAM_DIR_* value. Note that clients can e.g. allocate | |
191 | * server-initiated streams as they will need to allocate a QUIC_STREAM | |
192 | * structure to track any stream created by the server, etc. | |
193 | * | |
194 | * stream_id must be a valid value. Returns NULL if a stream already exists | |
195 | * with the given ID. | |
196 | */ | |
197 | QUIC_STREAM *ossl_quic_stream_map_alloc(QUIC_STREAM_MAP *qsm, | |
198 | uint64_t stream_id, | |
199 | int type); | |
200 | ||
201 | /* | |
202 | * Releases a stream object. Note that this must only be done once the teardown | |
203 | * process is entirely complete and the object will never be referenced again. | |
204 | */ | |
205 | void ossl_quic_stream_map_release(QUIC_STREAM_MAP *qsm, QUIC_STREAM *stream); | |
206 | ||
207 | /* | |
208 | * Calls visit_cb() for each stream in the map. visit_cb_arg is an opaque | |
209 | * argument which is passed through. | |
210 | */ | |
211 | void ossl_quic_stream_map_visit(QUIC_STREAM_MAP *qsm, | |
212 | void (*visit_cb)(QUIC_STREAM *stream, void *arg), | |
213 | void *visit_cb_arg); | |
214 | ||
215 | /* | |
216 | * Retrieves a stream by stream ID. Returns NULL if it does not exist. | |
217 | */ | |
218 | QUIC_STREAM *ossl_quic_stream_map_get_by_id(QUIC_STREAM_MAP *qsm, | |
219 | uint64_t stream_id); | |
220 | ||
221 | /* | |
222 | * Marks the given stream as active or inactive based on its state. Idempotent. | |
223 | * | |
224 | * When a stream is marked active, it becomes available in the iteration list, | |
225 | * and when a stream is marked inactive, it no longer appears in the iteration | |
226 | * list. | |
227 | * | |
228 | * Calling this function invalidates any iterator currently pointing at the | |
229 | * given stream object, but iterators not currently pointing at the given stream | |
230 | * object are not invalidated. | |
231 | */ | |
232 | void ossl_quic_stream_map_update_state(QUIC_STREAM_MAP *qsm, QUIC_STREAM *s); | |
233 | ||
234 | /* | |
235 | * Sets the RR stepping value, n. The RR rotation will be advanced every n | |
236 | * packets. The default value is 1. | |
237 | */ | |
238 | void ossl_quic_stream_map_set_rr_stepping(QUIC_STREAM_MAP *qsm, size_t stepping); | |
239 | ||
b89c81e4 HL |
240 | /* |
241 | * Resets the sending part of a stream. | |
e8b9f632 HL |
242 | * |
243 | * Returns 1 if the sending part of a stream was not already reset. | |
244 | * Returns 0 otherwise, which need not be considered an error. | |
245 | */ | |
246 | int ossl_quic_stream_map_reset_stream_send_part(QUIC_STREAM_MAP *qsm, | |
247 | QUIC_STREAM *qs, | |
248 | uint64_t aec); | |
249 | ||
250 | /* | |
251 | * Marks the receiving part of a stream for STOP_SENDING. | |
252 | * | |
253 | * Returns 1 if the receiving part of a stream was not already marked for | |
254 | * STOP_SENDING. | |
255 | * Returns 0 otherwise, which need not be considered an error. | |
b89c81e4 | 256 | */ |
e8b9f632 HL |
257 | int ossl_quic_stream_map_stop_sending_recv_part(QUIC_STREAM_MAP *qsm, |
258 | QUIC_STREAM *qs, | |
259 | uint64_t aec); | |
b89c81e4 | 260 | |
f20fdd16 HL |
261 | /* |
262 | * Adds a stream to the accept queue. | |
263 | */ | |
264 | void ossl_quic_stream_map_push_accept_queue(QUIC_STREAM_MAP *qsm, | |
265 | QUIC_STREAM *s); | |
266 | ||
267 | /* | |
268 | * Returns the next item to be popped from the accept queue, or NULL if it is | |
269 | * empty. | |
270 | */ | |
271 | QUIC_STREAM *ossl_quic_stream_map_peek_accept_queue(QUIC_STREAM_MAP *qsm); | |
272 | ||
273 | /* | |
90cecc40 HL |
274 | * Removes a stream from the accept queue. rtt is the estimated connection RTT. |
275 | * The stream is retired for the purposes of MAX_STREAMS RXFC. | |
f20fdd16 HL |
276 | * |
277 | * Precondition: s is in the accept queue. | |
278 | */ | |
279 | void ossl_quic_stream_map_remove_from_accept_queue(QUIC_STREAM_MAP *qsm, | |
90cecc40 HL |
280 | QUIC_STREAM *s, |
281 | OSSL_TIME rtt); | |
f20fdd16 HL |
282 | |
283 | /* Returns the length of the accept queue. */ | |
284 | size_t ossl_quic_stream_map_get_accept_queue_len(QUIC_STREAM_MAP *qsm); | |
285 | ||
a73078b7 HL |
286 | /* |
287 | * QUIC Stream Iterator | |
288 | * ==================== | |
289 | * | |
290 | * Allows the current set of active streams to be walked using a RR-based | |
291 | * algorithm. Each time ossl_quic_stream_iter_init is called, the RR algorithm | |
292 | * is stepped. The RR algorithm rotates the iteration order such that the next | |
293 | * active stream is returned first after n calls to ossl_quic_stream_iter_init, | |
294 | * where n is the stepping value configured via | |
295 | * ossl_quic_stream_map_set_rr_stepping. | |
296 | * | |
297 | * Suppose there are three active streams and the configured stepping is n: | |
298 | * | |
299 | * Iteration 0n: [Stream 1] [Stream 2] [Stream 3] | |
300 | * Iteration 1n: [Stream 2] [Stream 3] [Stream 1] | |
301 | * Iteration 2n: [Stream 3] [Stream 1] [Stream 2] | |
302 | * | |
303 | */ | |
304 | typedef struct quic_stream_iter_st { | |
305 | QUIC_STREAM_MAP *qsm; | |
306 | QUIC_STREAM *first_stream, *stream; | |
307 | } QUIC_STREAM_ITER; | |
308 | ||
309 | /* | |
310 | * Initialise an iterator, advancing the RR algorithm as necessary (if | |
311 | * advance_rr is 1). After calling this, it->stream will be the first stream in | |
312 | * the iteration sequence, or NULL if there are no active streams. | |
313 | */ | |
314 | void ossl_quic_stream_iter_init(QUIC_STREAM_ITER *it, QUIC_STREAM_MAP *qsm, | |
315 | int advance_rr); | |
316 | ||
317 | /* | |
318 | * Advances to next stream in iteration sequence. You do not need to call this | |
319 | * immediately after calling ossl_quic_stream_iter_init(). If the end of the | |
320 | * list is reached, it->stream will be NULL after calling this. | |
321 | */ | |
322 | void ossl_quic_stream_iter_next(QUIC_STREAM_ITER *it); | |
323 | ||
cbe7f586 HL |
324 | # endif |
325 | ||
a73078b7 | 326 | #endif |