ascii-chat 0.11.33
Video chat in your terminal
Loading...
Searching...
No Matches
keepalive.c
Go to the documentation of this file.
1
64#include "keepalive.h"
65#include "main.h"
66#include "../main.h" // Global exit API
67#include "server.h"
68#include "crypto.h"
69#include <ascii-chat/util/fps.h>
71
72#include <ascii-chat/common.h>
76
77#include <ascii-chat/atomic.h>
79
80/* ============================================================================
81 * Keepalive Thread Management
82 * ============================================================================ */
83
92static bool g_ping_thread_created = false;
93
102static atomic_t g_ping_thread_exited = {0};
103
104/* ============================================================================
105 * Keepalive Configuration
106 * ============================================================================ */
107
109#define PING_INTERVAL_NS (1LL * NS_PER_SEC_INT)
110
112#define PING_SLEEP_INTERVAL_NS (1LL * NS_PER_SEC_INT)
113
114/* ============================================================================
115 * Ping Thread Implementation
116 * ============================================================================ */
117
143static void *ping_thread_func(void *arg) {
144 (void)arg;
145
146#ifdef DEBUG_THREADS
147 log_debug("Ping thread started");
148#endif
149
150 // FPS tracking for keepalive thread (ping sent every 1 second)
151 static fps_t fps_tracker = {0};
152 static bool fps_tracker_initialized = false;
153 if (!fps_tracker_initialized) {
154 fps_init_with_interval(&fps_tracker, 1, "KEEPALIVE",
155 100 * NS_PER_MS_INT); // Report keepalive metrics every 100ms
156 fps_tracker_initialized = true;
157 }
158
159 // Startup grace period: Allow connection initialization to complete before checking state
160 // Prevents race condition where thread spawns before transport is fully configured
161 APP_CALLBACK_VOID(platform_pump_events);
163
164 while (!should_exit() && !server_connection_is_lost()) {
165 // Check if connection is still active before sending
167 log_debug("Connection inactive, exiting ping thread");
168 break;
169 }
170
171 // Check if session rekeying should be triggered
173 log_debug("Rekey threshold reached, initiating session rekey");
175 log_error("Failed to initiate rekey");
176 // Don't break - continue with keepalive, rekey will be retried
177 }
178 }
179
180 // Send ping packet every PING_INTERVAL_SECONDS to keep connection alive
181 // Server timeout is 5 seconds, so 3-second pings provide safety margin
182 if (threaded_send_ping_packet() < 0) {
183 log_debug("Failed to send ping packet");
184 // Set connection lost flag so main loop knows to reconnect
186 break;
187 }
188
189 // Track ping for FPS reporting
190 uint64_t ping_start_ns = time_get_ns();
191 fps_frame_ns(&fps_tracker, ping_start_ns, "ping sent");
192
193 // Sleep with early wake capability for responsive shutdown
194 // Break sleep into intervals to check shutdown flags and rekey triggers
196 uint64_t now_ns = time_get_ns();
197 uint64_t elapsed_ns = time_elapsed_ns(ping_start_ns, now_ns);
198
199 if (elapsed_ns >= PING_INTERVAL_NS) {
200 break; // Time for next ping
201 }
202
203 // Sleep for one interval or until next ping, whichever is sooner
204 uint64_t remaining_ns = PING_INTERVAL_NS - elapsed_ns;
205 uint64_t sleep_ns = (remaining_ns > PING_SLEEP_INTERVAL_NS) ? PING_SLEEP_INTERVAL_NS : remaining_ns;
206 platform_sleep_ns(sleep_ns);
207 }
208 }
209
210#ifdef DEBUG_THREADS
211 log_debug("Ping thread stopped");
212#endif
213
214 atomic_store_bool(&g_ping_thread_exited, true);
215
216 // Clean up thread-local error context before exit
218
219 return NULL;
220}
221
222/* ============================================================================
223 * Public Interface Functions
224 * ============================================================================ */
225
237 if (g_ping_thread_created) {
238 log_warn("Ping thread already created");
239 return 0;
240 }
241
242 // Register keepalive atomics with named debug registry
243 static bool keepalive_atomics_registered = false;
244 if (!keepalive_atomics_registered) {
245 NAMED_REGISTER_ATOMIC(&g_ping_thread_exited, "keepalive_ping_thread_exit_confirmation", NULL);
246 keepalive_atomics_registered = true;
247 }
248
249 // Start ping thread for keepalive
250 atomic_store_bool(&g_ping_thread_exited, false);
251 if (thread_pool_spawn(g_client_worker_pool, ping_thread_func, NULL, 3, "keepalive_ping") != ASCIICHAT_OK) {
252 log_error("Failed to spawn ping thread in worker pool");
253 LOG_ERRNO_IF_SET("Ping thread creation failed");
254 return -1;
255 }
256
257 g_ping_thread_created = true;
258 return 0;
259}
260
270 if (!g_ping_thread_created) {
271 return;
272 }
273
274 // Don't call signal_exit() here - that's for global shutdown only!
275 // The ping thread monitors connection state and will exit when connection is lost
276
277 // Wait for thread to exit gracefully
278 int wait_count = 0;
279 while (wait_count < 20 && !atomic_load_bool(&g_ping_thread_exited)) {
280 platform_sleep_ns(100 * NS_PER_MS_INT); // 100ms
281 wait_count++;
282 }
283
284 if (!atomic_load_bool(&g_ping_thread_exited)) {
285 log_warn("Ping thread not responding - will be joined by thread pool");
286 }
287
288 // Thread will be joined by thread_pool_stop_all() in protocol_stop_connection()
289 g_ping_thread_created = false;
290
291 log_debug("Ping thread stopped and joined");
292}
293
302 return atomic_load_bool(&g_ping_thread_exited);
303}
Platform abstraction layer umbrella header providing unified cross-platform API.
Application-level callbacks for library code.
#define APP_CALLBACK_VOID(callback_name)
#define LOG_ERRNO_IF_SET(message)
Check if any error occurred and log it if so.
void atomic_store_bool(atomic_t *a, bool value)
Atomically store a boolean value.
Definition atomic.c:177
bool atomic_load_bool(atomic_t *a)
Atomically load a boolean value.
Definition atomic.c:169
⚛️ Atomic operations abstraction layer with debug tracking
thread_pool_t * g_client_worker_pool
Global client worker thread pool.
⚙️ Common definitions, error codes, macros, and types shared throughout the application
asciichat_error_t thread_pool_spawn(void *pool, void *(*thread_func)(void *), void *thread_arg, int stop_id, const char *name)
Spawn a worker thread in the pool.
Named object registry for debugging — log identifiable resource names.
⏱️ 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:301
int keepalive_start_thread()
Start keepalive/ping thread.
Definition keepalive.c:236
void keepalive_stop_thread()
Stop keepalive/ping thread.
Definition keepalive.c:269
void fps_init_with_interval(fps_t *tracker, int expected_fps, const char *name, uint64_t report_interval_ns)
Initialize FPS tracker with custom report interval.
Definition fps.c:37
void fps_frame_ns(fps_t *tracker, uint64_t current_time_ns, const char *context)
Track a frame and detect lag conditions (nanosecond version - PRIMARY)
Definition fps.c:52
unsigned long long uint64_t
Definition common.h:59
#define NAMED_REGISTER_ATOMIC(a, name, parent_ptr)
Register an atomic_t with automatic format specifier.
void asciichat_errno_destroy(void)
Cleanup error system resources.
@ ASCIICHAT_OK
Definition error_codes.h:51
#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_debug(...)
Log a DEBUG message.
Definition log/log.h:548
uint64_t time_get_ns(void)
Get current monotonic time in nanoseconds.
Definition util/time.c:108
#define NS_PER_MS_INT
Definition time.h:156
uint64_t time_elapsed_ns(uint64_t start_ns, uint64_t end_ns)
Calculate elapsed time with wraparound safety.
Definition util/time.c:150
void platform_sleep_ns(uint64_t ns)
Platform-safe sleep function with nanosecond precision.
void platform_sleep_ms(unsigned int ms)
Sleep for a specified number of milliseconds.
#define PING_INTERVAL_NS
Definition keepalive.c:109
#define PING_SLEEP_INTERVAL_NS
Definition keepalive.c:112
ascii-chat Client Connection Keepalive Management Interface
bool should_exit(void)
Definition misc.c:131
ascii-chat Server Mode Entry Point Header
Server cryptographic operations and per-client handshake management.
Server-side H.265 decoding pipeline for multi-client streams.
Atomic value wrapper for integral/boolean types.
Definition atomic.h:76
FPS tracking state.
Definition fps.h:52
🧵 Generic thread pool abstraction for managing worker threads
⏱️ High-precision timing utilities using sokol_time.h and uthash