ascii-chat 0.8.38
Real-time terminal-based video chat with ASCII art conversion
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.
 

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 216 of file signaling.c.

218 {
219 if (!db || !tcp_server || !session_id || !packet) {
220 return SET_ERRNO(ERROR_INVALID_PARAM, "db, tcp_server, session_id, or packet is NULL");
221 }
222
223 /* Find session by UUID using database lookup */
224 session_entry_t *session = database_session_find_by_id(db, session_id);
225 if (!session) {
226 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Session not found for broadcast");
227 }
228 session_entry_destroy(session); // We only need to validate existence
229
230 // Broadcast to all participants in session (excluding sender if specified)
232 .exclude_participant_id = exclude_participant_id,
233 .packet_type = packet_type,
234 .packet = packet,
235 .packet_len = packet_len,
236 .sent_count = 0};
237
238 tcp_server_foreach_client(tcp_server, broadcast_callback, &ctx);
239
240 if (ctx.sent_count == 0) {
241 log_warn("Broadcast sent to 0 participants (all offline or not joined yet)");
242 } else {
243 log_debug("Broadcast sent to %zu participants", ctx.sent_count);
244 }
245
246 return ASCIICHAT_OK;
247}
session_entry_t * database_session_find_by_id(sqlite3 *db, const uint8_t session_id[16])
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)
uint8_t session_id[16]
Context for broadcasting to session participants.
Definition signaling.c:73
const uint8_t * target_session_id
Session to broadcast to.
Definition signaling.c:74
size_t sent_count
Number of successful sends.
Definition signaling.c:79

References database_session_find_by_id(), broadcast_context_t::sent_count, session_entry_destroy(), session_id, broadcast_context_t::target_session_id, and tcp_server_foreach_client().

Referenced by signaling_relay_ice(), 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 174 of file signaling.c.

175 {
176 if (!db || !tcp_server || !ice) {
177 return SET_ERRNO(ERROR_INVALID_PARAM, "db, tcp_server, or ice is NULL");
178 }
179
180 /* Find session by UUID using database lookup */
181 session_entry_t *session = database_session_find_by_id(db, ice->session_id);
182 if (!session) {
183 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Session not found for ICE relay");
184 }
185 session_entry_destroy(session); // We only need to validate existence
186
187 // Check if broadcast (recipient_id all zeros) or unicast
188 if (is_broadcast_uuid(ice->recipient_id)) {
189 // Broadcast to all participants in session (except sender)
190 log_debug("Broadcasting ICE candidate to all participants in session (excluding sender)");
191 return signaling_broadcast(db, tcp_server, ice->session_id, PACKET_TYPE_ACIP_WEBRTC_ICE, ice, total_packet_len,
192 ice->sender_id);
193 } else {
194 // Unicast to specific recipient
196 .target_participant_id = ice->recipient_id, .found_socket = INVALID_SOCKET_VALUE, .found = false};
197
198 tcp_server_foreach_client(tcp_server, find_participant_callback, &ctx);
199
200 if (!ctx.found) {
201 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Recipient participant not found (may be offline)");
202 }
203
204 // Send ICE packet to recipient
205 int result = send_packet(ctx.found_socket, PACKET_TYPE_ACIP_WEBRTC_ICE, ice, total_packet_len);
206 if (result != 0) {
207 return SET_ERRNO(ERROR_NETWORK, "Failed to send ICE packet to recipient");
208 }
209
210 log_debug("Relayed ICE candidate from sender to recipient (socket=%d)", ctx.found_socket);
211 }
212
213 return ASCIICHAT_OK;
214}
int send_packet(socket_t sockfd, packet_type_t type, const void *data, size_t len)
Send a basic packet without encryption.
Definition packet.c:753
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:216
Context for finding client by participant_id.
Definition signaling.c:42
socket_t found_socket
Socket if found.
Definition signaling.c:44
const uint8_t * target_participant_id
Participant to find.
Definition signaling.c:43
bool found
Whether client was found.
Definition signaling.c:45

References database_session_find_by_id(), find_client_context_t::found, find_client_context_t::found_socket, send_packet(), session_entry_destroy(), signaling_broadcast(), and tcp_server_foreach_client().

◆ 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 127 of file signaling.c.

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

References database_session_find_by_id(), find_client_context_t::found, find_client_context_t::found_socket, send_packet(), session_entry_destroy(), signaling_broadcast(), and tcp_server_foreach_client().