]> git.ipfire.org Git - thirdparty/openssl.git/blob - include/internal/quic_demux.h
QUIC DEMUX: Remove obsolete SRT handling code
[thirdparty/openssl.git] / include / internal / quic_demux.h
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 #ifndef OSSL_QUIC_DEMUX_H
11 # define OSSL_QUIC_DEMUX_H
12
13 # include <openssl/ssl.h>
14 # include "internal/quic_types.h"
15 # include "internal/bio_addr.h"
16 # include "internal/time.h"
17 # include "internal/list.h"
18
19 # ifndef OPENSSL_NO_QUIC
20
21 /*
22 * QUIC Demuxer
23 * ============
24 *
25 * The QUIC connection demuxer is the entity responsible for receiving datagrams
26 * from the network via a datagram BIO. It parses the headers of the first
27 * packet in the datagram to determine that packet's DCID and hands off
28 * processing of the entire datagram to a single callback function which can
29 * decide how to handle and route the datagram, for example by looking up
30 * a QRX instance and injecting the URXE into that QRX.
31 *
32 * A QRX will typically be instantiated per QUIC connection and contains the
33 * cryptographic resources needed to decrypt QUIC packets for that connection.
34 * However, it is up to the callback function to handle routing, for example by
35 * consulting a LCIDM instance. Thus the demuxer has no specific knowledge of
36 * any QRX and is not coupled to it. All CID knowledge is also externalised into
37 * a LCIDM or other CID state tracking object, without the DEMUX being coupled
38 * to any particular DCID resolution mechanism.
39 *
40 * URX Queue
41 * ---------
42 *
43 * Since the demuxer must handle the initial reception of datagrams from the OS,
44 * RX queue management for new, unprocessed datagrams is also handled by the
45 * demuxer.
46 *
47 * The demuxer maintains a queue of Unprocessed RX Entries (URXEs), which store
48 * unprocessed (i.e., encrypted, unvalidated) data received from the network.
49 * The URXE queue is designed to allow multiple datagrams to be received in a
50 * single call to BIO_recvmmsg, where supported.
51 *
52 * One URXE is used per received datagram. Each datagram may contain multiple
53 * packets, however, this is not the demuxer's concern. QUIC prohibits different
54 * packets in the same datagram from containing different DCIDs; the demuxer
55 * only considers the DCID of the first packet in a datagram when deciding how
56 * to route a received datagram, and it is the responsibility of the QRX to
57 * enforce this rule. Packets other than the first packet in a datagram are not
58 * examined by the demuxer, and the demuxer does not perform validation of
59 * packet headers other than to the minimum extent necessary to extract the
60 * DCID; further parsing and validation of packet headers is the responsibility
61 * of the QRX.
62 *
63 * Rather than defining an opaque interface, the URXE structure internals
64 * are exposed. Since the demuxer is only exposed to other parts of the QUIC
65 * implementation internals, this poses no problem, and has a number of
66 * advantages:
67 *
68 * - Fields in the URXE can be allocated to support requirements in other
69 * components, like the QRX, which would otherwise have to allocate extra
70 * memory corresponding to each URXE.
71 *
72 * - Other components, like the QRX, can keep the URXE in queues of its own
73 * when it is not being managed by the demuxer.
74 *
75 * URX Queue Structure
76 * -------------------
77 *
78 * The URXE queue is maintained as a simple doubly-linked list. URXE entries are
79 * moved between different lists in their lifecycle (for example, from a free
80 * list to a pending list and vice versa). The buffer into which datagrams are
81 * received immediately follows this URXE header structure and is part of the
82 * same allocation.
83 */
84
85 typedef struct quic_urxe_st QUIC_URXE;
86
87 /* Maximum number of packets we allow to exist in one datagram. */
88 #define QUIC_MAX_PKT_PER_URXE (sizeof(uint64_t) * 8)
89
90 struct quic_urxe_st {
91 OSSL_LIST_MEMBER(urxe, QUIC_URXE);
92
93 /*
94 * The URXE data starts after this structure so we don't need a pointer.
95 * data_len stores the current length (i.e., the length of the received
96 * datagram) and alloc_len stores the allocation length. The URXE will be
97 * reallocated if we need a larger allocation than is available, though this
98 * should not be common as we will have a good idea of worst-case MTUs up
99 * front.
100 */
101 size_t data_len, alloc_len;
102
103 /*
104 * Bitfields per packet. processed indicates the packet has been processed
105 * and must not be processed again, hpr_removed indicates header protection
106 * has already been removed. Used by QRX only; not used by the demuxer.
107 */
108 uint64_t processed, hpr_removed;
109
110 /*
111 * Address of peer we received the datagram from, and the local interface
112 * address we received it on. If local address support is not enabled, local
113 * is zeroed.
114 */
115 BIO_ADDR peer, local;
116
117 /*
118 * Time at which datagram was received (or ossl_time_zero()) if a now
119 * function was not provided).
120 */
121 OSSL_TIME time;
122
123 /*
124 * Used by the QRX to mark whether a datagram has been deferred. Used by the
125 * QRX only; not used by the demuxer.
126 */
127 char deferred;
128
129 /*
130 * Used by the DEMUX to track if a URXE has been handed out. Used primarily
131 * for debugging purposes.
132 */
133 char demux_state;
134 };
135
136 /* Accessors for URXE buffer. */
137 static ossl_unused ossl_inline unsigned char *
138 ossl_quic_urxe_data(const QUIC_URXE *e)
139 {
140 return (unsigned char *)&e[1];
141 }
142
143 static ossl_unused ossl_inline unsigned char *
144 ossl_quic_urxe_data_end(const QUIC_URXE *e)
145 {
146 return ossl_quic_urxe_data(e) + e->data_len;
147 }
148
149 /* List structure tracking a queue of URXEs. */
150 DEFINE_LIST_OF(urxe, QUIC_URXE);
151 typedef OSSL_LIST(urxe) QUIC_URXE_LIST;
152
153 /*
154 * List management helpers. These are used by the demuxer but can also be used
155 * by users of the demuxer to manage URXEs.
156 */
157 void ossl_quic_urxe_remove(QUIC_URXE_LIST *l, QUIC_URXE *e);
158 void ossl_quic_urxe_insert_head(QUIC_URXE_LIST *l, QUIC_URXE *e);
159 void ossl_quic_urxe_insert_tail(QUIC_URXE_LIST *l, QUIC_URXE *e);
160
161 /* Opaque type representing a demuxer. */
162 typedef struct quic_demux_st QUIC_DEMUX;
163
164 /*
165 * Called when a datagram is received for a given connection ID.
166 *
167 * e is a URXE containing the datagram payload. It is permissible for the callee
168 * to mutate this buffer; once the demuxer calls this callback, it will never
169 * read the buffer again.
170 *
171 * If a DCID was identified for the datagram, dcid is non-NULL; otherwise
172 * it is NULL.
173 *
174 * The callee must arrange for ossl_quic_demux_release_urxe or
175 * ossl_quic_demux_reinject_urxe to be called on the URXE at some point in the
176 * future (this need not be before the callback returns).
177 *
178 * At the time the callback is made, the URXE will not be in any queue,
179 * therefore the callee can use the prev and next fields as it wishes.
180 */
181 typedef void (ossl_quic_demux_cb_fn)(QUIC_URXE *e, void *arg,
182 const QUIC_CONN_ID *dcid);
183
184 /*
185 * Creates a new demuxer. The given BIO is used to receive datagrams from the
186 * network using BIO_recvmmsg. short_conn_id_len is the length of destination
187 * connection IDs used in RX'd packets; it must have the same value for all
188 * connections used on a socket. default_urxe_alloc_len is the buffer size to
189 * receive datagrams into; it should be a value large enough to contain any
190 * received datagram according to local MTUs, etc.
191 *
192 * now is an optional function used to determine the time a datagram was
193 * received. now_arg is an opaque argument passed to the function. If now is
194 * NULL, ossl_time_zero() is used as the datagram reception time.
195 */
196 QUIC_DEMUX *ossl_quic_demux_new(BIO *net_bio,
197 size_t short_conn_id_len,
198 OSSL_TIME (*now)(void *arg),
199 void *now_arg);
200
201 /*
202 * Destroy a demuxer. All URXEs must have been released back to the demuxer
203 * before calling this. No-op if demux is NULL.
204 */
205 void ossl_quic_demux_free(QUIC_DEMUX *demux);
206
207 /*
208 * Changes the BIO which the demuxer reads from. This also sets the MTU if the
209 * BIO supports querying the MTU.
210 */
211 void ossl_quic_demux_set_bio(QUIC_DEMUX *demux, BIO *net_bio);
212
213 /*
214 * Changes the MTU in bytes we use to receive datagrams.
215 */
216 int ossl_quic_demux_set_mtu(QUIC_DEMUX *demux, unsigned int mtu);
217
218 /*
219 * Set the default packet handler. This is used for incoming packets which don't
220 * match a registered DCID. This is only needed for servers. If a default packet
221 * handler is not set, a packet which doesn't match a registered DCID is
222 * silently dropped. A default packet handler may be unset by passing NULL.
223 *
224 * The handler is responsible for ensuring that ossl_quic_demux_reinject_urxe or
225 * ossl_quic_demux_release_urxe is called on the passed packet at some point in
226 * the future, which may or may not be before the handler returns.
227 */
228 void ossl_quic_demux_set_default_handler(QUIC_DEMUX *demux,
229 ossl_quic_demux_cb_fn *cb,
230 void *cb_arg);
231
232 /*
233 * Releases a URXE back to the demuxer. No reference must be made to the URXE or
234 * its buffer after calling this function. The URXE must not be in any queue;
235 * that is, its prev and next pointers must be NULL.
236 */
237 void ossl_quic_demux_release_urxe(QUIC_DEMUX *demux,
238 QUIC_URXE *e);
239
240 /*
241 * Reinjects a URXE which was issued to a registered DCID callback or the
242 * default packet handler callback back into the pending queue. This is useful
243 * when a packet has been handled by the default packet handler callback such
244 * that a DCID has now been registered and can be dispatched normally by DCID.
245 * Once this has been called, the caller must not touch the URXE anymore and
246 * must not also call ossl_quic_demux_release_urxe().
247 *
248 * The URXE is reinjected at the head of the queue, so it will be reprocessed
249 * immediately.
250 */
251 void ossl_quic_demux_reinject_urxe(QUIC_DEMUX *demux,
252 QUIC_URXE *e);
253
254 /*
255 * Process any unprocessed RX'd datagrams, by calling registered callbacks by
256 * connection ID, reading more datagrams from the BIO if necessary.
257 *
258 * Returns one of the following values:
259 *
260 * QUIC_DEMUX_PUMP_RES_OK
261 * At least one incoming datagram was processed.
262 *
263 * QUIC_DEMUX_PUMP_RES_TRANSIENT_FAIL
264 * No more incoming datagrams are currently available.
265 * Call again later.
266 *
267 * QUIC_DEMUX_PUMP_RES_PERMANENT_FAIL
268 * Either the network read BIO has failed in a non-transient fashion, or
269 * the QUIC implementation has encountered an internal state, assertion
270 * or allocation error. The caller should tear down the connection
271 * similarly to in the case of a protocol violation.
272 *
273 */
274 #define QUIC_DEMUX_PUMP_RES_OK 1
275 #define QUIC_DEMUX_PUMP_RES_TRANSIENT_FAIL (-1)
276 #define QUIC_DEMUX_PUMP_RES_PERMANENT_FAIL (-2)
277
278 int ossl_quic_demux_pump(QUIC_DEMUX *demux);
279
280 /*
281 * Artificially inject a packet into the demuxer for testing purposes. The
282 * buffer must not exceed the URXE size being used by the demuxer.
283 *
284 * If peer or local are NULL, their respective fields are zeroed in the injected
285 * URXE.
286 *
287 * Returns 1 on success or 0 on failure.
288 */
289 int ossl_quic_demux_inject(QUIC_DEMUX *demux,
290 const unsigned char *buf,
291 size_t buf_len,
292 const BIO_ADDR *peer,
293 const BIO_ADDR *local);
294
295 /*
296 * Returns 1 if there are any pending URXEs.
297 */
298 int ossl_quic_demux_has_pending(const QUIC_DEMUX *demux);
299
300 # endif
301
302 #endif