ascii-chat
Binary v0.15.83-53-gb711d8720
Library lib/v0.3.2-701-gb711d8720
Video chat in your terminal
Loading...
Searching...
No Matches
udp.c
Go to the documentation of this file.
1#include "udp.h"
2
3#include <ascii-chat/common.h>
5#include <ngtcp2/ngtcp2_crypto.h>
6#include <sodium.h>
7#include <string.h>
8
9#define QUIC_UDP_CID_LENGTH 16
10#define QUIC_UDP_PACKET_CAPACITY 1452
11#define QUIC_UDP_MAX_CONNECTIONS 64
12#define QUIC_UDP_READ_BATCH 128
13#define QUIC_UDP_WRITE_BATCH 16
14#define QUIC_RETRY_SECRET_LENGTH 32
15#define QUIC_RETRY_TOKEN_LIFETIME (10ULL * 1000000000ULL)
16
32
44
45static bool valid_sockaddr(const struct sockaddr *address, socklen_t length) {
46 if (!address || (size_t)length < sizeof(struct sockaddr) || (size_t)length > sizeof(ngtcp2_sockaddr_union))
47 return false;
48 if (address->sa_family == AF_INET && (size_t)length == sizeof(struct sockaddr_in))
49 return ((const struct sockaddr_in *)address)->sin_addr.s_addr != 0;
50 if (address->sa_family == AF_INET6 && (size_t)length == sizeof(struct sockaddr_in6)) {
51 static const uint8_t zero[16] = {0};
52 return memcmp(&((const struct sockaddr_in6 *)address)->sin6_addr, zero, sizeof(zero)) != 0;
53 }
54 return false;
55}
56
57static ngtcp2_path make_path(const quic_udp_endpoint_t *endpoint, const struct sockaddr *remote,
58 socklen_t remote_length) {
59 ngtcp2_path path = {0};
60 path.local.addr = (struct sockaddr *)&endpoint->local;
61 path.local.addrlen = endpoint->local_length;
62 path.remote.addr = (struct sockaddr *)remote;
63 path.remote.addrlen = remote_length;
64 return path;
65}
66
67asciichat_error_t quic_udp_endpoint_create(const struct sockaddr *address, socklen_t length, quic_tls_t *server_tls,
68 quic_udp_accept_fn accept, void *context, quic_udp_endpoint_t **out) {
69 if (!out)
70 return SET_ERRNO(ERROR_INVALID_PARAM, "Missing QUIC UDP endpoint output");
71 *out = NULL;
72 if (!valid_sockaddr(address, length) || (!!server_tls != !!accept) || (server_tls && !server_tls->server))
73 return SET_ERRNO(ERROR_INVALID_PARAM, "QUIC UDP requires a concrete bind address and valid listener");
74 quic_udp_endpoint_t *endpoint = SAFE_CALLOC(1, sizeof(*endpoint), quic_udp_endpoint_t *);
75 if (!endpoint)
76 return SET_ERRNO(ERROR_MEMORY, "Cannot allocate QUIC UDP endpoint");
77 endpoint->socket = socket_create("quic_udp", address->sa_family, SOCK_DGRAM, 0);
78 if (endpoint->socket == INVALID_SOCKET_VALUE || socket_bind(endpoint->socket, address, length) != 0 ||
79 socket_set_nonblocking(endpoint->socket, true) != 0) {
80 if (endpoint->socket != INVALID_SOCKET_VALUE)
81 socket_close(endpoint->socket);
82 SAFE_FREE(endpoint);
83 return SET_ERRNO(ERROR_NETWORK, "Cannot bind QUIC UDP endpoint");
84 }
85 endpoint->local_length = sizeof(endpoint->local);
86 if (socket_getsockname(endpoint->socket, (struct sockaddr *)&endpoint->local, &endpoint->local_length) != 0) {
87 socket_close(endpoint->socket);
88 SAFE_FREE(endpoint);
89 return SET_ERRNO(ERROR_NETWORK, "Cannot obtain QUIC UDP endpoint address");
90 }
91 endpoint->server_tls = server_tls;
92 if (server_tls) {
93 if (sodium_init() < 0) {
94 socket_close(endpoint->socket);
95 SAFE_FREE(endpoint);
96 return SET_ERRNO(ERROR_CRYPTO, "Cannot initialize QUIC Retry token secret");
97 }
98 randombytes_buf(endpoint->retry_secret, sizeof(endpoint->retry_secret));
99 }
100 endpoint->accept = accept;
101 endpoint->context = context;
102 *out = endpoint;
103 return ASCIICHAT_OK;
104}
105
106asciichat_error_t quic_udp_endpoint_address(const quic_udp_endpoint_t *endpoint, struct sockaddr_storage *address,
107 socklen_t *length) {
108 if (!endpoint || !address || !length)
109 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid QUIC UDP address output");
110 *address = endpoint->local;
111 *length = endpoint->local_length;
112 return ASCIICHAT_OK;
113}
114
115static udp_peer_t *new_peer(quic_udp_endpoint_t *endpoint) {
116 if (endpoint->count >= QUIC_UDP_MAX_CONNECTIONS)
117 return NULL;
118 return SAFE_CALLOC(1, sizeof(udp_peer_t), udp_peer_t *);
119}
120
121static void add_peer(quic_udp_endpoint_t *endpoint, udp_peer_t *peer) {
122 peer->next = endpoint->peers;
123 endpoint->peers = peer;
124 ++endpoint->count;
125}
126
127static void send_retry(quic_udp_endpoint_t *endpoint, const ngtcp2_pkt_hd *initial, const struct sockaddr *remote,
128 socklen_t remote_length, uint64_t now) {
129 ngtcp2_cid retry_scid = {.datalen = QUIC_UDP_CID_LENGTH};
130 randombytes_buf(retry_scid.data, retry_scid.datalen);
131 uint8_t token[NGTCP2_CRYPTO_MAX_RETRY_TOKENLEN2];
132 ngtcp2_ssize token_length =
133 ngtcp2_crypto_generate_retry_token2(token, endpoint->retry_secret, sizeof(endpoint->retry_secret),
134 initial->version, remote, remote_length, &retry_scid, &initial->dcid, now);
135 if (token_length < 0)
136 return;
137 uint8_t packet[1200];
138 ngtcp2_ssize length = ngtcp2_crypto_write_retry(packet, sizeof(packet), initial->version, &initial->scid, &retry_scid,
139 &initial->dcid, token, (size_t)token_length);
140 if (length > 0)
141 (void)socket_sendto(endpoint->socket, packet, (size_t)length, 0, remote, remote_length);
142}
143
144asciichat_error_t quic_udp_connect(quic_udp_endpoint_t *endpoint, quic_tls_t *client_tls, const char *server_name,
145 const struct sockaddr *remote, socklen_t remote_length, uint64_t now_ns,
147 if (!out)
148 return SET_ERRNO(ERROR_INVALID_PARAM, "Missing QUIC UDP connection output");
149 *out = NULL;
150 if (!endpoint || !client_tls || client_tls->server || !valid_sockaddr(remote, remote_length) ||
151 remote->sa_family != ((struct sockaddr *)&endpoint->local)->sa_family)
152 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid QUIC UDP connection configuration");
153 udp_peer_t *peer = new_peer(endpoint);
154 if (!peer)
155 return SET_ERRNO(ERROR_BUFFER_FULL, "QUIC UDP connection limit reached or allocation failed");
156 ngtcp2_path path = make_path(endpoint, remote, remote_length);
157 asciichat_error_t result = quic_connection_client_create(client_tls, server_name, &path, now_ns, &peer->connection);
158 if (result != ASCIICHAT_OK) {
159 SAFE_FREE(peer);
160 return result;
161 }
162 add_peer(endpoint, peer);
163 *out = peer->connection;
164 return ASCIICHAT_OK;
165}
166
167static asciichat_error_t receive_one(quic_udp_endpoint_t *endpoint, const uint8_t *data, size_t length,
168 const struct sockaddr *remote, socklen_t remote_length, uint64_t now,
169 quic_connection_t **failed) {
170 ngtcp2_version_cid header;
171 if (ngtcp2_pkt_decode_version_cid(&header, data, length, QUIC_UDP_CID_LENGTH) != 0)
172 return ASCIICHAT_OK;
173 udp_peer_t *peer = endpoint->peers;
174 while (peer) {
175 bool matches = false;
176 asciichat_error_t result = quic_connection_matches_cid(peer->connection, header.dcid, header.dcidlen, &matches);
177 if (result != ASCIICHAT_OK)
178 return result;
179 if (matches)
180 break;
181 peer = peer->next;
182 }
183 ngtcp2_path path = make_path(endpoint, remote, remote_length);
184 if (!peer) {
185 if (!endpoint->server_tls)
186 return ASCIICHAT_OK;
187 ngtcp2_pkt_hd initial;
188 if (length < NGTCP2_MAX_UDP_PAYLOAD_SIZE || ngtcp2_accept(&initial, data, length) != 0 ||
189 initial.version != NGTCP2_PROTO_VER_V1)
190 return ASCIICHAT_OK;
191 if (!initial.tokenlen) {
192 send_retry(endpoint, &initial, remote, remote_length, now);
193 return ASCIICHAT_OK;
194 }
195 ngtcp2_cid original_dcid;
196 if (ngtcp2_crypto_verify_retry_token2(&original_dcid, initial.token, initial.tokenlen, endpoint->retry_secret,
197 sizeof(endpoint->retry_secret), initial.version, remote, remote_length,
198 &initial.dcid, QUIC_RETRY_TOKEN_LIFETIME, now) != 0)
199 return ASCIICHAT_OK;
200 peer = new_peer(endpoint);
201 if (!peer)
202 return ASCIICHAT_OK;
203 asciichat_error_t result = quic_connection_server_create_validated(endpoint->server_tls, &path, data, length,
204 &original_dcid, now, &peer->connection);
205 if (result == ASCIICHAT_OK)
206 result = endpoint->accept(peer->connection, endpoint->context);
207 if (result != ASCIICHAT_OK) {
209 SAFE_FREE(peer);
210 if (result == ERROR_BUFFER_FULL)
211 return ASCIICHAT_OK;
212 return result;
213 }
214 add_peer(endpoint, peer);
215 }
216 asciichat_error_t result = quic_connection_receive(peer->connection, &path, data, length, now);
217 if (result != ASCIICHAT_OK)
218 *failed = peer->connection;
219 return result;
220}
221
223 if (!endpoint || !failed)
224 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid QUIC UDP pump arguments");
225 *failed = NULL;
226 for (unsigned i = 0; i < QUIC_UDP_READ_BATCH; ++i) {
227 uint8_t data[65536];
228 struct sockaddr_storage remote = {0};
229 socklen_t remote_length = sizeof(remote);
230 ssize_t received =
231 socket_recvfrom(endpoint->socket, data, sizeof(data), 0, (struct sockaddr *)&remote, &remote_length);
232 if (received < 0) {
233 int error = socket_get_last_error();
234 if (socket_is_would_block_error(error))
235 break;
236 /* An ICMP error for an earlier datagram does not identify a QUIC
237 * connection and must not terminate a shared listener. */
238 if (socket_is_connection_reset_error(error))
239 continue;
240 return SET_ERRNO(ERROR_NETWORK, "QUIC UDP receive failed");
241 }
242 if (!received || !valid_sockaddr((struct sockaddr *)&remote, remote_length))
243 continue;
244 asciichat_error_t result =
245 receive_one(endpoint, data, (size_t)received, (struct sockaddr *)&remote, remote_length, now, failed);
246 if (result != ASCIICHAT_OK)
247 return result;
248 }
249 for (udp_peer_t *peer = endpoint->peers; peer; peer = peer->next) {
250 if (quic_connection_expiry(peer->connection) <= now) {
252 if (result != ASCIICHAT_OK) {
253 *failed = peer->connection;
254 return result;
255 }
256 }
257 for (unsigned i = 0; i < QUIC_UDP_WRITE_BATCH; ++i) {
258 if (!peer->pending_length) {
260 sizeof(peer->pending), &peer->pending_length, now);
261 if (result != ASCIICHAT_OK) {
262 *failed = peer->connection;
263 return result;
264 }
265 if (!peer->pending_length)
266 break;
267 }
268 ngtcp2_addr *remote = &peer->pending_path.path.remote;
269 ssize_t sent = socket_sendto(endpoint->socket, peer->pending, peer->pending_length, 0, remote->addr,
270 (socklen_t)remote->addrlen);
271 if (sent < 0 && socket_is_would_block_error(socket_get_last_error()))
272 break;
273 if (sent < 0 || (size_t)sent != peer->pending_length)
274 return SET_ERRNO(ERROR_NETWORK, "QUIC UDP send failed");
275 peer->pending_length = 0;
277 if (result != ASCIICHAT_OK) {
278 *failed = peer->connection;
279 return result;
280 }
281 }
282 }
283 return ASCIICHAT_OK;
284}
285
287 uint64_t maximum_wait_ns, uint64_t *wait_ns, bool *want_write) {
288 if (!endpoint || !wait_ns || !want_write || now_ns == UINT64_MAX)
289 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid QUIC UDP wait parameters");
290 *wait_ns = maximum_wait_ns;
291 *want_write = false;
292 for (const udp_peer_t *peer = endpoint->peers; peer; peer = peer->next) {
294 if (expiry <= now_ns)
295 *wait_ns = 0;
296 else if (expiry != UINT64_MAX && expiry - now_ns < *wait_ns)
297 *wait_ns = expiry - now_ns;
298 if (peer->pending_length)
299 *want_write = true;
300 }
301 return ASCIICHAT_OK;
302}
303
304asciichat_error_t quic_udp_wait(quic_udp_endpoint_t *endpoint, uint64_t wait_ns, bool want_write, bool *ready) {
305 if (!endpoint || !ready)
306 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid QUIC UDP wait");
307 *ready = false;
308 struct pollfd fd = {.fd = endpoint->socket, .events = (short)(POLLIN | (want_write ? POLLOUT : 0))};
309 int64_t timeout = wait_ns > INT64_MAX ? INT64_MAX : (int64_t)wait_ns;
310 int result = socket_poll(&fd, 1, timeout);
311 if (result < 0)
312 return SET_ERRNO(ERROR_NETWORK, "QUIC UDP poll failed");
313 if (result > 0 && (fd.revents & (POLLERR | POLLNVAL)))
314 return SET_ERRNO(ERROR_NETWORK, "QUIC UDP socket poll reported an error");
315 *ready = result > 0;
316 return ASCIICHAT_OK;
317}
318
320 if (!endpoint)
321 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid QUIC UDP wake");
322 const uint8_t wake = 0;
323 ssize_t sent = socket_sendto(endpoint->socket, &wake, sizeof(wake), 0, (struct sockaddr *)&endpoint->local,
324 endpoint->local_length);
325 if (sent != (ssize_t)sizeof(wake))
326 return SET_ERRNO(ERROR_NETWORK, "Cannot wake QUIC UDP endpoint");
327 return ASCIICHAT_OK;
328}
329
330bool quic_udp_contains(const quic_udp_endpoint_t *endpoint, const quic_connection_t *connection) {
331 if (!endpoint || !connection)
332 return false;
333 for (const udp_peer_t *peer = endpoint->peers; peer; peer = peer->next)
334 if (peer->connection == connection)
335 return true;
336 return false;
337}
338
340 if (!quic_udp_contains(endpoint, connection))
341 return SET_ERRNO(ERROR_INVALID_PARAM, "QUIC UDP connection is not owned by endpoint");
343 ngtcp2_path_storage path;
344 size_t length = 0;
345 asciichat_error_t result =
346 quic_connection_write_close(connection, &path, packet, sizeof(packet), &length, time_get_ns());
347 if (result != ASCIICHAT_OK || !length)
348 return result;
349 ngtcp2_addr *remote = &path.path.remote;
350 ssize_t sent = socket_sendto(endpoint->socket, packet, length, 0, remote->addr, (socklen_t)remote->addrlen);
351 if (sent < 0 || (size_t)sent != length)
352 return SET_ERRNO(ERROR_NETWORK, "Cannot send QUIC close packet");
353 return ASCIICHAT_OK;
354}
355
357 if (!endpoint || !connection)
358 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid QUIC UDP removal");
359 udp_peer_t **next = &endpoint->peers;
360 while (*next && (*next)->connection != connection)
361 next = &(*next)->next;
362 if (!*next)
363 return SET_ERRNO(ERROR_INVALID_PARAM, "QUIC UDP connection is not owned by endpoint");
364 udp_peer_t *peer = *next;
365 *next = peer->next;
366 --endpoint->count;
368 SAFE_FREE(peer);
369 return ASCIICHAT_OK;
370}
371
373 if (!endpoint || !*endpoint)
374 return;
375 while ((*endpoint)->peers)
376 (void)quic_udp_remove(*endpoint, (*endpoint)->peers->connection);
377 socket_close((*endpoint)->socket);
378 sodium_memzero((*endpoint)->retry_secret, sizeof((*endpoint)->retry_secret));
379 SAFE_FREE(*endpoint);
380 *endpoint = NULL;
381}
382
383asciichat_error_t quic_udp_migrate(quic_udp_endpoint_t *endpoint, const struct sockaddr *address, socklen_t length,
384 uint64_t now_ns) {
385 if (!endpoint || endpoint->server_tls || endpoint->count != 1 || !valid_sockaddr(address, length))
386 return SET_ERRNO(ERROR_INVALID_PARAM, "QUIC migration requires a single client connection and concrete address");
387 if (endpoint->peers->pending_length)
388 return SET_ERRNO(ERROR_BUFFER_FULL, "Flush the pending UDP packet before migrating");
389 quic_udp_endpoint_t *candidate = NULL;
390 asciichat_error_t result = quic_udp_endpoint_create(address, length, NULL, NULL, NULL, &candidate);
391 if (result != ASCIICHAT_OK)
392 return result;
393 result = quic_connection_migrate(endpoint->peers->connection, (struct sockaddr *)&candidate->local,
394 candidate->local_length, now_ns);
395 if (result == ASCIICHAT_OK) {
396 socket_t old_socket = endpoint->socket;
397 endpoint->socket = candidate->socket;
398 candidate->socket = old_socket;
399 endpoint->local = candidate->local;
400 endpoint->local_length = candidate->local_length;
401 }
402 quic_udp_endpoint_destroy(&candidate);
403 return result;
404}
#define SET_ERRNO(code,...)
⚙️ Common definitions, error codes, macros, and types shared throughout the application
#define SAFE_FREE(ptr)
Definition common.h:377
#define SAFE_CALLOC(count, size, cast)
Definition common.h:275
unsigned long long uint64_t
Definition common.h:63
unsigned char uint8_t
Definition common.h:60
asciichat_error_t
Error and exit codes - unified status values (0-255).
Definition error_codes.h:44
@ ERROR_NETWORK
Definition error_codes.h:72
@ ERROR_BUFFER_FULL
@ ERROR_MEMORY
Definition error_codes.h:51
@ ASCIICHAT_OK
Definition error_codes.h:46
@ ERROR_CRYPTO
Definition error_codes.h:93
@ ERROR_INVALID_PARAM
int socket_t
asciichat_error_t quic_connection_client_create(quic_tls_t *tls, const char *server_name, const ngtcp2_path *path, uint64_t now_ns, quic_connection_t **out)
void quic_connection_destroy(quic_connection_t **connection)
asciichat_error_t quic_connection_handle_expiry(quic_connection_t *connection, uint64_t now_ns)
asciichat_error_t quic_connection_write_close(quic_connection_t *connection, ngtcp2_path_storage *path, void *packet, size_t capacity, size_t *length, uint64_t now_ns)
asciichat_error_t quic_connection_matches_cid(const quic_connection_t *connection, const uint8_t *cid, size_t length, bool *matches)
asciichat_error_t quic_connection_write(quic_connection_t *connection, ngtcp2_path_storage *path, void *packet, size_t capacity, size_t *length, uint64_t now_ns)
asciichat_error_t quic_connection_receive(quic_connection_t *connection, const ngtcp2_path *path, const void *packet, size_t length, uint64_t now_ns)
asciichat_error_t quic_connection_packet_sent(quic_connection_t *connection, uint64_t now_ns)
uint64_t quic_connection_expiry(const quic_connection_t *connection)
asciichat_error_t quic_connection_migrate(quic_connection_t *connection, const struct sockaddr *local, socklen_t length, uint64_t now_ns)
asciichat_error_t quic_connection_server_create_validated(quic_tls_t *tls, const ngtcp2_path *path, const void *initial, size_t initial_length, const ngtcp2_cid *original_dcid, uint64_t now_ns, quic_connection_t **out)
struct quic_connection quic_connection_t
static bool size_t gotel_query_t * out
Definition queries.h:8
🔤 String Manipulation and Shell Escaping Utilities
bool server
Definition tls.h:15
quic_tls_t * server_tls
Definition udp.c:37
struct sockaddr_storage local
Definition udp.c:35
udp_peer_t * peers
Definition udp.c:41
uint8_t retry_secret[32]
Definition udp.c:38
socklen_t local_length
Definition udp.c:36
size_t count
Definition udp.c:42
void * context
Definition udp.c:40
socket_t socket
Definition udp.c:34
quic_udp_accept_fn accept
Definition udp.c:39
acip quic udp endpoint is intentionally a small, concrete record. Fields such as socket,...
Definition udp.c:25
quic_connection_t * connection
Definition udp.c:27
size_t pending_length
Definition udp.c:30
ngtcp2_path_storage pending_path
Definition udp.c:28
struct udp_peer * next
Definition udp.c:26
uint8_t pending[1452]
Definition udp.c:29
⏱️ High-precision timing utilities using sokol_time.h and uthash
bool quic_udp_contains(const quic_udp_endpoint_t *endpoint, const quic_connection_t *connection)
Definition udp.c:330
#define QUIC_UDP_PACKET_CAPACITY
Definition udp.c:10
asciichat_error_t quic_udp_endpoint_address(const quic_udp_endpoint_t *endpoint, struct sockaddr_storage *address, socklen_t *length)
Definition udp.c:106
asciichat_error_t quic_udp_wake(quic_udp_endpoint_t *endpoint)
Definition udp.c:319
asciichat_error_t quic_udp_wait_parameters(const quic_udp_endpoint_t *endpoint, uint64_t now_ns, uint64_t maximum_wait_ns, uint64_t *wait_ns, bool *want_write)
Definition udp.c:286
#define QUIC_UDP_READ_BATCH
Definition udp.c:12
asciichat_error_t quic_udp_pump(quic_udp_endpoint_t *endpoint, uint64_t now, quic_connection_t **failed)
Definition udp.c:222
void quic_udp_endpoint_destroy(quic_udp_endpoint_t **endpoint)
Definition udp.c:372
#define QUIC_UDP_WRITE_BATCH
Definition udp.c:13
asciichat_error_t quic_udp_endpoint_create(const struct sockaddr *address, socklen_t length, quic_tls_t *server_tls, quic_udp_accept_fn accept, void *context, quic_udp_endpoint_t **out)
Definition udp.c:67
asciichat_error_t quic_udp_migrate(quic_udp_endpoint_t *endpoint, const struct sockaddr *address, socklen_t length, uint64_t now_ns)
Definition udp.c:383
#define QUIC_UDP_CID_LENGTH
Definition udp.c:9
asciichat_error_t quic_udp_close_peer(quic_udp_endpoint_t *endpoint, quic_connection_t *connection)
Definition udp.c:339
#define QUIC_RETRY_SECRET_LENGTH
Definition udp.c:14
asciichat_error_t quic_udp_connect(quic_udp_endpoint_t *endpoint, quic_tls_t *client_tls, const char *server_name, const struct sockaddr *remote, socklen_t remote_length, uint64_t now_ns, quic_connection_t **out)
Definition udp.c:144
struct udp_peer udp_peer_t
acip quic udp endpoint is intentionally a small, concrete record. Fields such as socket,...
#define QUIC_UDP_MAX_CONNECTIONS
Definition udp.c:11
#define QUIC_RETRY_TOKEN_LIFETIME
Definition udp.c:15
asciichat_error_t quic_udp_remove(quic_udp_endpoint_t *endpoint, quic_connection_t *connection)
Definition udp.c:356
asciichat_error_t quic_udp_wait(quic_udp_endpoint_t *endpoint, uint64_t wait_ns, bool want_write, bool *ready)
Definition udp.c:304
asciichat_error_t(* quic_udp_accept_fn)(quic_connection_t *, void *)
Definition udp.h:15
struct quic_udp_endpoint quic_udp_endpoint_t
Definition udp.h:14