ascii-chat 0.6.0
Real-time terminal-based video chat with ASCII art conversion
Loading...
Searching...
No Matches
signaling.c
Go to the documentation of this file.
1
14#include "acds/signaling.h"
15#include "acds/server.h"
16#include "acds/session.h"
17#include "log/logging.h"
18#include "network/network.h"
19#include <string.h>
20#include <urcu.h>
21#include <urcu/rculfhash.h>
22
26static bool is_broadcast_uuid(const uint8_t uuid[16]) {
27 for (int i = 0; i < 16; i++) {
28 if (uuid[i] != 0) {
29 return false;
30 }
31 }
32 return true;
33}
34
38static bool uuid_equals(const uint8_t a[16], const uint8_t b[16]) {
39 return memcmp(a, b, 16) == 0;
40}
41
50
54static void find_participant_callback(socket_t socket, void *client_data, void *user_arg) {
56
57 if (!client_data) {
58 return; // Client not yet joined a session
59 }
60
61 acds_client_data_t *acds_data = (acds_client_data_t *)client_data;
62 if (!acds_data->joined_session) {
63 return; // Client connected but hasn't joined
64 }
65
66 // Check if participant_id matches
67 if (uuid_equals(acds_data->participant_id, ctx->target_participant_id)) {
68 ctx->found_socket = socket;
69 ctx->found = true;
70 }
71}
72
83
87static void broadcast_callback(socket_t socket, void *client_data, void *user_arg) {
89
90 if (!client_data) {
91 return; // Client not yet joined a session
92 }
93
94 acds_client_data_t *acds_data = (acds_client_data_t *)client_data;
95 if (!acds_data->joined_session) {
96 return; // Client connected but hasn't joined
97 }
98
99 // Check if client is in target session
100 if (!uuid_equals(acds_data->session_id, ctx->target_session_id)) {
101 return; // Different session
102 }
103
104 // Send packet to this participant
105 int result = send_packet(socket, ctx->packet_type, ctx->packet, ctx->packet_len);
106 if (result == 0) {
107 ctx->sent_count++;
108 } else {
109 log_warn("Failed to send packet to participant (socket=%d)", socket);
110 }
111}
112
114 const acip_webrtc_sdp_t *sdp, size_t total_packet_len) {
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}
169
171 const acip_webrtc_ice_t *ice, size_t total_packet_len) {
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}
226
228 const uint8_t session_id[16], packet_type_t packet_type, const void *packet,
229 size_t packet_len) {
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}
acip_webrtc_ice_t
acip_webrtc_sdp_t
unsigned char uint8_t
Definition common.h:56
#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
@ ERROR_NETWORK
Definition error_codes.h:69
@ 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.
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_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_ACIP_WEBRTC_SDP
WebRTC SDP offer/answer (bidirectional)
Definition packet.h:388
int socket_t
Socket handle type (POSIX: int)
Definition socket.h:50
#define INVALID_SOCKET_VALUE
Invalid socket value (POSIX: -1)
Definition socket.h:52
void tcp_server_foreach_client(tcp_server_t *server, tcp_client_foreach_fn callback, void *user_arg)
Iterate over all clients.
📝 Logging API with multiple log levels and terminal output control
🌐 Core network I/O operations with timeout support
🎯 Session registry for discovery service (lock-free RCU implementation)
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.
Definition signaling.c:113
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
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.
Definition signaling.c:170
🎬 WebRTC SDP/ICE signaling relay
🌐 Discovery server TCP connection manager
uint8_t session_id[16]
Per-client connection data.
uint8_t session_id[16]
Session UUID (valid if joined_session)
uint8_t participant_id[16]
Participant UUID (valid if joined_session)
bool joined_session
Whether client has successfully joined a session.
Context for broadcasting to session participants.
Definition signaling.c:76
packet_type_t packet_type
Packet type to send.
Definition signaling.c:78
size_t packet_len
Packet length.
Definition signaling.c:80
const uint8_t * target_session_id
Session to broadcast to.
Definition signaling.c:77
const void * packet
Packet data.
Definition signaling.c:79
size_t sent_count
Number of successful sends.
Definition signaling.c:81
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
Session entry (RCU hash table node)
Definition session.h:55
uint8_t session_id[16]
UUID.
Definition session.h:57
Session registry (lock-free RCU)
Definition session.h:92
struct cds_lfht * sessions
RCU lock-free hash table.
Definition session.h:93
TCP server state.