ascii-chat
Binary v0.15.83-53-gb711d8720
Library lib/v0.3.2-701-gb711d8720
Video chat in your terminal
Loading...
Searching...
No Matches
quic/transport.c
Go to the documentation of this file.
1#include "transport.h"
2#include "datagram.h"
3
4#include <ascii-chat/buffer.h>
5#include <libplatform/atomic.h>
8#include <libplatform/cond.h>
11#include <errno.h>
12#include <string.h>
13
14#define QUIC_RECEIVE_BUDGET (16U * 1024U * 1024U)
15
23
49
50static const acip_transport_methods_t quic_methods;
51
52asciichat_error_t quic_transport_peer_address(acip_transport_t *transport, struct sockaddr_storage *address,
53 socklen_t *length) {
54 if (!transport || transport->methods != &quic_methods || !address || !length)
55 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid QUIC peer address query");
56 quic_transport_t *quic = transport->impl_data;
57 if (quic->lane)
58 mutex_lock(quic->lane);
59 asciichat_error_t result = quic->connected ? quic_connection_peer_address(quic->connection, address, length)
60 : SET_ERRNO(quic->failure, "QUIC transport is closed");
61 if (quic->lane)
62 mutex_unlock(quic->lane);
63 return result;
64}
65
66static void security_ready_notify(void *context) {
67 quic_transport_t *quic = context;
68 if (quic->lane)
69 cond_broadcast(&quic->security_changed);
70}
71
72static void keyframe_notify(uint16_t type, uint32_t id, void *context) {
73 quic_transport_t *quic = context;
74 if (id == 0 && type == PACKET_TYPE_IMAGE_FRAME_H264)
75 atomic_store_bool(&quic->request_h264, true);
76 else if (id == 0 && type == PACKET_TYPE_IMAGE_FRAME_H265)
77 atomic_store_bool(&quic->request_h265, true);
78}
79
80static bool quic_consume_keyframe_request(acip_transport_t *transport, uint16_t type, uint32_t id) {
81 quic_transport_t *quic = transport->impl_data;
82 if (id != 0)
83 return false;
85 return atomic_exchange_bool(&quic->request_h264, false);
87 return atomic_exchange_bool(&quic->request_h265, false);
88 return false;
89}
90
91static void lane_lock(quic_transport_t *quic) {
92 if (quic->lane)
93 mutex_lock(quic->lane);
94}
95
96static void lane_unlock(quic_transport_t *quic) {
97 if (quic->lane)
98 mutex_unlock(quic->lane);
99}
100
101static asciichat_error_t queue_received_packet(acip_traffic_class_t traffic_class, const void *packet, size_t length,
102 void *context) {
103 (void)traffic_class;
104 quic_transport_t *quic = context;
105 if (!quic->connected || length > QUIC_RECEIVE_BUDGET - quic->bytes)
106 return SET_ERRNO(ERROR_BUFFER_FULL, "QUIC receive queue is full or closed");
107 received_packet_t *item = SAFE_CALLOC(1, sizeof(*item), received_packet_t *);
108 if (!item)
109 return SET_ERRNO(ERROR_MEMORY, "Cannot allocate QUIC receive queue entry");
110 item->data = buffer_alloc(NULL, length);
111 if (!item->data) {
112 SAFE_FREE(item);
113 return SET_ERRNO(ERROR_MEMORY, "Cannot copy QUIC received packet");
114 }
115 item->length = length;
116 item->cost = buffer_capacity(item->data) + sizeof(*item);
117 if (item->cost > QUIC_RECEIVE_BUDGET - quic->bytes) {
118 buffer_release(item->data);
119 SAFE_FREE(item);
120 return SET_ERRNO(ERROR_BUFFER_FULL, "QUIC receive queue is full");
121 }
122 memcpy(item->data, packet, length);
123 if (quic->tail)
124 quic->tail->next = item;
125 else
126 quic->head = item;
127 quic->tail = item;
128 quic->bytes += item->cost;
129 if (quic->lane)
130 cond_signal(&quic->received);
131 return ASCIICHAT_OK;
132}
133
134static asciichat_error_t quic_sendv_ex(acip_transport_t *transport, const socket_buffer_t *buffers, size_t count,
135 const acip_send_options_t *options) {
136 quic_transport_t *quic = transport->impl_data;
137 if (!buffers || !count || count > SOCKET_IOV_MAX || !options)
138 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid QUIC transport send arguments");
139 if (options->delivery == ACIP_DELIVERY_RELIABLE && options->deadline_ns)
140 return SET_ERRNO(ERROR_NOT_SUPPORTED, "QUIC reliable deadlines are not available");
141 size_t length = 0;
142 for (size_t i = 0; i < count; ++i) {
143 if ((!buffers[i].data && buffers[i].len) || buffers[i].len > SOCKET_SEND_BUFFER_MAX - length)
144 return SET_ERRNO(ERROR_NETWORK_SIZE, "Invalid QUIC send vectors");
145 length += buffers[i].len;
146 }
147 if (length < sizeof(packet_header_t) || length - sizeof(packet_header_t) > MAX_PACKET_SIZE)
148 return SET_ERRNO(ERROR_NETWORK_SIZE, "Invalid QUIC packet size");
149 uint8_t *packet = buffer_alloc(NULL, length);
150 if (!packet)
151 return SET_ERRNO(ERROR_MEMORY, "Cannot assemble QUIC packet");
152 size_t offset = 0;
153 for (size_t i = 0; i < count; ++i) {
154 if (buffers[i].len)
155 memcpy(packet + offset, buffers[i].data, buffers[i].len);
156 offset += buffers[i].len;
157 }
158 lane_lock(quic);
159 asciichat_error_t result = !quic->connected ? SET_ERRNO(quic->failure, "QUIC transport is closed")
160 : options->delivery == ACIP_DELIVERY_DATAGRAM
161 ? quic_connection_submit_datagram(quic->connection, options->traffic_class, packet,
162 length, options->deadline_ns)
163 : quic_connection_submit(quic->connection, options->traffic_class, packet, length);
164 if (result == ASCIICHAT_OK && quic->wake)
165 quic->wake(quic->wake_context);
166 lane_unlock(quic);
167 buffer_release(packet);
168 return result;
169}
170
171static asciichat_error_t quic_send(acip_transport_t *transport, const void *data, size_t length) {
172 if (!data || length < sizeof(packet_header_t))
173 return SET_ERRNO(ERROR_INVALID_PARAM, "Missing QUIC ACIP packet header");
174 packet_header_t header;
175 memcpy(&header, data, sizeof(header));
176 acip_send_options_t options = {.traffic_class = acip_packet_traffic_class(NET_TO_HOST_U16(header.type)),
177 .delivery = ACIP_DELIVERY_RELIABLE};
178 socket_buffer_t slice = {data, length};
179 return quic_sendv_ex(transport, &slice, 1, &options);
180}
181
182static asciichat_error_t quic_recv(acip_transport_t *transport, void **buffer, size_t *length, void **allocation) {
183 if (!buffer || !length || !allocation)
184 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid QUIC receive output");
185 *buffer = NULL;
186 *length = 0;
187 *allocation = NULL;
188 quic_transport_t *quic = transport->impl_data;
189 lane_lock(quic);
190 if (quic->lane && quic->connected && !quic->head) {
191 uint64_t timeout = transport->receive_timeout_ns ? transport->receive_timeout_ns : NS_PER_SEC_INT;
192 uint64_t start = time_get_ns();
193 while (quic->connected && !quic->head) {
194 uint64_t elapsed = time_get_ns() - start;
195 if (elapsed >= timeout)
196 break;
197 uint64_t remaining = timeout - elapsed;
198 int wait_result =
199 cond_timedwait(&quic->received, quic->lane, remaining < NS_PER_SEC_INT ? remaining : NS_PER_SEC_INT);
200 if (wait_result != 0 && wait_result != ETIMEDOUT) {
201 lane_unlock(quic);
202 return SET_ERRNO(ERROR_NETWORK, "QUIC receive wait failed");
203 }
204 }
205 }
206 if (!quic->connected) {
207 asciichat_error_t failure = quic->failure;
208 lane_unlock(quic);
209 return SET_ERRNO(failure, "QUIC transport is closed");
210 }
211 received_packet_t *item = quic->head;
212 if (!item) {
213 lane_unlock(quic);
214 return SET_ERRNO(ERROR_NETWORK_TIMEOUT, "No QUIC packet is ready");
215 }
216 quic->head = item->next;
217 if (!quic->head)
218 quic->tail = NULL;
219 quic->bytes -= item->cost;
220 *buffer = *allocation = item->data;
221 *length = item->length;
222 lane_unlock(quic);
223 SAFE_FREE(item);
224 return ASCIICHAT_OK;
225}
226
227static asciichat_error_t quic_close_locked(quic_transport_t *quic, asciichat_error_t reason) {
228 if (!quic->connected) {
229 return ASCIICHAT_OK;
230 }
231 quic->connected = false;
232 quic->failure = reason;
233 quic->wake = NULL;
234 quic->wake_context = NULL;
235 if (quic->lane) {
236 cond_broadcast(&quic->received);
237 cond_broadcast(&quic->security_changed);
238 }
240 quic->connection = NULL;
241 while (quic->head) {
242 received_packet_t *item = quic->head;
243 quic->head = item->next;
244 buffer_release(item->data);
245 SAFE_FREE(item);
246 }
247 quic->tail = NULL;
248 quic->bytes = 0;
249 return result;
250}
251
252static asciichat_error_t quic_close(acip_transport_t *transport) {
253 quic_transport_t *quic = transport->impl_data;
254 lane_lock(quic);
255 if (quic->connected && quic->on_close)
256 quic->on_close(quic->connection, quic->close_context);
257 asciichat_error_t result = quic_close_locked(quic, ERROR_NETWORK);
258 lane_unlock(quic);
259 return result;
260}
261
263 void *context) {
264 quic_transport_t *quic = transport->impl_data;
265 quic->on_close = close;
266 quic->close_context = context;
267}
268
270 if (!transport || transport->methods != &quic_methods || reason == ASCIICHAT_OK)
271 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid QUIC transport failure");
272 quic_transport_t *quic = transport->impl_data;
273 lane_lock(quic);
274 asciichat_error_t result = quic_close_locked(quic, reason);
275 lane_unlock(quic);
276 return result;
277}
278
280 if (!transport || transport->methods != &quic_methods || reason == ASCIICHAT_OK)
281 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid QUIC transport failure");
282 return quic_close_locked(transport->impl_data, reason);
283}
284
286 if (!transport || !*transport || (*transport)->methods != &quic_methods || (*transport)->outbound ||
287 (*transport)->stats_peer || reason == ASCIICHAT_OK)
288 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid unclaimed QUIC transport");
289 quic_transport_t *quic = (*transport)->impl_data;
290 asciichat_error_t result = quic_close_locked(quic, reason);
291 if (result != ASCIICHAT_OK)
292 return result;
293 if (quic->lane)
294 cond_destroy(&quic->received);
295 if (quic->lane)
296 cond_destroy(&quic->security_changed);
297 SAFE_FREE((*transport)->impl_data);
298 SAFE_FREE(*transport);
299 *transport = NULL;
300 return ASCIICHAT_OK;
301}
302
303asciichat_error_t quic_transport_set_waker_on_lane(acip_transport_t *transport, void (*wake)(void *), void *context) {
304 if (!transport || transport->methods != &quic_methods)
305 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid QUIC transport waker");
306 quic_transport_t *quic = transport->impl_data;
307 if (!quic->connected)
308 return SET_ERRNO(ERROR_INVALID_STATE, "QUIC transport is closed");
309 quic->wake = wake;
310 quic->wake_context = wake ? context : NULL;
311 return ASCIICHAT_OK;
312}
313
314asciichat_error_t quic_transport_set_waker(acip_transport_t *transport, void (*wake)(void *), void *context) {
315 if (!transport || transport->methods != &quic_methods)
316 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid QUIC transport waker");
317 quic_transport_t *quic = transport->impl_data;
318 lane_lock(quic);
319 asciichat_error_t result = quic_transport_set_waker_on_lane(transport, wake, context);
320 lane_unlock(quic);
321 return result;
322}
323
325 if (!transport || transport->methods != &quic_methods || !crypto)
326 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid QUIC transport security context");
327 quic_transport_t *quic = transport->impl_data;
328 lane_lock(quic);
330 : SET_ERRNO(quic->failure, "QUIC transport is closed");
331 if (result == ASCIICHAT_OK) {
332 transport->crypto_ctx = crypto;
333 result = acip_security_activate(transport);
334 if (quic->wake)
335 quic->wake(quic->wake_context);
336 }
337 lane_unlock(quic);
338 if (result == ASCIICHAT_OK && quic->lane)
339 result = acip_outbound_create(transport);
340 return result;
341}
342
344 if (!transport || transport->methods != &quic_methods)
345 return false;
346 quic_transport_t *quic = transport->impl_data;
347 lane_lock(quic);
348 bool ready = quic->connected && quic_connection_security_ready(quic->connection);
349 lane_unlock(quic);
350 return ready;
351}
352
354 if (!transport || transport->methods != &quic_methods)
355 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid QUIC transport");
356 quic_transport_t *quic = transport->impl_data;
357 if (!quic->lane)
358 return SET_ERRNO(ERROR_NOT_SUPPORTED, "QUIC security wait requires a serialized endpoint");
359 uint64_t start = time_get_ns();
360 lane_lock(quic);
361 while (quic->connected && !quic_connection_security_ready(quic->connection)) {
362 uint64_t elapsed = time_get_ns() - start;
363 if (elapsed >= timeout_ns) {
364 lane_unlock(quic);
365 return SET_ERRNO(ERROR_NETWORK_TIMEOUT, "QUIC security readiness timed out");
366 }
367 int rc = cond_timedwait(&quic->security_changed, quic->lane, timeout_ns - elapsed);
368 if (rc != 0 && rc != ETIMEDOUT) {
369 lane_unlock(quic);
370 return SET_ERRNO(ERROR_THREAD, "QUIC security readiness wait failed");
371 }
372 }
373 asciichat_error_t result = quic->connected ? ASCIICHAT_OK : SET_ERRNO(quic->failure, "QUIC transport is closed");
374 lane_unlock(quic);
375 return result;
376}
377
379 if (!transport || transport->methods != &quic_methods)
380 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid QUIC transport");
381 quic_transport_t *quic = transport->impl_data;
382 lane_lock(quic);
384 : SET_ERRNO(quic->failure, "QUIC transport is closed");
385 lane_unlock(quic);
386 return result;
387}
388
389static void quic_interrupt(acip_transport_t *transport) {
390 (void)quic_close(transport);
391}
392static acip_transport_type_t quic_type(acip_transport_t *transport) {
393 (void)transport;
394 return ACIP_TRANSPORT_QUIC;
395}
396static socket_t quic_socket(acip_transport_t *transport) {
397 (void)transport;
398 return INVALID_SOCKET_VALUE;
399}
400static bool quic_connected(acip_transport_t *transport) {
401 quic_transport_t *quic = transport->impl_data;
402 lane_lock(quic);
403 bool connected = quic->connected;
404 lane_unlock(quic);
405 return connected;
406}
407static bool quic_pending(acip_transport_t *transport) {
408 quic_transport_t *quic = transport->impl_data;
409 lane_lock(quic);
410 bool pending = quic->head != NULL;
411 lane_unlock(quic);
412 return pending;
413}
414static size_t quic_queued(acip_transport_t *transport) {
415 quic_transport_t *quic = transport->impl_data;
416 lane_lock(quic);
417 size_t bytes = quic->connection ? quic_connection_pending_bytes(quic->connection) : 0;
418 lane_unlock(quic);
419 return bytes;
420}
421static asciichat_error_t quic_capabilities(acip_transport_t *transport, acip_transport_capabilities_t *out) {
422 quic_transport_t *quic = transport->impl_data;
423 lane_lock(quic);
424 if (!quic->connected) {
425 asciichat_error_t result = SET_ERRNO(quic->failure, "QUIC transport is closed");
426 lane_unlock(quic);
427 return result;
428 }
430 lane_unlock(quic);
431 return SET_ERRNO(ERROR_INVALID_STATE, "QUIC capabilities are not negotiated yet");
432 }
433 size_t payload = quic_connection_datagram_payload(quic->connection);
434 *out = (acip_transport_capabilities_t){.independent_streams = true,
435 .datagrams = payload != 0,
436 .max_datagram_payload = payload ? payload + QUIC_DATAGRAM_HEADER_SIZE : 0};
437 lane_unlock(quic);
438 return ASCIICHAT_OK;
439}
440
441static asciichat_error_t quic_validate_options(acip_transport_t *transport, const acip_send_options_t *options) {
442 if (options->delivery != ACIP_DELIVERY_DATAGRAM)
443 return SET_ERRNO(ERROR_NOT_SUPPORTED, "QUIC reliable deadlines are not available");
444 if (options->deadline_ns && options->deadline_ns <= time_get_ns())
445 return SET_ERRNO(ERROR_NETWORK_TIMEOUT, "QUIC datagram deadline expired");
446 quic_transport_t *quic = transport->impl_data;
447 lane_lock(quic);
448 asciichat_error_t result =
449 quic->connected
451 : SET_ERRNO(quic->failure, "QUIC transport is closed");
452 lane_unlock(quic);
453 return result;
454}
455static void quic_destroy_impl(acip_transport_t *transport) {
456 quic_transport_t *quic = transport->impl_data;
457 if (quic->on_destroy)
458 quic->on_destroy(transport, quic->destroy_context);
459 if (quic->lane)
460 cond_destroy(&quic->received);
461 if (quic->lane)
462 cond_destroy(&quic->security_changed);
463}
464static const acip_transport_methods_t quic_methods = {.send = quic_send,
465 .sendv_ex = quic_sendv_ex,
466 .recv = quic_recv,
467 .close = quic_close,
468 .interrupt = quic_interrupt,
469 .get_type = quic_type,
470 .get_socket = quic_socket,
471 .is_connected = quic_connected,
472 .has_pending_data = quic_pending,
473 .queued_bytes = quic_queued,
474 .get_capabilities = quic_capabilities,
475 .consume_keyframe_request = quic_consume_keyframe_request,
476 .validate_send_options = quic_validate_options,
477 .destroy_impl = quic_destroy_impl};
478
479static asciichat_error_t attach_transport(quic_connection_t *connection, crypto_context_t *crypto, mutex_t *lane,
480 bool lane_held, void (*wake)(void *), void *wake_context,
481 void (*on_destroy)(acip_transport_t *, void *), void *destroy_context,
483 if (!out)
484 return SET_ERRNO(ERROR_INVALID_PARAM, "Missing QUIC transport output");
485 *out = NULL;
486 if (!connection)
487 return SET_ERRNO(ERROR_INVALID_PARAM, "Missing QUIC connection");
488 acip_transport_t *transport = SAFE_CALLOC(1, sizeof(*transport), acip_transport_t *);
489 quic_transport_t *quic = SAFE_CALLOC(1, sizeof(*quic), quic_transport_t *);
490 if (!transport || !quic) {
491 SAFE_FREE(transport);
492 SAFE_FREE(quic);
493 return SET_ERRNO(ERROR_MEMORY, "Cannot allocate QUIC transport");
494 }
495 quic->connection = connection;
496 quic->lane = lane;
497 quic->wake = wake;
498 quic->wake_context = wake ? wake_context : NULL;
499 quic->on_destroy = on_destroy;
500 quic->destroy_context = destroy_context;
501 quic->connected = true;
502 if (lane && cond_init(&quic->received, "quic_receive") != 0) {
503 SAFE_FREE(quic);
504 SAFE_FREE(transport);
505 return SET_ERRNO(ERROR_MEMORY, "Cannot initialize QUIC receive wait");
506 }
507 if (lane && cond_init(&quic->security_changed, "quic_security") != 0) {
508 cond_destroy(&quic->received);
509 SAFE_FREE(quic);
510 SAFE_FREE(transport);
511 return SET_ERRNO(ERROR_MEMORY, "Cannot initialize QUIC security wait");
512 }
513 transport->methods = &quic_methods;
514 transport->impl_data = quic;
515 transport->crypto_ctx = crypto;
516 if (!lane_held)
517 lane_lock(quic);
518 asciichat_error_t result = quic_connection_set_receiver(connection, queue_received_packet, quic);
519 if (result == ASCIICHAT_OK) {
520 quic_connection_set_security_notifier(connection, security_ready_notify, quic);
521 quic_connection_set_keyframe_notifier(connection, keyframe_notify, quic);
522 }
523 if (!lane_held)
524 lane_unlock(quic);
525 if (result != ASCIICHAT_OK) {
526 if (lane) {
527 cond_destroy(&quic->received);
528 cond_destroy(&quic->security_changed);
529 }
530 SAFE_FREE(quic);
531 SAFE_FREE(transport);
532 return result;
533 }
534 *out = transport;
535 return ASCIICHAT_OK;
536}
537
540 return attach_transport(connection, crypto, NULL, false, NULL, NULL, NULL, NULL, out);
541}
542
544 mutex_t *lane, acip_transport_t **out) {
545 if (!lane) {
546 if (out)
547 *out = NULL;
548 return SET_ERRNO(ERROR_INVALID_PARAM, "Missing QUIC lane mutex");
549 }
550 return attach_transport(connection, crypto, lane, false, NULL, NULL, NULL, NULL, out);
551}
552
555 if (!lane) {
556 if (out)
557 *out = NULL;
558 return SET_ERRNO(ERROR_INVALID_PARAM, "Missing QUIC lane mutex");
559 }
560 return attach_transport(connection, crypto, lane, true, NULL, NULL, NULL, NULL, out);
561}
562
564 void (*wake)(void *), void *context,
565 void (*on_destroy)(acip_transport_t *, void *),
566 void *destroy_context, acip_transport_t **out) {
567 if (!lane) {
568 if (out)
569 *out = NULL;
570 return SET_ERRNO(ERROR_INVALID_PARAM, "Missing QUIC lane mutex");
571 }
572 return attach_transport(connection, NULL, lane, true, wake, context, on_destroy, destroy_context, out);
573}
#define SET_ERRNO(code,...)
asciichat_error_t acip_outbound_create(acip_transport_t *transport)
size_t buffer_capacity(const void *data)
Definition buffer.c:280
void * buffer_alloc(buffer_domain_t *domain, size_t size)
Definition buffer.c:274
#define buffer_release(data)
Definition buffer.h:91
#define QUIC_DATAGRAM_HEADER_SIZE
Definition datagram.h:11
🔄 Network byte order conversion helpers
#define NET_TO_HOST_U16(val)
Definition endian.h:111
unsigned short uint16_t
Definition common.h:61
unsigned int uint32_t
Definition common.h:62
#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_INVALID_STATE
@ 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_NETWORK_SIZE
Definition error_codes.h:77
@ ERROR_INVALID_PARAM
@ ERROR_NETWORK_TIMEOUT
Definition error_codes.h:75
@ ERROR_THREAD
@ ERROR_NOT_SUPPORTED
Definition error_codes.h:69
#define NS_PER_SEC_INT
Definition time.h:169
#define MAX_PACKET_SIZE
Maximum packet size (5MB).
Definition packet.h:130
@ PACKET_TYPE_IMAGE_FRAME_H265
H.265-encoded frame from client (HEVC/H.265 codec).
Definition packet.h:387
@ PACKET_TYPE_IMAGE_FRAME_H264
Definition packet.h:389
#define ETIMEDOUT
struct acip_transport acip_transport_t
Forward declaration of ACIP transport.
Definition host.h:506
int socket_t
acip_transport_type_t
Transport method table (virtual function table).
@ ACIP_TRANSPORT_QUIC
QUIC/UDP (future).
asciichat_error_t acip_security_activate(acip_transport_t *transport)
asciichat_error_t quic_connection_set_receiver(quic_connection_t *connection, quic_stream_emit_fn emit, void *context)
size_t quic_connection_pending_bytes(const quic_connection_t *connection)
asciichat_error_t quic_connection_peer_address(const quic_connection_t *connection, struct sockaddr_storage *address, socklen_t *length)
asciichat_error_t quic_connection_validate_datagram(const quic_connection_t *connection, acip_traffic_class_t flow, uint64_t deadline_ns)
bool quic_connection_tls_ready(const quic_connection_t *connection)
asciichat_error_t quic_connection_enable_security(quic_connection_t *connection, crypto_context_t *crypto)
asciichat_error_t quic_connection_submit(quic_connection_t *connection, acip_traffic_class_t traffic_class, const void *packet, size_t length)
void quic_connection_set_keyframe_notifier(quic_connection_t *connection, void(*notify)(uint16_t, uint32_t, void *), void *context)
bool quic_connection_security_ready(const quic_connection_t *connection)
asciichat_error_t quic_connection_submit_datagram(quic_connection_t *connection, acip_traffic_class_t flow, const void *packet, size_t length, uint64_t deadline_ns)
void quic_connection_set_security_notifier(quic_connection_t *connection, void(*notify)(void *), void *context)
size_t quic_connection_datagram_payload(const quic_connection_t *connection)
asciichat_error_t quic_connection_clear_receiver(quic_connection_t *connection, void *context)
asciichat_error_t quic_connection_allow_media(quic_connection_t *connection)
struct quic_connection quic_connection_t
static bool size_t gotel_query_t * out
Definition queries.h:8
void quic_transport_set_close_on_lane(acip_transport_t *transport, void(*close)(quic_connection_t *, void *), void *context)
asciichat_error_t quic_transport_wait_security(acip_transport_t *transport, uint64_t timeout_ns)
asciichat_error_t quic_transport_peer_address(acip_transport_t *transport, struct sockaddr_storage *address, socklen_t *length)
asciichat_error_t quic_transport_attach_serialized(quic_connection_t *connection, crypto_context_t *crypto, mutex_t *lane, acip_transport_t **out)
asciichat_error_t quic_transport_attach_on_lane_with_waker(quic_connection_t *connection, mutex_t *lane, void(*wake)(void *), void *context, void(*on_destroy)(acip_transport_t *, void *), void *destroy_context, acip_transport_t **out)
struct received_packet received_packet_t
asciichat_error_t quic_transport_begin_security(acip_transport_t *transport, crypto_context_t *crypto)
asciichat_error_t quic_transport_set_waker_on_lane(acip_transport_t *transport, void(*wake)(void *), void *context)
bool quic_transport_security_ready(acip_transport_t *transport)
asciichat_error_t quic_transport_destroy_unclaimed_on_lane(acip_transport_t **transport, asciichat_error_t reason)
asciichat_error_t quic_transport_fail(acip_transport_t *transport, asciichat_error_t reason)
asciichat_error_t quic_transport_allow_media(acip_transport_t *transport)
asciichat_error_t quic_transport_attach(quic_connection_t *connection, crypto_context_t *crypto, acip_transport_t **out)
asciichat_error_t quic_transport_fail_on_lane(acip_transport_t *transport, asciichat_error_t reason)
asciichat_error_t quic_transport_attach_on_lane(quic_connection_t *connection, crypto_context_t *crypto, mutex_t *lane, acip_transport_t **out)
asciichat_error_t quic_transport_set_waker(acip_transport_t *transport, void(*wake)(void *), void *context)
#define QUIC_RECEIVE_BUDGET
🔤 String Manipulation and Shell Escaping Utilities
uint64_t deadline_ns
Definition traffic.h:19
acip_delivery_t delivery
Definition traffic.h:18
acip_traffic_class_t traffic_class
Definition traffic.h:17
The useful part of acip transport capabilities is in independent_streams, datagrams,...
Transport method table (virtual function table).
void * impl_data
Transport-specific state.
const acip_transport_methods_t * methods
Method table (virtual functions).
crypto_context_t * crypto_ctx
Optional encryption context.
uint64_t receive_timeout_ns
Optional TCP receive timeout override; zero uses the normal polling timeout.
Endpoint cryptographic state for handshake, packet protection, authentication, and rekeying.
Fixed prefix shared by every ACIP packet on the wire.
Definition packet.h:628
quic_connection_t * connection
asciichat_error_t failure
void(* on_close)(quic_connection_t *, void *)
void(* wake)(void *)
void(* on_destroy)(acip_transport_t *, void *)
received_packet_t * head
received_packet_t * tail
struct received_packet * next
⏱️ High-precision timing utilities using sokol_time.h and uthash
acip_traffic_class_t acip_packet_traffic_class(uint16_t type)
Definition traffic.c:4
acip_traffic_class_t
Definition traffic.h:5
@ ACIP_DELIVERY_RELIABLE
Definition traffic.h:12
@ ACIP_DELIVERY_DATAGRAM
Definition traffic.h:13