blob: a6bee78eef092cfb2d0770ac49017f083243ca9d [file] [log] [blame]
James Kuszmaul4a42b182021-01-17 11:32:46 -08001#include "candidate.h"
2#include <rawrtc/ice_candidate.h>
3#include <rawrtcc/code.h>
4#include <re.h>
5#include <netinet/in.h> // IPPROTO_UDP, IPPROTO_TCP
6
7/*
8 * Translate an ICE candidate type to the corresponding re type.
9 */
10enum ice_cand_type rawrtc_ice_candidate_type_to_ice_cand_type(
11 enum rawrtc_ice_candidate_type const type) {
12 // No conversion needed
13 return (enum ice_cand_type) type;
14}
15
16/*
17 * Translate a re ICE candidate type to the corresponding rawrtc type.
18 */
19enum rawrtc_code rawrtc_ice_cand_type_to_ice_candidate_type(
20 enum rawrtc_ice_candidate_type* const typep, // de-referenced
21 enum ice_cand_type const re_type) {
22 // Check arguments
23 if (!typep) {
24 return RAWRTC_CODE_INVALID_ARGUMENT;
25 }
26
27 // Convert ice_cand_type
28 switch (re_type) {
29 case ICE_CAND_TYPE_HOST:
30 *typep = RAWRTC_ICE_CANDIDATE_TYPE_HOST;
31 return RAWRTC_CODE_SUCCESS;
32 case ICE_CAND_TYPE_SRFLX:
33 *typep = RAWRTC_ICE_CANDIDATE_TYPE_SRFLX;
34 return RAWRTC_CODE_SUCCESS;
35 case ICE_CAND_TYPE_PRFLX:
36 *typep = RAWRTC_ICE_CANDIDATE_TYPE_PRFLX;
37 return RAWRTC_CODE_SUCCESS;
38 case ICE_CAND_TYPE_RELAY:
39 *typep = RAWRTC_ICE_CANDIDATE_TYPE_RELAY;
40 return RAWRTC_CODE_SUCCESS;
41 default:
42 return RAWRTC_CODE_INVALID_ARGUMENT;
43 }
44}
45
46/*
47 * Translate an ICE TCP candidate type to the corresponding re type.
48 */
49enum ice_tcptype rawrtc_ice_tcp_candidate_type_to_ice_tcptype(
50 enum rawrtc_ice_tcp_candidate_type const type) {
51 // No conversion needed
52 return (enum ice_tcptype) type;
53}
54
55/*
56 * Translate a re ICE TCP candidate type to the corresponding rawrtc type.
57 */
58enum rawrtc_code rawrtc_ice_tcptype_to_ice_tcp_candidate_type(
59 enum rawrtc_ice_tcp_candidate_type* const typep, // de-referenced
60 enum ice_tcptype const re_type) {
61 // Check arguments
62 if (!typep) {
63 return RAWRTC_CODE_INVALID_ARGUMENT;
64 }
65
66 // Convert ice_cand_type
67 switch (re_type) {
68 case ICE_TCP_ACTIVE:
69 *typep = RAWRTC_ICE_TCP_CANDIDATE_TYPE_ACTIVE;
70 return RAWRTC_CODE_SUCCESS;
71 case ICE_TCP_PASSIVE:
72 *typep = RAWRTC_ICE_TCP_CANDIDATE_TYPE_PASSIVE;
73 return RAWRTC_CODE_SUCCESS;
74 case ICE_TCP_SO:
75 *typep = RAWRTC_ICE_TCP_CANDIDATE_TYPE_SO;
76 return RAWRTC_CODE_SUCCESS;
77 default:
78 return RAWRTC_CODE_INVALID_ARGUMENT;
79 }
80}
81
82/*
83 * Translate a protocol to the corresponding IPPROTO_*.
84 */
85int rawrtc_ice_protocol_to_ipproto(enum rawrtc_ice_protocol const protocol) {
86 // No conversion needed
87 return (int) protocol;
88}
89
90/*
91 * Translate a IPPROTO_* to the corresponding protocol.
92 */
93enum rawrtc_code rawrtc_ipproto_to_ice_protocol(
94 enum rawrtc_ice_protocol* const protocolp, // de-referenced
95 int const ipproto) {
96 // Check arguments
97 if (!protocolp) {
98 return RAWRTC_CODE_INVALID_ARGUMENT;
99 }
100
101 // Convert IPPROTO_*
102 switch (ipproto) {
103 case IPPROTO_UDP:
104 *protocolp = RAWRTC_ICE_PROTOCOL_UDP;
105 return RAWRTC_CODE_SUCCESS;
106 case IPPROTO_TCP:
107 *protocolp = RAWRTC_ICE_PROTOCOL_TCP;
108 return RAWRTC_CODE_SUCCESS;
109 default:
110 return RAWRTC_CODE_INVALID_ARGUMENT;
111 }
112}
113
114static enum rawrtc_ice_protocol const map_enum_ice_protocol[] = {
115 RAWRTC_ICE_PROTOCOL_UDP,
116 RAWRTC_ICE_PROTOCOL_TCP,
117};
118
119static char const* const map_str_ice_protocol[] = {
120 "udp",
121 "tcp",
122};
123
124static size_t const map_ice_protocol_length = ARRAY_SIZE(map_enum_ice_protocol);
125
126/*
127 * Translate an ICE protocol to str.
128 */
129char const* rawrtc_ice_protocol_to_str(enum rawrtc_ice_protocol const protocol) {
130 size_t i;
131
132 for (i = 0; i < map_ice_protocol_length; ++i) {
133 if (map_enum_ice_protocol[i] == protocol) {
134 return map_str_ice_protocol[i];
135 }
136 }
137
138 return "???";
139}
140
141/*
142 * Translate a pl to an ICE protocol (case-insensitive).
143 */
144enum rawrtc_code rawrtc_pl_to_ice_protocol(
145 enum rawrtc_ice_protocol* const protocolp, // de-referenced
146 struct pl const* const pl) {
147 size_t i;
148
149 // Check arguments
150 if (!protocolp || !pl_isset(pl)) {
151 return RAWRTC_CODE_INVALID_ARGUMENT;
152 }
153
154 for (i = 0; i < map_ice_protocol_length; ++i) {
155 if (pl_strcasecmp(pl, map_str_ice_protocol[i]) == 0) {
156 *protocolp = map_enum_ice_protocol[i];
157 return RAWRTC_CODE_SUCCESS;
158 }
159 }
160
161 return RAWRTC_CODE_NO_VALUE;
162}
163
164/*
165 * Translate a str to an ICE protocol (case-insensitive).
166 */
167enum rawrtc_code rawrtc_str_to_ice_protocol(
168 enum rawrtc_ice_protocol* const protocolp, // de-referenced
169 char const* const str) {
170 struct pl pl;
171
172 // Check arguments
173 if (!str) {
174 return RAWRTC_CODE_INVALID_ARGUMENT;
175 }
176
177 // Convert str to pl
178 pl_set_str(&pl, str);
179 return rawrtc_pl_to_ice_protocol(protocolp, &pl);
180}
181
182static enum rawrtc_ice_candidate_type const map_enum_ice_candidate_type[] = {
183 RAWRTC_ICE_CANDIDATE_TYPE_HOST,
184 RAWRTC_ICE_CANDIDATE_TYPE_SRFLX,
185 RAWRTC_ICE_CANDIDATE_TYPE_PRFLX,
186 RAWRTC_ICE_CANDIDATE_TYPE_RELAY,
187};
188
189static char const* const map_str_ice_candidate_type[] = {
190 "host",
191 "srflx",
192 "prflx",
193 "relay",
194};
195
196static size_t const map_ice_candidate_type_length = ARRAY_SIZE(map_enum_ice_candidate_type);
197
198/*
199 * Translate an ICE candidate type to str.
200 */
201char const* rawrtc_ice_candidate_type_to_str(enum rawrtc_ice_candidate_type const type) {
202 size_t i;
203
204 for (i = 0; i < map_ice_candidate_type_length; ++i) {
205 if (map_enum_ice_candidate_type[i] == type) {
206 return map_str_ice_candidate_type[i];
207 }
208 }
209
210 return "???";
211}
212
213/*
214 * Translate a pl to an ICE candidate type (case-insensitive).
215 */
216enum rawrtc_code rawrtc_pl_to_ice_candidate_type(
217 enum rawrtc_ice_candidate_type* const typep, // de-referenced
218 struct pl const* const pl) {
219 size_t i;
220
221 // Check arguments
222 if (!typep || !pl_isset(pl)) {
223 return RAWRTC_CODE_INVALID_ARGUMENT;
224 }
225
226 for (i = 0; i < map_ice_candidate_type_length; ++i) {
227 if (pl_strcasecmp(pl, map_str_ice_candidate_type[i]) == 0) {
228 *typep = map_enum_ice_candidate_type[i];
229 return RAWRTC_CODE_SUCCESS;
230 }
231 }
232
233 return RAWRTC_CODE_NO_VALUE;
234}
235
236/*
237 * Translate a str to an ICE candidate type (case-insensitive).
238 */
239enum rawrtc_code rawrtc_str_to_ice_candidate_type(
240 enum rawrtc_ice_candidate_type* const typep, // de-referenced
241 char const* const str) {
242 struct pl pl;
243
244 // Check arguments
245 if (!str) {
246 return RAWRTC_CODE_INVALID_ARGUMENT;
247 }
248
249 // Convert str to pl
250 pl_set_str(&pl, str);
251 return rawrtc_pl_to_ice_candidate_type(typep, &pl);
252}
253
254static enum rawrtc_ice_tcp_candidate_type const map_enum_ice_tcp_candidate_type[] = {
255 RAWRTC_ICE_TCP_CANDIDATE_TYPE_ACTIVE,
256 RAWRTC_ICE_TCP_CANDIDATE_TYPE_PASSIVE,
257 RAWRTC_ICE_TCP_CANDIDATE_TYPE_SO,
258};
259
260static char const* const map_str_ice_tcp_candidate_type[] = {
261 "active",
262 "passive",
263 "so",
264};
265
266static size_t const map_ice_tcp_candidate_type_length = ARRAY_SIZE(map_enum_ice_tcp_candidate_type);
267
268/*
269 * Translate an ICE TCP candidate type to str.
270 */
271char const* rawrtc_ice_tcp_candidate_type_to_str(enum rawrtc_ice_tcp_candidate_type const type) {
272 size_t i;
273
274 for (i = 0; i < map_ice_tcp_candidate_type_length; ++i) {
275 if (map_enum_ice_tcp_candidate_type[i] == type) {
276 return map_str_ice_tcp_candidate_type[i];
277 }
278 }
279
280 return "???";
281}
282
283/*
284 * Translate a str to an ICE TCP candidate type (case-insensitive).
285 */
286enum rawrtc_code rawrtc_pl_to_ice_tcp_candidate_type(
287 enum rawrtc_ice_tcp_candidate_type* const typep, // de-referenced
288 struct pl const* const pl) {
289 size_t i;
290
291 // Check arguments
292 if (!typep || !pl_isset(pl)) {
293 return RAWRTC_CODE_INVALID_ARGUMENT;
294 }
295
296 for (i = 0; i < map_ice_tcp_candidate_type_length; ++i) {
297 if (pl_strcasecmp(pl, map_str_ice_tcp_candidate_type[i]) == 0) {
298 *typep = map_enum_ice_tcp_candidate_type[i];
299 return RAWRTC_CODE_SUCCESS;
300 }
301 }
302
303 return RAWRTC_CODE_NO_VALUE;
304}
305
306/*
307 * Translate a str to an ICE TCP candidate type (case-insensitive).
308 */
309enum rawrtc_code rawrtc_str_to_ice_tcp_candidate_type(
310 enum rawrtc_ice_tcp_candidate_type* const typep, // de-referenced
311 char const* const str) {
312 struct pl pl;
313
314 // Check arguments
315 if (!str) {
316 return RAWRTC_CODE_INVALID_ARGUMENT;
317 }
318
319 // Convert str to pl
320 pl_set_str(&pl, str);
321 return rawrtc_pl_to_ice_tcp_candidate_type(typep, &pl);
322}
323
324static char const* const map_str_ice_candidate_storage[] = {
325 "raw",
326 "lcand",
327 "rcand",
328};
329
330static enum rawrtc_ice_candidate_storage const map_enum_ice_candidate_storage[] = {
331 RAWRTC_ICE_CANDIDATE_STORAGE_RAW,
332 RAWRTC_ICE_CANDIDATE_STORAGE_LCAND,
333 RAWRTC_ICE_CANDIDATE_STORAGE_RCAND,
334};
335
336static size_t const map_ice_candidate_storage_length = ARRAY_SIZE(map_enum_ice_candidate_storage);
337
338/*
339 * Translate an ICE candidate storage type to str.
340 */
341static char const* ice_candidate_storage_to_str(enum rawrtc_ice_candidate_storage const type) {
342 size_t i;
343
344 for (i = 0; i < map_ice_candidate_storage_length; ++i) {
345 if (map_enum_ice_candidate_storage[i] == type) {
346 return map_str_ice_candidate_storage[i];
347 }
348 }
349
350 return "???";
351}
352
353/*
354 * Print debug information for an ICE candidate.
355 */
356int rawrtc_ice_candidate_debug(
357 struct re_printf* const pf, struct rawrtc_ice_candidate* const candidate) {
358 int err = 0;
359 enum rawrtc_code error;
360 char* foundation = NULL;
361 uint32_t priority;
362 char* ip = NULL;
363 enum rawrtc_ice_protocol protocol;
364 uint16_t port;
365 enum rawrtc_ice_candidate_type type;
366 enum rawrtc_ice_tcp_candidate_type tcp_type;
367 char* related_address = NULL;
368 uint16_t related_port;
369
370 // Check arguments
371 if (!candidate) {
372 return 0;
373 }
374
375 err |= re_hprintf(pf, " ICE Candidate <%p>:\n", candidate);
376
377 // Storage type
378 err |= re_hprintf(
379 pf, " storage_type=%s\n", ice_candidate_storage_to_str(candidate->storage_type));
380
381 // Foundation
382 error = rawrtc_ice_candidate_get_foundation(&foundation, candidate);
383 if (error) {
384 goto out;
385 }
386 err |= re_hprintf(pf, " foundation=\"%s\"\n", foundation);
387
388 // Priority
389 error = rawrtc_ice_candidate_get_priority(&priority, candidate);
390 if (error) {
391 goto out;
392 }
393 err |= re_hprintf(pf, " priority=%" PRIu32 "\n", priority);
394
395 // IP
396 error = rawrtc_ice_candidate_get_ip(&ip, candidate);
397 if (error) {
398 goto out;
399 }
400 err |= re_hprintf(pf, " ip=%s\n", ip);
401
402 // Protocol
403 error = rawrtc_ice_candidate_get_protocol(&protocol, candidate);
404 if (error) {
405 goto out;
406 }
407 err |= re_hprintf(pf, " protocol=%s\n", rawrtc_ice_protocol_to_str(protocol));
408
409 // Port
410 error = rawrtc_ice_candidate_get_port(&port, candidate);
411 if (error) {
412 goto out;
413 }
414 err |= re_hprintf(pf, " port=%" PRIu16 "\n", port);
415
416 // Type
417 error = rawrtc_ice_candidate_get_type(&type, candidate);
418 if (error) {
419 goto out;
420 }
421 err |= re_hprintf(pf, " type=%s\n", rawrtc_ice_candidate_type_to_str(type));
422
423 // TCP type (if any)
424 err |= re_hprintf(pf, " tcp_type=");
425 error = rawrtc_ice_candidate_get_tcp_type(&tcp_type, candidate);
426 switch (error) {
427 case RAWRTC_CODE_SUCCESS:
428 err |= re_hprintf(pf, "%s\n", rawrtc_ice_tcp_candidate_type_to_str(tcp_type));
429 break;
430 case RAWRTC_CODE_NO_VALUE:
431 err |= re_hprintf(pf, "n/a\n");
432 break;
433 default:
434 goto out;
435 }
436
437 // Related address (if any)
438 err |= re_hprintf(pf, " related_address=");
439 error = rawrtc_ice_candidate_get_related_address(&related_address, candidate);
440 switch (error) {
441 case RAWRTC_CODE_SUCCESS:
442 err |= re_hprintf(pf, "%s\n", related_address);
443 break;
444 case RAWRTC_CODE_NO_VALUE:
445 err |= re_hprintf(pf, "n/a\n");
446 break;
447 default:
448 goto out;
449 }
450
451 // Related port (if any)
452 err |= re_hprintf(pf, " related_port=");
453 error = rawrtc_ice_candidate_get_related_port(&related_port, candidate);
454 switch (error) {
455 case RAWRTC_CODE_SUCCESS:
456 err |= re_hprintf(pf, "%" PRIu16 "\n", related_port);
457 break;
458 case RAWRTC_CODE_NO_VALUE:
459 err |= re_hprintf(pf, "n/a\n");
460 break;
461 default:
462 goto out;
463 }
464
465out:
466 // Un-reference
467 mem_deref(related_address);
468 mem_deref(ip);
469 mem_deref(foundation);
470
471 // Translate error & done
472 if (!err && error) {
473 err = EINVAL;
474 }
475 return err;
476}