ascii-chat
Binary v0.15.83-53-gb711d8720
Library lib/v0.3.2-701-gb711d8720
Video chat in your terminal
Loading...
Searching...
No Matches
async.c File Reference

Go to the source code of this file.

Data Structures

struct  async_packet
struct  async_tcp_t

Macros

#define ASYNC_RECEIVE_POOL_CAPACITY   (256u * 1024u)
#define ASYNC_RECEIVE_POOL_SIZE   64u

Typedefs

typedef struct async_packet async_packet_t

Functions

void acip_async_tcp_transport_detach (acip_transport_t *transport)
bool acip_async_tcp_transport_is (const acip_transport_t *transport)
size_t acip_async_tcp_transport_queued (acip_transport_t *transport)
acip_transport_t * acip_async_tcp_transport_create (platform_event_stream_t *stream, crypto_context_t *crypto)
acip_transport_t * acip_async_tcp_client_create (socket_t *socket, crypto_context_t *crypto)
acip_transport_t * acip_async_tcp_accepted_create (platform_event_stream_t *stream)

Macro Definition Documentation

◆ ASYNC_RECEIVE_POOL_CAPACITY

#define ASYNC_RECEIVE_POOL_CAPACITY   (256u * 1024u)

Definition at line 25 of file async.c.

Referenced by acip_async_tcp_client_create().

◆ ASYNC_RECEIVE_POOL_SIZE

#define ASYNC_RECEIVE_POOL_SIZE   64u

Definition at line 26 of file async.c.

Referenced by acip_async_tcp_client_create().

Typedef Documentation

◆ async_packet_t

typedef struct async_packet async_packet_t

Function Documentation

◆ acip_async_tcp_accepted_create()

acip_transport_t * acip_async_tcp_accepted_create ( platform_event_stream_t * stream)

Queue complete packets from an accepted stream on its listener's loop. The returned transport is owned by the accepting caller. Destroy it outside the loop thread while the listener is running, or after the listener stops.

Definition at line 576 of file async.c.

576 {
577 acip_transport_t *transport = acip_async_tcp_transport_create(stream, NULL);
578 if (!transport)
579 return NULL;
580 async_tcp_t *tcp = transport->impl_data;
581 if (cond_init(&tcp->received, "accepted_receive") != ASCIICHAT_OK) {
583 tcp->stream = NULL;
584 atomic_store_bool(&tcp->closed, true);
585 acip_transport_destroy(transport);
586 return NULL;
587 }
588 tcp->queued_receive = true;
589 asciichat_error_t result = platform_event_stream_start(stream, client_read, client_closed, tcp);
590 if (result != ASCIICHAT_OK) {
591 // The stream retains its callbacks on startup failure; release their state after close completes.
592 tcp->destroy_on_close = transport;
593 platform_event_stream_close(stream, result);
594 return NULL;
595 }
596 return transport;
597}
acip_transport_t * acip_async_tcp_transport_create(platform_event_stream_t *stream, crypto_context_t *crypto)
Definition async.c:407
void platform_event_stream_close(platform_event_stream_t *stream, asciichat_error_t reason)
Definition event.c:120
asciichat_error_t platform_event_stream_start(platform_event_stream_t *stream, platform_event_read_fn read, platform_event_close_fn close, void *arg)
Definition event.c:326
void platform_event_stream_observe_queue(platform_event_stream_t *stream, platform_event_queue_fn observer, void *context)
Definition event.c:712
asciichat_error_t
Error and exit codes - unified status values (0-255).
Definition error_codes.h:44
@ ASCIICHAT_OK
Definition error_codes.h:46
struct acip_transport acip_transport_t
Forward declaration of ACIP transport.
Definition host.h:506
void * impl_data
Transport-specific state.
bool queued_receive
Definition async.c:36
atomic_t closed
Definition async.c:32
acip_transport_t * destroy_on_close
Definition async.c:37
cond_t received
Definition async.c:38
platform_event_stream_t * stream
Definition async.c:29
void acip_transport_destroy(acip_transport_t *transport)
Destroy transport and free all resources.

References acip_async_tcp_transport_create(), acip_transport_destroy(), ASCIICHAT_OK, async_tcp_t::closed, async_tcp_t::destroy_on_close, acip_transport::impl_data, platform_event_stream_close(), platform_event_stream_observe_queue(), platform_event_stream_start(), async_tcp_t::queued_receive, async_tcp_t::received, and async_tcp_t::stream.

◆ acip_async_tcp_client_create()

acip_transport_t * acip_async_tcp_client_create ( socket_t * socket,
crypto_context_t * crypto )

Native client adapter. Owns a loop thread; recv waits on a bounded packet queue. Takes socket ownership when *socket becomes INVALID_SOCKET_VALUE.

Definition at line 525 of file async.c.

525 {
526 acip_transport_t *transport = acip_async_tcp_transport_create(NULL, crypto);
527 if (!transport)
528 return NULL;
529 async_tcp_t *tcp = transport->impl_data;
530 if (cond_init(&tcp->received, "async_tcp_receive") != ASCIICHAT_OK) {
531 acip_transport_destroy(transport);
532 return NULL;
533 }
534 tcp->queued_receive = true;
536 if (!tcp->receive_free)
537 goto client_pool_failure;
538 for (size_t i = 0; i < ASYNC_RECEIVE_POOL_SIZE; i++) {
539 void *pool_buffer = buffer_alloc(NULL, ASYNC_RECEIVE_POOL_CAPACITY);
540 if (!pool_buffer)
541 goto client_pool_failure;
542 if (!ringbuffer_write(tcp->receive_free, &pool_buffer)) {
543 buffer_release(pool_buffer);
544 goto client_pool_failure;
545 }
546 }
548 acip_transport_destroy(transport);
549 return NULL;
550 }
551 asciichat_error_t result = platform_event_stream_adopt(tcp->loop, socket, &tcp->stream);
552 if (result == ASCIICHAT_OK) {
553 platform_event_stream_observe_queue(tcp->stream, queue_changed, tcp);
554 result = platform_event_stream_start(tcp->stream, client_read, client_closed, tcp);
555 }
556 if (result == ASCIICHAT_OK)
557 result = platform_event_loop_tick(tcp->loop, 50, client_tick, tcp);
558 if (result == ASCIICHAT_OK)
559 result = platform_thread_create(&tcp->thread, "tcp_io", client_loop, tcp);
560 if (result != ASCIICHAT_OK) {
561 acip_transport_destroy(transport);
562 return NULL;
563 }
564 tcp->thread_started = true;
565 if (acip_outbound_create(transport) != ASCIICHAT_OK) {
566 acip_transport_destroy(transport);
567 return NULL;
568 }
569 return transport;
570
571client_pool_failure:
572 acip_transport_destroy(transport);
573 return NULL;
574}
#define ASYNC_RECEIVE_POOL_SIZE
Definition async.c:26
#define ASYNC_RECEIVE_POOL_CAPACITY
Definition async.c:25
asciichat_error_t acip_outbound_create(acip_transport_t *transport)
void * buffer_alloc(buffer_domain_t *domain, size_t size)
Definition buffer.c:274
#define buffer_release(data)
Definition buffer.h:91
asciichat_error_t platform_event_stream_adopt(platform_event_loop_t *loop, socket_t *socket, platform_event_stream_t **out)
Definition event.c:410
asciichat_error_t platform_event_loop_create(platform_event_loop_t **out)
Definition event.c:205
asciichat_error_t platform_event_loop_tick(platform_event_loop_t *loop, uint64_t interval, platform_event_task_fn fn, void *arg)
Definition event.c:296
ringbuffer_t * ringbuffer_create(size_t element_size, size_t capacity)
Create a new ring buffer.
Definition ringbuffer.c:34
bool ringbuffer_write(ringbuffer_t *rb, const void *data)
Try to write an element to the ring buffer (non-blocking).
Definition ringbuffer.c:71
bool thread_started
Definition async.c:35
platform_event_loop_t * loop
Definition async.c:33
ringbuffer_t * receive_free
Definition async.c:43
platform_thread_t thread
Definition async.c:34

References acip_async_tcp_transport_create(), acip_outbound_create(), acip_transport_destroy(), ASCIICHAT_OK, ASYNC_RECEIVE_POOL_CAPACITY, ASYNC_RECEIVE_POOL_SIZE, buffer_alloc(), buffer_release, acip_transport::impl_data, async_tcp_t::loop, platform_event_loop_create(), platform_event_loop_tick(), platform_event_stream_adopt(), platform_event_stream_observe_queue(), platform_event_stream_start(), async_tcp_t::queued_receive, async_tcp_t::receive_free, async_tcp_t::received, ringbuffer_create(), ringbuffer_write(), async_tcp_t::stream, async_tcp_t::thread, and async_tcp_t::thread_started.

◆ acip_async_tcp_transport_create()

acip_transport_t * acip_async_tcp_transport_create ( platform_event_stream_t * stream,
crypto_context_t * crypto )

Outbound ACIP adapter. Incoming packets are delivered by the connection's decoder. Destroy after the stream close callback, when workers have drained.

Definition at line 407 of file async.c.

407 {
408 acip_transport_t *transport = SAFE_CALLOC(1, sizeof(*transport), acip_transport_t *);
409 async_tcp_t *tcp = SAFE_CALLOC(1, sizeof(*tcp), async_tcp_t *);
410 if (mutex_init(&tcp->mutex, "tcp_packet_io_lifetime_guard") != ASCIICHAT_OK) {
411 SAFE_FREE(tcp);
412 SAFE_FREE(transport);
413 return NULL;
414 }
415 if (mutex_init(&tcp->receive_mutex, "tcp_receive_queue") != ASCIICHAT_OK) {
416 mutex_destroy(&tcp->mutex);
417 SAFE_FREE(tcp);
418 SAFE_FREE(transport);
419 return NULL;
420 }
421 if (cond_init(&tcp->writable, "tcp_output_writable") != ASCIICHAT_OK) {
422 mutex_destroy(&tcp->receive_mutex);
423 mutex_destroy(&tcp->mutex);
424 SAFE_FREE(tcp);
425 SAFE_FREE(transport);
426 return NULL;
427 }
428 tcp->receive_queue = ringbuffer_create(sizeof(async_packet_t *), 4096);
429 if (!tcp->receive_queue) {
431 cond_destroy(&tcp->writable);
432 mutex_destroy(&tcp->receive_mutex);
433 mutex_destroy(&tcp->mutex);
434 SAFE_FREE(tcp);
435 SAFE_FREE(transport);
436 return NULL;
437 }
438 tcp->stream = stream;
439 transport->methods = &async_methods;
440 transport->impl_data = tcp;
441 transport->crypto_ctx = crypto;
442 transport->stats_peer = stats_runtime_peer_open("TCP-async");
443 if (acip_outbound_create(transport) != ASCIICHAT_OK) {
444 acip_transport_destroy(transport);
445 return NULL;
446 }
447 platform_event_stream_observe_queue(stream, queue_changed, tcp);
448 return transport;
449}
struct async_packet async_packet_t
#define SAFE_FREE(ptr)
Definition common.h:377
#define SAFE_CALLOC(count, size, cast)
Definition common.h:275
void ringbuffer_destroy(ringbuffer_t *rb)
Destroy a ring buffer and free its memory.
Definition ringbuffer.c:61
stats_peer_t * stats_runtime_peer_open(const char *transport)
Definition runtime.c:152
stats_peer_t * stats_peer
Owned statistics handle, destroyed with transport.
const acip_transport_methods_t * methods
Method table (virtual functions).
crypto_context_t * crypto_ctx
Optional encryption context.
ringbuffer_t * receive_queue
Definition async.c:42
mutex_t mutex
Definition async.c:30
cond_t writable
Definition async.c:40
mutex_t receive_mutex
Definition async.c:31

References acip_outbound_create(), acip_transport_destroy(), ASCIICHAT_OK, acip_transport::crypto_ctx, acip_transport::impl_data, acip_transport::methods, async_tcp_t::mutex, platform_event_stream_observe_queue(), async_tcp_t::receive_mutex, async_tcp_t::receive_queue, ringbuffer_create(), ringbuffer_destroy(), SAFE_CALLOC, SAFE_FREE, acip_transport::stats_peer, stats_runtime_peer_open(), async_tcp_t::stream, and async_tcp_t::writable.

Referenced by acip_async_tcp_accepted_create(), and acip_async_tcp_client_create().

◆ acip_async_tcp_transport_detach()

void acip_async_tcp_transport_detach ( acip_transport_t * transport)

Definition at line 262 of file async.c.

262 {
263 async_tcp_t *tcp = transport->impl_data;
264 mutex_lock(&tcp->mutex);
265 atomic_store_bool(&tcp->closed, true);
267 tcp->stream = NULL;
268 mutex_unlock(&tcp->mutex);
269}

References async_tcp_t::closed, acip_transport::impl_data, async_tcp_t::mutex, platform_event_stream_observe_queue(), and async_tcp_t::stream.

◆ acip_async_tcp_transport_is()

bool acip_async_tcp_transport_is ( const acip_transport_t * transport)

Definition at line 388 of file async.c.

388 {
389 return transport && transport->methods == &async_methods;
390}

References acip_transport::methods.

◆ acip_async_tcp_transport_queued()

size_t acip_async_tcp_transport_queued ( acip_transport_t * transport)

Definition at line 392 of file async.c.

392 {
393 async_tcp_t *tcp = transport->impl_data;
394 return (size_t)atomic_load_u64(&tcp->queued_wire_bytes);
395}
atomic_t queued_wire_bytes
Definition async.c:51

References acip_transport::impl_data, and async_tcp_t::queued_wire_bytes.