63 type_preference = 126;
66 type_preference = 100;
69 type_preference = 110;
90 if (!line || !candidate) {
102 char *saveptr = NULL;
106 token = strtok_r(line_copy,
" ", &saveptr);
113 token = strtok_r(NULL,
" ", &saveptr);
114 if (!token || sscanf(token,
"%u", &candidate->
component_id) != 1) {
119 token = strtok_r(NULL,
" ", &saveptr);
123 if (strcmp(token,
"udp") == 0) {
125 }
else if (strcmp(token,
"tcp") == 0) {
132 token = strtok_r(NULL,
" ", &saveptr);
133 if (!token || sscanf(token,
"%u", &candidate->
priority) != 1) {
138 token = strtok_r(NULL,
" ", &saveptr);
145 token = strtok_r(NULL,
" ", &saveptr);
146 if (!token || sscanf(token,
"%hu", &candidate->
port) != 1) {
151 token = strtok_r(NULL,
" ", &saveptr);
152 if (!token || strcmp(token,
"typ") != 0) {
157 token = strtok_r(NULL,
" ", &saveptr);
162 if (strcmp(token,
"host") == 0) {
164 }
else if (strcmp(token,
"srflx") == 0) {
166 }
else if (strcmp(token,
"prflx") == 0) {
168 }
else if (strcmp(token,
"relay") == 0) {
177 token = strtok_r(NULL,
" ", &saveptr);
178 if (token && strcmp(token,
"raddr") == 0) {
179 token = strtok_r(NULL,
" ", &saveptr);
185 token = strtok_r(NULL,
" ", &saveptr);
186 if (!token || strcmp(token,
"rport") != 0) {
190 token = strtok_r(NULL,
" ", &saveptr);
191 if (!token || sscanf(token,
"%hu", &candidate->
rport) != 1) {
199 token = strtok_r(NULL,
" ", &saveptr);
201 if (strcmp(token,
"tcptype") == 0) {
202 token = strtok_r(NULL,
" ", &saveptr);
204 if (strcmp(token,
"active") == 0) {
206 }
else if (strcmp(token,
"passive") == 0) {
208 }
else if (strcmp(token,
"so") == 0) {
213 token = strtok_r(NULL,
" ", &saveptr);
221 if (!candidate || !line || line_size == 0) {
229 int written = snprintf(line, line_size,
"%s %u %s %u %s %u typ %s", candidate->
foundation, candidate->
component_id,
233 if (written < 0 || (
size_t)written >= line_size) {
237 size_t remaining = line_size - (size_t)written;
238 char *pos = line + written;
243 if (candidate->
raddr[0] !=
'\0') {
244 int appended = snprintf(pos, remaining,
" raddr %s rport %u", candidate->
raddr, candidate->
rport);
245 if (appended < 0 || (
size_t)appended >= remaining) {
249 remaining -= (size_t)appended;
255 const char *tcptype_str =
"passive";
257 tcptype_str =
"active";
262 int appended = snprintf(pos, remaining,
" tcptype %s", tcptype_str);
263 if (appended < 0 || (
size_t)appended >= remaining) {
267 remaining -= (size_t)appended;
272 int appended = snprintf(pos, remaining,
" %s", candidate->
extensions);
273 if (appended < 0 || (
size_t)appended >= remaining) {
295 log_debug(
"ICE: Starting candidate gathering (ufrag=%s, pwd=%s)", config->
ufrag, config->
pwd);
321 if (!candidate || !mid) {
330 log_debug(
"ICE: Adding remote candidate %s:%u (type=%s, foundation=%s) on mid=%s", candidate->
ip_address,
#define SAFE_STRNCPY(dst, src, size)
#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)
#define log_debug(...)
Log a DEBUG message.
asciichat_error_t ice_get_selected_pair(ice_candidate_t *local_candidate, ice_candidate_t *remote_candidate)
Get selected candidate pair.
const char * ice_protocol_name(ice_protocol_t protocol)
Get human-readable protocol name.
uint32_t ice_calculate_priority(ice_candidate_type_t type, uint16_t local_preference, uint8_t component_id)
Calculate candidate priority.
bool ice_is_connected(void)
Check ICE connection state.
asciichat_error_t ice_format_candidate(const ice_candidate_t *candidate, char *line, size_t line_size)
Format ICE candidate to attribute string.
asciichat_error_t ice_add_remote_candidate(const ice_candidate_t *candidate, const char *mid)
Add remote candidate to peer connection.
asciichat_error_t ice_parse_candidate(const char *line, ice_candidate_t *candidate)
Parse ICE candidate from attribute string.
const char * ice_candidate_type_name(ice_candidate_type_t type)
Get human-readable candidate type name.
asciichat_error_t ice_gather_candidates(const ice_config_t *config)
Start ICE candidate gathering.
ICE (Interactive Connectivity Establishment) for WebRTC.
ice_protocol_t
ICE candidate transport protocol.
ice_candidate_type_t
ICE candidate type enumeration (RFC 5245)
@ ICE_CANDIDATE_SRFLX
Server-reflexive (NAT-discovered via STUN)
@ ICE_CANDIDATE_HOST
Host candidate (local IP address)
@ ICE_CANDIDATE_RELAY
Relay candidate (TURN server)
@ ICE_CANDIDATE_PRFLX
Peer-reflexive (discovered during checks)
@ ICE_TCP_TYPE_SO
Simultaneous open.
@ ICE_TCP_TYPE_ACTIVE
Actively opens connection.
@ ICE_TCP_TYPE_PASSIVE
Passively waits for connection.
📝 Logging API with multiple log levels and terminal output control
Single ICE candidate for connectivity.
char ip_address[64]
IP address (IPv4 or IPv6)
char foundation[32]
Unique identifier for candidate (for pairing)
uint16_t port
Port number.
uint32_t component_id
Component (1=RTP, 2=RTCP; usually 1)
ice_candidate_type_t type
host, srflx, prflx, or relay
uint32_t priority
Candidate priority (used for preference)
uint16_t rport
Related port.
ice_protocol_t protocol
UDP or TCP.
char extensions[256]
Additional extensions (e.g., "tcptype passive")
ice_tcp_type_t tcp_type
active, passive, so
char raddr[64]
Related address (for srflx/prflx)
ICE gathering configuration.
const char * ufrag
Username fragment for ICE (from offer)
ice_send_candidate_callback_t send_callback
Called for each gathered candidate.
const char * pwd
Password for ICE (from offer)