ascii-chat 0.6.0
Real-time terminal-based video chat with ASCII art conversion
Loading...
Searching...
No Matches
Connection Keepalive

💓 Ping/pong keepalive and timeout detection More...

Files

file  keepalive.c
 ðŸ’“ Client keepalive: periodic ping/pong exchange for reliable connection failure detection
 
file  keepalive.h
 ascii-chat Client Connection Keepalive Management Interface
 

Functions

 __attribute__ ((unused))
 Ping/keepalive thread handle.
 
int keepalive_start_thread ()
 Start keepalive/ping thread.
 
void keepalive_stop_thread ()
 Stop keepalive/ping thread.
 
bool keepalive_thread_exited ()
 Check if keepalive thread has exited.
 

Detailed Description

💓 Ping/pong keepalive and timeout detection

Connection Keepalive

Overview

The keepalive subsystem manages connection liveness by sending periodic ping packets and detecting pong timeouts to identify dead connections.

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

Configuration

Timing Parameters:

  • Ping interval: 5 seconds
  • Pong timeout: 30 seconds
  • Timeout triggers reconnection

Keepalive Thread

static void *keepalive_thread_func(void *arg)
{
(void)arg;
time_t last_pong_time = time(NULL);
// Send ping packet
send_packet_to_server(PACKET_TYPE_PING, NULL, 0,
// Wait for ping interval
for (int i = 0; i < PING_INTERVAL_SEC * 10; i++) {
platform_sleep_usec(100000); // 100ms
}
// Check pong timeout
time_t now = time(NULL);
if (now - last_pong_time > PONG_TIMEOUT_SEC) {
log_warn("Pong timeout (%d seconds) - connection may be dead", PONG_TIMEOUT_SEC);
break;
}
}
atomic_store(&g_keepalive_thread_exited, true);
return NULL;
}
bool should_exit()
Check if client should exit.
bool server_connection_is_active()
Check if server connection is currently active.
uint32_t server_connection_get_client_id()
Get client ID assigned by server.
void server_connection_lost()
Signal that connection has been lost.
#define log_warn(...)
Log a WARN message.
@ PACKET_TYPE_PING
Keepalive ping packet.
Definition packet.h:295
void platform_sleep_usec(unsigned int usec)
High-precision sleep function with microsecond precision.

Pong Recording

void keepalive_record_pong(void)
{
// Update last pong time (called by protocol handler)
g_last_pong_time = time(NULL);
}
See also
src/client/keepalive.c
src/client/keepalive.h
Client Overview

Function Documentation

◆ __attribute__()

__attribute__ ( (unused)  )

#include <keepalive.c>

Ping/keepalive thread handle.

Thread handle for the background thread that sends periodic PING packets to detect connection health. Created during connection establishment, joined during shutdown. Ping interval in seconds (must be less than server timeout) Sleep interval for ping timing loop (1 second) Main ping/keepalive thread function

Implements periodic ping transmission to maintain connection health. Monitors connection state and coordinates with global shutdown logic.

Ping Loop Operation:

  1. Check global shutdown flags and connection status
  2. Validate socket file descriptor before transmission
  3. Send ping packet to server via connection module
  4. Handle transmission errors and connection loss detection
  5. Sleep with interruptible timing for responsive shutdown
  6. Repeat until connection loss or shutdown requested

Error Handling:

  • Socket validation failures trigger clean thread exit
  • Ping transmission failures signal connection loss
  • Network errors handled gracefully without panic
  • Thread coordination respects shutdown timing
Parameters
argUnused thread argument
Returns
NULL on thread exit

Definition at line 89 of file keepalive.c.

150 {
151 (void)arg;
152
153#ifdef DEBUG_THREADS
154 log_debug("Ping thread started");
155#endif
156
157 // FPS tracking for keepalive thread (ping sent every 3 seconds = ~0.33 Hz)
158 static fps_t fps_tracker = {0};
159 static bool fps_tracker_initialized = false;
160 if (!fps_tracker_initialized) {
161 fps_init_with_interval(&fps_tracker, 1, "KEEPALIVE", 10000000ULL); // 1 "frame" per 3 seconds, report every 10s
162 fps_tracker_initialized = true;
163 }
164
165 // Startup grace period: Allow connection initialization to complete before checking state
166 // Prevents race condition where thread spawns before transport is fully configured
168
169 while (!should_exit() && !server_connection_is_lost()) {
170 // Check if connection is still active before sending
172 log_debug("Connection inactive, exiting ping thread");
173 break;
174 }
175
176 // Check if session rekeying should be triggered
178 log_debug("Rekey threshold reached, initiating session rekey");
180 log_error("Failed to initiate rekey");
181 // Don't break - continue with keepalive, rekey will be retried
182 }
183 }
184
185 // Send ping packet every PING_INTERVAL_SECONDS to keep connection alive
186 // Server timeout is 5 seconds, so 3-second pings provide safety margin
187 if (threaded_send_ping_packet() < 0) {
188 log_debug("Failed to send ping packet");
189 // Set connection lost flag so main loop knows to reconnect
191 break;
192 }
193
194 // Track ping for FPS reporting
195 struct timespec current_time;
196 (void)clock_gettime(CLOCK_MONOTONIC, &current_time);
197 fps_frame(&fps_tracker, &current_time, "ping sent");
198
199 // Sleep with early wake capability for responsive shutdown
200 // Break sleep into 1-second intervals to check shutdown flags
201 for (int i = 0;
203 i++) {
204 platform_sleep_usec(PING_SLEEP_INTERVAL_SECONDS * 1000 * 1000); // 1 second
205 }
206 }
207
208#ifdef DEBUG_THREADS
209 log_debug("Ping thread stopped");
210#endif
211
212 atomic_store(&g_ping_thread_exited, true);
213
214 // Clean up thread-local error context before exit
216
217 return NULL;
218}
int threaded_send_ping_packet(void)
Thread-safe ping packet transmission.
bool server_connection_is_lost()
Check if connection loss has been detected.
bool crypto_client_should_rekey(void)
Check if session rekeying should be triggered.
int crypto_client_initiate_rekey(void)
Initiate session rekeying (client-initiated)
void fps_frame(fps_t *tracker, const struct timespec *current_time, const char *context)
Track a frame and detect lag conditions.
Definition fps.c:57
void fps_init_with_interval(fps_t *tracker, int expected_fps, const char *name, uint64_t report_interval_us)
Initialize FPS tracker with custom report interval.
Definition fps.c:40
void asciichat_errno_cleanup(void)
Cleanup error system resources.
#define log_error(...)
Log an ERROR message.
#define log_debug(...)
Log a DEBUG message.
void platform_sleep_ms(unsigned int ms)
Sleep for a specified number of milliseconds.
#define PING_SLEEP_INTERVAL_SECONDS
#define PING_INTERVAL_SECONDS
FPS tracking state.
Definition fps.h:51

References asciichat_errno_cleanup(), crypto_client_initiate_rekey(), crypto_client_should_rekey(), fps_frame(), fps_init_with_interval(), log_debug, log_error, PING_INTERVAL_SECONDS, PING_SLEEP_INTERVAL_SECONDS, platform_sleep_ms(), platform_sleep_usec(), server_connection_is_active(), server_connection_is_lost(), server_connection_lost(), should_exit(), and threaded_send_ping_packet().

◆ keepalive_start_thread()

int keepalive_start_thread ( )

#include <keepalive.c>

Start keepalive/ping thread.

Start keepalive/ping thread

Creates and starts the ping thread for connection keepalive. Must be called after successful server connection establishment.

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

Definition at line 234 of file keepalive.c.

234 {
235 if (g_ping_thread_created) {
236 log_warn("Ping thread already created");
237 return 0;
238 }
239
240 // Start ping thread for keepalive
241 atomic_store(&g_ping_thread_exited, false);
242 if (thread_pool_spawn(g_client_worker_pool, ping_thread_func, NULL, 3, "keepalive_ping") != ASCIICHAT_OK) {
243 log_error("Failed to spawn ping thread in worker pool");
244 LOG_ERRNO_IF_SET("Ping thread creation failed");
245 return -1;
246 }
247
248 g_ping_thread_created = true;
249 return 0;
250}
#define LOG_ERRNO_IF_SET(message)
Check if any error occurred and log it if so.
thread_pool_t * g_client_worker_pool
Global client worker thread pool.
@ ASCIICHAT_OK
Definition error_codes.h:48
asciichat_error_t thread_pool_spawn(thread_pool_t *pool, void *(*thread_func)(void *), void *thread_arg, int stop_id, const char *thread_name)
Spawn a worker thread in the pool.
Definition thread_pool.c:65

References ASCIICHAT_OK, g_client_worker_pool, LOG_ERRNO_IF_SET, log_error, log_warn, and thread_pool_spawn().

Referenced by protocol_start_connection().

◆ keepalive_stop_thread()

void keepalive_stop_thread ( )

#include <keepalive.c>

Stop keepalive/ping thread.

Stop keepalive/ping thread

Gracefully stops the ping thread and cleans up resources. Safe to call multiple times.

Definition at line 260 of file keepalive.c.

260 {
261 if (!g_ping_thread_created) {
262 return;
263 }
264
265 // Don't call signal_exit() here - that's for global shutdown only!
266 // The ping thread monitors connection state and will exit when connection is lost
267
268 // Wait for thread to exit gracefully
269 int wait_count = 0;
270 while (wait_count < 20 && !atomic_load(&g_ping_thread_exited)) {
271 platform_sleep_usec(100000); // 100ms
272 wait_count++;
273 }
274
275 if (!atomic_load(&g_ping_thread_exited)) {
276 log_warn("Ping thread not responding - will be joined by thread pool");
277 }
278
279 // Thread will be joined by thread_pool_stop_all() in protocol_stop_connection()
280 g_ping_thread_created = false;
281
282 log_info("Ping thread stopped and joined");
283}
#define log_info(...)
Log an INFO message.

References log_info, log_warn, and platform_sleep_usec().

Referenced by protocol_stop_connection().

◆ keepalive_thread_exited()

bool keepalive_thread_exited ( )

#include <keepalive.c>

Check if keepalive thread has exited.

Check if keepalive thread has exited

Returns
true if thread has exited, false otherwise
true if thread exited, false otherwise

Definition at line 292 of file keepalive.c.

292 {
293 return atomic_load(&g_ping_thread_exited);
294}