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

🎬 WebRTC SDP/ICE signaling relay implementation More...

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 (session_registry_t *registry, 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 (session_registry_t *registry, 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 (session_registry_t *registry, tcp_server_t *tcp_server, const uint8_t session_id[16], packet_type_t packet_type, const void *packet, size_t packet_len)
 Broadcast packet to all session participants.
 

Detailed Description

🎬 WebRTC SDP/ICE signaling relay implementation

Pure relay server for WebRTC signaling - no media processing. Relays SDP offers/answers and ICE candidates between participants using participant_id → socket mapping from tcp_server client registry.

RCU Integration:

  • Session lookups use RCU read-side critical sections (no locks)
  • Lock-free hash table access with cds_lfht_for_each_entry

Definition in file signaling.c.

Function Documentation

◆ signaling_broadcast()

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

Broadcast packet to all session participants.

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

Parameters
registrySession registry
tcp_serverTCP server with client registry
session_idSession UUID
packet_typePacket type to send
packetPacket data to broadcast
packet_lenPacket length
Returns
ASCIICHAT_OK on success, error code otherwise

Definition at line 227 of file signaling.c.

229 {
230 if (!registry || !tcp_server || !session_id || !packet) {
231 return SET_ERRNO(ERROR_INVALID_PARAM, "registry, tcp_server, session_id, or packet is NULL");
232 }
233
234 /* Find session by UUID - uses RCU lock-free iteration (no lock needed!) */
235 rcu_read_lock();
236
237 session_entry_t *session = NULL;
238 session_entry_t *iter;
239 struct cds_lfht_iter iter_ctx;
240
241 /* Iterate through hash table using RCU-safe iterator */
242 cds_lfht_for_each_entry(registry->sessions, &iter_ctx, iter, hash_node) {
243 if (uuid_equals(iter->session_id, session_id)) {
244 session = iter;
245 break;
246 }
247 }
248
249 if (!session) {
250 rcu_read_unlock();
251 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Session not found for broadcast");
252 }
253
254 rcu_read_unlock();
255
256 // Broadcast to all participants in session
258 .packet_type = packet_type,
259 .packet = packet,
260 .packet_len = packet_len,
261 .sent_count = 0};
262
263 tcp_server_foreach_client(tcp_server, broadcast_callback, &ctx);
264
265 if (ctx.sent_count == 0) {
266 log_warn("Broadcast sent to 0 participants (all offline or not joined yet)");
267 } else {
268 log_debug("Broadcast sent to %zu participants", ctx.sent_count);
269 }
270
271 return ASCIICHAT_OK;
272}
#define SET_ERRNO(code, context_msg,...)
Set error code with custom context message and log it.
@ ERROR_NETWORK_PROTOCOL
Definition error_codes.h:73
@ ASCIICHAT_OK
Definition error_codes.h:48
@ ERROR_INVALID_PARAM
#define log_warn(...)
Log a WARN message.
#define log_debug(...)
Log a DEBUG message.
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:81
Session entry (RCU hash table node)
Definition session.h:55
uint8_t session_id[16]
UUID.
Definition session.h:57
struct cds_lfht * sessions
RCU lock-free hash table.
Definition session.h:93
TCP server state.

References ASCIICHAT_OK, ERROR_INVALID_PARAM, ERROR_NETWORK_PROTOCOL, log_debug, log_warn, broadcast_context_t::sent_count, session_entry::session_id, session_id, session_registry_t::sessions, SET_ERRNO, 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 ( session_registry_t registry,
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
registrySession registry
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 170 of file signaling.c.

171 {
172 if (!registry || !tcp_server || !ice) {
173 return SET_ERRNO(ERROR_INVALID_PARAM, "registry, tcp_server, or ice is NULL");
174 }
175
176 /* Find session by UUID - uses RCU lock-free iteration (no lock needed!) */
177 rcu_read_lock();
178
179 session_entry_t *session = NULL;
180 session_entry_t *iter;
181 struct cds_lfht_iter iter_ctx;
182
183 /* Iterate through hash table using RCU-safe iterator */
184 cds_lfht_for_each_entry(registry->sessions, &iter_ctx, iter, hash_node) {
185 if (uuid_equals(iter->session_id, ice->session_id)) {
186 session = iter;
187 break;
188 }
189 }
190
191 if (!session) {
192 rcu_read_unlock();
193 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Session not found for ICE relay");
194 }
195
196 rcu_read_unlock();
197
198 // Check if broadcast (recipient_id all zeros) or unicast
199 if (is_broadcast_uuid(ice->recipient_id)) {
200 // Broadcast to all participants in session
201 log_debug("Broadcasting ICE candidate to all participants in session");
202 return signaling_broadcast(registry, tcp_server, ice->session_id, PACKET_TYPE_ACIP_WEBRTC_ICE, ice,
203 total_packet_len);
204 } else {
205 // Unicast to specific recipient
207 .target_participant_id = ice->recipient_id, .found_socket = INVALID_SOCKET_VALUE, .found = false};
208
209 tcp_server_foreach_client(tcp_server, find_participant_callback, &ctx);
210
211 if (!ctx.found) {
212 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Recipient participant not found (may be offline)");
213 }
214
215 // Send ICE packet to recipient
216 int result = send_packet(ctx.found_socket, PACKET_TYPE_ACIP_WEBRTC_ICE, ice, total_packet_len);
217 if (result != 0) {
218 return SET_ERRNO(ERROR_NETWORK, "Failed to send ICE packet to recipient");
219 }
220
221 log_debug("Relayed ICE candidate from sender to recipient (socket=%d)", ctx.found_socket);
222 }
223
224 return ASCIICHAT_OK;
225}
@ ERROR_NETWORK
Definition error_codes.h:69
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:754
@ PACKET_TYPE_ACIP_WEBRTC_ICE
WebRTC ICE candidate (bidirectional)
Definition packet.h:390
#define INVALID_SOCKET_VALUE
Invalid socket value (POSIX: -1)
Definition socket.h:52
asciichat_error_t signaling_broadcast(session_registry_t *registry, tcp_server_t *tcp_server, const uint8_t session_id[16], packet_type_t packet_type, const void *packet, size_t packet_len)
Broadcast packet to all session participants.
Definition signaling.c:227
Context for finding client by participant_id.
Definition signaling.c:45
socket_t found_socket
Socket if found.
Definition signaling.c:47
const uint8_t * target_participant_id
Participant to find.
Definition signaling.c:46
bool found
Whether client was found.
Definition signaling.c:48

References ASCIICHAT_OK, ERROR_INVALID_PARAM, ERROR_NETWORK, ERROR_NETWORK_PROTOCOL, find_client_context_t::found, find_client_context_t::found_socket, INVALID_SOCKET_VALUE, log_debug, PACKET_TYPE_ACIP_WEBRTC_ICE, send_packet(), session_entry::session_id, session_registry_t::sessions, SET_ERRNO, signaling_broadcast(), and tcp_server_foreach_client().

◆ signaling_relay_sdp()

asciichat_error_t signaling_relay_sdp ( session_registry_t registry,
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
registrySession registry
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 113 of file signaling.c.

114 {
115 if (!registry || !tcp_server || !sdp) {
116 return SET_ERRNO(ERROR_INVALID_PARAM, "registry, tcp_server, or sdp is NULL");
117 }
118
119 /* Find session by UUID - uses RCU lock-free iteration (no lock needed!) */
120 rcu_read_lock();
121
122 session_entry_t *session = NULL;
123 session_entry_t *iter;
124 struct cds_lfht_iter iter_ctx;
125
126 /* Iterate through hash table using RCU-safe iterator */
127 cds_lfht_for_each_entry(registry->sessions, &iter_ctx, iter, hash_node) {
128 if (uuid_equals(iter->session_id, sdp->session_id)) {
129 session = iter;
130 break;
131 }
132 }
133
134 if (!session) {
135 rcu_read_unlock();
136 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Session not found for SDP relay");
137 }
138
139 rcu_read_unlock();
140
141 // Check if broadcast (recipient_id all zeros) or unicast
142 if (is_broadcast_uuid(sdp->recipient_id)) {
143 // Broadcast to all participants in session
144 log_debug("Broadcasting SDP to all participants in session");
145 return signaling_broadcast(registry, tcp_server, sdp->session_id, PACKET_TYPE_ACIP_WEBRTC_SDP, sdp,
146 total_packet_len);
147 } else {
148 // Unicast to specific recipient
150 .target_participant_id = sdp->recipient_id, .found_socket = INVALID_SOCKET_VALUE, .found = false};
151
152 tcp_server_foreach_client(tcp_server, find_participant_callback, &ctx);
153
154 if (!ctx.found) {
155 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Recipient participant not found (may be offline)");
156 }
157
158 // Send SDP packet to recipient
159 int result = send_packet(ctx.found_socket, PACKET_TYPE_ACIP_WEBRTC_SDP, sdp, total_packet_len);
160 if (result != 0) {
161 return SET_ERRNO(ERROR_NETWORK, "Failed to send SDP packet to recipient");
162 }
163
164 log_debug("Relayed SDP from sender to recipient (socket=%d)", ctx.found_socket);
165 }
166
167 return ASCIICHAT_OK;
168}
@ PACKET_TYPE_ACIP_WEBRTC_SDP
WebRTC SDP offer/answer (bidirectional)
Definition packet.h:388

References ASCIICHAT_OK, ERROR_INVALID_PARAM, ERROR_NETWORK, ERROR_NETWORK_PROTOCOL, find_client_context_t::found, find_client_context_t::found_socket, INVALID_SOCKET_VALUE, log_debug, PACKET_TYPE_ACIP_WEBRTC_SDP, send_packet(), session_entry::session_id, session_registry_t::sessions, SET_ERRNO, signaling_broadcast(), and tcp_server_foreach_client().