|
ascii-chat 0.6.0
Real-time terminal-based video chat with ASCII art conversion
|
🚀 Server initialization, signal handling, and connection management More...
Files | |
| file | main.c |
| 🖥️ Server main entry point: multi-client connection manager with per-client rendering threads (60fps video + 172fps audio) | |
| file | main.h |
| ascii-chat Server Mode Entry Point Header | |
Data Structures | |
| struct | server_context_t |
| Server context - encapsulates all server state. More... | |
Typedefs | |
| typedef struct server_context_t | server_context_t |
| Server context - encapsulates all server state. | |
Variables | |
| bool | g_server_encryption_enabled = false |
| Global flag indicating if server encryption is enabled. | |
| private_key_t | g_server_private_key = {0} |
| Global server private key. | |
| public_key_t | g_client_whitelist [MAX_CLIENTS] = {0} |
| Global client public key whitelist. | |
| size_t | g_num_whitelisted_clients = 0 |
| Number of whitelisted clients. | |
🚀 Server initialization, signal handling, and connection management
The server main entry point orchestrates the complete server lifecycle, from initialization and socket binding through the multi-client connection accept loop to graceful shutdown. It serves as the conductor of the ascii-chat server's modular architecture, coordinating all subsystems while maintaining real-time performance and thread safety guarantees.
Implementation: src/server/main.c, src/server/main.h
Key Responsibilities:
The server initialization follows a strict dependency order:
The main connection loop orchestrates the complete multi-client lifecycle:
Critical Loop Design:
The SIGINT handler implements signal-safe shutdown:
Signal Safety Strategy:
Why Socket Closure: Without closing sockets, threads remain blocked in:
accept() in main loop (waiting for new connections)recv() in client receive threads (waiting for packets)send() in client send threads (if network is slow)Closing sockets causes these functions to return with errors, allowing threads to check g_server_should_exit and exit gracefully.
SIGTERM is sent by process managers (systemd, Docker) for graceful termination:
Conservative Approach:
SIGUSR1 triggers lock debugging output for troubleshooting deadlocks:
This allows external triggering of lock debugging without modifying running server.
The shutdown sequence ensures complete resource cleanup:
Cleanup Guarantees:
The server supports simultaneous binding to both IPv4 and IPv6:
Binding Logic:
Connection Acceptance:
select() to check both sockets simultaneouslyWith Client Management (client.c):
add_client() for each new connectionremove_client() for disconnectionsg_client_manager with proper lockingWith Protocol Handler (protocol.c):
g_server_should_exit)With Stream Generation (stream.c):
With Render Threads (render.c):
create_client_render_threads() in client.cWith Statistics (stats.c):
stats_logger_thread_func() in backgroundWith Cryptography (crypto.c):
init_server_crypto() during initializationg_server_private_key, g_client_whitelist)The original server.c became unmaintainable at 2408+ lines, making it:
The modular design enables:
Module Boundaries:
main.c: Server lifecycle, signal handling, connection acceptanceclient.c: Per-client lifecycle, threading, state managementprotocol.c: Packet processing, protocol state, media storagestream.c: Video mixing, ASCII conversion, frame generationrender.c: Render thread management, rate limiting, timingstats.c: Performance monitoring, resource tracking, reportingcrypto.c: Cryptographic handshake, key exchange, session encryptionInitialization Errors:
Connection Errors:
Runtime Errors:
Main Thread Responsibilities:
Background Thread Responsibilities:
Thread Safety:
g_client_manager_rwlock) protects client arrayg_server_should_exit) for shutdown coordinationSee Concurrency Documentation for complete details.
DO:
g_server_should_exit in loopsDON'T:
| typedef struct server_context_t server_context_t |
#include <main.h>
Server context - encapsulates all server state.
This structure holds all server-wide state that was previously stored in global variables. It's passed to client handlers via tcp_server user_data, reducing global state and improving modularity.
| public_key_t g_client_whitelist[MAX_CLIENTS] = {0} |
#include <main.c>
Global client public key whitelist.
Array of public keys for clients that are authorized to connect to the server. Used for client authentication when whitelist mode is enabled. Sized to hold up to MAX_CLIENTS entries.
Definition at line 355 of file server/main.c.
Referenced by server_crypto_handshake(), and server_main().
| size_t g_num_whitelisted_clients = 0 |
#include <main.c>
Number of whitelisted clients.
Tracks the current number of entries in g_client_whitelist that are valid and active. Used to iterate the whitelist and check authorization.
Definition at line 365 of file server/main.c.
Referenced by server_crypto_handshake(), and server_main().
#include <main.c>
Global flag indicating if server encryption is enabled.
Set to true when the server is configured to use encryption and has successfully loaded a private key. Controls whether the server performs cryptographic handshakes with clients.
Definition at line 330 of file server/main.c.
Referenced by server_crypto_handshake(), and server_main().
| private_key_t g_server_private_key = {0} |
#include <main.c>
Global server private key.
Stores the server's private key loaded from the key file. Used for cryptographic handshakes and packet encryption/decryption. Initialized during server startup from the configured key file path.
Definition at line 342 of file server/main.c.
Referenced by server_crypto_handshake(), and server_main().