ascii-chat 0.8.38
Real-time terminal-based video chat with ASCII art conversion
Loading...
Searching...
No Matches
Client Handler

📡 Client-side packet processing and data reception thread More...

Files

file  protocol.c
 ðŸ“¡ Client protocol handler: packet reception, parsing, and dispatch with data thread coordination
 
file  protocol.h
 ascii-chat Client Protocol Handler Interface
 

Data Structures

struct  remote_client_info_t
 Remote client information structure for multi-user client tracking. More...
 

Functions

int protocol_start_connection ()
 Start protocol connection handling.
 
void protocol_stop_connection ()
 Stop protocol connection handling.
 
bool protocol_connection_lost ()
 Check if connection has been lost.
 
const acip_client_callbacks_t * protocol_get_acip_callbacks ()
 Get ACIP client callbacks for packet dispatch.
 

Detailed Description

📡 Client-side packet processing and data reception thread

Client Protocol README

Overview

The protocol handler manages the data reception thread, processes incoming packets from the server, and dispatches them to appropriate handlers based on packet type.

Implementation: src/client/protocol.c, src/client/protocol.h

Data Reception Thread

static void *data_reception_thread(void *arg)
{
(void)arg;
const crypto_context_t *crypto_ctx = crypto_client_get_context();
packet_header_t header;
void *payload = NULL;
size_t payload_len = 0;
// Receive and decrypt packet
int result = receive_packet(sockfd, crypto_ctx, &header, &payload, &payload_len);
if (result < 0) {
log_debug("receive_packet failed - connection lost");
break;
}
// Dispatch based on packet type
handle_packet(&header, payload, payload_len);
if (payload) {
free(payload);
payload = NULL;
}
}
atomic_store(&g_data_thread_exited, true);
return NULL;
}
bool should_exit(void)
Definition main.c:90
bool server_connection_is_active()
Check if server connection is currently active.
socket_t server_connection_get_socket()
Get current socket file descriptor.
void server_connection_lost()
Signal that connection has been lost.
const crypto_context_t * crypto_client_get_context(void)
Get crypto context for encryption/decryption.
int socket_t
int receive_packet(socket_t sockfd, packet_type_t *type, void **data, size_t *len)
Receive a basic packet without encryption.
Definition packet.c:766

Packet Handlers

ASCII Frame Handler

static void handle_ascii_frame(const void *payload, size_t payload_len)
{
// Render ASCII frame to terminal
display_render_frame((const char *)payload, opt_snapshot);
// Snapshot mode: exit after displaying frame
if (opt_snapshot) {
}
}
void display_render_frame(const char *frame_data)
Render ASCII frame to display.
void signal_exit(void)
Definition main.c:94

Audio Batch Handler

static void handle_audio_batch(const void *payload, size_t payload_len)
{
const float *samples = (const float *)payload;
int num_samples = payload_len / sizeof(float);
// Process received audio samples
audio_process_received_samples(samples, num_samples);
}
void audio_process_received_samples(const float *samples, int num_samples)
Process received audio samples from server.

Pong Handler

static void handle_pong(void)
{
// Update last pong time for keepalive timeout tracking
keepalive_record_pong();
}

Clear Console Handler

static void handle_clear_console(void)
{
// Server requests terminal clear
}
void display_full_reset()
Perform full display reset.

Server State Handler

static void handle_server_state(const void *payload, size_t payload_len)
{
// Log server state information
log_debug("Received server state update");
}

Connection Loss Detection

Loss triggers in protocol thread:

  • receive_packet() returns error
  • Socket read error (connection closed by server)
  • Decryption failure (corrupted stream)
  • Invalid packet magic number
if (receive_packet(...) < 0) {
server_connection_lost(); // Signal connection loss
break; // Exit thread
}
See also
src/client/protocol.c
src/client/protocol.h
Client Overview

Function Documentation

◆ protocol_connection_lost()

bool protocol_connection_lost ( )

#include <protocol.c>

Check if connection has been lost.

Check if connection has been lost

Returns
true if protocol detected connection loss, false otherwise
true if connection lost, false otherwise

Definition at line 1118 of file client/protocol.c.

1118 {
1119 return atomic_load(&g_data_thread_exited) || server_connection_is_lost();
1120}
bool server_connection_is_lost()
Check if connection loss has been detected.

References server_connection_is_lost().

◆ protocol_get_acip_callbacks()

const acip_client_callbacks_t * protocol_get_acip_callbacks ( )

#include <protocol.h>

Get ACIP client callbacks for packet dispatch.

Returns
Pointer to client callbacks structure

Used by WebRTC sessions to receive and dispatch ACDS signaling packets.

Returns pointer to the global callback structure for use by WebRTC sessions that need to receive ACDS signaling packets.

Returns
Pointer to client callbacks (never NULL)

Definition at line 880 of file client/protocol.c.

880 {
881 return &g_acip_client_callbacks;
882}

◆ protocol_start_connection()

int protocol_start_connection ( )

#include <protocol.c>

Start protocol connection handling.

Start protocol connection handling

Initializes protocol state and starts the data reception thread. Must be called after successful server connection establishment.

Returns
0 on success, negative on error
0 on success, negative on error

Definition at line 985 of file client/protocol.c.

985 {
986 // Reset protocol state for new connection
987 g_server_state_initialized = false;
988 g_last_active_count = 0;
989 g_should_clear_before_next_frame = false;
990
991 // Reset display state for new connection
993
994 // Send CLIENT_CAPABILITIES packet FIRST before starting any threads
995 // Server expects this as the first packet after crypto handshake
996 log_debug("Sending client capabilities to server...");
997 asciichat_error_t cap_result = threaded_send_terminal_size_with_auto_detect(GET_OPTION(width), GET_OPTION(height));
998 if (cap_result != ASCIICHAT_OK) {
999 log_error("Failed to send client capabilities to server");
1000 return -1;
1001 }
1002 log_debug("Client capabilities sent successfully");
1003
1004 // Send STREAM_START packet with combined stream types BEFORE starting worker threads
1005 // This tells the server what streams to expect before any data arrives
1006 uint32_t stream_types = STREAM_TYPE_VIDEO; // Always have video
1007 if (GET_OPTION(audio_enabled)) {
1008 stream_types |= STREAM_TYPE_AUDIO; // Add audio if enabled
1009 }
1010 log_debug("Sending STREAM_START packet (types=0x%x: %s%s)...", stream_types, "video",
1011 (stream_types & STREAM_TYPE_AUDIO) ? "+audio" : "");
1012 asciichat_error_t stream_result = threaded_send_stream_start_packet(stream_types);
1013 if (stream_result != ASCIICHAT_OK) {
1014 log_error("Failed to send STREAM_START packet");
1015 return -1;
1016 }
1017 log_debug("STREAM_START packet sent successfully");
1018
1019 // Start data reception thread
1020 atomic_store(&g_data_thread_exited, false);
1021 if (thread_pool_spawn(g_client_worker_pool, data_reception_thread_func, NULL, 1, "data_reception") != ASCIICHAT_OK) {
1022 log_error("Failed to spawn data reception thread in worker pool");
1023 LOG_ERRNO_IF_SET("Data reception thread creation failed");
1024 return -1;
1025 }
1026
1027 // Start webcam capture thread
1028 log_debug("Starting webcam capture thread...");
1029 if (capture_start_thread() != 0) {
1030 log_error("Failed to start webcam capture thread");
1031 return -1;
1032 }
1033 log_debug("Webcam capture thread started successfully");
1034
1035 // Start audio capture thread if audio is enabled
1036 log_debug("Starting audio capture thread...");
1037 if (audio_start_thread() != 0) {
1038 log_error("Failed to start audio capture thread");
1039 return -1;
1040 }
1041 log_debug("Audio capture thread started successfully (or skipped if audio disabled)");
1042
1043 // Start keepalive/ping thread to prevent server timeout
1044 log_debug("Starting keepalive/ping thread...");
1045 if (keepalive_start_thread() != 0) {
1046 log_error("Failed to start keepalive/ping thread");
1047 return -1;
1048 }
1049 log_debug("Keepalive/ping thread started successfully");
1050
1051 g_data_thread_created = true;
1052 return 0;
1053}
thread_pool_t * g_client_worker_pool
Global client worker thread pool.
int audio_start_thread()
Start audio capture thread.
int capture_start_thread()
Start capture thread.
asciichat_error_t threaded_send_terminal_size_with_auto_detect(unsigned short width, unsigned short height)
Thread-safe terminal size packet transmission with auto-detection.
asciichat_error_t threaded_send_stream_start_packet(uint32_t stream_type)
Thread-safe stream start packet transmission.
void display_reset_for_new_connection()
Reset display state for new connection.
int keepalive_start_thread()
Start keepalive/ping thread.
Definition keepalive.c:233
asciichat_error_t thread_pool_spawn(thread_pool_t *pool, void *(*thread_func)(void *), void *thread_arg, int stop_id, const char *thread_name)
Definition thread_pool.c:70

References audio_start_thread(), capture_start_thread(), display_reset_for_new_connection(), g_client_worker_pool, keepalive_start_thread(), thread_pool_spawn(), threaded_send_stream_start_packet(), and threaded_send_terminal_size_with_auto_detect().

◆ protocol_stop_connection()

void protocol_stop_connection ( )

#include <protocol.c>

Stop protocol connection handling.

Stop protocol connection handling

Gracefully shuts down the data reception thread and cleans up protocol state. Safe to call multiple times.

Definition at line 1063 of file client/protocol.c.

1063 {
1064 if (!g_data_thread_created) {
1065 return;
1066 }
1067
1068 // Don't call signal_exit() here - that's for global shutdown only!
1069 // We just want to stop threads for this connection, not exit the entire client
1070
1071 // Shutdown the socket to interrupt any blocking recv() in data thread
1073
1074 // Stop keepalive/ping thread - it checks connection status and will exit
1076
1077 // Stop webcam capture thread
1079
1080 // Stop audio threads if running
1082
1083 // Wait for data reception thread to exit gracefully
1084 int wait_count = 0;
1085 while (wait_count < 20 && !atomic_load(&g_data_thread_exited)) {
1086 platform_sleep_us(100 * US_PER_MS_INT); // 100ms
1087 wait_count++;
1088 }
1089
1090 if (!atomic_load(&g_data_thread_exited)) {
1091 log_warn("Data thread not responding after 2 seconds - will be joined by thread pool");
1092 }
1093
1094 // Join all threads in the client worker pool (in stop_id order)
1095 // This handles the data reception thread and (eventually) all other worker threads
1097 asciichat_error_t result = thread_pool_stop_all(g_client_worker_pool);
1098 if (result != ASCIICHAT_OK) {
1099 log_error("Failed to stop client worker threads");
1100 LOG_ERRNO_IF_SET("Thread pool stop failed");
1101 }
1102 }
1103
1104 g_data_thread_created = false;
1105
1106#ifdef DEBUG_THREADS
1107 log_debug("Data reception thread stopped and joined by thread pool");
1108#endif
1109}
void audio_stop_thread()
Stop audio capture thread.
void capture_stop_thread()
Stop capture thread.
void server_connection_shutdown()
Emergency connection shutdown for signal handlers.
void keepalive_stop_thread()
Stop keepalive/ping thread.
Definition keepalive.c:259
void platform_sleep_us(unsigned int us)
asciichat_error_t thread_pool_stop_all(thread_pool_t *pool)

References audio_stop_thread(), capture_stop_thread(), g_client_worker_pool, keepalive_stop_thread(), platform_sleep_us(), server_connection_shutdown(), and thread_pool_stop_all().