24#include <ascii-chat/network/acip/acds.h>
25#include <ascii-chat/network/acip/protocol.h>
26#include <ascii-chat/network/acip/send.h>
27#include <ascii-chat/util/endian.h>
28#include <ascii-chat/common.h>
29#include <ascii-chat/platform/abstraction.h>
30#include <ascii-chat/platform/init.h>
44static acip_transport_t *g_acds_transport = NULL;
53static acip_transport_t *g_webrtc_transport = NULL;
65} g_session_context = {0};
70static mutex_t g_signaling_mutex;
71static bool g_signaling_mutex_initialized =
false;
72static static_mutex_t g_signaling_init_mutex = STATIC_MUTEX_INIT;
84static void ensure_mutex_initialized(
void) {
85 static_mutex_lock(&g_signaling_init_mutex);
88 if (!g_signaling_mutex_initialized) {
90 g_signaling_mutex_initialized =
true;
93 static_mutex_unlock(&g_signaling_init_mutex);
109static asciichat_error_t client_send_sdp(
const uint8_t
session_id[16],
const uint8_t recipient_id[16],
110 const char *sdp_type,
const char *sdp,
void *user_data) {
113 if (!
session_id || !recipient_id || !sdp_type || !sdp) {
114 return SET_ERRNO(ERROR_INVALID_PARAM,
"Invalid SDP parameters");
117 ensure_mutex_initialized();
118 mutex_lock(&g_signaling_mutex);
121 if (!g_acds_transport) {
122 mutex_unlock(&g_signaling_mutex);
123 return SET_ERRNO(ERROR_INVALID_STATE,
"ACDS transport not available");
127 if (!g_session_context.is_set) {
128 mutex_unlock(&g_signaling_mutex);
129 return SET_ERRNO(ERROR_INVALID_STATE,
"Session context not set");
133 size_t sdp_len = strlen(sdp);
134 if (sdp_len == 0 || sdp_len >= 8192) {
135 mutex_unlock(&g_signaling_mutex);
136 return SET_ERRNO(ERROR_INVALID_PARAM,
"Invalid SDP length: %zu", sdp_len);
140 size_t total_len =
sizeof(acip_webrtc_sdp_t) + sdp_len;
141 uint8_t *packet = SAFE_MALLOC(total_len, uint8_t *);
143 mutex_unlock(&g_signaling_mutex);
144 return SET_ERRNO(ERROR_MEMORY,
"Failed to allocate SDP packet");
148 acip_webrtc_sdp_t *header = (acip_webrtc_sdp_t *)packet;
150 memcpy(header->sender_id, g_session_context.participant_id, 16);
151 memcpy(header->recipient_id, recipient_id, 16);
152 header->sdp_type = (strcmp(sdp_type,
"offer") == 0) ? 0 : 1;
153 header->sdp_len = HOST_TO_NET_U16((uint16_t)sdp_len);
155 log_debug(
"SDP packet: session_id=%02x%02x%02x%02x..., sender=%02x%02x%02x%02x..., recipient=%02x%02x%02x%02x...",
157 g_session_context.participant_id[1], g_session_context.participant_id[2],
158 g_session_context.participant_id[3], recipient_id[0], recipient_id[1], recipient_id[2], recipient_id[3]);
161 memcpy(packet +
sizeof(acip_webrtc_sdp_t), sdp, sdp_len);
163 log_info(
"Sending WebRTC SDP %s to participant (%.8s...) via ACDS", sdp_type, (
const char *)recipient_id);
166 asciichat_error_t result =
169 mutex_unlock(&g_signaling_mutex);
173 if (result != ASCIICHAT_OK) {
174 return SET_ERRNO(result,
"Failed to send SDP via ACDS");
189static asciichat_error_t client_send_ice(
const uint8_t
session_id[16],
const uint8_t recipient_id[16],
190 const char *candidate,
const char *mid,
void *user_data) {
193 if (!
session_id || !recipient_id || !candidate || !mid) {
194 return SET_ERRNO(ERROR_INVALID_PARAM,
"Invalid ICE parameters");
197 ensure_mutex_initialized();
198 mutex_lock(&g_signaling_mutex);
201 if (!g_acds_transport) {
202 mutex_unlock(&g_signaling_mutex);
203 return SET_ERRNO(ERROR_INVALID_STATE,
"ACDS transport not available");
207 if (!g_session_context.is_set) {
208 mutex_unlock(&g_signaling_mutex);
209 return SET_ERRNO(ERROR_INVALID_STATE,
"Session context not set");
213 size_t candidate_len = strlen(candidate);
214 size_t mid_len = strlen(mid);
215 size_t payload_len = candidate_len + 1 + mid_len + 1;
217 if (payload_len >= 8192) {
218 mutex_unlock(&g_signaling_mutex);
219 return SET_ERRNO(ERROR_INVALID_PARAM,
"ICE payload too large: %zu", payload_len);
223 size_t total_len =
sizeof(acip_webrtc_ice_t) + payload_len;
224 uint8_t *packet = SAFE_MALLOC(total_len, uint8_t *);
226 mutex_unlock(&g_signaling_mutex);
227 return SET_ERRNO(ERROR_MEMORY,
"Failed to allocate ICE packet");
231 acip_webrtc_ice_t *header = (acip_webrtc_ice_t *)packet;
233 memcpy(header->sender_id, g_session_context.participant_id, 16);
234 memcpy(header->recipient_id, recipient_id, 16);
235 header->candidate_len = HOST_TO_NET_U16((uint16_t)candidate_len);
238 uint8_t *payload = packet +
sizeof(acip_webrtc_ice_t);
239 memcpy(payload, candidate, candidate_len);
240 payload[candidate_len] =
'\0';
241 memcpy(payload + candidate_len + 1, mid, mid_len);
242 payload[candidate_len + 1 + mid_len] =
'\0';
244 log_debug(
"Sending WebRTC ICE candidate to participant (%.8s..., mid=%s) via ACDS", (
const char *)recipient_id, mid);
247 asciichat_error_t result =
250 mutex_unlock(&g_signaling_mutex);
254 if (result != ASCIICHAT_OK) {
255 return SET_ERRNO(result,
"Failed to send ICE via ACDS");
266 ensure_mutex_initialized();
268 webrtc_signaling_callbacks_t callbacks = {
269 .send_sdp = client_send_sdp, .send_ice = client_send_ice, .user_data = NULL};
275 ensure_mutex_initialized();
276 mutex_lock(&g_signaling_mutex);
278 g_acds_transport = transport;
281 log_debug(
"ACDS transport set for WebRTC signaling");
283 log_debug(
"ACDS transport cleared for WebRTC signaling");
286 mutex_unlock(&g_signaling_mutex);
291 log_error(
"Invalid session context parameters");
295 ensure_mutex_initialized();
296 mutex_lock(&g_signaling_mutex);
298 memcpy(g_session_context.session_id,
session_id, 16);
300 g_session_context.is_set =
true;
302 log_info(
"Session context set for WebRTC signaling (session=%.8s..., participant=%.8s...)", (
const char *)
session_id,
305 mutex_unlock(&g_signaling_mutex);
320 ensure_mutex_initialized();
321 mutex_lock(&g_signaling_mutex);
323 g_webrtc_transport = transport;
326 log_debug(
"WebRTC data channel transport set");
328 log_debug(
"WebRTC data channel transport cleared");
331 mutex_unlock(&g_signaling_mutex);
345 ensure_mutex_initialized();
346 mutex_lock(&g_signaling_mutex);
348 acip_transport_t *transport = g_webrtc_transport;
350 mutex_unlock(&g_signaling_mutex);
366 ensure_mutex_initialized();
367 mutex_lock(&g_signaling_mutex);
369 if (g_webrtc_transport) {
370 log_debug(
"Cleaning up WebRTC data channel transport");
371 g_webrtc_transport = NULL;
374 mutex_unlock(&g_signaling_mutex);
WebRTC P2P signaling for discovery mode failover.
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)
acip_transport_t * webrtc_get_transport(void)
Get the current WebRTC data channel transport.
void webrtc_set_session_context(const uint8_t session_id[16], const uint8_t participant_id[16])
Set session and participant IDs for signaling.
void webrtc_set_acds_transport(acip_transport_t *transport)
Set the ACDS transport for signaling callbacks.
void webrtc_set_transport(acip_transport_t *transport)
Set the WebRTC data channel transport.
webrtc_signaling_callbacks_t webrtc_get_signaling_callbacks(void)
Get signaling callbacks for WebRTC peer manager.
void webrtc_cleanup_transport(void)
Cleanup and release the WebRTC data channel transport.
uint8_t participant_id[16]
int mutex_init(mutex_t *mutex)