ascii-chat 0.11.33
Video chat in your terminal
Loading...
Searching...
No Matches
signaling.c File Reference

Go to the source code of this file.

Data Structures

struct  find_client_context_t
 Context for finding client by participant_id. More...
 
struct  broadcast_context_t
 Context for broadcasting to session participants. More...
 

Functions

asciichat_error_t signaling_relay_sdp (sqlite3 *db, tcp_server_t *tcp_server, const acip_webrtc_sdp_t *sdp, size_t total_packet_len)
 Relay SDP offer/answer to recipient.
 
asciichat_error_t signaling_relay_ice (sqlite3 *db, tcp_server_t *tcp_server, const acip_webrtc_ice_t *ice, size_t total_packet_len)
 Relay ICE candidate to recipient.
 
asciichat_error_t signaling_broadcast (sqlite3 *db, tcp_server_t *tcp_server, const uint8_t session_id[16], packet_type_t packet_type, const void *packet, size_t packet_len, const uint8_t *exclude_participant_id)
 Broadcast packet to all session participants.
 
asciichat_error_t signaling_relay_network_quality (sqlite3 *db, tcp_server_t *tcp_server, const acip_nat_quality_t *quality, size_t total_packet_len)
 Relay NETWORK_QUALITY to session participants.
 

Function Documentation

◆ signaling_broadcast()

asciichat_error_t signaling_broadcast ( sqlite3 *  db,
tcp_server_t *  tcp_server,
const uint8_t  session_id[16],
packet_type_t  packet_type,
const void *  packet,
size_t  packet_len,
const uint8_t *  exclude_participant_id 
)

Broadcast packet to all session participants.

Sends packet to all participants in a session (optionally excluding one). Used internally by SDP/ICE relay when recipient_id is all zeros.

Parameters
dbSQLite database handle (for session validation)
tcp_serverTCP server with client registry
session_idSession UUID
packet_typePacket type to send
packetPacket data to broadcast
packet_lenPacket length
exclude_participant_idParticipant to exclude (NULL = no exclusion, typically sender)
Returns
ASCIICHAT_OK on success, error code otherwise

Definition at line 230 of file signaling.c.

232 {
233 if (!db || !tcp_server || !session_id || !packet) {
234 return SET_ERRNO(ERROR_INVALID_PARAM, "db, tcp_server, session_id, or packet is NULL");
235 }
236
237 log_info("★ SIGNALING_BROADCAST_START: packet_type=%u, packet_len=%zu, session=%02x%02x...", packet_type, packet_len,
238 session_id[0], session_id[1]);
239 if (exclude_participant_id) {
240 log_debug("★ SIGNALING_BROADCAST: excluding participant=%02x%02x...", exclude_participant_id[0],
241 exclude_participant_id[1]);
242 }
243
244 /* Find session by UUID using database lookup */
246 if (!session) {
247 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Session not found for broadcast");
248 }
249 session_entry_destroy(session); // We only need to validate existence
250
251 // Broadcast to all participants in session (excluding sender if specified)
253 .exclude_participant_id = exclude_participant_id,
254 .packet_type = packet_type,
255 .packet = packet,
256 .packet_len = packet_len,
257 .sent_count = 0};
258
259 tcp_server_foreach_client(tcp_server, broadcast_callback, &ctx);
260
261 if (ctx.sent_count == 0) {
262 log_warn("★ SIGNALING_BROADCAST_COMPLETE: sent to 0 participants (all offline or not joined yet)");
263 } else {
264 log_info("★ SIGNALING_BROADCAST_COMPLETE: successfully sent to %zu participants", ctx.sent_count);
265 }
266
267 return ASCIICHAT_OK;
268}
session_entry_t * database_session_find_by_id(sqlite3 *db, const uint8_t session_id[16])
Find session by session_id.
#define SET_ERRNO(code, context_msg,...)
Set error code with custom context message and log it, returning the error code.
@ ERROR_NETWORK_PROTOCOL
Definition error_codes.h:81
@ ASCIICHAT_OK
Definition error_codes.h:51
@ ERROR_INVALID_PARAM
#define log_warn(...)
Log a WARN message.
Definition log/log.h:574
#define log_info(...)
Log an INFO message.
Definition log/log.h:561
#define log_debug(...)
Log a DEBUG message.
Definition log/log.h:548
void session_entry_destroy(session_entry_t *entry)
Free a session entry and all its resources.
void tcp_server_foreach_client(tcp_server_t *server, tcp_client_foreach_fn callback, void *user_arg)
Iterate over all clients.
uint8_t session_id[16]
Context for broadcasting to session participants.
Definition signaling.c:76
const uint8_t * target_session_id
Session to broadcast to.
Definition signaling.c:77
size_t sent_count
Number of successful sends.
Definition signaling.c:82
Session entry data structure.

References ASCIICHAT_OK, database_session_find_by_id(), ERROR_INVALID_PARAM, ERROR_NETWORK_PROTOCOL, log_debug, log_info, log_warn, broadcast_context_t::sent_count, session_entry_destroy(), session_id, SET_ERRNO, broadcast_context_t::target_session_id, and tcp_server_foreach_client().

Referenced by signaling_relay_ice(), signaling_relay_network_quality(), and signaling_relay_sdp().

◆ signaling_relay_ice()

asciichat_error_t signaling_relay_ice ( sqlite3 *  db,
tcp_server_t *  tcp_server,
const acip_webrtc_ice_t *  ice,
size_t  total_packet_len 
)

Relay ICE candidate to recipient.

Relays ICE packet to specific participant or broadcasts to all participants in the session if recipient_id is all zeros.

Parameters
dbSQLite database handle (for session validation)
tcp_serverTCP server with client registry
iceICE packet to relay (with variable-length candidate data following struct)
total_packet_lenTotal packet length including variable data
Returns
ASCIICHAT_OK on success, error code otherwise

Definition at line 187 of file signaling.c.

188 {
189 if (!db || !tcp_server || !ice) {
190 return SET_ERRNO(ERROR_INVALID_PARAM, "db, tcp_server, or ice is NULL");
191 }
192
193 /* Find session by UUID using database lookup */
194 session_entry_t *session = database_session_find_by_id(db, ice->session_id);
195 if (!session) {
196 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Session not found for ICE relay");
197 }
198 session_entry_destroy(session); // We only need to validate existence
199
200 // Check if broadcast (recipient_id all zeros) or unicast
201 if (is_broadcast_uuid(ice->recipient_id)) {
202 // Broadcast to all participants in session (except sender)
203 log_debug("Broadcasting ICE candidate to all participants in session (excluding sender)");
204 return signaling_broadcast(db, tcp_server, ice->session_id, PACKET_TYPE_ACIP_WEBRTC_ICE, ice, total_packet_len,
205 ice->sender_id);
206 } else {
207 // Unicast to specific recipient
209 .target_participant_id = ice->recipient_id, .found_socket = INVALID_SOCKET_VALUE, .found = false};
210
211 tcp_server_foreach_client(tcp_server, find_participant_callback, &ctx);
212
213 if (!ctx.found) {
214 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Recipient participant not found (may be offline)");
215 }
216
217 // Send ICE packet to recipient
218 asciichat_error_t result =
220 if (result != ASCIICHAT_OK) {
221 return SET_ERRNO(ERROR_NETWORK, "Failed to send ICE packet to recipient");
222 }
223
224 log_debug("Relayed ICE candidate from sender to recipient (socket=%d)", ctx.found_socket);
225 }
226
227 return ASCIICHAT_OK;
228}
asciichat_error_t
Error and exit codes - unified status values (0-255)
Definition error_codes.h:49
@ ERROR_NETWORK
Definition error_codes.h:77
@ PACKET_TYPE_ACIP_WEBRTC_ICE
WebRTC ICE candidate (bidirectional)
Definition packet.h:428
#define INVALID_SOCKET_VALUE
Invalid socket value (POSIX: -1)
Definition socket.h:278
asciichat_error_t packet_send_via_transport(acip_transport_t *transport, packet_type_t type, const void *payload, size_t payload_len, uint32_t client_id)
Send packet via transport with proper header (exported for generic wrappers)
Definition send.c:41
asciichat_error_t signaling_broadcast(sqlite3 *db, tcp_server_t *tcp_server, const uint8_t session_id[16], packet_type_t packet_type, const void *packet, size_t packet_len, const uint8_t *exclude_participant_id)
Broadcast packet to all session participants.
Definition signaling.c:230
Context for finding client by participant_id.
Definition signaling.c:43
socket_t found_socket
Socket if found.
Definition signaling.c:45
const uint8_t * target_participant_id
Participant to find.
Definition signaling.c:44
bool found
Whether client was found.
Definition signaling.c:47
acip_transport_t * found_transport
Transport if found.
Definition signaling.c:46

References ASCIICHAT_OK, database_session_find_by_id(), ERROR_INVALID_PARAM, ERROR_NETWORK, ERROR_NETWORK_PROTOCOL, find_client_context_t::found, find_client_context_t::found_socket, find_client_context_t::found_transport, INVALID_SOCKET_VALUE, log_debug, packet_send_via_transport(), PACKET_TYPE_ACIP_WEBRTC_ICE, session_entry_destroy(), SET_ERRNO, signaling_broadcast(), and tcp_server_foreach_client().

◆ signaling_relay_network_quality()

asciichat_error_t signaling_relay_network_quality ( sqlite3 *  db,
tcp_server_t *  tcp_server,
const acip_nat_quality_t *  quality,
size_t  total_packet_len 
)

Relay NETWORK_QUALITY to session participants.

Relays NAT quality metrics to all participants in the session (excluding sender). Used during NAT negotiation phase to help peers determine optimal host.

Parameters
dbSQLite database handle (for session validation)
tcp_serverTCP server with client registry
qualityNAT quality packet (includes session_id and participant_id)
total_packet_lenTotal packet length
Returns
ASCIICHAT_OK on success, error code otherwise

Definition at line 270 of file signaling.c.

271 {
272 if (!db || !tcp_server || !quality) {
273 return SET_ERRNO(ERROR_INVALID_PARAM, "db, tcp_server, or quality is NULL");
274 }
275
276 // Validate packet size
277 if (total_packet_len < sizeof(acip_nat_quality_t)) {
278 return SET_ERRNO(ERROR_NETWORK_SIZE, "NETWORK_QUALITY packet too small");
279 }
280
281 // Extract session_id and sender_id from the quality packet
282 const uint8_t *session_id = quality->session_id;
283 const uint8_t *sender_id = quality->participant_id;
284
285 // Find session by UUID using database lookup
286 log_debug("NETWORK_QUALITY relay: session_id=%02x%02x..., sender_id=%02x%02x...", session_id[0], session_id[1],
287 sender_id[0], sender_id[1]);
289 if (!session) {
290 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Session not found for NETWORK_QUALITY relay");
291 }
292 session_entry_destroy(session); // We only need to validate existence
293
294 // Broadcast to all participants in session (except sender)
295 log_debug("Broadcasting NETWORK_QUALITY to all participants in session (excluding sender)");
296 return signaling_broadcast(db, tcp_server, session_id, PACKET_TYPE_ACIP_NETWORK_QUALITY, quality, total_packet_len,
297 sender_id);
298}
acip_nat_quality_t
Definition acds.h:891
unsigned char uint8_t
Definition common.h:56
@ ERROR_NETWORK_SIZE
Definition error_codes.h:82
@ PACKET_TYPE_ACIP_NETWORK_QUALITY
NETWORK_QUALITY exchange (unified packet for all quality metrics)
Definition packet.h:455

References acip_nat_quality_t, database_session_find_by_id(), ERROR_INVALID_PARAM, ERROR_NETWORK_PROTOCOL, ERROR_NETWORK_SIZE, log_debug, PACKET_TYPE_ACIP_NETWORK_QUALITY, session_entry_destroy(), session_id, SET_ERRNO, and signaling_broadcast().

◆ signaling_relay_sdp()

asciichat_error_t signaling_relay_sdp ( sqlite3 *  db,
tcp_server_t *  tcp_server,
const acip_webrtc_sdp_t *  sdp,
size_t  total_packet_len 
)

Relay SDP offer/answer to recipient.

Relays SDP packet to specific participant or broadcasts to all participants in the session if recipient_id is all zeros.

Parameters
dbSQLite database handle (for session validation)
tcp_serverTCP server with client registry
sdpSDP packet to relay (with variable-length SDP data following struct)
total_packet_lenTotal packet length including variable data
Returns
ASCIICHAT_OK on success, error code otherwise

Definition at line 139 of file signaling.c.

140 {
141 if (!db || !tcp_server || !sdp) {
142 return SET_ERRNO(ERROR_INVALID_PARAM, "db, tcp_server, or sdp is NULL");
143 }
144
145 /* Find session by UUID using database lookup */
146 log_debug("SDP relay: Looking up session_id=%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
147 sdp->session_id[0], sdp->session_id[1], sdp->session_id[2], sdp->session_id[3], sdp->session_id[4],
148 sdp->session_id[5], sdp->session_id[6], sdp->session_id[7], sdp->session_id[8], sdp->session_id[9],
149 sdp->session_id[10], sdp->session_id[11], sdp->session_id[12], sdp->session_id[13], sdp->session_id[14],
150 sdp->session_id[15]);
151 session_entry_t *session = database_session_find_by_id(db, sdp->session_id);
152 if (!session) {
153 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Session not found for SDP relay");
154 }
155 session_entry_destroy(session); // We only need to validate existence
156
157 // Check if broadcast (recipient_id all zeros) or unicast
158 if (is_broadcast_uuid(sdp->recipient_id)) {
159 // Broadcast to all participants in session (except sender)
160 log_debug("Broadcasting SDP to all participants in session (excluding sender)");
161 return signaling_broadcast(db, tcp_server, sdp->session_id, PACKET_TYPE_ACIP_WEBRTC_SDP, sdp, total_packet_len,
162 sdp->sender_id);
163 } else {
164 // Unicast to specific recipient
166 .target_participant_id = sdp->recipient_id, .found_socket = INVALID_SOCKET_VALUE, .found = false};
167
168 tcp_server_foreach_client(tcp_server, find_participant_callback, &ctx);
169
170 if (!ctx.found) {
171 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Recipient participant not found (may be offline)");
172 }
173
174 // Send SDP packet to recipient
175 asciichat_error_t result =
177 if (result != ASCIICHAT_OK) {
178 return SET_ERRNO(ERROR_NETWORK, "Failed to send SDP packet to recipient");
179 }
180
181 log_debug("Relayed SDP from sender to recipient (socket=%d)", ctx.found_socket);
182 }
183
184 return ASCIICHAT_OK;
185}
@ PACKET_TYPE_ACIP_WEBRTC_SDP
WebRTC SDP offer/answer (bidirectional)
Definition packet.h:426

References ASCIICHAT_OK, database_session_find_by_id(), ERROR_INVALID_PARAM, ERROR_NETWORK, ERROR_NETWORK_PROTOCOL, find_client_context_t::found, find_client_context_t::found_socket, find_client_context_t::found_transport, INVALID_SOCKET_VALUE, log_debug, packet_send_via_transport(), PACKET_TYPE_ACIP_WEBRTC_SDP, session_entry_destroy(), SET_ERRNO, signaling_broadcast(), and tcp_server_foreach_client().