ascii-chat 0.6.0
Real-time terminal-based video chat with ASCII art conversion
Loading...
Searching...
No Matches
keepalive.c
Go to the documentation of this file.
1
64#include "keepalive.h"
65#include "main.h"
66#include "server.h"
67#include "crypto.h"
68#include "util/fps.h"
69
70#include "common.h"
72#include "thread_pool.h"
73
74#include <stdatomic.h>
75
76/* ============================================================================
77 * Keepalive Thread Management
78 * ============================================================================ */
79
89__attribute__((unused)) static asciichat_thread_t g_ping_thread;
90
99static bool g_ping_thread_created = false;
100
109static atomic_bool g_ping_thread_exited = false;
110
111/* ============================================================================
112 * Keepalive Configuration
113 * ============================================================================ */
114
116#define PING_INTERVAL_SECONDS 3
117
119#define PING_SLEEP_INTERVAL_SECONDS 1
120
121/* ============================================================================
122 * Ping Thread Implementation
123 * ============================================================================ */
124
150static void *ping_thread_func(void *arg) {
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}
219
220/* ============================================================================
221 * Public Interface Functions
222 * ============================================================================ */
223
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}
251
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}
284
293 return atomic_load(&g_ping_thread_exited);
294}
🔌 Cross-platform abstraction layer umbrella header for ascii-chat
#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.
bool should_exit()
Check if client should exit.
⏱️ FPS tracking utility for monitoring frame throughput across all threads
bool server_connection_is_active()
Check if server connection is currently active.
int threaded_send_ping_packet(void)
Thread-safe ping packet transmission.
bool server_connection_is_lost()
Check if connection loss has been detected.
void server_connection_lost()
Signal that connection has been lost.
bool crypto_client_should_rekey(void)
Check if session rekeying should be triggered.
int crypto_client_initiate_rekey(void)
Initiate session rekeying (client-initiated)
bool keepalive_thread_exited()
Check if keepalive thread has exited.
Definition keepalive.c:292
int keepalive_start_thread()
Start keepalive/ping thread.
Definition keepalive.c:234
void keepalive_stop_thread()
Stop keepalive/ping thread.
Definition keepalive.c:260
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.
@ ASCIICHAT_OK
Definition error_codes.h:48
#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.
void platform_sleep_usec(unsigned int usec)
High-precision sleep function with microsecond precision.
void platform_sleep_ms(unsigned int ms)
Sleep for a specified number of milliseconds.
pthread_t asciichat_thread_t
Thread handle type (POSIX: pthread_t)
#define PING_SLEEP_INTERVAL_SECONDS
#define PING_INTERVAL_SECONDS
ascii-chat Client Connection Keepalive Management Interface
ascii-chat Server Mode Entry Point Header
ascii-chat Client Server Connection Management Interface
Server cryptographic operations and per-client handshake management.
RGB pixel structure.
Definition video/image.h:80
FPS tracking state.
Definition fps.h:51
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
🧵 Generic thread pool abstraction for managing worker threads