14#include <ascii-chat/common.h>
15#include <ascii-chat/log/logging.h>
16#include <ascii-chat/network/acip/protocol.h>
17#include <ascii-chat/network/acip/acds.h>
18#include <ascii-chat/network/acip/send.h>
19#include <ascii-chat/network/packet.h>
20#include <ascii-chat/network/network.h>
21#include <ascii-chat/platform/abstraction.h>
22#include <ascii-chat/platform/init.h>
23#include <ascii-chat/util/endian.h>
38static acip_transport_t *g_tcp_transport = NULL;
50} g_session_context = {0};
55static mutex_t g_webrtc_mutex;
56static bool g_webrtc_mutex_initialized =
false;
57static static_mutex_t g_webrtc_init_mutex = STATIC_MUTEX_INIT;
69static void ensure_mutex_initialized(
void) {
70 static_mutex_lock(&g_webrtc_init_mutex);
73 if (!g_webrtc_mutex_initialized) {
75 g_webrtc_mutex_initialized =
true;
78 static_mutex_unlock(&g_webrtc_init_mutex);
95static asciichat_error_t discovery_send_sdp(
const uint8_t
session_id[16],
const uint8_t recipient_id[16],
96 const char *sdp_type,
const char *sdp,
void *user_data) {
100 ensure_mutex_initialized();
101 mutex_lock(&g_webrtc_mutex);
104 if (!g_tcp_transport) {
105 mutex_unlock(&g_webrtc_mutex);
106 SET_ERRNO(ERROR_INVALID_STATE,
"TCP transport not set for direct signaling");
107 return ERROR_INVALID_STATE;
110 if (!g_session_context.is_set) {
111 mutex_unlock(&g_webrtc_mutex);
112 SET_ERRNO(ERROR_INVALID_STATE,
"Session context not set for direct signaling");
113 return ERROR_INVALID_STATE;
118 mutex_unlock(&g_webrtc_mutex);
119 SET_ERRNO(ERROR_INVALID_PARAM,
"SDP is NULL");
120 return ERROR_INVALID_PARAM;
123 size_t sdp_len = strlen(sdp);
124 if (sdp_len > 4096) {
125 mutex_unlock(&g_webrtc_mutex);
126 SET_ERRNO(ERROR_INVALID_PARAM,
"SDP too large (>4096 bytes)");
127 return ERROR_INVALID_PARAM;
133 uint8_t sdp_msg_buf[
sizeof(acip_webrtc_sdp_t) + 4096];
134 acip_webrtc_sdp_t *sdp_msg = (acip_webrtc_sdp_t *)sdp_msg_buf;
137 memcpy(sdp_msg->sender_id, g_session_context.participant_id, 16);
138 memset(sdp_msg->recipient_id, 0, 16);
139 sdp_msg->sdp_type = (strcmp(sdp_type,
"answer") == 0) ? 1 : 0;
140 sdp_msg->sdp_len = (uint16_t)sdp_len;
141 memcpy(sdp_msg_buf +
sizeof(acip_webrtc_sdp_t), sdp, sdp_len);
144 size_t msg_size =
sizeof(acip_webrtc_sdp_t) + sdp_len;
145 asciichat_error_t result =
148 mutex_unlock(&g_webrtc_mutex);
150 if (result != ASCIICHAT_OK) {
151 log_error(
"Failed to send SDP via direct TCP: %d", result);
155 log_debug(
"Sent SDP %s directly to peer (TCP transport)", sdp_type);
164static asciichat_error_t discovery_send_ice(
const uint8_t
session_id[16],
const uint8_t recipient_id[16],
165 const char *candidate,
const char *mid,
void *user_data) {
169 ensure_mutex_initialized();
170 mutex_lock(&g_webrtc_mutex);
173 if (!g_tcp_transport) {
174 mutex_unlock(&g_webrtc_mutex);
175 SET_ERRNO(ERROR_INVALID_STATE,
"TCP transport not set for direct signaling");
176 return ERROR_INVALID_STATE;
179 if (!g_session_context.is_set) {
180 mutex_unlock(&g_webrtc_mutex);
181 SET_ERRNO(ERROR_INVALID_STATE,
"Session context not set for direct signaling");
182 return ERROR_INVALID_STATE;
186 if (!candidate || !mid) {
187 mutex_unlock(&g_webrtc_mutex);
188 SET_ERRNO(ERROR_INVALID_PARAM,
"Candidate or mid is NULL");
189 return ERROR_INVALID_PARAM;
193 size_t candidate_len = strlen(candidate);
194 size_t mid_len = strlen(mid);
195 size_t payload_len = candidate_len + 1 + mid_len + 1;
197 if (payload_len > 4096) {
198 mutex_unlock(&g_webrtc_mutex);
199 SET_ERRNO(ERROR_INVALID_PARAM,
"ICE candidate + mid too large (>4096 bytes)");
200 return ERROR_INVALID_PARAM;
206 uint8_t ice_msg_buf[
sizeof(acip_webrtc_ice_t) + 4096];
207 acip_webrtc_ice_t *ice_msg = (acip_webrtc_ice_t *)ice_msg_buf;
211 memcpy(ice_msg->sender_id, g_session_context.participant_id, 16);
212 memset(ice_msg->recipient_id, 0, 16);
213 ice_msg->candidate_len = HOST_TO_NET_U16((uint16_t)candidate_len);
216 uint8_t *payload = ice_msg_buf +
sizeof(acip_webrtc_ice_t);
217 memcpy(payload, candidate, candidate_len);
218 payload[candidate_len] =
'\0';
219 memcpy(payload + candidate_len + 1, mid, mid_len);
220 payload[candidate_len + 1 + mid_len] =
'\0';
222 log_debug(
"Sending ICE candidate directly to peer (candidate_len=%zu, mid=%s)", candidate_len, mid);
225 size_t msg_size =
sizeof(acip_webrtc_ice_t) + payload_len;
226 asciichat_error_t result =
229 mutex_unlock(&g_webrtc_mutex);
231 if (result != ASCIICHAT_OK) {
232 log_error(
"Failed to send ICE candidate via direct TCP: %d", result);
236 log_debug(
"Sent ICE candidate directly to peer (TCP transport)");
247 ensure_mutex_initialized();
248 mutex_lock(&g_webrtc_mutex);
250 g_tcp_transport = tcp_transport;
253 memcpy(g_session_context.session_id,
session_id, 16);
255 g_session_context.is_set =
true;
258 mutex_unlock(&g_webrtc_mutex);
260 webrtc_signaling_callbacks_t callbacks = {
261 .send_sdp = discovery_send_sdp,
262 .send_ice = discovery_send_ice,
270 ensure_mutex_initialized();
271 mutex_lock(&g_webrtc_mutex);
272 g_tcp_transport = transport;
273 mutex_unlock(&g_webrtc_mutex);
277 ensure_mutex_initialized();
278 mutex_lock(&g_webrtc_mutex);
281 memcpy(g_session_context.session_id,
session_id, 16);
283 g_session_context.is_set =
true;
285 g_session_context.is_set =
false;
288 mutex_unlock(&g_webrtc_mutex);
292 ensure_mutex_initialized();
293 mutex_lock(&g_webrtc_mutex);
295 g_tcp_transport = NULL;
296 g_session_context.is_set =
false;
298 mutex_unlock(&g_webrtc_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)
void discovery_webrtc_cleanup_transport(void)
Cleanup and release the direct peer-to-peer transport.
void discovery_webrtc_set_tcp_transport(acip_transport_t *transport)
Set the TCP transport for direct peer-to-peer signaling.
uint8_t participant_id[16]
webrtc_signaling_callbacks_t discovery_webrtc_get_direct_signaling_callbacks(acip_transport_t *tcp_transport, const uint8_t session_id[16], const uint8_t participant_id[16])
Create signaling callbacks for direct peer-to-peer connection during failover.
void discovery_webrtc_set_session_context(const uint8_t session_id[16], const uint8_t participant_id[16])
Set session and participant IDs for direct signaling.
int mutex_init(mutex_t *mutex)