ascii-chat 0.6.0
Real-time terminal-based video chat with ASCII art conversion
Loading...
Searching...
No Matches
client.h File Reference

Per-client state management and lifecycle orchestration. More...

Go to the source code of this file.

Data Structures

struct  client_manager_t
 Global client manager structure for server-side client coordination. More...
 

Typedefs

typedef struct server_context_t server_context_t
 

Functions

int add_client (server_context_t *server_ctx, socket_t socket, const char *client_ip, int port)
 
int add_webrtc_client (server_context_t *server_ctx, acip_transport_t *transport, const char *client_ip)
 
int remove_client (server_context_t *server_ctx, uint32_t client_id)
 
client_info_tfind_client_by_id (uint32_t client_id)
 
client_info_tfind_client_by_socket (socket_t socket)
 Find client by socket descriptor using linear search.
 
void cleanup_client_media_buffers (client_info_t *client)
 
void cleanup_client_packet_queues (client_info_t *client)
 
void * client_receive_thread (void *arg)
 
void stop_client_threads (client_info_t *client)
 
int process_encrypted_packet (client_info_t *client, packet_type_t *type, void **data, size_t *len, uint32_t *sender_id)
 
void process_decrypted_packet (client_info_t *client, packet_type_t type, void *data, size_t len)
 
void initialize_client_info (client_info_t *client)
 

Variables

client_manager_t g_client_manager
 Global client manager singleton - central coordination point.
 
rwlock_t g_client_manager_rwlock
 Reader-writer lock protecting the global client manager.
 

Detailed Description

Per-client state management and lifecycle orchestration.

This header provides server-specific client management functions. The client_info_t structure and network logging macros are defined in lib/network/client.h.

Definition in file src/server/client.h.

Typedef Documentation

◆ server_context_t

Definition at line 16 of file src/server/client.h.

Function Documentation

◆ add_client()

int add_client ( server_context_t server_ctx,
socket_t  socket,
const char *  client_ip,
int  port 
)

◆ add_webrtc_client()

int add_webrtc_client ( server_context_t server_ctx,
acip_transport_t transport,
const char *  client_ip 
)

◆ cleanup_client_media_buffers()

void cleanup_client_media_buffers ( client_info_t client)

Definition at line 1851 of file src/server/client.c.

1851 {
1852 if (!client) {
1853 SET_ERRNO(ERROR_INVALID_PARAM, "Client is NULL");
1854 return;
1855 }
1856
1857 if (client->incoming_video_buffer) {
1859 client->incoming_video_buffer = NULL;
1860 }
1861
1862 // Clean up outgoing video buffer (for ASCII frames)
1863 if (client->outgoing_video_buffer) {
1865 client->outgoing_video_buffer = NULL;
1866 }
1867
1868 // Clean up pre-allocated send buffer
1869 if (client->send_buffer) {
1870 SAFE_FREE(client->send_buffer);
1871 client->send_buffer = NULL;
1872 client->send_buffer_size = 0;
1873 }
1874
1875 if (client->incoming_audio_buffer) {
1877 client->incoming_audio_buffer = NULL;
1878 }
1879
1880 // Clean up Opus decoder
1881 if (client->opus_decoder) {
1883 client->opus_decoder = NULL;
1884 }
1885}
void audio_ring_buffer_destroy(audio_ring_buffer_t *rb)
Destroy an audio ring buffer.
void opus_codec_destroy(opus_codec_t *codec)
Destroy an Opus codec instance.
Definition opus_codec.c:215
#define SAFE_FREE(ptr)
Definition common.h:320
#define SET_ERRNO(code, context_msg,...)
Set error code with custom context message and log it.
@ ERROR_INVALID_PARAM
void video_frame_buffer_destroy(video_frame_buffer_t *vfb)
Destroy frame buffer and free all resources.
Definition video_frame.c:83
video_frame_buffer_t * outgoing_video_buffer
video_frame_buffer_t * incoming_video_buffer
audio_ring_buffer_t * incoming_audio_buffer
Opus codec context for encoding or decoding.
Definition opus_codec.h:95

References audio_ring_buffer_destroy(), ERROR_INVALID_PARAM, client_info::incoming_audio_buffer, client_info::incoming_video_buffer, opus_codec_destroy(), client_info::opus_decoder, client_info::outgoing_video_buffer, SAFE_FREE, client_info::send_buffer, client_info::send_buffer_size, SET_ERRNO, and video_frame_buffer_destroy().

◆ cleanup_client_packet_queues()

void cleanup_client_packet_queues ( client_info_t client)

Definition at line 1887 of file src/server/client.c.

1887 {
1888 if (!client)
1889 return;
1890
1891 if (client->audio_queue) {
1893 client->audio_queue = NULL;
1894 }
1895
1896 // Video now uses double buffer, cleaned up in cleanup_client_media_buffers
1897}
void packet_queue_destroy(packet_queue_t *queue)
Destroy a packet queue and free all resources.
packet_queue_t * audio_queue

References client_info::audio_queue, and packet_queue_destroy().

◆ client_receive_thread()

void * client_receive_thread ( void *  arg)

Definition at line 1240 of file src/server/client.c.

1240 {
1241 client_info_t *client = (client_info_t *)arg;
1242
1243 // CRITICAL: Validate client pointer immediately before any access
1244 // This prevents crashes if remove_client() has zeroed the client struct
1245 // while the thread was still starting at RtlUserThreadStart
1246 if (!client) {
1247 log_error("Invalid client info in receive thread (NULL pointer)");
1248 return NULL;
1249 }
1250
1251 if (atomic_load(&client->protocol_disconnect_requested)) {
1252 log_debug("Receive thread for client %u exiting before start (protocol disconnect requested)",
1253 atomic_load(&client->client_id));
1254 return NULL;
1255 }
1256
1257 // Check if client_id is 0 (client struct has been zeroed by remove_client)
1258 // This must be checked BEFORE accessing any client fields
1259 if (atomic_load(&client->client_id) == 0) {
1260 log_debug("Receive thread: client_id is 0, client struct may have been zeroed, exiting");
1261 return NULL;
1262 }
1263
1264 // Additional validation: check socket is valid
1265 if (client->socket == INVALID_SOCKET_VALUE) {
1266 log_error("Invalid client socket in receive thread");
1267 return NULL;
1268 }
1269
1270 // Enable thread cancellation for clean shutdown
1271 // Thread cancellation not available in platform abstraction
1272 // Threads should exit when g_server_should_exit is set
1273
1274 log_debug("Started receive thread for client %u (%s)", atomic_load(&client->client_id), client->display_name);
1275
1276 // DEBUG: Check loop entry conditions
1277 bool should_exit = atomic_load(&g_server_should_exit);
1278 bool is_active = atomic_load(&client->active);
1279 socket_t sock = client->socket;
1280 log_debug("RECV_THREAD_START: Client %u conditions: should_exit=%d, active=%d, socket=%d (INVALID=%d)",
1281 atomic_load(&client->client_id), should_exit, is_active, sock, INVALID_SOCKET_VALUE);
1282
1283 while (!atomic_load(&g_server_should_exit) && atomic_load(&client->active) &&
1284 client->socket != INVALID_SOCKET_VALUE) {
1285
1286 // Use unified secure packet reception with auto-decryption
1287 // CRITICAL: Check client_id is still valid before accessing transport
1288 // This prevents accessing freed memory if remove_client() has zeroed the client struct
1289 if (atomic_load(&client->client_id) == 0) {
1290 log_debug("Client client_id reset, exiting receive thread");
1291 break;
1292 }
1293
1294 // Receive and dispatch packet using ACIP transport API
1295 // This combines packet reception, decryption, parsing, handler dispatch, and cleanup
1296 asciichat_error_t acip_result =
1297 acip_server_receive_and_dispatch(client->transport, client, &g_acip_server_callbacks);
1298
1299 // Check if shutdown was requested during the network call
1300 if (atomic_load(&g_server_should_exit)) {
1301 break;
1302 }
1303
1304 // Handle receive errors
1305 if (acip_result != ASCIICHAT_OK) {
1306 // Check error type to determine if we should disconnect
1308 if (HAS_ERRNO(&err_ctx)) {
1309 if (err_ctx.code == ERROR_NETWORK) {
1310 // Network error or EOF - client disconnected
1311 log_debug("Client %u disconnected (network error): %s", client->client_id, err_ctx.context_message);
1312 break;
1313 } else if (err_ctx.code == ERROR_CRYPTO) {
1314 // Security violation
1315 log_error_client(client,
1316 "SECURITY VIOLATION: Unencrypted packet when encryption required - terminating connection");
1317 atomic_store(&g_server_should_exit, true);
1318 break;
1319 }
1320 }
1321
1322 // Other errors - log but don't disconnect immediately
1323 log_warn("ACIP receive/dispatch failed for client %u: %s", client->client_id,
1324 asciichat_error_string(acip_result));
1325 }
1326 }
1327
1328 // Mark client as inactive and stop all threads
1329 // CRITICAL: Must stop render threads when client disconnects
1330 // OPTIMIZED: Use atomic operations for thread control flags (lock-free)
1331 atomic_store(&client->active, false);
1332 atomic_store(&client->send_thread_running, false);
1333 atomic_store(&client->video_render_thread_running, false);
1334 atomic_store(&client->audio_render_thread_running, false);
1335
1336 // Don't call remove_client() from the receive thread itself - this causes a deadlock
1337 // because main thread may be trying to join this thread via remove_client()
1338 // The main cleanup code will handle client removal after threads exit
1339
1340 log_debug("Receive thread for client %u terminated, signaled all threads to stop", client->client_id);
1341
1342 // Clean up thread-local error context before exit
1344
1345 return NULL;
1346}
bool should_exit()
Check if client should exit.
#define HAS_ERRNO(var)
Check if an error occurred and get full context.
void asciichat_errno_cleanup(void)
Cleanup error system resources.
asciichat_error_t
Error and exit codes - unified status values (0-255)
Definition error_codes.h:46
@ ERROR_NETWORK
Definition error_codes.h:69
@ ASCIICHAT_OK
Definition error_codes.h:48
@ ERROR_CRYPTO
Definition error_codes.h:88
#define log_warn(...)
Log a WARN message.
#define log_error(...)
Log an ERROR message.
#define log_debug(...)
Log a DEBUG message.
#define log_error_client(client, fmt,...)
Server sends ERROR log message to client.
int socket_t
Socket handle type (POSIX: int)
Definition socket.h:50
#define INVALID_SOCKET_VALUE
Invalid socket value (POSIX: -1)
Definition socket.h:52
asciichat_error_t acip_server_receive_and_dispatch(acip_transport_t *transport, void *client_ctx, const acip_server_callbacks_t *callbacks)
Receive packet from client and dispatch to callbacks.
atomic_bool g_server_should_exit
Global shutdown flag from main.c.
Error context structure.
char * context_message
Optional custom message (dynamically allocated, owned by system)
asciichat_error_t code
Error code (asciichat_error_t enum value)
Per-client state structure for server-side client management.
atomic_bool video_render_thread_running
atomic_uint client_id
acip_transport_t * transport
char display_name[MAX_DISPLAY_NAME_LEN]
atomic_bool protocol_disconnect_requested
atomic_bool audio_render_thread_running
atomic_bool active
atomic_bool send_thread_running

References acip_server_receive_and_dispatch(), client_info::active, asciichat_errno_cleanup(), ASCIICHAT_OK, client_info::audio_render_thread_running, client_info::client_id, asciichat_error_context_t::code, asciichat_error_context_t::context_message, client_info::display_name, ERROR_CRYPTO, ERROR_NETWORK, g_server_should_exit, HAS_ERRNO, INVALID_SOCKET_VALUE, log_debug, log_error, log_error_client, log_warn, client_info::protocol_disconnect_requested, client_info::send_thread_running, should_exit(), client_info::socket, client_info::transport, and client_info::video_render_thread_running.

◆ find_client_by_id()

◆ find_client_by_socket()

client_info_t * find_client_by_socket ( socket_t  socket)

Find client by socket descriptor using linear search.

This function provides socket-based client lookup, primarily used during connection establishment before client IDs are assigned. Less efficient than find_client_by_id() but necessary for socket-based operations.

PERFORMANCE CHARACTERISTICS:

  • Time Complexity: O(n) where n = number of active clients
  • Space Complexity: O(1)
  • Thread Safety: Internally acquires read lock on g_client_manager_rwlock

USAGE PATTERNS:

  • Connection establishment during add_client() processing
  • Socket error handling and cleanup operations
  • Debugging and diagnostic functions
Parameters
socketPlatform-abstracted socket descriptor to search for
Returns
Pointer to client_info_t if found, NULL if not found
Note
Only searches active clients (avoids returning stale entries)
Caller should use snapshot pattern when accessing returned client data

Definition at line 289 of file src/server/client.c.

289 {
291
292 for (int i = 0; i < MAX_CLIENTS; i++) {
293 if (g_client_manager.clients[i].socket == socket && atomic_load(&g_client_manager.clients[i].active)) {
296 return client;
297 }
298 }
299
301 return NULL;
302}
#define MAX_CLIENTS
Maximum possible clients (static array size) - actual runtime limit set by –max-clients (1-32)
Definition limits.h:23
#define rwlock_rdlock(lock)
Acquire a read lock (with debug tracking in debug builds)
Definition rwlock.h:194
#define rwlock_rdunlock(lock)
Release a read lock (with debug tracking in debug builds)
Definition rwlock.h:231
rwlock_t g_client_manager_rwlock
Reader-writer lock protecting the global client manager.
client_manager_t g_client_manager
Global client manager singleton - central coordination point.
client_info_t clients[MAX_CLIENTS]
Array of client_info_t structures (backing storage)

References client_info::active, client_manager_t::clients, g_client_manager, g_client_manager_rwlock, MAX_CLIENTS, rwlock_rdlock, rwlock_rdunlock, and client_info::socket.

◆ initialize_client_info()

void initialize_client_info ( client_info_t client)

◆ process_decrypted_packet()

void process_decrypted_packet ( client_info_t client,
packet_type_t  type,
void *  data,
size_t  len 
)

Process a decrypted packet from a client

Parameters
clientClient info structure
typePacket type
dataPacket data
lenPacket length

Definition at line 2390 of file src/server/client.c.

2390 {
2391 // Rate limiting: Check and record packet-specific rate limits
2392 if (g_rate_limiter) {
2393 if (!check_and_record_packet_rate_limit(g_rate_limiter, client->client_ip, client->socket, type)) {
2394 // Rate limit exceeded - error response already sent by utility function
2395 return;
2396 }
2397 }
2398
2399 switch (type) {
2401 handle_protocol_version_packet(client, data, len);
2402 break;
2403
2405 handle_image_frame_packet(client, data, len);
2406 break;
2407
2408 case PACKET_TYPE_AUDIO:
2409 handle_audio_packet(client, data, len);
2410 break;
2411
2413 handle_audio_batch_packet(client, data, len);
2414 break;
2415
2417 // Single-frame Opus packet: 16-byte header (sample_rate + frame_duration + reserved) + Opus data
2418 // Extract metadata and forward to mixer
2419 if (len >= 16) {
2420 const uint8_t *payload = (const uint8_t *)data;
2421 // Use unaligned read helpers - network data may not be aligned
2422 int sample_rate = (int)NET_TO_HOST_U32(read_u32_unaligned(payload));
2423 int frame_duration = (int)NET_TO_HOST_U32(read_u32_unaligned(payload + 4));
2424 // Reserved bytes at offset 8-15
2425 size_t opus_size = len - 16;
2426
2427 if (opus_size > 0 && opus_size <= 1024 && sample_rate == 48000 && frame_duration == 20) {
2428 // Create a synthetic Opus batch packet (frame_count=1) and process it
2429 // This reuses the batch handler logic
2430 uint8_t batch_buffer[1024 + 20]; // Max Opus + header
2431 uint8_t *batch_ptr = batch_buffer;
2432
2433 // Write batch header (batch_buffer is stack-aligned, writes are safe)
2434 write_u32_unaligned(batch_ptr, HOST_TO_NET_U32((uint32_t)sample_rate));
2435 batch_ptr += 4;
2436 write_u32_unaligned(batch_ptr, HOST_TO_NET_U32((uint32_t)frame_duration));
2437 batch_ptr += 4;
2438 write_u32_unaligned(batch_ptr, HOST_TO_NET_U32(1)); // frame_count = 1
2439 batch_ptr += 4;
2440 memset(batch_ptr, 0, 4); // reserved
2441 batch_ptr += 4;
2442
2443 // Write frame size
2444 write_u16_unaligned(batch_ptr, HOST_TO_NET_U16((uint16_t)opus_size));
2445 batch_ptr += 2;
2446
2447 // Write Opus data
2448 memcpy(batch_ptr, payload + 16, opus_size);
2449 batch_ptr += opus_size;
2450
2451 // Process as batch packet
2452 size_t batch_size = (size_t)(batch_ptr - batch_buffer);
2453 handle_audio_opus_batch_packet(client, batch_buffer, batch_size);
2454 }
2455 }
2456 break;
2457
2459 handle_audio_opus_batch_packet(client, data, len);
2460 break;
2461
2463 handle_client_join_packet(client, data, len);
2464 break;
2465
2467 handle_client_leave_packet(client, data, len);
2468 break;
2469
2471 handle_stream_start_packet(client, data, len);
2472 break;
2473
2475 handle_stream_stop_packet(client, data, len);
2476 break;
2477
2479 handle_client_capabilities_packet(client, data, len);
2480 break;
2481
2482 case PACKET_TYPE_PING: {
2483 // Respond with PONG using ACIP transport
2484 // CRITICAL: Protect socket write with send_mutex to prevent concurrent writes
2485 mutex_lock(&client->send_mutex);
2486 asciichat_error_t pong_result = acip_send_pong(client->transport);
2487 mutex_unlock(&client->send_mutex);
2488 if (pong_result != ASCIICHAT_OK) {
2489 SET_ERRNO(ERROR_NETWORK, "Failed to send PONG response to client %u: %s", client->client_id,
2490 asciichat_error_string(pong_result));
2491 }
2492 break;
2493 }
2494
2495 case PACKET_TYPE_PONG:
2496 // Client acknowledged our PING - no action needed
2497 break;
2498
2500 handle_remote_log_packet_from_client(client, data, len);
2501 break;
2502
2503 default:
2504 disconnect_client_for_bad_data(client, "Unknown packet type: %d (len=%zu)", type, len);
2505 break;
2506 }
2507}
#define HOST_TO_NET_U16(val)
Definition endian.h:101
#define HOST_TO_NET_U32(val)
Definition endian.h:71
#define NET_TO_HOST_U32(val)
Definition endian.h:86
bool check_and_record_packet_rate_limit(rate_limiter_t *rate_limiter, const char *client_ip, socket_t client_socket, packet_type_t packet_type)
Map packet type to rate event type and check rate limit.
Definition errors.c:54
unsigned short uint16_t
Definition common.h:57
unsigned int uint32_t
Definition common.h:58
#define read_u32_unaligned
Definition common.h:405
unsigned char uint8_t
Definition common.h:56
#define write_u32_unaligned
Definition common.h:407
#define write_u16_unaligned
Definition common.h:406
@ PACKET_TYPE_AUDIO_OPUS_BATCH
Batched Opus-encoded audio frames.
Definition packet.h:359
@ PACKET_TYPE_AUDIO_OPUS
Opus-encoded single audio frame.
Definition packet.h:357
@ PACKET_TYPE_CLIENT_LEAVE
Clean disconnect notification.
Definition packet.h:302
@ PACKET_TYPE_IMAGE_FRAME
Complete RGB image with dimensions.
Definition packet.h:288
@ PACKET_TYPE_PONG
Keepalive pong response.
Definition packet.h:297
@ PACKET_TYPE_STREAM_START
Client requests to start sending video/audio.
Definition packet.h:304
@ PACKET_TYPE_AUDIO
Single audio packet (legacy)
Definition packet.h:291
@ PACKET_TYPE_REMOTE_LOG
Bidirectional remote logging packet.
Definition packet.h:354
@ PACKET_TYPE_PROTOCOL_VERSION
Protocol version and capabilities negotiation.
Definition packet.h:283
@ PACKET_TYPE_CLIENT_JOIN
Client announces capability to send media.
Definition packet.h:300
@ PACKET_TYPE_CLIENT_CAPABILITIES
Client reports terminal capabilities.
Definition packet.h:293
@ PACKET_TYPE_PING
Keepalive ping packet.
Definition packet.h:295
@ PACKET_TYPE_AUDIO_BATCH
Batched audio packets for efficiency.
Definition packet.h:343
@ PACKET_TYPE_STREAM_STOP
Client stops sending media.
Definition packet.h:306
#define mutex_lock(mutex)
Lock a mutex (with debug tracking in debug builds)
Definition mutex.h:140
#define mutex_unlock(mutex)
Unlock a mutex (with debug tracking in debug builds)
Definition mutex.h:175
void handle_audio_opus_batch_packet(client_info_t *client, const void *data, size_t len)
Process AUDIO_OPUS_BATCH packet - efficient Opus-encoded audio batch from client.
void disconnect_client_for_bad_data(client_info_t *client, const char *format,...)
asciichat_error_t acip_send_pong(acip_transport_t *transport)
Send pong packet.
Definition send.c:184
rate_limiter_t * g_rate_limiter
Global rate limiter for connection attempts and packet processing.
void handle_client_join_packet(client_info_t *client, const void *data, size_t len)
Process CLIENT_JOIN packet - client announces identity and capabilities.
void handle_protocol_version_packet(client_info_t *client, const void *data, size_t len)
Process PROTOCOL_VERSION packet - validate protocol compatibility.
void handle_image_frame_packet(client_info_t *client, void *data, size_t len)
Process IMAGE_FRAME packet - store client's video data for rendering.
void handle_audio_batch_packet(client_info_t *client, const void *data, size_t len)
Process AUDIO_BATCH packet - store efficiently batched audio samples.
void handle_audio_packet(client_info_t *client, const void *data, size_t len)
Process AUDIO packet - store single audio sample batch (legacy format)
void handle_client_leave_packet(client_info_t *client, const void *data, size_t len)
Process CLIENT_LEAVE packet - handle clean client disconnect.
void handle_stream_stop_packet(client_info_t *client, const void *data, size_t len)
Process STREAM_STOP packet - client requests to halt media transmission.
void handle_client_capabilities_packet(client_info_t *client, const void *data, size_t len)
Process CLIENT_CAPABILITIES packet - configure client-specific rendering.
void handle_stream_start_packet(client_info_t *client, const void *data, size_t len)
Process STREAM_START packet - client requests to begin media transmission.
void handle_remote_log_packet_from_client(client_info_t *client, const void *data, size_t len)
char client_ip[INET_ADDRSTRLEN]

References acip_send_pong(), ASCIICHAT_OK, check_and_record_packet_rate_limit(), client_info::client_id, client_info::client_ip, disconnect_client_for_bad_data(), ERROR_NETWORK, g_rate_limiter, handle_audio_batch_packet(), handle_audio_opus_batch_packet(), handle_audio_packet(), handle_client_capabilities_packet(), handle_client_join_packet(), handle_client_leave_packet(), handle_image_frame_packet(), handle_protocol_version_packet(), handle_remote_log_packet_from_client(), handle_stream_start_packet(), handle_stream_stop_packet(), HOST_TO_NET_U16, HOST_TO_NET_U32, mutex_lock, mutex_unlock, NET_TO_HOST_U32, PACKET_TYPE_AUDIO, PACKET_TYPE_AUDIO_BATCH, PACKET_TYPE_AUDIO_OPUS, PACKET_TYPE_AUDIO_OPUS_BATCH, PACKET_TYPE_CLIENT_CAPABILITIES, PACKET_TYPE_CLIENT_JOIN, PACKET_TYPE_CLIENT_LEAVE, PACKET_TYPE_IMAGE_FRAME, PACKET_TYPE_PING, PACKET_TYPE_PONG, PACKET_TYPE_PROTOCOL_VERSION, PACKET_TYPE_REMOTE_LOG, PACKET_TYPE_STREAM_START, PACKET_TYPE_STREAM_STOP, read_u32_unaligned, client_info::send_mutex, SET_ERRNO, client_info::socket, client_info::transport, write_u16_unaligned, and write_u32_unaligned.

◆ process_encrypted_packet()

int process_encrypted_packet ( client_info_t client,
packet_type_t type,
void **  data,
size_t *  len,
uint32_t sender_id 
)

Process an encrypted packet from a client

Parameters
clientClient info structure
typePointer to packet type (will be updated with decrypted type)
dataPointer to packet data (will be updated with decrypted data)
lenPointer to packet length (will be updated with decrypted length)
sender_idPointer to sender ID (will be updated with decrypted sender ID)
Returns
0 on success, -1 on error

Definition at line 1923 of file src/server/client.c.

1924 {
1925 if (!crypto_server_is_ready(client->client_id)) {
1926 log_error("Received encrypted packet but crypto not ready for client %u", client->client_id);
1927 buffer_pool_free(NULL, *data, *len);
1928 *data = NULL;
1929 return -1;
1930 }
1931
1932 // Store original allocation size before it gets modified
1933 size_t original_alloc_size = *len;
1934 void *decrypted_data = buffer_pool_alloc(NULL, original_alloc_size);
1935 size_t decrypted_len;
1936 int decrypt_result = crypto_server_decrypt_packet(client->client_id, (const uint8_t *)*data, *len,
1937 (uint8_t *)decrypted_data, original_alloc_size, &decrypted_len);
1938
1939 if (decrypt_result != 0) {
1940 SET_ERRNO(ERROR_CRYPTO, "Failed to process encrypted packet from client %u (result=%d)", client->client_id,
1941 decrypt_result);
1942 buffer_pool_free(NULL, *data, original_alloc_size);
1943 buffer_pool_free(NULL, decrypted_data, original_alloc_size);
1944 *data = NULL;
1945 return -1;
1946 }
1947
1948 // Replace encrypted data with decrypted data
1949 // Use original allocation size for freeing the encrypted buffer
1950 buffer_pool_free(NULL, *data, original_alloc_size);
1951
1952 *data = decrypted_data;
1953 *len = decrypted_len;
1954
1955 // Now process the decrypted packet by parsing its header
1956 if (*len < sizeof(packet_header_t)) {
1957 SET_ERRNO(ERROR_CRYPTO, "Decrypted packet too small for header from client %u", client->client_id);
1958 buffer_pool_free(NULL, *data, *len);
1959 *data = NULL;
1960 return -1;
1961 }
1962
1963 packet_header_t *header = (packet_header_t *)*data;
1964 *type = (packet_type_t)NET_TO_HOST_U16(header->type);
1965 *sender_id = NET_TO_HOST_U32(header->client_id);
1966
1967 // Adjust data pointer to skip header
1968 *data = (uint8_t *)*data + sizeof(packet_header_t);
1969 *len -= sizeof(packet_header_t);
1970
1971 return 0;
1972}
#define NET_TO_HOST_U16(val)
Definition endian.h:116
void buffer_pool_free(buffer_pool_t *pool, void *data, size_t size)
Free a buffer back to the pool (lock-free)
void * buffer_pool_alloc(buffer_pool_t *pool, size_t size)
Allocate a buffer from the pool (lock-free fast path)
uint32_t client_id
Client ID (0 = server, >0 = client identifier)
Definition packet.h:500
uint16_t type
Packet type (packet_type_t enumeration)
Definition packet.h:494
packet_type_t
Network protocol packet type enumeration.
Definition packet.h:281
int crypto_server_decrypt_packet(uint32_t client_id, const uint8_t *ciphertext, size_t ciphertext_len, uint8_t *plaintext, size_t plaintext_size, size_t *plaintext_len)
bool crypto_server_is_ready(uint32_t client_id)
Network packet header structure.
Definition packet.h:490

References buffer_pool_alloc(), buffer_pool_free(), client_info::client_id, packet_header_t::client_id, crypto_server_decrypt_packet(), crypto_server_is_ready(), ERROR_CRYPTO, log_error, NET_TO_HOST_U16, NET_TO_HOST_U32, SET_ERRNO, and packet_header_t::type.

◆ remove_client()

int remove_client ( server_context_t server_ctx,
uint32_t  client_id 
)

Referenced by server_main().

◆ stop_client_threads()

void stop_client_threads ( client_info_t client)

Definition at line 1832 of file src/server/client.c.

1832 {
1833 if (!client) {
1834 SET_ERRNO(ERROR_INVALID_PARAM, "Client is NULL");
1835 return;
1836 }
1837
1838 // Signal threads to stop
1839 atomic_store(&client->active, false);
1840 atomic_store(&client->send_thread_running, false);
1841
1842 // Wait for threads to finish
1844 asciichat_thread_join(&client->send_thread, NULL);
1845 }
1847 asciichat_thread_join(&client->receive_thread, NULL);
1848 }
1849}
bool asciichat_thread_is_initialized(asciichat_thread_t *thread)
Check if a thread handle has been initialized.
int asciichat_thread_join(asciichat_thread_t *thread, void **retval)
Wait for a thread to complete (blocking)
asciichat_thread_t send_thread
asciichat_thread_t receive_thread

References client_info::active, asciichat_thread_is_initialized(), asciichat_thread_join(), ERROR_INVALID_PARAM, client_info::receive_thread, client_info::send_thread, client_info::send_thread_running, and SET_ERRNO.

Variable Documentation

◆ g_client_manager

client_manager_t g_client_manager
extern

Global client manager singleton - central coordination point.

This is the primary data structure for managing all connected clients. It serves as the bridge between main.c's connection accept loop and the per-client threading architecture.

STRUCTURE COMPONENTS:

  • clients[]: Array backing storage for client_info_t structs
  • client_hashtable: O(1) lookup table for client_id -> client_info_t*
  • client_count: Current number of active clients
  • mutex: Legacy mutex (mostly replaced by rwlock)
  • next_client_id: Monotonic counter for unique client identification

THREAD SAFETY: Protected by g_client_manager_rwlock for concurrent access

Definition at line 189 of file src/server/client.c.

189{0};

◆ g_client_manager_rwlock

rwlock_t g_client_manager_rwlock
extern

Reader-writer lock protecting the global client manager.

This lock enables high-performance concurrent access patterns:

  • Multiple threads can read client data simultaneously (stats, rendering)
  • Only one thread can modify client data at a time (add/remove operations)
  • Eliminates contention between read-heavy operations

USAGE PATTERN:

Definition at line 204 of file src/server/client.c.

204{0};