14#include <ascii-chat/discovery/database.h>
15#include <ascii-chat/discovery/session.h>
16#include <ascii-chat/log/logging.h>
17#include <ascii-chat/network/network.h>
23static bool is_broadcast_uuid(
const uint8_t uuid[16]) {
24 for (
int i = 0; i < 16; i++) {
35static bool uuid_equals(
const uint8_t a[16],
const uint8_t b[16]) {
36 return memcmp(a, b, 16) == 0;
51static void find_participant_callback(
socket_t socket,
void *client_data,
void *user_arg) {
85static void broadcast_callback(
socket_t socket,
void *client_data,
void *user_arg) {
89 log_debug(
"Broadcast: socket=%d has no client_data", socket);
95 log_debug(
"Broadcast: socket=%d not joined (joined_session=false)", socket);
99 log_debug(
"Broadcast: checking socket=%d (session=%02x%02x..., participant=%02x%02x...)", socket,
105 log_debug(
"Broadcast: socket=%d in different session", socket);
111 log_debug(
"Broadcast: socket=%d is excluded sender (participant=%02x%02x...)", socket, acds_data->
participant_id[0],
117 log_debug(
"Broadcast: sending to socket=%d (participant=%02x%02x...)", socket, acds_data->
participant_id[0],
123 log_warn(
"Failed to send packet to participant (socket=%d)", socket);
128 size_t total_packet_len) {
129 if (!db || !tcp_server || !sdp) {
130 return SET_ERRNO(ERROR_INVALID_PARAM,
"db, tcp_server, or sdp is NULL");
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]);
141 return SET_ERRNO(ERROR_NETWORK_PROTOCOL,
"Session not found for SDP relay");
146 if (is_broadcast_uuid(sdp->recipient_id)) {
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,
154 .target_participant_id = sdp->recipient_id, .found_socket = INVALID_SOCKET_VALUE, .found =
false};
159 return SET_ERRNO(ERROR_NETWORK_PROTOCOL,
"Recipient participant not found (may be offline)");
165 return SET_ERRNO(ERROR_NETWORK,
"Failed to send SDP packet to recipient");
168 log_debug(
"Relayed SDP from sender to recipient (socket=%d)", ctx.
found_socket);
175 size_t total_packet_len) {
176 if (!db || !tcp_server || !ice) {
177 return SET_ERRNO(ERROR_INVALID_PARAM,
"db, tcp_server, or ice is NULL");
183 return SET_ERRNO(ERROR_NETWORK_PROTOCOL,
"Session not found for ICE relay");
188 if (is_broadcast_uuid(ice->recipient_id)) {
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,
196 .target_participant_id = ice->recipient_id, .found_socket = INVALID_SOCKET_VALUE, .found =
false};
201 return SET_ERRNO(ERROR_NETWORK_PROTOCOL,
"Recipient participant not found (may be offline)");
207 return SET_ERRNO(ERROR_NETWORK,
"Failed to send ICE packet to recipient");
210 log_debug(
"Relayed ICE candidate from sender to recipient (socket=%d)", ctx.
found_socket);
217 packet_type_t packet_type,
const void *packet,
size_t packet_len,
218 const uint8_t *exclude_participant_id) {
219 if (!db || !tcp_server || !
session_id || !packet) {
220 return SET_ERRNO(ERROR_INVALID_PARAM,
"db, tcp_server, session_id, or packet is NULL");
226 return SET_ERRNO(ERROR_NETWORK_PROTOCOL,
"Session not found for broadcast");
232 .exclude_participant_id = exclude_participant_id,
233 .packet_type = packet_type,
235 .packet_len = packet_len,
241 log_warn(
"Broadcast sent to 0 participants (all offline or not joined yet)");
243 log_debug(
"Broadcast sent to %zu participants", ctx.
sent_count);
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)
int send_packet(socket_t sockfd, packet_type_t type, const void *data, size_t len)
Send a basic packet without encryption.
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.
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_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.
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.
packet_type_t packet_type
Packet type to send.
size_t packet_len
Packet length.
const uint8_t * target_session_id
Session to broadcast to.
const void * packet
Packet data.
const uint8_t * exclude_participant_id
Participant to exclude (NULL = no exclusion)
size_t sent_count
Number of successful sends.
Context for finding client by participant_id.
socket_t found_socket
Socket if found.
const uint8_t * target_participant_id
Participant to find.
bool found
Whether client was found.