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

🎯 Connection fallback orchestrator for Phase 3 WebRTC integration More...

Go to the source code of this file.

Functions

const char * connection_state_name (connection_state_t state)
 Get human-readable state name for logging.
 
uint32_t connection_get_stage (connection_state_t state)
 Get current stage number (1, 2, or 3) from state.
 
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.
 
void connection_context_cleanup (connection_attempt_context_t *ctx)
 Cleanup connection attempt context.
 
asciichat_error_t connection_state_transition (connection_attempt_context_t *ctx, connection_state_t new_state)
 Transition to next connection state with validation.
 
bool connection_check_timeout (const connection_attempt_context_t *ctx)
 Check if current stage has exceeded timeout.
 
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.
 

Detailed Description

🎯 Connection fallback orchestrator for Phase 3 WebRTC integration

Implements the 3-stage connection fallback sequence:

  1. Stage 1: Direct TCP (3s timeout) - Fastest path for accessible servers
  2. Stage 2: WebRTC + STUN (8s timeout) - NAT traversal via hole punching
  3. Stage 3: WebRTC + TURN (15s timeout) - Last resort relay

Features:

  • State machine with 13 states tracking all stages
  • Automatic timeout-based progression between stages
  • CLI flags to override or force specific connection methods
  • Proper resource cleanup on transitions and failures
  • Detailed logging of state transitions and errors

Integration Points:

  • Called from src/client/main.c connection loop (replaces direct TCP attempt)
  • Returns active transport when connection succeeds
  • Maintains session context for WebRTC handshake via ACDS
Date
January 2026
Version
1.0

Definition in file connection_attempt.c.

Function Documentation

◆ connection_attempt_with_fallback()

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.

Attempt connection with 3-stage fallback sequence.

Implements 3-stage fallback sequence:

  1. Direct TCP (3s) - Fastest for accessible servers
  2. WebRTC + STUN (8s) - NAT traversal
  3. WebRTC + TURN (15s) - Last resort relay

Each stage is attempted until success or timeout. On timeout, falls back to next stage. Returns ASCIICHAT_OK and sets ctx->active_transport when connection succeeds. Returns error code when all stages fail.

Called from src/client/main.c in the connection loop. Replaces direct TCP connection attempt with automatic fallback.

Parameters
ctxConnection context (initialized by caller)
server_addressServer IP/hostname
server_portServer port
acds_serverACDS discovery server address
acds_portACDS discovery server port
Returns
ASCIICHAT_OK on successful connection, error code otherwise

Definition at line 882 of file connection_attempt.c.

883 {
884 if (!ctx || !server_address || !acds_server) {
885 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid parameters");
886 }
887
888 log_info("=== Connection attempt %u: %s:%u (fallback strategy: TCP β†’ STUN β†’ TURN) ===", ctx->reconnect_attempt,
889 server_address, server_port);
890
892
893 // ─────────────────────────────────────────────────────────────
894 // Stage 1: Direct TCP (3s timeout)
895 // ─────────────────────────────────────────────────────────────
896
897 if (!ctx->prefer_webrtc && !ctx->no_webrtc) {
898 // Normal path: try TCP first unless WebRTC preferred
899 result = attempt_direct_tcp(ctx, server_address, server_port);
900 if (result == ASCIICHAT_OK) {
901 log_info("Connection succeeded via Direct TCP");
903 return ASCIICHAT_OK;
904 }
905
906 // Check if timeout (fall back to next stage)
907 if (connection_check_timeout(ctx)) {
908 log_info("Stage 1 timeout, proceeding to Stage 2 (WebRTC+STUN)");
909 } else {
910 // Actual failure (not just timeout) - could be local error
911 log_warn("Stage 1 failed immediately, proceeding to Stage 2");
912 }
913 } else if (ctx->no_webrtc) {
914 // TCP-only mode - don't try WebRTC at all
915 result = attempt_direct_tcp(ctx, server_address, server_port);
916 if (result == ASCIICHAT_OK) {
917 log_info("Connection succeeded via Direct TCP (--no-webrtc)");
919 return ASCIICHAT_OK;
920 }
921 log_error("Direct TCP failed with --no-webrtc flag");
923 return result;
924 }
925
926 // ─────────────────────────────────────────────────────────────
927 // Stage 2: WebRTC + STUN (8s timeout)
928 // ─────────────────────────────────────────────────────────────
929
930 result = attempt_webrtc_stun(ctx, server_address, server_port, acds_server, acds_port);
931 if (result == ASCIICHAT_OK) {
932 log_info("Connection succeeded via WebRTC+STUN");
934 return ASCIICHAT_OK;
935 }
936
937 if (result == ERROR_NETWORK) {
938 log_debug("WebRTC+STUN stage skipped per CLI flags");
939 } else if (connection_check_timeout(ctx)) {
940 log_info("Stage 2 timeout, proceeding to Stage 3 (WebRTC+TURN)");
941 } else {
942 log_warn("Stage 2 failed immediately, proceeding to Stage 3");
943 }
944
945 // ─────────────────────────────────────────────────────────────
946 // Stage 3: WebRTC + TURN (15s timeout)
947 // ─────────────────────────────────────────────────────────────
948
949 result = attempt_webrtc_turn(ctx, server_address, server_port, acds_server, acds_port);
950 if (result == ASCIICHAT_OK) {
951 log_info("Connection succeeded via WebRTC+TURN");
953 return ASCIICHAT_OK;
954 }
955
956 if (result == ERROR_NETWORK) {
957 log_debug("WebRTC+TURN stage skipped per CLI flags");
958 } else if (connection_check_timeout(ctx)) {
959 log_error("Stage 3 timeout - all fallback stages exhausted");
960 } else {
961 log_error("Stage 3 failed - all fallback stages exhausted");
962 }
963
964 // ─────────────────────────────────────────────────────────────
965 // All stages failed
966 // ─────────────────────────────────────────────────────────────
967
969 return SET_ERRNO(ERROR_NETWORK, "All fallback stages exhausted (TCP: failed, STUN: %s, TURN: %s)",
970 ctx->webrtc_skip_stun ? "skipped" : "failed", ctx->webrtc_disable_turn ? "skipped" : "failed");
971}
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.
@ CONN_STATE_CONNECTED
Successfully connected (any transport)
@ CONN_STATE_FAILED
All fallback stages exhausted.
#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)
Definition error_codes.h:46
@ ERROR_NETWORK
Definition error_codes.h:69
@ ASCIICHAT_OK
Definition error_codes.h:48
@ ERROR_INVALID_PARAM
#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.
uint32_t reconnect_attempt
Reconnection attempt number (1st, 2nd, etc.)
bool prefer_webrtc
–prefer-webrtc flag
bool no_webrtc
–no-webrtc flag (disable WebRTC, TCP only)
bool webrtc_skip_stun
–webrtc-skip-stun flag (skip Stage 2 STUN)

References ASCIICHAT_OK, CONN_STATE_CONNECTED, CONN_STATE_FAILED, connection_check_timeout(), connection_state_transition(), ERROR_INVALID_PARAM, ERROR_NETWORK, log_debug, log_error, log_info, log_warn, connection_attempt_context_t::no_webrtc, connection_attempt_context_t::prefer_webrtc, connection_attempt_context_t::reconnect_attempt, SET_ERRNO, connection_attempt_context_t::webrtc_disable_turn, and connection_attempt_context_t::webrtc_skip_stun.

Referenced by client_main().

◆ connection_check_timeout()

bool connection_check_timeout ( const connection_attempt_context_t ctx)

Check if current stage has exceeded timeout.

Compares elapsed time since stage_start_time against current_stage_timeout_seconds.

Parameters
ctxConnection context
Returns
true if timeout exceeded, false otherwise

Definition at line 234 of file connection_attempt.c.

234 {
235 if (!ctx)
236 return false;
237
238 time_t elapsed = time(NULL) - ctx->stage_start_time;
239 bool timeout_exceeded = elapsed > (time_t)ctx->current_stage_timeout_seconds;
240
241 if (timeout_exceeded) {
242 log_warn("Stage timeout exceeded: stage %u, elapsed %ld seconds > %u seconds limit",
244 }
245
246 return timeout_exceeded;
247}
uint32_t connection_get_stage(connection_state_t state)
Get current stage number (1, 2, or 3) from state.
time_t stage_start_time
When current stage began.
connection_state_t current_state
Current connection state.
uint32_t current_stage_timeout_seconds
Timeout for current stage (3/8/15)

References connection_get_stage(), connection_attempt_context_t::current_stage_timeout_seconds, connection_attempt_context_t::current_state, log_warn, and connection_attempt_context_t::stage_start_time.

Referenced by connection_attempt_with_fallback().

◆ connection_context_cleanup()

void connection_context_cleanup ( connection_attempt_context_t ctx)

Cleanup connection attempt context.

Closes and releases any active transports, frees WebRTC peer manager. Called on connection success, failure, or shutdown.

Parameters
ctxConnection context to cleanup

Definition at line 156 of file connection_attempt.c.

156 {
157 if (!ctx)
158 return;
159
160 // Destroy TCP client instance if created
161 if (ctx->tcp_client_instance) {
163 ctx->tcp_client_instance = NULL;
164 log_debug("TCP client instance destroyed");
165 }
166
167 // Close TCP transport if still open
168 if (ctx->tcp_transport) {
169 acip_transport_close(ctx->tcp_transport);
171 ctx->tcp_transport = NULL;
172 }
173
174 // Close WebRTC transport if still open
175 if (ctx->webrtc_transport) {
176 acip_transport_close(ctx->webrtc_transport);
178 ctx->webrtc_transport = NULL;
179 }
180
181 // Cleanup peer manager
182 if (ctx->peer_manager) {
184 ctx->peer_manager = NULL;
185 }
186
187 ctx->active_transport = NULL;
188 log_debug("Connection context cleaned up");
189}
void webrtc_peer_manager_destroy(webrtc_peer_manager_t *manager)
Destroy peer manager and close all connections.
void tcp_client_destroy(tcp_client_t **client_ptr)
Destroy TCP client and free resources.
webrtc_peer_manager_t * peer_manager
WebRTC peer manager (Stages 2/3)
struct tcp_client * tcp_client_instance
TCP client instance (Direct TCP only) - owned by context.
acip_transport_t * active_transport
Currently active transport (whichever succeeded)
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.
void acip_transport_destroy(acip_transport_t *transport)
Destroy transport and free all resources.

References acip_transport_destroy(), connection_attempt_context_t::active_transport, log_debug, connection_attempt_context_t::peer_manager, tcp_client_destroy(), connection_attempt_context_t::tcp_client_instance, connection_attempt_context_t::tcp_transport, webrtc_peer_manager_destroy(), and connection_attempt_context_t::webrtc_transport.

Referenced by client_main().

◆ connection_context_init()

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.

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

Parameters
ctxConnection context to initialize
prefer_webrtcCLI flag: prefer WebRTC over TCP
no_webrtcCLI flag: disable WebRTC, use TCP only
webrtc_skip_stunCLI flag: skip STUN stage, go straight to TURN
webrtc_disable_turnCLI flag: disable TURN stage (use STUN as fallback)
Returns
ASCIICHAT_OK on success, error code otherwise

Definition at line 118 of file connection_attempt.c.

119 {
120 if (!ctx) {
121 return SET_ERRNO(ERROR_INVALID_PARAM, "Context pointer is NULL");
122 }
123
124 // Reset context
125 memset(ctx, 0, sizeof(connection_attempt_context_t));
126
127 // Initialize state
130
131 // Set CLI preferences
132 ctx->prefer_webrtc = prefer_webrtc;
133 ctx->no_webrtc = no_webrtc;
134 ctx->webrtc_skip_stun = webrtc_skip_stun;
135 ctx->webrtc_disable_turn = webrtc_disable_turn;
136
137 // Initialize timeout
138 ctx->stage_start_time = time(NULL);
140
141 // Initialize counters
142 ctx->reconnect_attempt = 1;
143 ctx->stage_failures = 0;
144 ctx->total_transitions = 0;
145
146 log_debug(
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);
149
150 return ASCIICHAT_OK;
151}
#define CONN_TIMEOUT_DIRECT_TCP
Stage 1: Direct TCP timeout.
@ CONN_STATE_IDLE
Not connected, no attempt in progress.
Master context for connection attempt with fallback.
connection_state_t previous_state
Previous state (for debugging)
uint32_t stage_failures
How many stages have failed.
bool webrtc_disable_turn
–webrtc-disable-turn flag (skip Stage 3 TURN)
uint32_t total_transitions
Total state transitions (for metrics)

References ASCIICHAT_OK, CONN_STATE_IDLE, CONN_TIMEOUT_DIRECT_TCP, connection_attempt_context_t::current_stage_timeout_seconds, connection_attempt_context_t::current_state, ERROR_INVALID_PARAM, log_debug, connection_attempt_context_t::no_webrtc, connection_attempt_context_t::prefer_webrtc, connection_attempt_context_t::previous_state, connection_attempt_context_t::reconnect_attempt, SET_ERRNO, connection_attempt_context_t::stage_failures, connection_attempt_context_t::stage_start_time, connection_attempt_context_t::total_transitions, connection_attempt_context_t::webrtc_disable_turn, and connection_attempt_context_t::webrtc_skip_stun.

Referenced by client_main().

◆ connection_get_stage()

uint32_t connection_get_stage ( connection_state_t  state)

Get current stage number (1, 2, or 3) from state.

Get current stage number (1, 2, or 3)

Definition at line 98 of file connection_attempt.c.

98 {
100 return 1;
101 }
103 return 2;
104 }
106 return 3;
107 }
108 return 0; // Idle or terminal state
109}
@ CONN_STATE_ATTEMPTING_WEBRTC_TURN
Initiating WebRTC + TURN connection.
@ CONN_STATE_DIRECT_TCP_FAILED
Direct TCP failed, falling back to STUN.
@ 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.

References CONN_STATE_ATTEMPTING_DIRECT_TCP, CONN_STATE_ATTEMPTING_WEBRTC_STUN, CONN_STATE_ATTEMPTING_WEBRTC_TURN, CONN_STATE_DIRECT_TCP_FAILED, CONN_STATE_WEBRTC_STUN_FAILED, and CONN_STATE_WEBRTC_TURN_FAILED.

Referenced by connection_check_timeout(), and connection_state_transition().

◆ 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., "DIRECT_TCP_CONNECTED")

Definition at line 54 of file connection_attempt.c.

54 {
55 switch (state) {
56 case CONN_STATE_IDLE:
57 return "IDLE";
59 return "CONNECTED";
61 return "DISCONNECTED";
63 return "FAILED";
64
66 return "ATTEMPTING_DIRECT_TCP";
68 return "DIRECT_TCP_CONNECTED";
70 return "DIRECT_TCP_FAILED";
71
73 return "ATTEMPTING_WEBRTC_STUN";
75 return "WEBRTC_STUN_SIGNALING";
77 return "WEBRTC_STUN_CONNECTED";
79 return "WEBRTC_STUN_FAILED";
80
82 return "ATTEMPTING_WEBRTC_TURN";
84 return "WEBRTC_TURN_SIGNALING";
86 return "WEBRTC_TURN_CONNECTED";
88 return "WEBRTC_TURN_FAILED";
89
90 default:
91 return "UNKNOWN";
92 }
93}
@ CONN_STATE_WEBRTC_STUN_SIGNALING
Exchanging SDP/ICE candidates via ACDS.
@ 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_DISCONNECTED
Clean disconnect (user initiated)
@ CONN_STATE_DIRECT_TCP_CONNECTED
Direct TCP connection established.

References CONN_STATE_ATTEMPTING_DIRECT_TCP, CONN_STATE_ATTEMPTING_WEBRTC_STUN, CONN_STATE_ATTEMPTING_WEBRTC_TURN, CONN_STATE_CONNECTED, CONN_STATE_DIRECT_TCP_CONNECTED, CONN_STATE_DIRECT_TCP_FAILED, CONN_STATE_DISCONNECTED, CONN_STATE_FAILED, CONN_STATE_IDLE, CONN_STATE_WEBRTC_STUN_CONNECTED, CONN_STATE_WEBRTC_STUN_FAILED, CONN_STATE_WEBRTC_STUN_SIGNALING, CONN_STATE_WEBRTC_TURN_CONNECTED, CONN_STATE_WEBRTC_TURN_FAILED, and CONN_STATE_WEBRTC_TURN_SIGNALING.

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 with validation.

Transition to next connection state.

Definition at line 194 of file connection_attempt.c.

194 {
195 if (!ctx) {
196 return SET_ERRNO(ERROR_INVALID_PARAM, "Context pointer is NULL");
197 }
198
199 // Store previous state
200 ctx->previous_state = ctx->current_state;
201 ctx->current_state = new_state;
202 ctx->total_transitions++;
203
204 // Update timeout based on new stage
205 uint32_t new_stage = connection_get_stage(new_state);
207
208 if (new_stage != old_stage && new_stage > 0) {
209 ctx->stage_start_time = time(NULL);
210 switch (new_stage) {
211 case 1:
213 break;
214 case 2:
216 break;
217 case 3:
219 break;
220 default:
221 break;
222 }
223 }
224
225 log_debug("State transition: %s β†’ %s (stage %u β†’ %u)", connection_state_name(ctx->previous_state),
226 connection_state_name(new_state), old_stage, new_stage);
227
228 return ASCIICHAT_OK;
229}
const char * connection_state_name(connection_state_t state)
Get human-readable state name for logging.
#define CONN_TIMEOUT_WEBRTC_TURN
Stage 3: WebRTC+TURN timeout.
#define CONN_TIMEOUT_WEBRTC_STUN
Stage 2: WebRTC+STUN timeout.
unsigned int uint32_t
Definition common.h:58

References ASCIICHAT_OK, CONN_TIMEOUT_DIRECT_TCP, CONN_TIMEOUT_WEBRTC_STUN, CONN_TIMEOUT_WEBRTC_TURN, connection_get_stage(), connection_state_name(), connection_attempt_context_t::current_stage_timeout_seconds, connection_attempt_context_t::current_state, ERROR_INVALID_PARAM, log_debug, connection_attempt_context_t::previous_state, SET_ERRNO, connection_attempt_context_t::stage_start_time, and connection_attempt_context_t::total_transitions.

Referenced by connection_attempt_with_fallback().