ascii-chat
Binary v0.15.83-53-gb711d8720
Library lib/v0.3.2-701-gb711d8720
Video chat in your terminal
Loading...
Searching...
No Matches
connections.c
Go to the documentation of this file.
1#include "connections.h"
2#include "render.h"
3#include "protocol.h"
4#include "main.h"
8
9static asciichat_error_t server_connection_open(network_connection_t *connection, void *arg) {
10 server_context_t *server = arg;
11 if (server->rate_limiter) {
12 bool allowed = false;
14 RATE_EVENT_CONNECTION, NULL, &allowed);
15 if (result != ASCIICHAT_OK)
16 return result;
17 if (!allowed)
18 return SET_ERRNO(ERROR_RATE_LIMITED, "Connection rate limit exceeded");
20 if (result != ASCIICHAT_OK)
21 return result;
22 }
24 network_connection_set_context(connection, state);
25 bool adopted_ready = network_connection_state(connection) == NETWORK_READY;
27 state->negotiation = (network_negotiation_t){
28 .protocol = NETWORK_PROTOCOL_MEDIA,
29 .handshake = handshake,
30 .initialized = adopted_ready && crypto_handshake_is_ready(handshake),
31 .encrypt_data = adopted_ready && ACIP_CRYPTO_HAS_ENCRYPT(network_connection_crypto_mode(connection)),
32 .identity_keys = g_server_identity_keys,
33 .identity_key_count = g_num_server_identity_keys,
34 .whitelist = g_client_whitelist,
35 .whitelist_count = g_num_whitelisted_clients,
36 .password = GET_OPTION(password),
37 .secure = network_connection_secure(connection),
38 .require_auth = GET_OPTION(password)[0] || g_num_whitelisted_clients || GET_OPTION(require_server_verify),
39 .require_identity = g_num_whitelisted_clients || GET_OPTION(require_server_verify),
40 .require_encryption = GET_OPTION(encrypt_enabled),
41 .forbid_encryption = GET_OPTION(no_encrypt)};
42 return network_connection_state(connection) == NETWORK_READY
45}
46static asciichat_error_t server_connection_packet(network_connection_t *connection, packet_type_t type,
47 const void *payload, size_t length, void *arg) {
48 server_context_t *server = arg;
52 &state->negotiation, network_connection_transport(connection), type, payload, length);
53 if (result == ASCIICHAT_OK && state->negotiation.ready) {
54 network_connection_ready(connection);
56 }
57 return result;
58 }
59 client_info_t *client = atomic_ptr_load(&state->client);
60 if (!client) {
62 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Expected initial client capabilities");
63 // Authentication and capabilities precede allocation of media slots and buffers.
64 client =
66 if (!client)
67 return SET_ERRNO(ERROR_SESSION_FULL, "Cannot admit client");
68 client->network_connection = connection;
69 client->crypto_handshake_ctx = state->negotiation.handshake;
70 client->crypto_initialized = state->negotiation.initialized;
71 client->encrypt_data = state->negotiation.encrypt_data;
73 client->security_ready = true;
74 atomic_ptr_store(&state->client, client);
75 handle_client_capabilities_packet(client, payload, length);
76 return start_transport_client_threads(server, client->client_id) == 0
78 : SET_ERRNO(ERROR_THREAD, "Cannot start client rendering");
79 }
80 return server_dispatch_packet(client, type, payload, length);
81}
82static asciichat_error_t server_connection_closing(network_connection_t *connection, void *arg) {
83 (void)arg;
85 client_info_t *client = state ? atomic_ptr_load(&state->client) : NULL;
86 if (!client)
87 return ASCIICHAT_OK;
88 atomic_store_bool(&client->active, false);
89 atomic_store_bool(&client->event_ready, false);
90 /* Keep transport teardown serialized with the media/control senders. */
91 mutex_lock(&client->send_mutex);
92 client->transport = NULL;
93 client->network_connection = NULL;
94 mutex_unlock(&client->send_mutex);
95 // Render-thread joins and client-buffer destruction are owned by
96 // server_connection_closed()->remove_client(). Doing that work here too
97 // races the closed callback and can tear down the same client twice.
98 return ASCIICHAT_OK;
99}
100static void server_connection_closed(network_connection_t *connection, void *arg) {
102 client_info_t *client = state ? atomic_ptr_load(&state->client) : NULL;
103 if (client) {
104 atomic_store_bool(&client->event_cleanup, true);
105 remove_client(arg, client->client_id);
106 }
107 SAFE_FREE(state);
108 network_connection_set_context(connection, NULL);
109}
110const network_connection_callbacks_t server_network_callbacks = {server_connection_open, server_connection_packet,
111 server_connection_closing, server_connection_closed};
112
113void server_send_video(client_info_t *client, acip_frame_workspace_t *workspace, const char *data, size_t length,
114 uint32_t width, uint32_t height, int sources, const acip_render_settings_t *rendering) {
115 mutex_lock(&client->send_mutex);
116 acip_transport_t *transport = client->transport;
117 if (transport && !atomic_load_bool(&client->shutting_down) && atomic_load_bool(&client->event_ready)) {
118 if (sources > 0 && atomic_load_u64(&client->last_sent_grid_sources) != (uint64_t)sources) {
119 acip_send_clear_console(transport);
120 atomic_store_u64(&client->last_sent_grid_sources, (uint64_t)sources);
121 }
123 transport, workspace, data, length, width, height, rendering,
124 (rendering->caps.capabilities & TERM_CAP_MATRIX_RAIN) ? FRAME_RENDER_CONTRACT_RAIN : 0,
125 client->client_id) == ASCIICHAT_OK)
126 atomic_fetch_add_u64(&client->frames_sent_count, 1);
127 }
128 mutex_unlock(&client->send_mutex);
129}
130
131asciichat_error_t server_send_audio(client_info_t *client, const void *data, size_t length) {
132 mutex_lock(&client->send_mutex);
134 if (client->transport && !atomic_load_bool(&client->shutting_down) && atomic_load_bool(&client->event_ready))
136 fnv1a_hash_string(client->client_id));
137 mutex_unlock(&client->send_mutex);
138 return result;
139}
#define SET_ERRNO(code,...)
void server_send_video(client_info_t *client, acip_frame_workspace_t *workspace, const char *data, size_t length, uint32_t width, uint32_t height, int sources, const acip_render_settings_t *rendering)
const network_connection_callbacks_t server_network_callbacks
asciichat_error_t server_send_audio(client_info_t *client, const void *data, size_t length)
bool crypto_handshake_is_ready(const crypto_handshake_context_t *ctx)
Check if handshake is complete and encryption is ready.
unsigned int height
Definition fft.c:23
unsigned int width
Definition fft.c:23
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
asciichat_error_t
Error and exit codes - unified status values (0-255).
Definition error_codes.h:44
@ ERROR_NETWORK_PROTOCOL
Definition error_codes.h:76
@ ASCIICHAT_OK
Definition error_codes.h:46
@ ERROR_RATE_LIMITED
Definition error_codes.h:80
@ ERROR_SESSION_FULL
Definition error_codes.h:82
@ ERROR_THREAD
#define ACIP_CRYPTO_HAS_ENCRYPT(mode)
Check if crypto mode includes payload encryption.
Definition packet.h:1148
packet_type_t
Network protocol packet type enumeration.
Definition packet.h:301
@ PACKET_TYPE_AUDIO_OPUS_BATCH
Batched Opus-encoded audio frames.
Definition packet.h:398
@ PACKET_TYPE_CLIENT_CAPABILITIES
Client reports terminal capabilities.
Definition packet.h:405
#define GET_OPTION(field)
Safely get a specific option field (lock-free read).
Definition options.h:1336
struct acip_transport acip_transport_t
Forward declaration of ACIP transport.
Definition host.h:506
struct client_info client_info_t
struct network_connection network_connection_t
asciichat_error_t acip_send_ascii_frame_contract(acip_transport_t *transport, acip_frame_workspace_t *workspace, const char *frame_data, size_t frame_size, uint32_t width, uint32_t height, const acip_render_settings_t *settings, uint32_t effects, const char *client_id)
asciichat_error_t acip_send_clear_console(acip_transport_t *transport)
Send clear console command to client (server → client).
void network_connection_ready(network_connection_t *c)
network_connection_state_t network_connection_state(network_connection_t *c)
const char * network_connection_peer(network_connection_t *c)
void network_connection_set_context(network_connection_t *c, void *context)
void * network_connection_context(network_connection_t *c)
crypto_handshake_context_t * network_connection_handshake(network_connection_t *c)
bool network_connection_secure(network_connection_t *c)
acip_transport_t * network_connection_transport(network_connection_t *c)
uint8_t network_connection_crypto_mode(network_connection_t *c)
asciichat_error_t network_negotiation_receive(network_negotiation_t *n, acip_transport_t *transport, packet_type_t type, const void *payload, size_t length)
@ NETWORK_PROTOCOL_MEDIA
Definition negotiation.h:5
⚙️ Unified options parsing system for ascii-chat with builder pattern and lock-free access
asciichat_error_t rate_limiter_record(rate_limiter_t *limiter, const char *ip_address, rate_event_type_t event_type)
Record a rate limit event.
Definition rate_limit.c:162
asciichat_error_t rate_limiter_check(rate_limiter_t *limiter, const char *ip_address, rate_event_type_t event_type, const rate_limit_config_t *config, bool *allowed)
Check if an event from an IP address should be rate limited.
Definition rate_limit.c:138
@ RATE_EVENT_CONNECTION
New connection.
Definition rate_limit.h:55
#define FRAME_RENDER_CONTRACT_RAIN
asciichat_error_t packet_send_via_transport(acip_transport_t *transport, packet_type_t type, const void *payload, size_t payload_len, uint32_t client_id)
Definition send.c:190
ACIP shared/bidirectional packet sending functions.
size_t g_num_whitelisted_clients
Number of whitelisted clients.
private_key_t g_server_identity_keys[MAX_SESSION_KEYS]
Global server identity keys array (multi-key support).
public_key_t g_client_whitelist[MAX_CLIENTS]
Global client public key whitelist.
size_t g_num_server_identity_keys
Number of loaded server identity keys.
void handle_client_capabilities_packet(client_info_t *client, const void *data, size_t len)
asciichat_error_t server_send_state(acip_transport_t *transport)
int start_transport_client_threads(server_context_t *server_ctx, const char *client_id)
int remove_client(server_context_t *server_ctx, const char *client_id)
asciichat_error_t server_dispatch_packet(client_info_t *client, packet_type_t type, const void *data, size_t length)
client_info_t * add_transport_client(server_context_t *server_ctx, acip_transport_t *transport, const char *client_ip)
Server packet processing and protocol implementation.
Per-client rendering threads with rate limiting.
Send ASCII frame to client (server → client).
acip render settings keeps the values that move through the subsystem: caps, width,...
bool transport_encrypted
TLS or DTLS already encrypts this client's transport.
crypto_handshake_context_t * crypto_handshake_ctx
network_connection_t * network_connection
char client_id[MAX_CLIENT_ID_LEN]
Cryptographic handshake context structure.
Callbacks and operations used by network connection callbacks. Packet payloads are borrowed until ret...
When code needs to work with network negotiation, it keeps protocol, handshake, identity_keys,...
Definition negotiation.h:12
Server context - encapsulates all server state.
rate_limiter_t * rate_limiter
Connection and packet rate limiter.
⏱️ High-precision timing utilities using sokol_time.h and uthash