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.h File Reference

Go to the source code of this file.

Typedefs

typedef struct quic_udp_endpoint quic_udp_endpoint_t
typedef asciichat_error_t(* quic_udp_accept_fn) (quic_connection_t *, void *)

Functions

asciichat_error_t quic_udp_endpoint_create (const struct sockaddr *bind_address, socklen_t bind_length, quic_tls_t *server_tls, quic_udp_accept_fn accept, void *context, quic_udp_endpoint_t **out)
asciichat_error_t quic_udp_endpoint_address (const quic_udp_endpoint_t *endpoint, struct sockaddr_storage *address, socklen_t *length)
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)
asciichat_error_t quic_udp_pump (quic_udp_endpoint_t *endpoint, uint64_t now_ns, quic_connection_t **failed)
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)
asciichat_error_t quic_udp_wait (quic_udp_endpoint_t *endpoint, uint64_t wait_ns, bool want_write, bool *ready)
asciichat_error_t quic_udp_wake (quic_udp_endpoint_t *endpoint)
bool quic_udp_contains (const quic_udp_endpoint_t *endpoint, const quic_connection_t *connection)
asciichat_error_t quic_udp_close_peer (quic_udp_endpoint_t *endpoint, quic_connection_t *connection)
asciichat_error_t quic_udp_remove (quic_udp_endpoint_t *endpoint, quic_connection_t *connection)
void quic_udp_endpoint_destroy (quic_udp_endpoint_t **endpoint)
asciichat_error_t quic_udp_migrate (quic_udp_endpoint_t *endpoint, const struct sockaddr *address, socklen_t length, uint64_t now_ns)

Typedef Documentation

◆ quic_udp_accept_fn

typedef asciichat_error_t(* quic_udp_accept_fn) (quic_connection_t *, void *)

Definition at line 15 of file udp.h.

◆ quic_udp_endpoint_t

Definition at line 14 of file udp.h.

Function Documentation

◆ quic_udp_close_peer()

asciichat_error_t quic_udp_close_peer ( quic_udp_endpoint_t * endpoint,
quic_connection_t * connection )

Definition at line 339 of file udp.c.

339 {
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}
#define SET_ERRNO(code,...)
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
@ ASCIICHAT_OK
Definition error_codes.h:46
@ ERROR_INVALID_PARAM
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)
socket_t socket
Definition udp.c:34
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

References ASCIICHAT_OK, ERROR_INVALID_PARAM, ERROR_NETWORK, quic_connection_write_close(), quic_udp_contains(), QUIC_UDP_PACKET_CAPACITY, SET_ERRNO, and quic_udp_endpoint::socket.

◆ quic_udp_connect()

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 at line 144 of file udp.c.

146 {
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}
#define SAFE_FREE(ptr)
Definition common.h:377
@ ERROR_BUFFER_FULL
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)
static bool size_t gotel_query_t * out
Definition queries.h:8
bool server
Definition tls.h:15
struct sockaddr_storage local
Definition udp.c:35
quic_connection_t * connection
Definition udp.c:27
struct udp_peer udp_peer_t
acip quic udp endpoint is intentionally a small, concrete record. Fields such as socket,...

References ASCIICHAT_OK, udp_peer::connection, ERROR_BUFFER_FULL, ERROR_INVALID_PARAM, quic_udp_endpoint::local, out, quic_connection_client_create(), SAFE_FREE, quic_tls_t::server, and SET_ERRNO.

Referenced by quic_connect().

◆ quic_udp_contains()

bool quic_udp_contains ( const quic_udp_endpoint_t * endpoint,
const quic_connection_t * connection )

Definition at line 330 of file udp.c.

330 {
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}
udp_peer_t * peers
Definition udp.c:41
struct udp_peer * next
Definition udp.c:26

References udp_peer::connection, udp_peer::next, and quic_udp_endpoint::peers.

Referenced by quic_udp_close_peer().

◆ quic_udp_endpoint_address()

asciichat_error_t quic_udp_endpoint_address ( const quic_udp_endpoint_t * endpoint,
struct sockaddr_storage * address,
socklen_t * length )

Definition at line 106 of file udp.c.

107 {
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}
socklen_t local_length
Definition udp.c:36

References ASCIICHAT_OK, ERROR_INVALID_PARAM, quic_udp_endpoint::local, quic_udp_endpoint::local_length, and SET_ERRNO.

Referenced by quic_endpoint_address().

◆ quic_udp_endpoint_create()

asciichat_error_t quic_udp_endpoint_create ( const struct sockaddr * bind_address,
socklen_t bind_length,
quic_tls_t * server_tls,
quic_udp_accept_fn accept,
void * context,
quic_udp_endpoint_t ** out )

Definition at line 67 of file udp.c.

68 {
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}
#define SAFE_CALLOC(count, size, cast)
Definition common.h:275
@ ERROR_MEMORY
Definition error_codes.h:51
@ ERROR_CRYPTO
Definition error_codes.h:93
quic_tls_t * server_tls
Definition udp.c:37
uint8_t retry_secret[32]
Definition udp.c:38
void * context
Definition udp.c:40
quic_udp_accept_fn accept
Definition udp.c:39
struct quic_udp_endpoint quic_udp_endpoint_t
Definition udp.h:14

References quic_udp_endpoint::accept, ASCIICHAT_OK, quic_udp_endpoint::context, ERROR_CRYPTO, ERROR_INVALID_PARAM, ERROR_MEMORY, ERROR_NETWORK, quic_udp_endpoint::local, quic_udp_endpoint::local_length, out, quic_udp_endpoint::retry_secret, SAFE_CALLOC, SAFE_FREE, quic_tls_t::server, quic_udp_endpoint::server_tls, SET_ERRNO, and quic_udp_endpoint::socket.

Referenced by quic_endpoint_open(), and quic_udp_migrate().

◆ quic_udp_endpoint_destroy()

void quic_udp_endpoint_destroy ( quic_udp_endpoint_t ** endpoint)

Definition at line 372 of file udp.c.

372 {
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}
asciichat_error_t quic_udp_remove(quic_udp_endpoint_t *endpoint, quic_connection_t *connection)
Definition udp.c:356

References udp_peer::connection, quic_udp_endpoint::peers, quic_udp_remove(), and SAFE_FREE.

Referenced by quic_endpoint_destroy(), quic_endpoint_open(), and quic_udp_migrate().

◆ quic_udp_migrate()

asciichat_error_t quic_udp_migrate ( quic_udp_endpoint_t * endpoint,
const struct sockaddr * address,
socklen_t length,
uint64_t now_ns )

Definition at line 383 of file udp.c.

384 {
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}
int socket_t
asciichat_error_t quic_connection_migrate(quic_connection_t *connection, const struct sockaddr *local, socklen_t length, uint64_t now_ns)
size_t count
Definition udp.c:42
size_t pending_length
Definition udp.c:30
void quic_udp_endpoint_destroy(quic_udp_endpoint_t **endpoint)
Definition udp.c:372
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

References ASCIICHAT_OK, udp_peer::connection, quic_udp_endpoint::count, ERROR_BUFFER_FULL, ERROR_INVALID_PARAM, quic_udp_endpoint::local, quic_udp_endpoint::local_length, quic_udp_endpoint::peers, udp_peer::pending_length, quic_connection_migrate(), quic_udp_endpoint_create(), quic_udp_endpoint_destroy(), quic_udp_endpoint::server_tls, SET_ERRNO, and quic_udp_endpoint::socket.

Referenced by quic_endpoint_migrate().

◆ quic_udp_pump()

asciichat_error_t quic_udp_pump ( quic_udp_endpoint_t * endpoint,
uint64_t now_ns,
quic_connection_t ** failed )

Definition at line 222 of file udp.c.

222 {
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) {
251 asciichat_error_t result = quic_connection_handle_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) {
259 asciichat_error_t result = quic_connection_write(peer->connection, &peer->pending_path, peer->pending,
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;
276 asciichat_error_t result = quic_connection_packet_sent(peer->connection, now);
277 if (result != ASCIICHAT_OK) {
278 *failed = peer->connection;
279 return result;
280 }
281 }
282 }
283 return ASCIICHAT_OK;
284}
asciichat_error_t quic_connection_handle_expiry(quic_connection_t *connection, uint64_t now_ns)
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_packet_sent(quic_connection_t *connection, uint64_t now_ns)
uint64_t quic_connection_expiry(const quic_connection_t *connection)
#define QUIC_UDP_READ_BATCH
Definition udp.c:12
#define QUIC_UDP_WRITE_BATCH
Definition udp.c:13

References ASCIICHAT_OK, udp_peer::connection, ERROR_INVALID_PARAM, ERROR_NETWORK, udp_peer::next, quic_udp_endpoint::peers, udp_peer::pending, udp_peer::pending_length, udp_peer::pending_path, quic_connection_expiry(), quic_connection_handle_expiry(), quic_connection_packet_sent(), quic_connection_write(), QUIC_UDP_READ_BATCH, QUIC_UDP_WRITE_BATCH, SET_ERRNO, and quic_udp_endpoint::socket.

◆ quic_udp_remove()

asciichat_error_t quic_udp_remove ( quic_udp_endpoint_t * endpoint,
quic_connection_t * connection )

Definition at line 356 of file udp.c.

356 {
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}
void quic_connection_destroy(quic_connection_t **connection)

References ASCIICHAT_OK, udp_peer::connection, quic_udp_endpoint::count, ERROR_INVALID_PARAM, udp_peer::next, quic_udp_endpoint::peers, quic_connection_destroy(), SAFE_FREE, and SET_ERRNO.

Referenced by quic_connect(), quic_endpoint_stop(), quic_release(), and quic_udp_endpoint_destroy().

◆ quic_udp_wait()

asciichat_error_t quic_udp_wait ( quic_udp_endpoint_t * endpoint,
uint64_t wait_ns,
bool want_write,
bool * ready )

Definition at line 304 of file udp.c.

304 {
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}

References ASCIICHAT_OK, ERROR_INVALID_PARAM, ERROR_NETWORK, SET_ERRNO, and quic_udp_endpoint::socket.

◆ quic_udp_wait_parameters()

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 at line 286 of file udp.c.

287 {
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) {
293 uint64_t expiry = quic_connection_expiry(peer->connection);
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}
unsigned long long uint64_t
Definition common.h:63

References ASCIICHAT_OK, udp_peer::connection, ERROR_INVALID_PARAM, udp_peer::next, quic_udp_endpoint::peers, udp_peer::pending_length, quic_connection_expiry(), and SET_ERRNO.

◆ quic_udp_wake()

asciichat_error_t quic_udp_wake ( quic_udp_endpoint_t * endpoint)

Definition at line 319 of file udp.c.

319 {
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}

References ASCIICHAT_OK, ERROR_INVALID_PARAM, ERROR_NETWORK, quic_udp_endpoint::local, quic_udp_endpoint::local_length, SET_ERRNO, and quic_udp_endpoint::socket.

Referenced by quic_worker_wake().