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

WebSocket server implementation. More...

Go to the source code of this file.

Data Structures

struct  websocket_connection_data_t
 Per-connection user data. More...
 

Functions

asciichat_error_t websocket_server_init (websocket_server_t *server, const websocket_server_config_t *config)
 
asciichat_error_t websocket_server_run (websocket_server_t *server)
 
void websocket_server_cancel_service (websocket_server_t *server)
 
void websocket_server_destroy (websocket_server_t *server)
 

Detailed Description

WebSocket server implementation.

Author
Zachary Fogg me@zf.nosp@m.o.gg
Date
February 2026

Definition in file lib/network/websocket/server.c.

Function Documentation

◆ websocket_server_cancel_service()

void websocket_server_cancel_service ( websocket_server_t *  server)

Definition at line 880 of file lib/network/websocket/server.c.

880 {
881 if (server && server->context) {
882 lws_cancel_service(server->context);
883 }
884}

Referenced by server_main().

◆ websocket_server_destroy()

void websocket_server_destroy ( websocket_server_t *  server)

Definition at line 886 of file lib/network/websocket/server.c.

886 {
887 if (!server) {
888 return;
889 }
890
891 atomic_store(&server->running, false);
892
893 // Context is normally destroyed by websocket_server_run (from the event loop
894 // thread) for fast shutdown. This handles the case where run() wasn't called
895 // or didn't complete normally.
896 if (server->context) {
897 log_debug("WebSocket context still alive in destroy, cleaning up");
898 lws_context_destroy(server->context);
899 server->context = NULL;
900 }
901
902 log_debug("WebSocket server destroyed");
903}

Referenced by acds_main(), and server_main().

◆ websocket_server_init()

asciichat_error_t websocket_server_init ( websocket_server_t *  server,
const websocket_server_config_t *  config 
)

Definition at line 791 of file lib/network/websocket/server.c.

791 {
792 if (!server || !config || !config->client_handler) {
793 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid parameters");
794 }
795
796 memset(server, 0, sizeof(*server));
797 server->handler = config->client_handler;
798 server->user_data = config->user_data;
799 server->port = config->port;
800 atomic_store(&server->running, true);
801
802 // Store server pointer in protocol user data so callbacks can access it
803 // Both the HTTP and ACIP protocols need access to the server
804 websocket_protocols[0].user = server; // http protocol
805 websocket_protocols[1].user = server; // acip protocol
806
807 // Enable libwebsockets debug logging with custom callback
808 lws_set_log_level(LLL_ERR | LLL_WARN | LLL_NOTICE | LLL_INFO | LLL_DEBUG, websocket_lws_log_callback);
809
810 // Configure libwebsockets context
811 struct lws_context_creation_info info = {0};
812 info.port = config->port;
813 info.protocols = websocket_protocols;
814 info.gid = (gid_t)-1; // Cast to avoid undefined behavior with unsigned type
815 info.uid = (uid_t)-1; // Cast to avoid undefined behavior with unsigned type
816 info.options = 0; // Don't validate UTF8 - we send binary ACIP packets
817 info.extensions = NULL; // Disable permessage-deflate - causes rx buffer underflow in LWS 4.5.2
818 // TODO: Re-enable compression with proper LWS configuration if needed for bandwidth optimization
819 // Current issue: Even with server_max_window_bits=11, large fragmented messages still trigger
820 // "lws_extension_callback_pm_deflate: rx buffer underflow" errors in LWS 4.5.2
821
822 // Create libwebsockets context
823 server->context = lws_create_context(&info);
824 if (!server->context) {
825 return SET_ERRNO(ERROR_NETWORK_BIND, "Failed to create libwebsockets context");
826 }
827
828 log_info("WebSocket server initialized on port %d with static file serving", config->port);
829 return ASCIICHAT_OK;
830}

Referenced by acds_main(), and server_main().

◆ websocket_server_run()

asciichat_error_t websocket_server_run ( websocket_server_t *  server)

Definition at line 832 of file lib/network/websocket/server.c.

832 {
833 if (!server || !server->context) {
834 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid server");
835 }
836
837 log_info("WebSocket server starting event loop on port %d", server->port);
838
839 // Run libwebsockets event loop
840 uint64_t last_service_ns = 0;
841 int service_call_count = 0;
842 while (atomic_load(&server->running)) {
843 // Service libwebsockets with 50ms timeout.
844 // This provides frequent event processing (~20 callback invocations per second) for all
845 // connected WebSocket clients while avoiding excessive CPU usage from polling.
846 // All client connections share this single server context, so a single lws_service() call
847 // services fragments and events for all clients simultaneously.
848 uint64_t service_start_ns = time_get_ns();
849 if (last_service_ns && service_start_ns - last_service_ns > 30 * US_PER_MS_INT) {
850 // > 30ms gap between service calls
851 double gap_ms = (double)(service_start_ns - last_service_ns) / 1e6;
852 log_info_every(1 * US_PER_MS_INT, "[LWS_SERVICE_GAP] %.1fms gap between lws_service calls", gap_ms);
853 }
854 service_call_count++;
855 log_debug_every(500 * US_PER_MS_INT, "[LWS_SERVICE] Call #%d, context=%p", service_call_count,
856 (void *)server->context);
857 int result = lws_service(server->context, 50);
858 if (result < 0) {
859 log_error("libwebsockets service error: %d", result);
860 break;
861 }
862 }
863
864 log_info("WebSocket server event loop exited, destroying context from event loop thread");
865
866 // Destroy context from the event loop thread. When called from a different
867 // thread after the event loop has stopped, lws_context_destroy tries to
868 // gracefully close WebSocket connections but can't process close responses
869 // (no event loop running), so it waits for the close handshake timeout
870 // (5+ seconds). Destroying from the event loop thread avoids this.
871 if (server->context) {
872 lws_context_destroy(server->context);
873 server->context = NULL;
874 }
875
876 log_info("WebSocket server context destroyed");
877 return ASCIICHAT_OK;
878}
uint64_t time_get_ns(void)
Definition util/time.c:48

References time_get_ns().