ascii-chat 0.11.33
Video chat in your terminal
Loading...
Searching...
No Matches
client.h File Reference

WebSocket client abstraction for ascii-chat connections. More...

Go to the source code of this file.

Data Structures

struct  websocket_client
 WebSocket client connection state. More...
 

Typedefs

typedef struct websocket_client websocket_client_t
 WebSocket client connection state.
 

Functions

websocket_client_t * websocket_client_create (const char *name)
 Create and initialize a named WebSocket client instance.
 
void websocket_client_destroy (websocket_client_t **client_ptr)
 Destroy WebSocket client and free all resources.
 
bool websocket_client_is_active (const websocket_client_t *client)
 Check if connection is currently active.
 
bool websocket_client_is_lost (const websocket_client_t *client)
 Check if connection was lost.
 
bool websocket_client_should_reconnect (const websocket_client_t *client)
 Check if reconnection should be attempted.
 
void websocket_client_signal_lost (websocket_client_t *client)
 Signal that connection was lost (triggers reconnection)
 
void websocket_client_signal_reconnect (websocket_client_t *client)
 Signal that reconnection should be attempted.
 
void websocket_client_clear_reconnect_flag (websocket_client_t *client)
 Clear reconnection flag (called after successful reconnect)
 
bool websocket_client_is_encryption_enabled (const websocket_client_t *client)
 Check if encryption is enabled.
 
void websocket_client_enable_encryption (websocket_client_t *client)
 Enable encryption for this connection.
 
void websocket_client_disable_encryption (websocket_client_t *client)
 Disable encryption for this connection.
 
void websocket_client_close (websocket_client_t *client)
 Close connection gracefully.
 
void websocket_client_shutdown (websocket_client_t *client)
 Shutdown connection forcefully (for signal handlers)
 
acip_transport_t * websocket_client_connect (websocket_client_t *client, const char *url, struct crypto_context_t *crypto_ctx)
 Establish WebSocket connection to server.
 
acip_transport_t * websocket_client_get_transport (const websocket_client_t *client)
 Get active transport instance.
 
int websocket_client_send_packet (websocket_client_t *client, packet_type_t type, const void *data, size_t len)
 Send a packet through WebSocket connection (thread-safe)
 
int websocket_client_send_ping (websocket_client_t *client)
 Send ping frame (keepalive heartbeat)
 
int websocket_client_send_pong (websocket_client_t *client)
 Send pong frame (keepalive response)
 
uint32_t websocket_client_get_id (const websocket_client_t *client)
 Get the client's unique ID.
 
bool websocket_client_is_encrypted (const websocket_client_t *client)
 Check if encryption is enabled for this connection.
 

Detailed Description

WebSocket client abstraction for ascii-chat connections.

This module provides a reusable WebSocket client implementation that parallels tcp_client.h, enabling WebSocket connections as a transport alternative to TCP.

Architecture

The websocket_client module encapsulates WebSocket-specific connection state, mirroring the structure of tcp_client_t:

  • Connection lifecycle management (create, connect, destroy)
  • Connection state tracking (active, lost, signals)
  • Transport abstraction (returns acip_transport_t for protocol agnostic use)

Unlike tcp_client_t, this module does NOT contain:

  • Audio/video thread management (handled by client_context_t)
  • Capture threads (handled by client_context_t)
  • Protocol-specific packet builders (handled by application)

Usage Pattern

// Create WebSocket client
// Connect to server
acip_transport_t *transport = websocket_client_connect(ws_client, "ws://localhost:27226", crypto_ctx);
if (!transport) {
log_error("Connection failed");
return;
}
// Use transport with ACIP protocol handlers
acip_send_packet(transport, packet_type, data, len);
// Check connection state
if (!websocket_client_is_active(ws_client)) {
log_warn("Connection lost");
}
// Cleanup when done
#define log_warn(...)
Log a WARN message.
Definition log/log.h:574
#define log_error(...)
Log an ERROR message.
Definition log/log.h:587
bool websocket_client_is_active(const websocket_client_t *client)
Check if connection is currently active.
acip_transport_t * websocket_client_connect(websocket_client_t *client, const char *url, struct crypto_context_t *crypto_ctx)
Establish WebSocket connection to server.
websocket_client_t * websocket_client_create(const char *name)
Create and initialize named WebSocket client.
void websocket_client_close(websocket_client_t *client)
Close connection gracefully.
void websocket_client_destroy(websocket_client_t **client_ptr)
Destroy WebSocket client and free resources.
struct websocket_client_t websocket_client_t
Transport instance structure.
Definition transport.h:214

Comparison with tcp_client_t

Aspect tcp_client_t websocket_client_t
Connection type TCP socket WebSocket (TCP-based)
State tracking Yes Yes
Audio queues Yes (TO REMOVE) No (in client_context)
Thread management Yes (TO REMOVE) No (in client_context)
Transport return N/A acip_transport_t*
Author
Zachary Fogg me@zf.nosp@m.o.gg
Date
February 2026
Version
1.0

Definition in file include/ascii-chat/network/websocket/client.h.

Typedef Documentation

◆ websocket_client_t

WebSocket client connection state.

Encapsulates WebSocket-specific connection state, including:

  • Connection URL and state flags
  • Client ID and encryption state
  • Active transport (owned by websocket_client)
  • Thread-safe packet transmission mutex

This structure mirrors tcp_client_t for API compatibility. Application state (audio, threads, crypto) lives in client_context_t instead.

Thread Safety

  • Atomic fields: Safe for concurrent read/write without locks
  • Immutable after init: url is set once, then read-only
  • Mutex: Protects concurrent packet transmission

Function Documentation

◆ websocket_client_clear_reconnect_flag()

void websocket_client_clear_reconnect_flag ( websocket_client_t *  client)

Clear reconnection flag (called after successful reconnect)

Parameters
clientWebSocket client instance

◆ websocket_client_close()

void websocket_client_close ( websocket_client_t *  client)

Close connection gracefully.

Parameters
clientWebSocket client instance

Definition at line 136 of file lib/network/websocket/client.c.

136 {
137 if (!client) {
138 return;
139 }
140
141 log_debug("Closing WebSocket client");
142
143 if (client->transport) {
144 acip_transport_close(client->transport);
145 }
146
147 atomic_store_bool(&client->connection_active, false);
148}
void atomic_store_bool(atomic_t *a, bool value)
Atomically store a boolean value.
Definition atomic.c:177
#define log_debug(...)
Log a DEBUG message.
Definition log/log.h:548

References atomic_store_bool(), and log_debug.

◆ websocket_client_connect()

acip_transport_t * websocket_client_connect ( websocket_client_t *  client,
const char *  url,
struct crypto_context_t *  crypto_ctx 
)

Establish WebSocket connection to server.

Performs full connection lifecycle including URL resolution and WebSocket handshake. Does NOT perform crypto handshake - that's application responsibility.

Parameters
clientWebSocket client instance
urlWebSocket server URL (e.g., "ws://localhost:27226")
crypto_ctxCryptographic context for encrypted connections
Returns
acip_transport_t pointer on success, NULL on failure
Note
The returned transport is owned by websocket_client_t
Call websocket_client_is_active() after connecting to verify success

Delegates to acip_websocket_client_transport_create() which handles:

  • URL parsing and validation
  • WebSocket handshake
  • Transport setup and lifecycle

Definition at line 177 of file lib/network/websocket/client.c.

178 {
179 if (!client || !url) {
180 log_error("Invalid arguments to websocket_client_connect");
181 return NULL;
182 }
183
184 log_info("Connecting WebSocket client to %s", url);
185
186 // Store URL for reference
187 SAFE_STRNCPY(client->url, url, sizeof(client->url));
188
189 // Create transport using ACIP layer
190 acip_transport_t *transport = acip_websocket_client_transport_create("client", url, crypto_ctx);
191 if (!transport) {
192 log_error("Failed to create WebSocket transport");
193 atomic_store_bool(&client->connection_lost, true);
194 return NULL;
195 }
196
197 // Derive client ID from URL hash using FNV-1a (proper implementation with 64-bit arithmetic)
198 // This provides a stable, unique ID per connection URL without undefined behavior
199 client->my_client_id = fnv1a_hash_string(url);
200
201 // Update registration name now that we have a client ID
202 {
203 char client_name[64];
204 SAFE_SNPRINTF(client_name, sizeof(client_name), "websocket_client_%u", client->my_client_id);
205 named_update_name((uintptr_t)client, client_name);
206 }
207
208 // Mark encryption as enabled if crypto context provided
209 client->encryption_enabled = (crypto_ctx != NULL);
210
211 // Store transport and mark as active
212 client->transport = transport;
213 atomic_store_bool(&client->connection_active, true);
214 atomic_store_bool(&client->connection_lost, false);
215
216 log_info("WebSocket client connected to %s (ID: %u)", url, client->my_client_id);
217
218 return transport;
219}
#define SAFE_STRNCPY(dst, src, size)
Definition common.h:414
#define SAFE_SNPRINTF(buffer, buffer_size,...)
Definition common.h:492
const char * named_update_name(uintptr_t key, const char *new_base_name)
Update the registered name for a resource with a new base name.
#define log_info(...)
Log an INFO message.
Definition log/log.h:561
acip_transport_t * acip_websocket_client_transport_create(const char *name, const char *url, crypto_context_t *crypto_ctx)
Create WebSocket client transport.

References acip_websocket_client_transport_create(), atomic_store_bool(), log_error, log_info, named_update_name(), SAFE_SNPRINTF, and SAFE_STRNCPY.

Referenced by connection_attempt_tcp(), and connection_attempt_websocket().

◆ websocket_client_create()

websocket_client_t * websocket_client_create ( const char *  name)

Create and initialize a named WebSocket client instance.

Parameters
nameDebug name for the WebSocket client

Allocates a new websocket_client_t structure and initializes all fields to safe defaults. The transport remains NULL until websocket_client_connect() is called. The client is automatically registered with the debug naming system.

Returns
Pointer to initialized client, or NULL on failure
Note
Caller must call websocket_client_destroy() when done
See also
websocket_client_destroy() For proper cleanup

Create and initialize a named WebSocket client instance.

Definition at line 27 of file lib/network/websocket/client.c.

27 {
28 if (!name) {
29 log_error("WebSocket client name is required");
30 return NULL;
31 }
32
34 if (!client) {
35 log_error("Failed to allocate websocket_client_t");
36 return NULL;
37 }
38
39 // Zero-initialize all fields
40 memset(client, 0, sizeof(*client));
41
42 // Initialize connection state
43 atomic_store_bool(&client->connection_active, false);
44 atomic_store_bool(&client->connection_lost, false);
45 client->transport = NULL;
46 client->my_client_id = 0;
47 client->encryption_enabled = false;
48 atomic_store_bool(&client->should_reconnect, false);
49
50 // Initialize thread-safe mutex for packet transmission
51 if (mutex_init(&client->send_mutex, "client_send") != 0) {
52 log_error("Failed to initialize send_mutex");
53 SAFE_FREE(client);
54 return NULL;
55 }
56
57 // Register WebSocket client with debug naming system
58 NAMED_REGISTER_WEBSOCKET(client, name, NULL);
59
60 // Register atomic fields for sync state monitoring - descriptive names showing control purpose
61 NAMED_REGISTER_ATOMIC(&client->connection_active, "connection_is_active", (uintptr_t)(const void *)(client));
62 NAMED_REGISTER_ATOMIC(&client->connection_lost, "connection_was_lost", (uintptr_t)(const void *)(client));
63 NAMED_REGISTER_ATOMIC(&client->should_reconnect, "needs_reconnection_attempt", (uintptr_t)(const void *)(client));
64
65 log_debug("WebSocket client created");
66
67 return client;
68}
#define SAFE_FREE(ptr)
Definition common.h:376
#define SAFE_MALLOC(size, cast)
Definition common.h:264
#define NAMED_REGISTER_ATOMIC(a, name, parent_ptr)
Register an atomic_t with automatic format specifier.
#define NAMED_REGISTER_WEBSOCKET(websocket, name, parent_ptr)
Register a WebSocket connection with automatic format specifier.
int mutex_init(mutex_t *mutex, const char *name)
Initialize a mutex with a name.
Definition threading.c:16

References atomic_store_bool(), log_debug, log_error, mutex_init(), NAMED_REGISTER_ATOMIC, NAMED_REGISTER_WEBSOCKET, SAFE_FREE, and SAFE_MALLOC.

Referenced by connection_attempt_tcp(), and connection_attempt_websocket().

◆ websocket_client_destroy()

void websocket_client_destroy ( websocket_client_t **  client_ptr)

Destroy WebSocket client and free all resources.

Destroys the transport and frees the client structure. Must be called AFTER the transport is no longer in use.

Parameters
client_ptrPointer to client pointer (set to NULL after free)
Warning
All operations on transport must be complete before calling
Note
No-op if client_ptr is NULL or *client_ptr is NULL

Destroy WebSocket client and free all resources.

Definition at line 73 of file lib/network/websocket/client.c.

73 {
74 if (!client_ptr || !*client_ptr) {
75 return; // No-op if NULL
76 }
77
78 websocket_client_t *client = *client_ptr;
79
80 log_debug("Destroying WebSocket client");
81
82 // Note: Do NOT destroy the transport. The transport is created and owned by the
83 // connection layer (acip_websocket_client_transport_create). The WebSocket client
84 // is just a thin wrapper that holds a reference. The transport will be destroyed
85 // by the connection context or server connection cleanup code.
86 client->transport = NULL;
87
88 // Unregister atomic fields
89 NAMED_UNREGISTER(&client->connection_active);
90 NAMED_UNREGISTER(&client->connection_lost);
91 NAMED_UNREGISTER(&client->should_reconnect);
92
93 NAMED_UNREGISTER(client);
94
95 // Destroy mutex
96 mutex_destroy(&client->send_mutex);
97
98 SAFE_FREE(*client_ptr);
99}
#define NAMED_UNREGISTER(ptr)
Unregister a pointer.
int mutex_destroy(mutex_t *mutex)
Destroy a mutex.
Definition threading.c:22

References log_debug, mutex_destroy(), NAMED_UNREGISTER, and SAFE_FREE.

Referenced by connection_attempt_tcp(), and connection_attempt_websocket().

◆ websocket_client_disable_encryption()

void websocket_client_disable_encryption ( websocket_client_t *  client)

Disable encryption for this connection.

Parameters
clientWebSocket client instance

◆ websocket_client_enable_encryption()

void websocket_client_enable_encryption ( websocket_client_t *  client)

Enable encryption for this connection.

Parameters
clientWebSocket client instance

◆ websocket_client_get_id()

uint32_t websocket_client_get_id ( const websocket_client_t *  client)

Get the client's unique ID.

Parameters
clientWebSocket client instance
Returns
Client ID, or 0 if not set
Note
Equivalent to tcp_client_get_id() for API compatibility

Definition at line 291 of file lib/network/websocket/client.c.

291 {
292 return client ? client->my_client_id : 0;
293}

◆ websocket_client_get_transport()

acip_transport_t * websocket_client_get_transport ( const websocket_client_t *  client)

Get active transport instance.

Parameters
clientWebSocket client instance
Returns
acip_transport_t pointer or NULL if not connected

Definition at line 224 of file lib/network/websocket/client.c.

224 {
225 if (!client) {
226 return NULL;
227 }
228 return client->transport;
229}

◆ websocket_client_is_active()

bool websocket_client_is_active ( const websocket_client_t *  client)

Check if connection is currently active.

Parameters
clientWebSocket client instance
Returns
true if connection is active, false otherwise

Definition at line 104 of file lib/network/websocket/client.c.

104 {
105 if (!client) {
106 return false;
107 }
108 return atomic_load_bool(&client->connection_active);
109}
bool atomic_load_bool(atomic_t *a)
Atomically load a boolean value.
Definition atomic.c:169

References atomic_load_bool().

◆ websocket_client_is_encrypted()

bool websocket_client_is_encrypted ( const websocket_client_t *  client)

Check if encryption is enabled for this connection.

Parameters
clientWebSocket client instance
Returns
true if encryption is enabled, false otherwise

Definition at line 298 of file lib/network/websocket/client.c.

298 {
299 if (!client)
300 return false;
301 return client->encryption_enabled;
302}

◆ websocket_client_is_encryption_enabled()

bool websocket_client_is_encryption_enabled ( const websocket_client_t *  client)

Check if encryption is enabled.

Parameters
clientWebSocket client instance
Returns
true if encryption is enabled, false otherwise

◆ websocket_client_is_lost()

bool websocket_client_is_lost ( const websocket_client_t *  client)

Check if connection was lost.

Parameters
clientWebSocket client instance
Returns
true if connection loss was detected, false otherwise

Definition at line 114 of file lib/network/websocket/client.c.

114 {
115 if (!client) {
116 return false;
117 }
118 return atomic_load_bool(&client->connection_lost);
119}

References atomic_load_bool().

◆ websocket_client_send_packet()

int websocket_client_send_packet ( websocket_client_t *  client,
packet_type_t  type,
const void *  data,
size_t  len 
)

Send a packet through WebSocket connection (thread-safe)

Acquires send_mutex, transmits packet, releases mutex. Checks connection state before sending.

Parameters
clientWebSocket client instance
typePacket type to send
dataPacket payload (NULL for empty packets)
lenPayload length in bytes
Returns
0 on success, -1 on failure
Note
Equivalent to tcp_client_send_packet() for API compatibility
Thread-safe: multiple threads can call concurrently

Acquires send_mutex, transmits packet via transport, releases mutex. Checks connection state before sending.

Definition at line 237 of file lib/network/websocket/client.c.

237 {
238 if (!client) {
239 return SET_ERRNO(ERROR_INVALID_PARAM, "NULL client");
240 }
241
242 if (!atomic_load_bool(&client->connection_active)) {
243 return SET_ERRNO(ERROR_NETWORK, "Connection not active");
244 }
245
246 if (!client->transport) {
247 return SET_ERRNO(ERROR_NETWORK, "No active transport");
248 }
249
250 // Acquire send mutex for thread-safe transmission
251 mutex_lock(&client->send_mutex);
252
253 // Send packet through transport with client ID
254 asciichat_error_t result = packet_send_via_transport(client->transport, type, data, len, client->my_client_id);
255
256 mutex_unlock(&client->send_mutex);
257
258 if (result != ASCIICHAT_OK) {
259 log_debug("Failed to send packet type %d: %s", type, asciichat_error_string(result));
260 return -1;
261 }
262
263 return 0;
264}
#define SET_ERRNO(code, context_msg,...)
Set error code with custom context message and log it, returning the error code.
asciichat_error_t
Error and exit codes - unified status values (0-255)
Definition error_codes.h:49
@ ERROR_NETWORK
Definition error_codes.h:77
@ ASCIICHAT_OK
Definition error_codes.h:51
@ ERROR_INVALID_PARAM
#define mutex_lock(mutex)
Lock a mutex (with debug tracking in debug builds)
#define mutex_unlock(mutex)
Unlock a mutex (with debug tracking in debug builds)
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)
Send packet via transport with proper header (exported for generic wrappers)
Definition send.c:41

References ASCIICHAT_OK, atomic_load_bool(), ERROR_INVALID_PARAM, ERROR_NETWORK, log_debug, mutex_lock, mutex_unlock, packet_send_via_transport(), and SET_ERRNO.

Referenced by websocket_client_send_ping(), and websocket_client_send_pong().

◆ websocket_client_send_ping()

int websocket_client_send_ping ( websocket_client_t *  client)

Send ping frame (keepalive heartbeat)

Routes through websocket_client_send_packet() with PACKET_TYPE_PING.

Parameters
clientWebSocket client instance
Returns
0 on success, -1 on failure
Note
Equivalent to tcp_client_send_ping() for API compatibility

Routes through websocket_client_send_packet() with PACKET_TYPE_PING.

Definition at line 271 of file lib/network/websocket/client.c.

271 {
272 if (!client)
273 return -1;
274 return websocket_client_send_packet(client, PACKET_TYPE_PING, NULL, 0);
275}
@ PACKET_TYPE_PING
Keepalive ping packet.
Definition packet.h:383
int websocket_client_send_packet(websocket_client_t *client, packet_type_t type, const void *data, size_t len)
Send a packet through WebSocket connection (thread-safe)

References PACKET_TYPE_PING, and websocket_client_send_packet().

◆ websocket_client_send_pong()

int websocket_client_send_pong ( websocket_client_t *  client)

Send pong frame (keepalive response)

Routes through websocket_client_send_packet() with PACKET_TYPE_PONG.

Parameters
clientWebSocket client instance
Returns
0 on success, -1 on failure
Note
Equivalent to tcp_client_send_pong() for API compatibility

Routes through websocket_client_send_packet() with PACKET_TYPE_PONG.

Definition at line 282 of file lib/network/websocket/client.c.

282 {
283 if (!client)
284 return -1;
285 return websocket_client_send_packet(client, PACKET_TYPE_PONG, NULL, 0);
286}
@ PACKET_TYPE_PONG
Keepalive pong response.
Definition packet.h:385

References PACKET_TYPE_PONG, and websocket_client_send_packet().

◆ websocket_client_should_reconnect()

bool websocket_client_should_reconnect ( const websocket_client_t *  client)

Check if reconnection should be attempted.

Parameters
clientWebSocket client instance
Returns
true if reconnection is needed, false otherwise

◆ websocket_client_shutdown()

void websocket_client_shutdown ( websocket_client_t *  client)

Shutdown connection forcefully (for signal handlers)

Parameters
clientWebSocket client instance

Shutdown connection forcefully (for signal handlers)

Definition at line 153 of file lib/network/websocket/client.c.

153 {
154 if (!client) {
155 return;
156 }
157
158 log_debug("Shutting down WebSocket client");
159
160 // Force close the transport
161 if (client->transport) {
162 acip_transport_close(client->transport);
163 }
164
165 atomic_store_bool(&client->connection_active, false);
166 atomic_store_bool(&client->connection_lost, true);
167}

References atomic_store_bool(), and log_debug.

◆ websocket_client_signal_lost()

void websocket_client_signal_lost ( websocket_client_t *  client)

Signal that connection was lost (triggers reconnection)

Parameters
clientWebSocket client instance

Signal that connection was lost (triggers reconnection)

Definition at line 124 of file lib/network/websocket/client.c.

124 {
125 if (!client) {
126 return;
127 }
128 atomic_store_bool(&client->connection_lost, true);
129 atomic_store_bool(&client->connection_active, false);
130 log_debug("WebSocket connection marked as lost");
131}

References atomic_store_bool(), and log_debug.

◆ websocket_client_signal_reconnect()

void websocket_client_signal_reconnect ( websocket_client_t *  client)

Signal that reconnection should be attempted.

Parameters
clientWebSocket client instance