61 return "DISCONNECTED";
66 return "ATTEMPTING_DIRECT_TCP";
68 return "DIRECT_TCP_CONNECTED";
70 return "DIRECT_TCP_FAILED";
73 return "ATTEMPTING_WEBRTC_STUN";
75 return "WEBRTC_STUN_SIGNALING";
77 return "WEBRTC_STUN_CONNECTED";
79 return "WEBRTC_STUN_FAILED";
82 return "ATTEMPTING_WEBRTC_TURN";
84 return "WEBRTC_TURN_SIGNALING";
86 return "WEBRTC_TURN_CONNECTED";
88 return "WEBRTC_TURN_FAILED";
119 bool webrtc_skip_stun,
bool webrtc_disable_turn) {
147 "Connection context initialized (prefer_webrtc=%d, no_webrtc=%d, webrtc_skip_stun=%d, webrtc_disable_turn=%d)",
148 prefer_webrtc, no_webrtc, webrtc_skip_stun, webrtc_disable_turn);
164 log_debug(
"TCP client instance destroyed");
188 log_debug(
"Connection context cleaned up");
208 if (new_stage != old_stage && new_stage > 0) {
241 if (timeout_exceeded) {
242 log_warn(
"Stage timeout exceeded: stage %u, elapsed %ld seconds > %u seconds limit",
246 return timeout_exceeded;
261 if (!ctx || !server_address) {
265 log_info(
"Stage 1/3: Attempting direct TCP connection to %s:%u (3s timeout)", server_address, server_port);
276 log_error(
"Failed to create TCP client");
290 if (tcp_result != 0) {
291 log_debug(
"Direct TCP connection failed (tcp_client_connect returned %d)", tcp_result);
301 log_error(
"Failed to get socket from TCP client");
312 log_warn(
"TCP client did not populate server_ip field");
318 log_debug(
"Initializing crypto context...");
320 log_error(
"Failed to initialize crypto context");
324 log_debug(
"Crypto context initialized successfully");
327 log_debug(
"Performing crypto handshake with server...");
333 log_debug(
"Crypto handshake completed successfully");
342 log_error(
"Failed to create ACIP transport for Direct TCP");
347 log_info(
"Direct TCP connection established to %s:%u", server_address, server_port);
354 log_debug(
"TCP client instance stored in connection context");
377 if (!ctx || !transport) {
378 log_error(
"on_webrtc_transport_ready: Invalid parameters");
407 if (!ctx || !server_address || !acds_server) {
417 log_info(
"Stage 2/3: Attempting WebRTC + STUN connection via %s:%u (8s timeout)", acds_server, acds_port);
441 log_warn(
"Failed to connect to ACDS server %s:%u: %d", acds_server, acds_port, result);
451 log_warn(
"No session context available - ACDS discovery may have failed or not been performed");
461 if (opts && opts->
password[0] !=
'\0') {
481 log_debug(
"Joined ACDS session: session_id=%.*s, participant_id=%.*s", 16, (
char *)join_result.
session_id, 16,
490 SAFE_STRNCPY(stun_server1.host,
"stun:stun.ascii-chat.com:3478",
sizeof(stun_server1.host));
493 SAFE_STRNCPY(stun_server2.host,
"stun:stun.l.google.com:19302",
sizeof(stun_server2.host));
502 .stun_servers = stun_servers,
504 .turn_servers = NULL,
506 .on_transport_ready = on_webrtc_transport_ready,
507 .user_data = (
void *)ctx,
518 log_error(
"Failed to create ACDS transport wrapper");
531 log_warn(
"Failed to create WebRTC peer manager: %d", result);
543 log_warn(
"Failed to initiate WebRTC connection: %d", result);
557 log_error(
"Failed to get ACIP client callbacks for WebRTC signaling");
565 time_t wait_start = time(NULL);
567 bool connection_successful =
false;
569 while ((time(NULL) - wait_start) < timeout_seconds) {
573 connection_successful =
true;
586 log_warn(
"ACDS connection closed during WebRTC signaling");
589 log_error(
"ACDS crypto error during WebRTC signaling");
593 log_debug(
"ACDS receive error (non-fatal): %s", asciichat_error_string(recv_result));
597 if (!connection_successful) {
598 log_warn(
"WebRTC+STUN connection timed out after %ld seconds", timeout_seconds);
605 log_info(
"WebRTC+STUN connection established");
632 if (!ctx || !server_address || !acds_server) {
638 log_debug(
"Skipping WebRTC+TURN (webrtc_disable_turn=true)");
642 log_info(
"Stage 3/3: Attempting WebRTC + TURN connection via %s:%u (15s timeout)", acds_server, acds_port);
666 log_warn(
"Failed to connect to ACDS server %s:%u for TURN: %d", acds_server, acds_port, result);
676 log_warn(
"No session context available for TURN stage (ACDS discovery required before WebRTC)");
689 if (opts_turn && opts_turn->
password[0] !=
'\0') {
720 SAFE_STRNCPY(stun_server1_turn.host,
"stun:stun.ascii-chat.com:3478",
sizeof(stun_server1_turn.host));
723 SAFE_STRNCPY(stun_server2_turn.host,
"stun:stun.l.google.com:19302",
sizeof(stun_server2_turn.host));
725 stun_server_t stun_servers[] = {stun_server1_turn, stun_server2_turn};
728 char turn_url[128] = {0};
732 turn_server.url_len = strlen(turn_url);
733 SAFE_STRNCPY(turn_server.url, turn_url,
sizeof(turn_server.url));
746 .stun_servers = stun_servers,
748 .turn_servers = turn_servers,
750 .on_transport_ready = on_webrtc_transport_ready,
751 .user_data = (
void *)ctx,
762 log_error(
"Failed to create ACDS transport wrapper for TURN");
775 log_warn(
"Failed to create WebRTC peer manager for TURN: %d", result);
783 log_warn(
"Failed to initiate WebRTC+TURN connection: %d", result);
797 log_error(
"Failed to get ACIP client callbacks for TURN signaling");
804 time_t wait_start = time(NULL);
806 bool connection_successful =
false;
808 while ((time(NULL) - wait_start) < timeout_seconds) {
812 connection_successful =
true;
824 log_warn(
"ACDS connection closed during WebRTC TURN signaling");
827 log_error(
"ACDS crypto error during WebRTC TURN signaling");
831 log_debug(
"ACDS receive error (non-fatal): %s", asciichat_error_string(recv_result));
838 if (!connection_successful) {
839 log_warn(
"WebRTC+TURN connection timed out after %ld seconds", timeout_seconds);
846 log_info(
"WebRTC+TURN connection established");
884 if (!ctx || !server_address || !acds_server) {
889 server_address, server_port);
899 result = attempt_direct_tcp(ctx, server_address, server_port);
901 log_info(
"Connection succeeded via Direct TCP");
908 log_info(
"Stage 1 timeout, proceeding to Stage 2 (WebRTC+STUN)");
911 log_warn(
"Stage 1 failed immediately, proceeding to Stage 2");
915 result = attempt_direct_tcp(ctx, server_address, server_port);
917 log_info(
"Connection succeeded via Direct TCP (--no-webrtc)");
921 log_error(
"Direct TCP failed with --no-webrtc flag");
930 result = attempt_webrtc_stun(ctx, server_address, server_port, acds_server, acds_port);
932 log_info(
"Connection succeeded via WebRTC+STUN");
938 log_debug(
"WebRTC+STUN stage skipped per CLI flags");
940 log_info(
"Stage 2 timeout, proceeding to Stage 3 (WebRTC+TURN)");
942 log_warn(
"Stage 2 failed immediately, proceeding to Stage 3");
949 result = attempt_webrtc_turn(ctx, server_address, server_port, acds_server, acds_port);
951 log_info(
"Connection succeeded via WebRTC+TURN");
957 log_debug(
"WebRTC+TURN stage skipped per CLI flags");
959 log_error(
"Stage 3 timeout - all fallback stages exhausted");
961 log_error(
"Stage 3 failed - all fallback stages exhausted");
🔌 Cross-platform abstraction layer umbrella header for ascii-chat
asciichat_error_t acds_session_join(acds_client_t *client, const acds_session_join_params_t *params, acds_session_join_result_t *result)
Join an existing session.
asciichat_error_t acds_client_connect(acds_client_t *client, const acds_client_config_t *config)
Connect to ACDS server.
void acds_client_disconnect(acds_client_t *client)
Disconnect from ACDS server.
asciichat_error_t connection_context_init(connection_attempt_context_t *ctx, bool prefer_webrtc, bool no_webrtc, bool webrtc_skip_stun, bool webrtc_disable_turn)
Initialize connection attempt context.
asciichat_error_t connection_attempt_with_fallback(connection_attempt_context_t *ctx, const char *server_address, uint16_t server_port, const char *acds_server, uint16_t acds_port)
Orchestrate connection attempt with automatic fallback.
void connection_context_cleanup(connection_attempt_context_t *ctx)
Cleanup connection attempt context.
bool connection_check_timeout(const connection_attempt_context_t *ctx)
Check if current stage has exceeded timeout.
asciichat_error_t connection_state_transition(connection_attempt_context_t *ctx, connection_state_t new_state)
Transition to next connection state with validation.
uint32_t connection_get_stage(connection_state_t state)
Get current stage number (1, 2, or 3) from state.
const char * connection_state_name(connection_state_t state)
Get human-readable state name for logging.
🎯 Connection state machine for Phase 3 WebRTC fallback integration
#define CONN_TIMEOUT_WEBRTC_TURN
Stage 3: WebRTC+TURN timeout.
#define CONN_TIMEOUT_DIRECT_TCP
Stage 1: Direct TCP timeout.
connection_state_t
13-state connection state machine
@ CONN_STATE_WEBRTC_STUN_SIGNALING
Exchanging SDP/ICE candidates via ACDS.
@ CONN_STATE_CONNECTED
Successfully connected (any transport)
@ CONN_STATE_WEBRTC_TURN_SIGNALING
Exchanging SDP/ICE candidates with TURN relay.
@ CONN_STATE_WEBRTC_TURN_CONNECTED
WebRTC + TURN connection established.
@ CONN_STATE_WEBRTC_STUN_CONNECTED
WebRTC + STUN connection established.
@ CONN_STATE_ATTEMPTING_WEBRTC_TURN
Initiating WebRTC + TURN connection.
@ CONN_STATE_IDLE
Not connected, no attempt in progress.
@ CONN_STATE_DIRECT_TCP_FAILED
Direct TCP failed, falling back to STUN.
@ CONN_STATE_DISCONNECTED
Clean disconnect (user initiated)
@ CONN_STATE_DIRECT_TCP_CONNECTED
Direct TCP connection established.
@ CONN_STATE_FAILED
All fallback stages exhausted.
@ CONN_STATE_ATTEMPTING_WEBRTC_STUN
Initiating WebRTC + STUN connection.
@ CONN_STATE_WEBRTC_STUN_FAILED
STUN failed, falling back to TURN.
@ CONN_STATE_ATTEMPTING_DIRECT_TCP
Attempting direct TCP connection.
@ CONN_STATE_WEBRTC_TURN_FAILED
All stages exhausted.
#define CONN_TIMEOUT_WEBRTC_STUN
Stage 2: WebRTC+STUN timeout.
void server_connection_set_ip(const char *ip)
Set the server IP address.
const crypto_context_t * crypto_client_get_context(void)
Get crypto context for encryption/decryption.
int client_crypto_init(void)
Initialize client crypto handshake.
int client_crypto_handshake(socket_t socket)
Perform crypto handshake with server.
bool crypto_client_is_ready(void)
Check if crypto handshake is ready.
const acip_client_callbacks_t * protocol_get_acip_callbacks()
Get ACIP client callbacks for packet dispatch.
#define SAFE_STRNCPY(dst, src, size)
#define SET_ERRNO(code, context_msg,...)
Set error code with custom context message and log it.
asciichat_error_t
Error and exit codes - unified status values (0-255)
#define log_warn(...)
Log a WARN message.
#define log_error(...)
Log an ERROR message.
#define log_info(...)
Log an INFO message.
#define log_debug(...)
Log a DEBUG message.
#define GET_OPTION(field)
Safely get a specific option field (lock-free read)
const options_t * options_get(void)
Get current options (lock-free read)
asciichat_error_t webrtc_peer_manager_create(const webrtc_peer_manager_config_t *config, const webrtc_signaling_callbacks_t *signaling_callbacks, webrtc_peer_manager_t **manager_out)
Create a WebRTC peer manager.
void webrtc_peer_manager_destroy(webrtc_peer_manager_t *manager)
Destroy peer manager and close all connections.
asciichat_error_t webrtc_peer_manager_connect(webrtc_peer_manager_t *manager, const uint8_t session_id[16], const uint8_t participant_id[16])
Initiate connection to remote peer (joiner role only)
@ WEBRTC_ROLE_JOINER
Session joiner - generates offers, receives answers.
asciichat_error_t acip_client_receive_and_dispatch(acip_transport_t *transport, const acip_client_callbacks_t *callbacks)
Receive packet from server and dispatch to callbacks.
ACIP client-side protocol library.
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.
📝 Logging API with multiple log levels and terminal output control
ASCII-Chat Discovery Service (ACDS) Protocol Message Formats.
⚙️ Command-line options parsing and configuration management for ascii-chat
ascii-chat Client Server Connection Management Interface
void webrtc_set_session_context(const uint8_t session_id[16], const uint8_t participant_id[16])
Set session and participant IDs for signaling.
void webrtc_set_acds_transport(acip_transport_t *transport)
Set the ACDS transport for signaling callbacks.
webrtc_signaling_callbacks_t webrtc_get_signaling_callbacks(void)
Get signaling callbacks for WebRTC peer manager.
uint8_t participant_id[16]
Client-side WebRTC signaling callback implementations.
Server cryptographic operations and per-client handshake management.
Server packet processing and protocol implementation.
ACDS client connection configuration.
char server_address[256]
ACDS server address (e.g., "discovery.ascii.chat" or "127.0.0.1")
uint32_t timeout_ms
Connection timeout in milliseconds.
uint16_t server_port
ACDS server port (default: 27225)
ACDS client connection handle.
socket_t socket
TCP socket to ACDS server.
bool has_password
Password provided.
char password[128]
Password (if has_password)
const char * session_string
Session to join.
char error_message[129]
Error message (if !success, null-terminated)
uint8_t error_code
Error code (if !success)
uint8_t participant_id[16]
Participant UUID (if success)
bool success
Join succeeded.
char server_address[65]
Server IP/hostname (if success, null-terminated)
uint16_t server_port
Server port (if success)
uint8_t session_id[16]
Session UUID (if success)
Client-side packet handler callbacks.
Transport instance structure.
Master context for connection attempt with fallback.
acip_transport_t * acds_transport
ACDS signaling transport (Stages 2/3) - may be NULL.
time_t stage_start_time
When current stage began.
connection_state_t current_state
Current connection state.
webrtc_peer_manager_t * peer_manager
WebRTC peer manager (Stages 2/3)
uint32_t current_stage_timeout_seconds
Timeout for current stage (3/8/15)
connection_state_t previous_state
Previous state (for debugging)
uint32_t stage_failures
How many stages have failed.
uint32_t reconnect_attempt
Reconnection attempt number (1st, 2nd, etc.)
bool prefer_webrtc
–prefer-webrtc flag
struct tcp_client * tcp_client_instance
TCP client instance (Direct TCP only) - owned by context.
mutex_t webrtc_mutex
Mutex for WebRTC callback synchronization.
acip_transport_t * active_transport
Currently active transport (whichever succeeded)
bool no_webrtc
–no-webrtc flag (disable WebRTC, TCP only)
bool webrtc_skip_stun
–webrtc-skip-stun flag (skip Stage 2 STUN)
bool webrtc_disable_turn
–webrtc-disable-turn flag (skip Stage 3 TURN)
connection_stun_turn_config_t stun_turn_cfg
STUN/TURN server config.
acip_transport_t * webrtc_transport
WebRTC transport (Stages 2/3) - may be NULL.
acip_transport_t * tcp_transport
TCP transport (Stage 1) - may be NULL.
cond_t webrtc_ready_cond
Condition variable for on_transport_ready.
connection_session_context_t session_ctx
Session context from ACDS.
uint32_t total_transitions
Total state transitions (for metrics)
bool webrtc_transport_received
Flag: transport_ready callback fired.
char session_string[128]
Session string (e.g., "mystic-stone-obelisk")
uint16_t server_port
Server port for connection.
uint8_t session_id[16]
Session UUID (binary)
char server_address[64]
Server IP/hostname for connection.
uint8_t participant_id[16]
Client's participant UUID (binary)
char turn_server[256]
TURN relay server address.
uint16_t turn_port
TURN relay port.
char turn_password[256]
TURN password (from ACDS or defaults)
char turn_username[128]
TURN username (from ACDS or defaults)
Cryptographic context structure.
Consolidated options structure.
char password[256]
Password string.
TCP client connection and state management.
Peer manager configuration.
webrtc_peer_role_t role
Session role (creator or joiner)
Signaling callbacks for sending SDP/ICE.
⏱️ High-precision timing utilities using sokol_time.h and uthash
acip_transport_t * acip_tcp_transport_create(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.