ascii-chat
Binary v0.15.83-53-gb711d8720
Library lib/v0.3.2-701-gb711d8720
Video chat in your terminal
Loading...
Searching...
No Matches
Stun

Macros

#define STUN_URL_BUFFER_SIZE   64
 STUN server configuration.

Functions

struct __attribute__ ((packed))
int stun_servers_parse (const char *csv_servers, const char *default_csv, stun_server_t *out_servers, int max_count)
 Parse comma-separated STUN server URLs into stun_server_t array.

Variables

 stun_server_t

STUN Protocol Constants

#define STUN_DEFAULT_PORT   3478
 Standard STUN port (RFC 5389).
#define STUN_TLS_DEFAULT_PORT   5349
 STUN over TLS port (RFC 5389).

Detailed Description

This module defines STUN server configuration structures for WebRTC connectivity. STUN servers help clients discover their public IP addresses and port mappings when behind NAT.

RFC 5389: Session Traversal Utilities for NAT (STUN) RFC 8489: Session Traversal Utilities for NAT (STUN) - updated

STUN SERVER ROLE:

  • Helps clients discover their public-facing IP address and port
  • Essential for WebRTC peer-to-peer connection establishment
  • No relay (unlike TURN) - only provides connectivity information

USAGE IN ACDS:

  • Discovery server provides STUN server list in SESSION_CREATED response
  • Clients use STUN servers for ICE candidate gathering
  • Multiple STUN servers can be provided for redundancy
Note
All structures are packed with attribute((packed)) for wire format
Author
Zachary Fogg me@zf.nosp@m.o.gg
Date
January 2026
Version
1.0

Macro Definition Documentation

◆ STUN_DEFAULT_PORT

#define STUN_DEFAULT_PORT   3478

#include <include/ascii-chat/network/webrtc/stun.h>

Standard STUN port (RFC 5389).

Definition at line 87 of file stun.h.

◆ STUN_TLS_DEFAULT_PORT

#define STUN_TLS_DEFAULT_PORT   5349

#include <include/ascii-chat/network/webrtc/stun.h>

STUN over TLS port (RFC 5389).

Definition at line 90 of file stun.h.

◆ STUN_URL_BUFFER_SIZE

#define STUN_URL_BUFFER_SIZE   64

#include <include/ascii-chat/network/webrtc/stun.h>

STUN server configuration.

Used in ACDS SESSION_CREATED response to provide WebRTC connectivity information.

Protocol Format:

  • host_len: 1 byte (length of host string)
  • host: 64 bytes (null-terminated STUN URL)

URL Format Examples:

  • Stun:discovery.ascii.chat:3478 (standard port)
  • Stun:stun.l.google.com:19302 (Google public STUN)
  • Stun:stun.example.com:5349 (custom port)

Wire Format (65 bytes total):

+----------+----------------------------------------+
| host_len | host[64] |
+----------+----------------------------------------+
| 1 byte | 64 bytes |
+----------+----------------------------------------+

STUN wire URL capacity in bytes, including NUL (63 URL bytes).

Definition at line 73 of file stun.h.

Referenced by stun_servers_parse().

Function Documentation

◆ __attribute__()

struct __attribute__ ( (packed) )

#include <include/ascii-chat/network/webrtc/stun.h>

< Length of host string (actual URL length)

< STUN server URL (e.g., "stun:discovery.ascii.chat:3478")

Definition at line 1 of file stun.h.

75 {
76 uint8_t host_len;
77 char host[STUN_URL_BUFFER_SIZE];
unsigned char uint8_t
Definition common.h:60
stun_server_t
Definition stun.h:78
#define STUN_URL_BUFFER_SIZE
STUN server configuration.
Definition stun.h:73

◆ stun_servers_parse()

int stun_servers_parse ( const char * csv_servers,
const char * default_csv,
stun_server_t * out_servers,
int max_count )

#include <include/ascii-chat/network/webrtc/stun.h>

Parse comma-separated STUN server URLs into stun_server_t array.

Parses a comma-separated string of STUN server URLs (e.g., "stun:server1:3478,stun:server2:3478") into an array of stun_server_t structs. If the input string is empty or NULL, uses the default endpoints from the options system.

Example Input Formats:

  • Empty: "" (will use defaults from OPT_STUN_SERVERS_DEFAULT)
  • Single: "stun:stun.example.com:3478"
  • Multiple: "stun:server1:3478,stun:server2:19302,stun:server3:5349"
Parameters
csv_serversComma-separated STUN server URLs (can be empty)
default_csvDefault servers to use if csv_servers is empty
out_serversOutput array of stun_server_t structs (must be pre-allocated)
max_countMaximum number of servers to parse
Returns
Number of servers parsed (0-max_count), or -1 on error
Note
Each server URL is limited to STUN_URL_BUFFER_SIZE - 1 bytes, excluding NUL
Function gracefully stops at max_count or if a server exceeds max length

Parses a comma-separated string of STUN server URLs into stun_server_t structs. If the input string is empty or NULL, uses the provided default string.

Parameters
csv_serversComma-separated STUN server URLs (can be empty)
default_csvDefault servers to use if csv_servers is empty
out_serversOutput array of stun_server_t structs (must be pre-allocated)
max_countMaximum number of servers to parse
Returns
Number of servers parsed (0-max_count), or -1 on error

Definition at line 45 of file stun.c.

45 {
46 if (!out_servers || max_count <= 0) {
47 log_warn("Invalid output array or max_count");
48 return -1;
49 }
50
51 // Use defaults if input is empty
52 const char *servers_to_parse = csv_servers;
53 if (!servers_to_parse || servers_to_parse[0] == '\0') {
54 servers_to_parse = default_csv;
55 }
56
57 if (!servers_to_parse || servers_to_parse[0] == '\0') {
58 log_warn("No servers to parse and no defaults provided");
59 return 0;
60 }
61
62 // Get compiled regex (owned by the caller)
63 pcre2_code *regex = stun_entry_regex_get();
64
65 // If regex not available, fall back to manual parsing
66 if (!regex) {
67 log_warn("PCRE2 regex not available, falling back to manual parsing");
68 // Fallback: manual character-by-character parsing (original implementation)
69 int count = 0;
70 const char *current = servers_to_parse;
71 const char *end;
72
73 while (count < max_count && *current != '\0') {
74 while (isspace(*current)) {
75 current++;
76 }
77 if (*current == '\0')
78 break;
79
80 end = strchr(current, ',');
81 if (!end) {
82 end = current + strlen(current);
83 }
84
85 while (end > current && isspace(*(end - 1))) {
86 end--;
87 }
88
89 size_t len = end - current;
90 if (len == 0) {
91 current = *end ? end + 1 : end;
92 continue;
93 }
94
95 if (len >= STUN_URL_BUFFER_SIZE) {
96 log_warn("STUN server URL too long (max %d): %.*s", STUN_URL_BUFFER_SIZE - 1, (int)len, current);
97 return -1;
98 }
99
100 out_servers[count].host_len = (uint8_t)len;
101 memcpy(out_servers[count].host, current, len);
102 out_servers[count].host[len] = '\0';
103 count++;
104
105 current = *end ? end + 1 : end;
106 }
107 return count;
108 }
109
110 // Parse using PCRE2 regex: match each trimmed entry
111 int count = 0;
112 pcre2_match_data *match_data = pcre2_match_data_create_from_pattern(regex, NULL);
113 if (!match_data) {
114 pcre2_code_free(regex);
115 log_warn("Failed to allocate PCRE2 match data");
116 return -1;
117 }
118
119 size_t offset = 0;
120 int rc;
121
122 while (count < max_count) {
123 rc = asciichat_pcre2_match(regex, (PCRE2_SPTR8)servers_to_parse, strlen(servers_to_parse), offset, 0, match_data,
124 NULL);
125
126 if (rc < 0) {
127 // No more matches (PCRE2_ERROR_NOMATCH or other error)
128 break;
129 }
130
131 // Extract the captured group (group 1)
132 size_t len;
133 const char *server_url = asciichat_pcre2_extract_group_ptr(match_data, 1, servers_to_parse, &len);
134
135 if (!server_url) {
136 break; // Group not matched
137 }
138
139 if (len >= STUN_URL_BUFFER_SIZE) {
140 log_warn("STUN server URL too long (max %d): %.*s", STUN_URL_BUFFER_SIZE - 1, (int)len, server_url);
141 pcre2_match_data_free(match_data);
142 pcre2_code_free(regex);
143 return -1;
144 }
145
146 // Copy trimmed entry to output
147 out_servers[count].host_len = (uint8_t)len;
148 memcpy(out_servers[count].host, server_url, len);
149 out_servers[count].host[len] = '\0';
150
151 count++;
152
153 // Move offset to end of this match (need ovector for overall match end)
154 PCRE2_SIZE *ovector = pcre2_get_ovector_pointer(match_data);
155 offset = ovector[1];
156
157 // Skip comma if present
158 if (offset < strlen(servers_to_parse) && servers_to_parse[offset] == ',') {
159 offset++;
160 }
161 }
162
163 pcre2_match_data_free(match_data);
164 pcre2_code_free(regex);
165 return count;
166}
#define log_warn(...)
Log a WARN message.
Definition log/log.h:621
int asciichat_pcre2_match(const pcre2_code *code, PCRE2_SPTR subject, PCRE2_SIZE length, PCRE2_SIZE startoffset, uint32_t options, pcre2_match_data *match_data, pcre2_match_context *context)
Definition pcre2.c:164
const char * asciichat_pcre2_extract_group_ptr(pcre2_match_data *match_data, int group_num, const char *subject, size_t *out_len)
Extract numbered capture group as pointer into subject (non-allocating).
Definition pcre2.c:104

References asciichat_pcre2_extract_group_ptr(), asciichat_pcre2_match(), log_warn, stun_server_t, and STUN_URL_BUFFER_SIZE.

Variable Documentation

◆ stun_server_t

stun_server_t

#include <include/ascii-chat/network/webrtc/stun.h>

Definition at line 78 of file stun.h.

Referenced by stun_servers_parse().