blob: 2c52d0d50e9512558d14df53768faadde43a174c [file] [log] [blame]
James Kuszmaul4a42b182021-01-17 11:32:46 -08001#include "server.h"
2#include "../main/config.h"
3#include <rawrtc/config.h>
4#include <rawrtc/ice_gather_options.h>
5#include <rawrtc/ice_server.h>
6#include <rawrtcc/code.h>
7#include <rawrtcc/utils.h>
8#include <re.h>
9#include <string.h> // strlen
10
11#define DEBUG_MODULE "ice-server"
12//#define RAWRTC_DEBUG_MODULE_LEVEL 7 // Note: Uncomment this to debug this module only
13#include <rawrtcc/debug.h>
14
15/*
16 * ICE server URL-related regular expressions.
17 */
18static char const ice_server_url_regex[] = "[a-z]+:[^?]+[^]*";
19static char const ice_server_host_port_regex[] = "[^:]+[:]*[0-9]*";
20static char const ice_server_host_port_ipv6_regex[] = "\\[[0-9a-f:]+\\][:]*[0-9]*";
21static char const ice_server_transport_regex[] = "\\?transport=[a-z]+";
22
23/*
24 * Valid ICE server schemes.
25 *
26 * Note: Update `ice_server_scheme_type_mapping`,
27 * `ice_server_scheme_secure_mapping` and
28 * `ice_server_scheme_port_mapping` if changed.
29 */
30static char const* const ice_server_schemes[] = {
31 "stun",
32 "stuns",
33 "turn",
34 "turns",
35};
36static size_t const ice_server_schemes_length = ARRAY_SIZE(ice_server_schemes);
37
38/*
39 * ICE server scheme to server type mapping.
40 */
41static enum rawrtc_ice_server_type ice_server_scheme_type_mapping[] = {
42 RAWRTC_ICE_SERVER_TYPE_STUN,
43 RAWRTC_ICE_SERVER_TYPE_STUN,
44 RAWRTC_ICE_SERVER_TYPE_TURN,
45 RAWRTC_ICE_SERVER_TYPE_TURN,
46};
47
48/*
49 * ICE server scheme to secure mapping.
50 */
51static bool ice_server_scheme_secure_mapping[] = {
52 false,
53 true,
54 false,
55 true,
56};
57
58/*
59 * ICE server scheme to default port mapping.
60 */
61static uint_fast16_t ice_server_scheme_port_mapping[] = {
62 3478,
63 5349,
64 3478,
65 5349,
66};
67
68/*
69 * Valid ICE server transports.
70 *
71 * Note: Update `ice_server_transport_normal_transport_mapping` and
72 * `ice_server_transport_secure_transport_mapping` if changed.
73 */
74static char const* const ice_server_transports[] = {
75 "udp",
76 "tcp",
77};
78static size_t const ice_server_transports_length = ARRAY_SIZE(ice_server_transports);
79
80/*
81 * ICE server transport to non-secure transport mapping.
82 */
83static enum rawrtc_ice_server_transport ice_server_transport_normal_transport_mapping[] = {
84 RAWRTC_ICE_SERVER_TRANSPORT_UDP,
85 RAWRTC_ICE_SERVER_TRANSPORT_TCP,
86};
87
88/*
89 * ICE server transport to secure transport mapping.
90 */
91static enum rawrtc_ice_server_transport ice_server_transport_secure_transport_mapping[] = {
92 RAWRTC_ICE_SERVER_TRANSPORT_DTLS,
93 RAWRTC_ICE_SERVER_TRANSPORT_TLS,
94};
95
96/*
97 * Parse ICE server's transport.
98 */
99static enum rawrtc_code decode_ice_server_transport(
100 enum rawrtc_ice_server_transport* const transportp, // de-referenced, not checked
101 struct pl* const query, // not checked
102 bool const secure) {
103 enum rawrtc_code error;
104 struct pl transport;
105 size_t i;
106
107 // Decode transport
108 error =
109 rawrtc_error_to_code(re_regex(query->p, query->l, ice_server_transport_regex, &transport));
110 if (error) {
111 return error;
112 }
113
114 // Translate transport to ICE server transport
115 for (i = 0; i < ice_server_transports_length; ++i) {
116 if (pl_strcmp(&transport, ice_server_transports[i]) == 0) {
117 if (!secure) {
118 *transportp = ice_server_transport_normal_transport_mapping[i];
119 } else {
120 *transportp = ice_server_transport_secure_transport_mapping[i];
121 }
122 return RAWRTC_CODE_SUCCESS;
123 }
124 }
125
126 // Not found
127 return RAWRTC_CODE_INVALID_ARGUMENT;
128}
129
130/*
131 * Parse an ICE scheme to an ICE server type, 'secure' flag and
132 * default port.
133 */
134static enum rawrtc_code decode_ice_server_scheme(
135 enum rawrtc_ice_server_type* const typep, // de-referenced, not checked
136 bool* const securep, // de-referenced, not checked
137 uint_fast16_t* const portp, // de-referenced, not checked
138 struct pl* const scheme // not checked
139) {
140 size_t i;
141
142 // Translate scheme to ICE server type (and set if secure)
143 for (i = 0; i < ice_server_schemes_length; ++i) {
144 if (pl_strcmp(scheme, ice_server_schemes[i]) == 0) {
145 // Set values
146 *typep = ice_server_scheme_type_mapping[i];
147 *securep = ice_server_scheme_secure_mapping[i];
148 *portp = ice_server_scheme_port_mapping[i];
149
150 // Done
151 return RAWRTC_CODE_SUCCESS;
152 }
153 }
154
155 // Not found
156 return RAWRTC_CODE_INVALID_ARGUMENT;
157}
158
159/*
160 * Parse an ICE server URL according to RFC 7064 and RFC 7065
161 * (although the `transport` part is inaccurate for RFC 7064 but it
162 * seems useful)
163 */
164static enum rawrtc_code decode_ice_server_url(
165 struct rawrtc_ice_server_url* const url // not checked
166) {
167 enum rawrtc_code error;
168 struct pl scheme;
169 struct pl host_port;
170 struct pl query;
171 bool secure;
172 struct pl port_pl;
173 uint_fast16_t port;
174
175 // Decode URL
176 error = rawrtc_error_to_code(
177 re_regex(url->url, strlen(url->url), ice_server_url_regex, &scheme, &host_port, &query));
178 if (error) {
179 DEBUG_WARNING("Invalid ICE server URL: %s\n", url->url);
180 goto out;
181 }
182
183 // TODO: Can scheme or host be NULL?
184
185 // Get server type, secure flag and default port from scheme
186 error = decode_ice_server_scheme(&url->type, &secure, &port, &scheme);
187 if (error) {
188 DEBUG_WARNING("Invalid scheme in ICE server URL (%s): %r\n", url->url, &scheme);
189 goto out;
190 }
191
192 // Set default address
193 sa_set_in(&url->resolved_address, INADDR_ANY, (uint16_t) port);
194
195 // Decode host: Either IPv4 or IPv6 including the port (if any)
196 // Try IPv6 first, then normal hostname/IPv4.
197 error = rawrtc_error_to_code(re_regex(
198 host_port.p, host_port.l, ice_server_host_port_ipv6_regex, &url->host, NULL, &port_pl));
199 if (error) {
200 error = rawrtc_error_to_code(re_regex(
201 host_port.p, host_port.l, ice_server_host_port_regex, &url->host, NULL, &port_pl));
202 if (error) {
203 DEBUG_WARNING(
204 "Invalid host or port in ICE server URL (%s): %r\n", url->url, &host_port);
205 goto out;
206 }
207
208 // Try decoding IPv4
209 sa_set(&url->resolved_address, &url->host, (uint16_t) port);
210 } else {
211 // Try decoding IPv6
212 error = rawrtc_error_to_code(sa_set(&url->resolved_address, &url->host, (uint16_t) port));
213 if (error) {
214 DEBUG_WARNING(
215 "Invalid IPv6 address in ICE server URL (%s): %r\n", url->url, &host_port);
216 goto out;
217 }
218 }
219
220 // Decode port (if any)
221 if (pl_isset(&port_pl)) {
222 uint_fast32_t port_u32;
223
224 // Get port
225 port_u32 = pl_u32(&port_pl);
226 if (port_u32 == 0 || port_u32 > UINT16_MAX) {
227 DEBUG_WARNING(
228 "Invalid port number in ICE server URL (%s): %" PRIu32 "\n", url->url, port_u32);
229 error = RAWRTC_CODE_INVALID_ARGUMENT;
230 goto out;
231 }
232
233 // Set port
234 sa_set_port(&url->resolved_address, (uint16_t) port_u32);
235 }
236
237 // Translate transport (if any) & secure flag to ICE server transport
238 if (pl_isset(&query)) {
239 error = decode_ice_server_transport(&url->transport, &query, secure);
240 if (error) {
241 DEBUG_WARNING("Invalid transport in ICE server URL (%s): %r\n", url->url, &query);
242 goto out;
243 }
244 } else {
245 // Set default transport (depending on secure flag)
246 if (secure) {
247 url->transport = rawrtc_default_config.ice_server_secure_transport;
248 } else {
249 url->transport = rawrtc_default_config.ice_server_normal_transport;
250 }
251 }
252
253 // Done
254 error = RAWRTC_CODE_SUCCESS;
255
256out:
257 return error;
258}
259
260/*
261 * Destructor for URLs of the ICE gatherer.
262 */
263static void rawrtc_ice_server_url_destroy(void* arg) {
264 struct rawrtc_ice_server_url* const url = arg;
265
266 // Remove from list
267 list_unlink(&url->le);
268
269 // Un-reference
270 mem_deref(url->url);
271}
272
273/*
274 * Copy a URL for the ICE gatherer.
275 */
276static enum rawrtc_code rawrtc_ice_server_url_create(
277 struct rawrtc_ice_server_url** const urlp, // de-referenced
278 char* const url_s // copied
279) {
280 struct rawrtc_ice_server_url* url;
281 enum rawrtc_code error;
282
283 // Check arguments
284 if (!urlp || !url_s) {
285 return RAWRTC_CODE_INVALID_ARGUMENT;
286 }
287
288 // Allocate
289 url = mem_zalloc(sizeof(*url), rawrtc_ice_server_url_destroy);
290 if (!url) {
291 return RAWRTC_CODE_NO_MEMORY;
292 }
293
294 // Copy URL
295 error = rawrtc_strdup(&url->url, url_s);
296 if (error) {
297 goto out;
298 }
299
300 // Parse URL
301 // Note: `url->host` points inside `url->url`, so we MUST have copied the URL first.
302 error = decode_ice_server_url(url);
303 if (error) {
304 goto out;
305 }
306
307 // Done
308 error = RAWRTC_CODE_SUCCESS;
309
310out:
311 if (error) {
312 mem_deref(url);
313 } else {
314 // Set pointer
315 *urlp = url;
316 }
317 return error;
318}
319
320/*
321 * Destructor for an existing ICE server.
322 */
323static void rawrtc_ice_server_destroy(void* arg) {
324 struct rawrtc_ice_server* const server = arg;
325
326 // Un-reference
327 list_flush(&server->urls);
328 mem_deref(server->username);
329 mem_deref(server->credential);
330}
331
332/*
333 * Create an ICE server.
334 */
335enum rawrtc_code rawrtc_ice_server_create(
336 struct rawrtc_ice_server** const serverp, // de-referenced
337 char* const* const urls, // copied
338 size_t const n_urls,
339 char* const username, // nullable, copied
340 char* const credential, // nullable, copied
341 enum rawrtc_ice_credential_type const credential_type) {
342 struct rawrtc_ice_server* server;
343 enum rawrtc_code error = RAWRTC_CODE_SUCCESS;
344 size_t i;
345
346 // Check arguments
347 if (!serverp || !urls) {
348 return RAWRTC_CODE_INVALID_ARGUMENT;
349 }
350
351 // Allocate
352 server = mem_zalloc(sizeof(*server), rawrtc_ice_server_destroy);
353 if (!server) {
354 return RAWRTC_CODE_NO_MEMORY;
355 }
356
357 // Copy URLs to list
358 list_init(&server->urls);
359 for (i = 0; i < n_urls; ++i) {
360 struct rawrtc_ice_server_url* url;
361
362 // Ensure URLs aren't null
363 if (!urls[i]) {
364 error = RAWRTC_CODE_INVALID_ARGUMENT;
365 goto out;
366 }
367
368 // Copy URL
369 error = rawrtc_ice_server_url_create(&url, urls[i]);
370 if (error) {
371 goto out;
372 }
373
374 // Append URL to list
375 list_append(&server->urls, &url->le, url);
376 }
377
378 // Set fields
379 if (credential_type != RAWRTC_ICE_CREDENTIAL_TYPE_NONE) {
380 if (username) {
381 error = rawrtc_strdup(&server->username, username);
382 if (error) {
383 goto out;
384 }
385 }
386 if (credential) {
387 error = rawrtc_strdup(&server->credential, credential);
388 if (error) {
389 goto out;
390 }
391 }
392 }
393 server->credential_type = credential_type; // TODO: Validation needed in case TOKEN is used?
394
395out:
396 if (error) {
397 mem_deref(server);
398 } else {
399 // Set pointer
400 *serverp = server;
401 }
402 return error;
403}
404
405/*
406 * Copy an ICE server.
407 */
408enum rawrtc_code rawrtc_ice_server_copy(
409 struct rawrtc_ice_server** const serverp, // de-referenced
410 struct rawrtc_ice_server* const source_server) {
411 size_t n_urls;
412 char** urls = NULL;
413 struct le* le;
414 size_t i;
415 enum rawrtc_code error;
416
417 // Check arguments
418 if (!serverp || !source_server) {
419 return RAWRTC_CODE_INVALID_ARGUMENT;
420 }
421
422 // Create temporary ICE server URL array
423 n_urls = list_count(&source_server->urls);
424 if (n_urls > 0) {
425 urls = mem_alloc(sizeof(char*) * n_urls, NULL);
426 if (!urls) {
427 return RAWRTC_CODE_NO_MEMORY;
428 }
429 }
430
431 // Copy ICE server URL (str) pointers
432 for (le = list_head(&source_server->urls), i = 0; le != NULL; le = le->next, ++i) {
433 struct rawrtc_ice_server_url* const url = le->data;
434 urls[i] = url->url;
435 }
436
437 // Copy
438 error = rawrtc_ice_server_create(
439 serverp, urls, n_urls, source_server->username, source_server->credential,
440 source_server->credential_type);
441 if (error) {
442 goto out;
443 }
444
445out:
446 // Un-reference
447 mem_deref(urls);
448 return error;
449}