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

Connection state machine and attempt logic for TCP/WebSocket clients. More...

Go to the source code of this file.

Data Structures

struct  connection_attempt_context_t
 Context for connection attempts (TCP or WebSocket) More...
 

Macros

#define CONN_TIMEOUT_TCP   (3LL * NS_PER_SEC_INT)
 TCP/WebSocket timeout (3s)
 

Enumerations

enum  connection_state_t {
  CONN_STATE_IDLE = 0 , CONN_STATE_ATTEMPTING = 1 , CONN_STATE_CONNECTED = 2 , CONN_STATE_DISCONNECTED = 3 ,
  CONN_STATE_FAILED = 4
}
 Simple TCP connection state machine. More...
 

Functions

asciichat_error_t connection_context_init (connection_attempt_context_t *ctx)
 Initialize connection attempt context.
 
asciichat_error_t connection_state_transition (connection_attempt_context_t *ctx, connection_state_t new_state)
 Transition to next connection state.
 
bool connection_check_timeout (const connection_attempt_context_t *ctx)
 Check if connection attempt has exceeded timeout.
 
const char * connection_state_name (connection_state_t state)
 Get human-readable state name for logging.
 
void connection_context_cleanup (connection_attempt_context_t *ctx)
 Cleanup connection attempt context.
 
asciichat_error_t connection_attempt_tcp (connection_attempt_context_t *ctx, const char *server_address, uint16_t server_port)
 Attempt TCP connection.
 
asciichat_error_t connection_attempt_websocket (connection_attempt_context_t *ctx, const char *ws_url)
 Attempt WebSocket connection.
 

Detailed Description

Connection state machine and attempt logic for TCP/WebSocket clients.

Implements direct TCP and WebSocket connections for client mode. Manages connection state transitions, timeouts, and transport lifecycle.

Features:

  • Direct TCP connection to server
  • WebSocket connection support (ws:// and wss://)
  • Timeout management
  • Crypto handshake integration (when encryption enabled)
  • ACIP transport creation
  • Proper resource cleanup

Integration Points:

  • Called from src/client/main.c connection loop
  • Returns active transport when connection succeeds
  • Uses crypto subsystem for optional encryption/authentication
Date
January 2026
Version
2.0

Definition in file connection_attempt.h.

Macro Definition Documentation

◆ CONN_TIMEOUT_TCP

#define CONN_TIMEOUT_TCP   (3LL * NS_PER_SEC_INT)

TCP/WebSocket timeout (3s)

Definition at line 65 of file connection_attempt.h.

Enumeration Type Documentation

◆ connection_state_t

Simple TCP connection state machine.

States:

  • IDLE: Not connected, no attempt in progress
  • ATTEMPTING: TCP/WebSocket connection in progress
  • CONNECTED: Successfully connected
  • DISCONNECTED: Clean disconnect (user initiated)
  • FAILED: Connection attempt failed
Enumerator
CONN_STATE_IDLE 

Not connected, no attempt in progress.

CONN_STATE_ATTEMPTING 

Attempting connection.

CONN_STATE_CONNECTED 

Successfully connected.

CONN_STATE_DISCONNECTED 

Clean disconnect (user initiated)

CONN_STATE_FAILED 

Connection attempt failed.

Definition at line 53 of file connection_attempt.h.

53 {
54 CONN_STATE_IDLE = 0,
connection_state_t
Simple TCP connection state machine.
@ CONN_STATE_CONNECTED
Successfully connected.
@ CONN_STATE_IDLE
Not connected, no attempt in progress.
@ CONN_STATE_DISCONNECTED
Clean disconnect (user initiated)
@ CONN_STATE_FAILED
Connection attempt failed.
@ CONN_STATE_ATTEMPTING
Attempting connection.

Function Documentation

◆ connection_attempt_tcp()

asciichat_error_t connection_attempt_tcp ( connection_attempt_context_t *  ctx,
const char *  server_address,
uint16_t  server_port 
)

Attempt TCP connection.

Attempts a direct TCP connection to the specified server. On success, sets the transport in the context handle.

Handles:

  • WebSocket URL detection (ws:// or wss://)
  • TCP connection and handshake
  • Crypto initialization and handshake (when encryption enabled)
  • ACIP transport creation
Parameters
ctxConnection context (initialized via connection_context_init)
server_addressServer hostname, IP address, or WebSocket URL
server_portServer port number (ignored if server_address is WebSocket URL)
Returns
ASCIICHAT_OK on successful connection
ERROR_* code on failure
Note
ctx.connection.transport will be set to the transport on success
ctx.current_state will be set to CONN_STATE_CONNECTED on success

Attempt TCP connection.

Connects to server via TCP, performs crypto handshake if enabled, and creates ACIP transport for protocol communication.

Definition at line 168 of file connection_attempt.c.

169 {
170 log_info("=== connection_attempt_tcp CALLED: address='%s', port=%u ===", server_address, server_port);
171
172 if (!ctx || !server_address) {
173 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid parameters");
174 }
175
176 // Check if shutdown was requested before attempting connection (via callback if available)
178 return SET_ERRNO(ERROR_NETWORK, "Connection attempt aborted due to shutdown request");
179 }
180
181 // Normalize the endpoint once so TCP and WebSocket paths use the same rules.
182 connection_endpoint_t endpoint = {0};
183 asciichat_error_t endpoint_result = connection_endpoint_resolve(server_address, server_port, &endpoint);
184 if (endpoint_result != ASCIICHAT_OK) {
185 return endpoint_result;
186 }
187
188 log_debug("connection_attempt_tcp: server_address='%s', normalized=%s host=%s port=%u", server_address,
189 connection_endpoint_protocol_name(endpoint.protocol), endpoint.host, endpoint.port);
190
191 if (endpoint.protocol == CONNECTION_ENDPOINT_WEBSOCKET) {
192 // WebSocket connection path
193 const char *ws_url = endpoint.input;
194
195 // Set server IP/port for crypto handshake known_hosts verification
198 log_debug("Set server IP=%s, port=%u for WebSocket crypto handshake", endpoint.host, endpoint.port);
199
200 log_info("Attempting WebSocket connection to %s", ws_url);
201
202 // Transition to attempting state
204 if (result != ASCIICHAT_OK) {
205 return result;
206 }
207
208 // Set timeout for this attempt
210 ctx->timeout_ns = CONN_TIMEOUT_TCP; // Use same timeout as TCP
211
212 // Compute crypto mode from CLI options
213 // Determine if client has authentication material (keys or password)
214 bool has_auth_material =
215 (GET_OPTION(encrypt_key)[0] != '\0' || GET_OPTION(num_identity_keys) > 0 || GET_OPTION(password)[0] != '\0');
216 bool no_encrypt = GET_OPTION(no_encrypt);
217 bool no_auth = GET_OPTION(no_auth);
218
219 uint8_t crypto_mode;
220 if (!no_encrypt && !no_auth && !has_auth_material)
221 crypto_mode = ACIP_CRYPTO_ENCRYPT; // default: encrypt only
222 else if (!no_encrypt && !no_auth && has_auth_material)
223 crypto_mode = ACIP_CRYPTO_FULL; // full: encrypt + auth
224 else if (no_encrypt && !no_auth && has_auth_material)
225 crypto_mode = ACIP_CRYPTO_AUTH; // auth-only mode
226 else
227 crypto_mode = ACIP_CRYPTO_NONE; // no crypto
228
229 log_debug("WebSocket crypto mode computed: 0x%02x (encrypt=%d, auth=%d)", crypto_mode,
230 ACIP_CRYPTO_HAS_ENCRYPT(crypto_mode), ACIP_CRYPTO_HAS_AUTH(crypto_mode));
231
232 // Set crypto mode before initialization via callback
233 // NOTE: Always initialize crypto context, even in NONE mode!
234 // The server always sends KEY_EXCHANGE_INIT packets, and the context
235 // must be initialized to handle them (even if in disabled/none mode).
236 const crypto_context_t *crypto_ctx = NULL;
237
238 log_debug("Initializing crypto context for WebSocket with mode 0x%02x...", crypto_mode);
239
241
243 log_error("Failed to initialize crypto context");
244 return SET_ERRNO(ERROR_CRYPTO, "Crypto initialization failed");
245 }
246 log_debug("Crypto context initialized successfully");
247
248 // Get crypto context if ready
251 }
252
253 // Create WebSocket client instance
254 websocket_client_t *ws_client = websocket_client_create("discovery_connection");
255 if (!ws_client) {
256 log_error("Failed to create WebSocket client");
258 return SET_ERRNO(ERROR_NETWORK, "WebSocket client creation failed");
259 }
260
261 // Connect via WebSocket
262 acip_transport_t *transport = websocket_client_connect(ws_client, ws_url, (crypto_context_t *)crypto_ctx);
263 if (!transport) {
264 log_error("Failed to create WebSocket ACIP transport");
265 websocket_client_destroy(&ws_client);
267 return SET_ERRNO(ERROR_NETWORK, "WebSocket connection failed");
268 }
269
270 // CRITICAL: Wait for the WebSocket handshake to actually complete
271 // The transport is created but the TLS/crypto handshake happens in the service thread
272 log_info("WebSocket transport created, waiting for TLS handshake completion...");
273 const int MAX_HANDSHAKE_WAIT_ITERATIONS = 300; // 300 * 50ms = 15 seconds
274 int handshake_wait_count = 0;
275 while (!acip_transport_is_connected(transport) && handshake_wait_count < MAX_HANDSHAKE_WAIT_ITERATIONS) {
276 platform_sleep_us(50000); // Sleep 50ms between checks
277 handshake_wait_count++;
278 if (handshake_wait_count % 20 == 0) {
279 log_info("WebSocket handshake waiting... (%d seconds elapsed)", handshake_wait_count / 20);
280 }
281 }
282
283 if (!acip_transport_is_connected(transport)) {
284 log_error("WebSocket TLS handshake failed or timed out after 15 seconds");
285 websocket_client_destroy(&ws_client);
287 return SET_ERRNO(ERROR_NETWORK, "WebSocket handshake timeout");
288 }
289
290 log_info("WebSocket connection established to %s", ws_url);
292 ctx->connection.transport = transport;
294 ctx->connection.owner = ws_client;
295 ctx->connection.owner_destroy = destroy_websocket_client_owner;
296
297 return ASCIICHAT_OK;
298 }
299
300 // TCP connection path (original logic)
301 log_info("Attempting TCP connection to %s:%u (3s timeout)", endpoint.host, endpoint.port);
302
303 // Transition to attempting state
305 if (result != ASCIICHAT_OK) {
306 return result;
307 }
308
309 // Create TCP client internally so connection ownership stays in this layer.
311 if (!tcp_client) {
312 log_error("Failed to create TCP client");
314 return SET_ERRNO(ERROR_NETWORK, "TCP client creation failed");
315 }
316
317 // Set timeout for this attempt
320
321 // Attempt TCP connection (reconnect_attempt is 0-based, convert for tcp_client_connect)
322 // Use effective_address/port which may be parsed from tcp:// URL scheme
323 int tcp_result = tcp_client_connect(tcp_client, endpoint.host, endpoint.port, (int)ctx->reconnect_attempt,
324 ctx->reconnect_attempt == 0, ctx->reconnect_attempt > 0);
325
326 if (tcp_result != 0) {
327 log_debug("TCP connection failed (tcp_client_connect returned %d)", tcp_result);
330 return SET_ERRNO(ERROR_NETWORK, "TCP connection failed after %u attempts", ctx->reconnect_attempt);
331 }
332
333 // Extract socket from TCP client for crypto handshake
335 if (sockfd == INVALID_SOCKET_VALUE) {
336 log_error("Failed to get socket from TCP client");
338 return SET_ERRNO(ERROR_NETWORK, "Invalid socket after TCP connection");
339 }
340
341 // Note: TCP client stores server IP in tcp_client->server_ip for potential crypto context use
342 if (tcp_client->server_ip[0] != '\0') {
343 log_debug("Server IP available from TCP client: %s", tcp_client->server_ip);
345 } else {
346 log_warn("TCP client did not populate server_ip field");
347 }
348
349 // Compute crypto mode from CLI options
350 // Determine if client has authentication material (keys or password)
351 bool has_auth_material =
352 (GET_OPTION(encrypt_key)[0] != '\0' || GET_OPTION(num_identity_keys) > 0 || GET_OPTION(password)[0] != '\0');
353 bool no_encrypt = GET_OPTION(no_encrypt);
354 bool no_auth = GET_OPTION(no_auth);
355
356 uint8_t crypto_mode;
357 if (!no_encrypt && !no_auth && !has_auth_material)
358 crypto_mode = ACIP_CRYPTO_ENCRYPT; // default: encrypt only
359 else if (!no_encrypt && !no_auth && has_auth_material)
360 crypto_mode = ACIP_CRYPTO_FULL; // full: encrypt + auth
361 else if (no_encrypt && !no_auth && has_auth_material)
362 crypto_mode = ACIP_CRYPTO_AUTH; // auth-only mode
363 else
364 crypto_mode = ACIP_CRYPTO_NONE; // no crypto
365
366 log_debug("TCP crypto mode computed: 0x%02x (encrypt=%d, auth=%d)", crypto_mode, ACIP_CRYPTO_HAS_ENCRYPT(crypto_mode),
367 ACIP_CRYPTO_HAS_AUTH(crypto_mode));
368
369 // Setup crypto operations via callbacks
370 const crypto_context_t *crypto_ctx = NULL;
371 acip_transport_t *transport = NULL;
372
373 if (crypto_mode != ACIP_CRYPTO_NONE) {
375
376 // Initialize crypto context if mode requires handshake (not ACIP_CRYPTO_NONE)
377 // This must happen AFTER setting server IP, as crypto init reads server IP/port
378 log_debug("Initializing crypto context...");
380 log_error("Failed to initialize crypto context");
382 return SET_ERRNO(ERROR_CRYPTO, "Crypto initialization failed");
383 }
384 log_debug("Crypto context initialized successfully");
385
386 // Create transport before handshake (starts with NULL crypto, set after)
387 transport = acip_tcp_transport_create("connection", sockfd, NULL);
388 if (!transport) {
389 log_error("Failed to create ACIP transport for TCP");
391 return SET_ERRNO(ERROR_NETWORK, "Failed to create ACIP transport");
392 }
393
394 // Perform crypto handshake with server
395 log_debug("Performing crypto handshake with server...");
397 log_error("Crypto handshake failed");
398 acip_transport_destroy(transport);
400 return SET_ERRNO(ERROR_NETWORK, "Crypto handshake failed");
401 }
402 log_debug("Crypto handshake completed successfully");
403
404 // Get crypto context after handshake and set it on the transport
407 transport->crypto_ctx = (crypto_context_t *)crypto_ctx;
408 }
409 } else {
410 // No crypto — create transport without encryption
411 transport = acip_tcp_transport_create("connection", sockfd, NULL);
412 if (!transport) {
413 log_error("Failed to create ACIP transport for TCP");
415 return SET_ERRNO(ERROR_NETWORK, "Failed to create ACIP transport");
416 }
417 }
418
419 log_info("TCP connection established to %s:%u", endpoint.host, endpoint.port);
421 ctx->connection.transport = transport;
424 ctx->connection.owner_destroy = destroy_tcp_client_owner;
425 log_debug("TCP owner stored in connection context for cleanup");
426
427 return ASCIICHAT_OK;
428}
#define APP_CALLBACK_PTR(callback_name)
#define APP_CALLBACK_BOOL(callback_name)
#define APP_CALLBACK_VOID_INT(callback_name, value)
#define APP_CALLBACK_INT(callback_name)
#define APP_CALLBACK_INT_TRANSPORT(callback_name, transport)
#define APP_CALLBACK_VOID_UINT8(callback_name, value)
#define APP_CALLBACK_VOID_STR(callback_name, value)
void tcp_client_t
asciichat_error_t connection_state_transition(connection_attempt_context_t *ctx, connection_state_t new_state)
Transition to next connection state with validation.
#define CONN_TIMEOUT_TCP
TCP/WebSocket timeout (3s)
asciichat_error_t connection_endpoint_resolve(const char *input, uint16_t default_port, connection_endpoint_t *endpoint_out)
const char * connection_endpoint_protocol_name(connection_endpoint_protocol_t protocol)
@ CONNECTION_ENDPOINT_WEBSOCKET
void server_connection_set_ip(const char *ip)
Set the server IP address.
void server_connection_set_port(int port)
Set the server port.
const crypto_context_t * crypto_client_get_context(void)
Get crypto context for encryption/decryption.
int client_crypto_handshake(acip_transport_t *transport)
Perform crypto handshake with server.
void client_crypto_set_mode(uint8_t mode)
Set crypto mode for handshake (encryption + authentication)
int client_crypto_init(void)
Initialize client crypto handshake.
bool crypto_client_is_ready(void)
Check if crypto handshake is ready.
unsigned char uint8_t
Definition common.h:56
#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_CRYPTO
Definition error_codes.h:96
@ ERROR_INVALID_PARAM
#define log_warn(...)
Log a WARN message.
Definition log/log.h:574
#define log_error(...)
Log an ERROR message.
Definition log/log.h:587
#define log_info(...)
Log an INFO message.
Definition log/log.h:561
#define log_debug(...)
Log a DEBUG message.
Definition log/log.h:548
uint64_t time_get_realtime_ns(void)
Get current wall-clock (real) time in nanoseconds.
Definition util/time.c:119
#define ACIP_CRYPTO_NONE
No encryption, no authentication (plaintext only)
Definition packet.h:1082
#define ACIP_CRYPTO_HAS_AUTH(mode)
Check if crypto mode includes authentication.
Definition packet.h:1099
#define ACIP_CRYPTO_HAS_ENCRYPT(mode)
Check if crypto mode includes payload encryption.
Definition packet.h:1092
#define ACIP_CRYPTO_ENCRYPT
Encryption only (no identity verification)
Definition packet.h:1083
#define ACIP_CRYPTO_AUTH
Authentication only (no payload encryption)
Definition packet.h:1084
#define ACIP_CRYPTO_FULL
Full crypto: encryption + authentication.
Definition packet.h:1085
#define GET_OPTION(field)
Safely get a specific option field (lock-free read)
#define INVALID_SOCKET_VALUE
Invalid socket value (POSIX: -1)
Definition socket.h:278
void platform_sleep_us(unsigned int us)
High-precision sleep function with microsecond precision.
int socket_t
tcp_client_t * tcp_client_create(void)
Create and initialize TCP client.
socket_t tcp_client_get_socket(const tcp_client_t *client)
Get current socket descriptor.
int tcp_client_connect(tcp_client_t *client, const char *address, int port, int reconnect_attempt, bool first_connection, bool has_ever_connected)
Establish TCP connection to server.
void tcp_client_destroy(tcp_client_t **client_ptr)
Destroy TCP client and free resources.
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_destroy(websocket_client_t **client_ptr)
Destroy WebSocket client and free resources.
bool should_exit(void)
Definition misc.c:131
struct websocket_client_t websocket_client_t
Transport instance structure.
Definition transport.h:214
crypto_context_t * crypto_ctx
Optional encryption context.
Definition transport.h:216
uint32_t reconnect_attempt
Reconnection attempt number (1st, 2nd, etc.)
uint64_t timeout_ns
Timeout for connection attempt.
uint64_t attempt_start_time_ns
When current attempt began.
connection_handle_t connection
Shared transport/client ownership handle.
connection_endpoint_protocol_t protocol
acip_transport_t * transport
void(* owner_destroy)(void *owner)
acip_transport_type_t transport_type
Cryptographic context structure.
TCP client connection state (network-layer only)
acip_transport_t * acip_tcp_transport_create(const char *name, socket_t sockfd, crypto_context_t *crypto_ctx)
Create TCP transport from existing socket.
void acip_transport_destroy(acip_transport_t *transport)
Destroy transport and free all resources.
@ ACIP_TRANSPORT_TCP
Raw TCP socket.
Definition transport.h:94
@ ACIP_TRANSPORT_WEBSOCKET
WebSocket over TCP.
Definition transport.h:95

References ACIP_CRYPTO_AUTH, ACIP_CRYPTO_ENCRYPT, ACIP_CRYPTO_FULL, ACIP_CRYPTO_HAS_AUTH, ACIP_CRYPTO_HAS_ENCRYPT, ACIP_CRYPTO_NONE, acip_tcp_transport_create(), acip_transport_destroy(), ACIP_TRANSPORT_TCP, ACIP_TRANSPORT_WEBSOCKET, APP_CALLBACK_BOOL, APP_CALLBACK_INT, APP_CALLBACK_INT_TRANSPORT, APP_CALLBACK_PTR, APP_CALLBACK_VOID_INT, APP_CALLBACK_VOID_STR, APP_CALLBACK_VOID_UINT8, ASCIICHAT_OK, connection_attempt_context_t::attempt_start_time_ns, client_crypto_handshake(), client_crypto_init(), client_crypto_set_mode(), CONN_STATE_ATTEMPTING, CONN_STATE_CONNECTED, CONN_STATE_FAILED, CONN_TIMEOUT_TCP, connection_attempt_context_t::connection, connection_endpoint_protocol_name(), connection_endpoint_resolve(), CONNECTION_ENDPOINT_WEBSOCKET, connection_state_transition(), crypto_client_get_context(), crypto_client_is_ready(), acip_transport::crypto_ctx, ERROR_CRYPTO, ERROR_INVALID_PARAM, ERROR_NETWORK, GET_OPTION, connection_endpoint_t::host, connection_endpoint_t::input, INVALID_SOCKET_VALUE, log_debug, log_error, log_info, log_warn, connection_handle_t::owner, connection_handle_t::owner_destroy, platform_sleep_us(), connection_endpoint_t::port, connection_endpoint_t::protocol, connection_attempt_context_t::reconnect_attempt, server_connection_set_ip(), server_connection_set_port(), tcp_client::server_ip, SET_ERRNO, should_exit(), tcp_client_connect(), tcp_client_create(), tcp_client_destroy(), tcp_client_get_socket(), time_get_realtime_ns(), connection_attempt_context_t::timeout_ns, connection_handle_t::transport, connection_handle_t::transport_type, websocket_client_connect(), websocket_client_create(), and websocket_client_destroy().

◆ connection_attempt_websocket()

asciichat_error_t connection_attempt_websocket ( connection_attempt_context_t *  ctx,
const char *  ws_url 
)

Attempt WebSocket connection.

Attempts a WebSocket connection to the specified server (ws:// or wss://). On success, sets the transport in the context handle.

Handles:

  • WebSocket URL parsing
  • Crypto initialization (when encryption enabled)
  • ACIP transport creation
Parameters
ctxConnection context (initialized via connection_context_init)
ws_urlWebSocket URL (e.g., "ws://localhost:27226" or "wss://server.com")
Returns
ASCIICHAT_OK on successful connection
ERROR_* code on failure
Note
ctx.connection.transport will be set to the WebSocket transport on success
ctx.current_state will be set to CONN_STATE_CONNECTED on success

Attempt WebSocket connection.

Connects to server via WebSocket, performs crypto handshake if enabled, and creates ACIP transport for protocol communication.

Definition at line 436 of file connection_attempt.c.

436 {
437 log_info("=== connection_attempt_websocket CALLED: url='%s' ===", ws_url);
438
439 if (!ctx || !ws_url) {
440 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid parameters");
441 }
442
443 // Check if shutdown was requested (via callback if available)
445 return SET_ERRNO(ERROR_NETWORK, "Connection attempt aborted due to shutdown request");
446 }
447
448 log_info("Attempting WebSocket connection to %s", ws_url);
449
450 // Transition to attempting state
452 if (result != ASCIICHAT_OK) {
453 return result;
454 }
455
456 // Set timeout for this attempt
459
460 // Initialize crypto context if encryption is enabled
461 const crypto_context_t *crypto_ctx = NULL;
462 if (!GET_OPTION(no_encrypt)) {
463 log_debug("Initializing crypto context for WebSocket...");
464
466 log_error("Failed to initialize crypto context");
467 return SET_ERRNO(ERROR_CRYPTO, "Crypto initialization failed");
468 }
469 log_debug("Crypto context initialized successfully");
470
471 // Get crypto context if ready
474 }
475 }
476
477 // Create WebSocket client instance
478 websocket_client_t *ws_client = websocket_client_create("connection");
479 if (!ws_client) {
480 log_error("Failed to create WebSocket client");
482 return SET_ERRNO(ERROR_NETWORK, "WebSocket client creation failed");
483 }
484
485 // Connect via WebSocket
486 acip_transport_t *transport = websocket_client_connect(ws_client, ws_url, (crypto_context_t *)crypto_ctx);
487 if (!transport) {
488 log_error("Failed to create WebSocket ACIP transport");
489 websocket_client_destroy(&ws_client);
491 return SET_ERRNO(ERROR_NETWORK, "WebSocket connection failed");
492 }
493
494 log_info("WebSocket connection established to %s", ws_url);
496 ctx->connection.transport = transport;
498 ctx->connection.owner = ws_client;
499 ctx->connection.owner_destroy = destroy_websocket_client_owner;
500 log_debug("WebSocket owner stored in connection context");
501
502 return ASCIICHAT_OK;
503}

References ACIP_TRANSPORT_WEBSOCKET, APP_CALLBACK_BOOL, APP_CALLBACK_INT, APP_CALLBACK_PTR, ASCIICHAT_OK, connection_attempt_context_t::attempt_start_time_ns, client_crypto_init(), CONN_STATE_ATTEMPTING, CONN_STATE_CONNECTED, CONN_STATE_FAILED, CONN_TIMEOUT_TCP, connection_attempt_context_t::connection, connection_state_transition(), crypto_client_get_context(), crypto_client_is_ready(), ERROR_CRYPTO, ERROR_INVALID_PARAM, ERROR_NETWORK, GET_OPTION, log_debug, log_error, log_info, connection_handle_t::owner, connection_handle_t::owner_destroy, SET_ERRNO, should_exit(), time_get_realtime_ns(), connection_attempt_context_t::timeout_ns, connection_handle_t::transport, connection_handle_t::transport_type, websocket_client_connect(), websocket_client_create(), and websocket_client_destroy().

◆ connection_check_timeout()

bool connection_check_timeout ( const connection_attempt_context_t *  ctx)

Check if connection attempt has exceeded timeout.

Compares elapsed time since attempt start against timeout.

Parameters
ctxConnection context
Returns
true if timeout exceeded, false otherwise

Definition at line 141 of file connection_attempt.c.

141 {
142 if (!ctx)
143 return false;
144
146 bool timeout_exceeded = elapsed_ns > ctx->timeout_ns;
147
148 if (timeout_exceeded) {
149 char elapsed_str[32], timeout_str[32];
150 time_pretty(elapsed_ns, -1, elapsed_str, sizeof(elapsed_str));
151 time_pretty(ctx->timeout_ns, -1, timeout_str, sizeof(timeout_str));
152 log_warn("Connection timeout exceeded: elapsed %s > %s limit", elapsed_str, timeout_str);
153 }
154
155 return timeout_exceeded;
156}
unsigned long long uint64_t
Definition common.h:59
int time_pretty(uint64_t nanoseconds, int decimals, char *buffer, size_t buffer_size)
Format nanoseconds as pretty duration with spaces and configurable precision.
Definition util/time.c:424

References connection_attempt_context_t::attempt_start_time_ns, log_warn, time_get_realtime_ns(), time_pretty(), and connection_attempt_context_t::timeout_ns.

◆ connection_context_cleanup()

void connection_context_cleanup ( connection_attempt_context_t *  ctx)

Cleanup connection attempt context.

Closes and releases any active transports. Called on connection success, failure, or shutdown.

Parameters
ctxConnection context to cleanup

Definition at line 111 of file connection_attempt.c.

111 {
112 if (!ctx)
113 return;
114
116
117 log_debug("Connection context cleaned up");
118}
void connection_handle_cleanup(connection_handle_t *handle)

References connection_attempt_context_t::connection, connection_handle_cleanup(), and log_debug.

Referenced by client_main().

◆ connection_context_init()

asciichat_error_t connection_context_init ( connection_attempt_context_t *  ctx)

Initialize connection attempt context.

Sets up initial state, resets timeouts, and prepares for connection attempt.

Parameters
ctxConnection context to initialize
Returns
ASCIICHAT_OK on success, error code otherwise

Definition at line 82 of file connection_attempt.c.

82 {
83 if (!ctx) {
84 return SET_ERRNO(ERROR_INVALID_PARAM, "Context pointer is NULL");
85 }
86
87 // Reset context
88 memset(ctx, 0, sizeof(connection_attempt_context_t));
90
91 // Initialize state
94
95 // Initialize timeout
98
99 // Initialize counters
100 ctx->reconnect_attempt = 1;
101 ctx->total_transitions = 0;
102
103 log_debug("Connection context initialized");
104
105 return ASCIICHAT_OK;
106}
void connection_handle_init(connection_handle_t *handle)
Context for connection attempts (TCP or WebSocket)
connection_state_t current_state
Current connection state.
connection_state_t previous_state
Previous state (for debugging)
uint32_t total_transitions
Total state transitions (for metrics)

References ASCIICHAT_OK, connection_attempt_context_t::attempt_start_time_ns, CONN_STATE_IDLE, CONN_TIMEOUT_TCP, connection_attempt_context_t::connection, connection_handle_init(), connection_attempt_context_t::current_state, ERROR_INVALID_PARAM, ERROR_NOT_SUPPORTED, log_debug, connection_attempt_context_t::previous_state, connection_attempt_context_t::reconnect_attempt, SET_ERRNO, time_get_realtime_ns(), connection_attempt_context_t::timeout_ns, and connection_attempt_context_t::total_transitions.

Referenced by client_main().

◆ connection_state_name()

const char * connection_state_name ( connection_state_t  state)

Get human-readable state name for logging.

Parameters
stateConnection state
Returns
Static string representation (e.g., "CONNECTED")

Definition at line 58 of file connection_attempt.c.

58 {
59 switch (state) {
60 case CONN_STATE_IDLE:
61 return "IDLE";
63 return "ATTEMPTING";
65 return "CONNECTED";
67 return "DISCONNECTED";
69 return "FAILED";
70 default:
71 return "UNKNOWN";
72 }
73}

References CONN_STATE_ATTEMPTING, CONN_STATE_CONNECTED, CONN_STATE_DISCONNECTED, CONN_STATE_FAILED, and CONN_STATE_IDLE.

Referenced by connection_state_transition().

◆ connection_state_transition()

asciichat_error_t connection_state_transition ( connection_attempt_context_t *  ctx,
connection_state_t  new_state 
)

Transition to next connection state.

Updates current/previous states, logs transition, and updates timeout if stage changed. Validates state transitions to prevent invalid sequences.

Parameters
ctxConnection context
new_stateNext state to transition to
Returns
ASCIICHAT_OK on success, error code on invalid transition

Transition to next connection state.

Definition at line 123 of file connection_attempt.c.

123 {
124 if (!ctx) {
125 return SET_ERRNO(ERROR_INVALID_PARAM, "Context pointer is NULL");
126 }
127
128 // Store previous state
129 ctx->previous_state = ctx->current_state;
130 ctx->current_state = new_state;
131 ctx->total_transitions++;
132
133 log_debug("State transition: %s → %s", connection_state_name(ctx->previous_state), connection_state_name(new_state));
134
135 return ASCIICHAT_OK;
136}
const char * connection_state_name(connection_state_t state)
Get human-readable state name for logging.

References ASCIICHAT_OK, connection_state_name(), connection_attempt_context_t::current_state, ERROR_INVALID_PARAM, log_debug, connection_attempt_context_t::previous_state, SET_ERRNO, and connection_attempt_context_t::total_transitions.

Referenced by connection_attempt_tcp(), and connection_attempt_websocket().