ascii-chat 0.6.0
Real-time terminal-based video chat with ASCII art conversion
Loading...
Searching...
No Matches
acds_handlers.c
Go to the documentation of this file.
1
14#include "network/packet.h"
15#include "log/logging.h"
16#include "asciichat_errno.h"
17#include "common.h"
18#include <string.h>
19
20// =============================================================================
21// ACDS Handler Function Types
22// =============================================================================
23
24// ACDS handler function signature
25typedef asciichat_error_t (*acip_acds_handler_func_t)(const void *payload, size_t payload_len, int client_socket,
26 const char *client_ip, const acip_acds_callbacks_t *callbacks);
27
28// =============================================================================
29// Forward Declarations
30// =============================================================================
31
32static asciichat_error_t handle_acds_session_create(const void *payload, size_t payload_len, int client_socket,
33 const char *client_ip, const acip_acds_callbacks_t *callbacks);
34static asciichat_error_t handle_acds_session_lookup(const void *payload, size_t payload_len, int client_socket,
35 const char *client_ip, const acip_acds_callbacks_t *callbacks);
36static asciichat_error_t handle_acds_session_join(const void *payload, size_t payload_len, int client_socket,
37 const char *client_ip, const acip_acds_callbacks_t *callbacks);
38static asciichat_error_t handle_acds_session_leave(const void *payload, size_t payload_len, int client_socket,
39 const char *client_ip, const acip_acds_callbacks_t *callbacks);
40static asciichat_error_t handle_acds_webrtc_sdp(const void *payload, size_t payload_len, int client_socket,
41 const char *client_ip, const acip_acds_callbacks_t *callbacks);
42static asciichat_error_t handle_acds_webrtc_ice(const void *payload, size_t payload_len, int client_socket,
43 const char *client_ip, const acip_acds_callbacks_t *callbacks);
44static asciichat_error_t handle_acds_discovery_ping(const void *payload, size_t payload_len, int client_socket,
45 const char *client_ip, const acip_acds_callbacks_t *callbacks);
46static asciichat_error_t handle_acds_ping(const void *payload, size_t payload_len, int client_socket,
47 const char *client_ip, const acip_acds_callbacks_t *callbacks);
48static asciichat_error_t handle_acds_pong(const void *payload, size_t payload_len, int client_socket,
49 const char *client_ip, const acip_acds_callbacks_t *callbacks);
50
51// =============================================================================
52// ACDS Packet Dispatch Table (O(1) lookup)
53// =============================================================================
54
55static const acip_acds_handler_func_t g_acds_packet_handlers[200] = {
56 [PACKET_TYPE_PING] = handle_acds_ping,
57 [PACKET_TYPE_PONG] = handle_acds_pong,
58 [PACKET_TYPE_ACIP_SESSION_CREATE] = handle_acds_session_create,
59 [PACKET_TYPE_ACIP_SESSION_LOOKUP] = handle_acds_session_lookup,
60 [PACKET_TYPE_ACIP_SESSION_JOIN] = handle_acds_session_join,
61 [PACKET_TYPE_ACIP_SESSION_LEAVE] = handle_acds_session_leave,
62 [PACKET_TYPE_ACIP_WEBRTC_SDP] = handle_acds_webrtc_sdp,
63 [PACKET_TYPE_ACIP_WEBRTC_ICE] = handle_acds_webrtc_ice,
64 [PACKET_TYPE_ACIP_DISCOVERY_PING] = handle_acds_discovery_ping,
65};
66
67// =============================================================================
68// Public API
69// =============================================================================
70
72 size_t payload_len, int client_socket, const char *client_ip,
73 const acip_acds_callbacks_t *callbacks) {
74 if (!callbacks) {
75 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid callbacks");
76 }
77
78 // TODO: Implement transport abstraction for ACDS responses or future protocol features
79 (void)transport;
80
81 // O(1) array-based dispatch - bounds check packet type
82 if (type >= 200) {
83 log_warn("Invalid ACDS packet type: %d (out of range)", type);
84 return ASCIICHAT_OK;
85 }
86
87 // Lookup handler in dispatch table
88 acip_acds_handler_func_t handler = g_acds_packet_handlers[type];
89 if (!handler) {
90 log_warn("Unhandled ACDS packet type: %d from %s", type, client_ip);
91 return ASCIICHAT_OK;
92 }
93
94 // Dispatch to handler
95 return handler(payload, payload_len, client_socket, client_ip, callbacks);
96}
97
98// =============================================================================
99// ACDS Handler Implementations
100// =============================================================================
101
102static asciichat_error_t handle_acds_session_create(const void *payload, size_t payload_len, int client_socket,
103 const char *client_ip, const acip_acds_callbacks_t *callbacks) {
104 if (!callbacks->on_session_create) {
105 return ASCIICHAT_OK;
106 }
107
108 if (payload_len < sizeof(acip_session_create_t)) {
109 return SET_ERRNO(ERROR_INVALID_PARAM, "SESSION_CREATE payload too small from %s", client_ip);
110 }
111
112 const acip_session_create_t *req = (const acip_session_create_t *)payload;
113
114 // Validate session parameters
115 if (req->max_participants == 0 || req->max_participants > 32) {
116 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid max_participants: %u from %s (expected: 1-32)",
117 req->max_participants, client_ip);
118 }
119
120 if (req->session_type > 1) {
121 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid session_type: %u from %s (expected: 0=DIRECT_TCP or 1=WEBRTC)",
122 req->session_type, client_ip);
123 }
124
125 // Validate server port (0 = system assigned, 1-65535 = valid)
126 // Allow 0 for auto-assignment during WEBRTC mode
127 if (req->session_type == 0 && req->server_port == 0) {
128 return SET_ERRNO(ERROR_INVALID_PARAM, "DIRECT_TCP session requires valid server_port from %s", client_ip);
129 }
130
131 callbacks->on_session_create(req, client_socket, client_ip, callbacks->app_ctx);
132 return ASCIICHAT_OK;
133}
134
135static asciichat_error_t handle_acds_session_lookup(const void *payload, size_t payload_len, int client_socket,
136 const char *client_ip, const acip_acds_callbacks_t *callbacks) {
137 if (!callbacks->on_session_lookup) {
138 return ASCIICHAT_OK;
139 }
140
141 if (payload_len < sizeof(acip_session_lookup_t)) {
142 return SET_ERRNO(ERROR_INVALID_PARAM, "SESSION_LOOKUP payload too small from %s", client_ip);
143 }
144
145 const acip_session_lookup_t *req = (const acip_session_lookup_t *)payload;
146 callbacks->on_session_lookup(req, client_socket, client_ip, callbacks->app_ctx);
147 return ASCIICHAT_OK;
148}
149
150static asciichat_error_t handle_acds_session_join(const void *payload, size_t payload_len, int client_socket,
151 const char *client_ip, const acip_acds_callbacks_t *callbacks) {
152 if (!callbacks->on_session_join) {
153 return ASCIICHAT_OK;
154 }
155
156 if (payload_len < sizeof(acip_session_join_t)) {
157 return SET_ERRNO(ERROR_INVALID_PARAM, "SESSION_JOIN payload too small from %s", client_ip);
158 }
159
160 const acip_session_join_t *req = (const acip_session_join_t *)payload;
161 callbacks->on_session_join(req, client_socket, client_ip, callbacks->app_ctx);
162 return ASCIICHAT_OK;
163}
164
165static asciichat_error_t handle_acds_session_leave(const void *payload, size_t payload_len, int client_socket,
166 const char *client_ip, const acip_acds_callbacks_t *callbacks) {
167 if (!callbacks->on_session_leave) {
168 return ASCIICHAT_OK;
169 }
170
171 if (payload_len < sizeof(acip_session_leave_t)) {
172 return SET_ERRNO(ERROR_INVALID_PARAM, "SESSION_LEAVE payload too small from %s", client_ip);
173 }
174
175 const acip_session_leave_t *req = (const acip_session_leave_t *)payload;
176 callbacks->on_session_leave(req, client_socket, client_ip, callbacks->app_ctx);
177 return ASCIICHAT_OK;
178}
179
180static asciichat_error_t handle_acds_webrtc_sdp(const void *payload, size_t payload_len, int client_socket,
181 const char *client_ip, const acip_acds_callbacks_t *callbacks) {
182 if (!callbacks->on_webrtc_sdp) {
183 return ASCIICHAT_OK;
184 }
185
186 if (payload_len < sizeof(acip_webrtc_sdp_t)) {
187 return SET_ERRNO(ERROR_INVALID_PARAM, "WEBRTC_SDP payload too small from %s", client_ip);
188 }
189
190 const acip_webrtc_sdp_t *sdp = (const acip_webrtc_sdp_t *)payload;
191 callbacks->on_webrtc_sdp(sdp, client_socket, client_ip, callbacks->app_ctx);
192 return ASCIICHAT_OK;
193}
194
195static asciichat_error_t handle_acds_webrtc_ice(const void *payload, size_t payload_len, int client_socket,
196 const char *client_ip, const acip_acds_callbacks_t *callbacks) {
197 if (!callbacks->on_webrtc_ice) {
198 return ASCIICHAT_OK;
199 }
200
201 if (payload_len < sizeof(acip_webrtc_ice_t)) {
202 return SET_ERRNO(ERROR_INVALID_PARAM, "WEBRTC_ICE payload too small from %s", client_ip);
203 }
204
205 const acip_webrtc_ice_t *ice = (const acip_webrtc_ice_t *)payload;
206 callbacks->on_webrtc_ice(ice, client_socket, client_ip, callbacks->app_ctx);
207 return ASCIICHAT_OK;
208}
209
210static asciichat_error_t handle_acds_discovery_ping(const void *payload, size_t payload_len, int client_socket,
211 const char *client_ip, const acip_acds_callbacks_t *callbacks) {
212 (void)payload;
213 (void)payload_len;
214
215 if (callbacks->on_discovery_ping) {
216 callbacks->on_discovery_ping(payload, payload_len, client_socket, client_ip, callbacks->app_ctx);
217 }
218 return ASCIICHAT_OK;
219}
220
221static asciichat_error_t handle_acds_ping(const void *payload, size_t payload_len, int client_socket,
222 const char *client_ip, const acip_acds_callbacks_t *callbacks) {
223 (void)payload;
224 (void)payload_len;
225 (void)callbacks;
226
227 log_debug("ACDS keepalive: Received PING from %s, responding with PONG", client_ip);
228
229 // Respond with PONG to keep connection alive
230 asciichat_error_t result = packet_send(client_socket, PACKET_TYPE_PONG, NULL, 0);
231 if (result != ASCIICHAT_OK) {
232 log_warn("ACDS keepalive: Failed to send PONG to %s: %s", client_ip, asciichat_error_string(result));
233 return result;
234 }
235
236 log_debug("ACDS keepalive: Sent PONG to %s", client_ip);
237 return ASCIICHAT_OK;
238}
239
240static asciichat_error_t handle_acds_pong(const void *payload, size_t payload_len, int client_socket,
241 const char *client_ip, const acip_acds_callbacks_t *callbacks) {
242 (void)payload;
243 (void)payload_len;
244 (void)client_socket;
245 (void)callbacks;
246
247 log_debug("ACDS keepalive: Received PONG from %s", client_ip);
248 return ASCIICHAT_OK;
249}
asciichat_error_t(* acip_acds_handler_func_t)(const void *payload, size_t payload_len, int client_socket, const char *client_ip, const acip_acds_callbacks_t *callbacks)
asciichat_error_t acip_handle_acds_packet(acip_transport_t *transport, packet_type_t type, const void *payload, size_t payload_len, int client_socket, const char *client_ip, const acip_acds_callbacks_t *callbacks)
Handle incoming ACDS packet with O(1) dispatch.
ACIP Discovery Server (ACDS) packet handlers.
⚠️‼️ Error and/or exit() when things go bad.
acip_session_join_t
acip_session_lookup_t
acip_webrtc_ice_t
acip_webrtc_sdp_t
acip_session_create_t
acip_session_leave_t
#define SET_ERRNO(code, context_msg,...)
Set error code with custom context message and log it.
asciichat_error_t
Error and exit codes - unified status values (0-255)
Definition error_codes.h:46
@ ASCIICHAT_OK
Definition error_codes.h:48
@ ERROR_INVALID_PARAM
#define log_warn(...)
Log a WARN message.
#define log_debug(...)
Log a DEBUG message.
asciichat_error_t packet_send(socket_t sockfd, packet_type_t type, const void *data, size_t len)
Send a packet with proper header and CRC32.
Definition packet.c:291
packet_type_t
Network protocol packet type enumeration.
Definition packet.h:281
@ PACKET_TYPE_ACIP_WEBRTC_ICE
WebRTC ICE candidate (bidirectional)
Definition packet.h:390
@ PACKET_TYPE_PONG
Keepalive pong response.
Definition packet.h:297
@ PACKET_TYPE_ACIP_SESSION_CREATE
Create new session (Client -> Discovery Server)
Definition packet.h:369
@ PACKET_TYPE_ACIP_DISCOVERY_PING
Discovery server ping (keepalive)
Definition packet.h:402
@ PACKET_TYPE_ACIP_SESSION_LOOKUP
Lookup session by string (Client -> Discovery Server)
Definition packet.h:373
@ PACKET_TYPE_ACIP_SESSION_LEAVE
Leave session (Client -> Discovery Server)
Definition packet.h:381
@ PACKET_TYPE_ACIP_WEBRTC_SDP
WebRTC SDP offer/answer (bidirectional)
Definition packet.h:388
@ PACKET_TYPE_ACIP_SESSION_JOIN
Join existing session (Client -> Discovery Server)
Definition packet.h:377
@ PACKET_TYPE_PING
Keepalive ping packet.
Definition packet.h:295
📝 Logging API with multiple log levels and terminal output control
ACIP protocol message structures and helpers.
Packet protocol implementation with encryption and compression support.
ACDS packet handler callbacks.
void(* on_discovery_ping)(const void *payload, size_t payload_len, int client_socket, const char *client_ip, void *app_ctx)
Called when client sends discovery ping.
void(* on_session_join)(const acip_session_join_t *req, int client_socket, const char *client_ip, void *app_ctx)
Called when client joins a session.
void(* on_webrtc_ice)(const acip_webrtc_ice_t *ice, int client_socket, const char *client_ip, void *app_ctx)
Called when client sends WebRTC ICE candidate.
void(* on_session_lookup)(const acip_session_lookup_t *req, int client_socket, const char *client_ip, void *app_ctx)
Called when client looks up session info.
void * app_ctx
Application context (passed to all callbacks)
void(* on_webrtc_sdp)(const acip_webrtc_sdp_t *sdp, int client_socket, const char *client_ip, void *app_ctx)
Called when client sends WebRTC SDP offer/answer.
void(* on_session_leave)(const acip_session_leave_t *req, int client_socket, const char *client_ip, void *app_ctx)
Called when client leaves a session.
void(* on_session_create)(const acip_session_create_t *req, int client_socket, const char *client_ip, void *app_ctx)
Called when client requests session creation.
Transport instance structure.
Definition transport.h:169