blob: deb23c4959b6ec99b5fc257c9d0a5e4cab136916 [file] [log] [blame]
James Kuszmaul871d0712021-01-17 11:30:43 -08001/**
2 * @file candpair.c ICE Candidate Pairs
3 *
4 * Copyright (C) 2010 Creytiv.com
5 */
6#include <string.h>
7#include <re_types.h>
8#include <re_fmt.h>
9#include <re_mem.h>
10#include <re_mbuf.h>
11#include <re_list.h>
12#include <re_tmr.h>
13#include <re_sa.h>
14#include <re_udp.h>
15#include <re_stun.h>
16#include <re_ice.h>
17#include <re_trice.h>
18#include "trice.h"
19
20
21#define DEBUG_MODULE "candpair"
22#define DEBUG_LEVEL 5
23#include <re_dbg.h>
24
25
26/*
27 * generic routines to operate on "struct ice_candpair"
28 * (for both checkl and validl)
29 */
30
31
32/*
33 * g = controlling agent
34 * d = controlled agent
35
36 pair priority = 2^32*MIN(G,D) + 2*MAX(G,D) + (G>D?1:0)
37
38 */
39static uint64_t ice_calc_pair_prio(uint32_t g, uint32_t d)
40{
41 const uint64_t m = min(g, d);
42 const uint64_t x = max(g, d);
43
44 return (m<<32) + 2*x + (g>d?1:0);
45}
46
47
48static void candpair_destructor(void *arg)
49{
50 struct ice_candpair *cp = arg;
51
52 list_unlink(&cp->le);
53 mem_deref(cp->lcand);
54 mem_deref(cp->rcand);
55 mem_deref(cp->tc);
56
57 mem_deref(cp->conn);
58}
59
60
61static bool sort_handler(struct le *le1, struct le *le2, void *arg)
62{
63 const struct ice_candpair *cp1 = le1->data, *cp2 = le2->data;
64 (void)arg;
65
66 return cp1->pprio >= cp2->pprio;
67}
68
69
70static void candpair_set_pprio(struct ice_candpair *cp, bool controlling)
71{
72 uint32_t g, d;
73
74 if (controlling) {
75 g = cp->lcand->attr.prio;
76 d = cp->rcand->attr.prio;
77 }
78 else {
79 g = cp->rcand->attr.prio;
80 d = cp->lcand->attr.prio;
81 }
82
83 cp->pprio = ice_calc_pair_prio(g, d);
84}
85
86
87/**
88 * Add candidate pair to list, sorted by pair priority (highest is first)
89 */
90static void list_add_sorted(struct list *list, struct ice_candpair *cp)
91{
92 struct le *le;
93
94 /* find our slot */
95 for (le = list_tail(list); le; le = le->prev) {
96 struct ice_candpair *cp0 = le->data;
97
98 if (cp->pprio < cp0->pprio) {
99 list_insert_after(list, le, &cp->le, cp);
100 return;
101 }
102 }
103
104 list_prepend(list, &cp->le, cp);
105}
106
107
108int trice_candpair_alloc(struct ice_candpair **cpp, struct trice *icem,
109 struct ice_lcand *lcand, struct ice_rcand *rcand)
110{
111 struct ice_candpair *cp;
112
113 if (!icem || !lcand || !rcand)
114 return EINVAL;
115
116 if (icem->lrole == ICE_ROLE_UNKNOWN) {
117 DEBUG_WARNING("trice_candpair_alloc: invalid local role!\n");
118 return EINVAL;
119 }
120
121 cp = mem_zalloc(sizeof(*cp), candpair_destructor);
122 if (!cp)
123 return ENOMEM;
124
125 cp->lcand = mem_ref(lcand);
126 cp->rcand = mem_ref(rcand);
127 cp->state = ICE_CANDPAIR_FROZEN;
128
129 candpair_set_pprio(cp, icem->lrole == ICE_ROLE_CONTROLLING);
130
131 list_add_sorted(&icem->checkl, cp);
132
133 if (cpp)
134 *cpp = cp;
135
136 return 0;
137}
138
139
140/** Computing Pair Priority and Ordering Pairs */
141void trice_candpair_prio_order(struct list *lst, bool controlling)
142{
143 struct le *le;
144
145 for (le = list_head(lst); le; le = le->next) {
146 struct ice_candpair *cp = le->data;
147
148 candpair_set_pprio(cp, controlling);
149 }
150
151 list_sort(lst, sort_handler, NULL);
152}
153
154
155void trice_candpair_make_valid(struct trice *icem, struct ice_candpair *pair)
156{
157 if (!icem || !pair)
158 return;
159
160 if (pair->state == ICE_CANDPAIR_FAILED) {
161 DEBUG_WARNING("make_valid: pair already FAILED [%H]\n",
162 trice_candpair_debug, pair);
163 }
164
165 pair->err = 0;
166 pair->scode = 0;
167 pair->valid = true;
168
169 trice_candpair_set_state(pair, ICE_CANDPAIR_SUCCEEDED);
170
171 list_unlink(&pair->le);
172 list_add_sorted(&icem->validl, pair);
173}
174
175
176void trice_candpair_failed(struct ice_candpair *cp, int err, uint16_t scode)
177{
178 if (!cp)
179 return;
180
181 if (cp->state == ICE_CANDPAIR_SUCCEEDED) {
182 DEBUG_WARNING("set_failed(%m): pair already SUCCEEDED [%H]\n",
183 err, trice_candpair_debug, cp);
184 }
185
186 cp->err = err;
187 cp->scode = scode;
188 cp->valid = false;
189
190 cp->conn = mem_deref(cp->conn);
191
192 trice_candpair_set_state(cp, ICE_CANDPAIR_FAILED);
193}
194
195
196void trice_candpair_set_state(struct ice_candpair *pair,
197 enum ice_candpair_state state)
198{
199 if (!pair)
200 return;
201 if (pair->state == state)
202 return;
203
204 if (trice_candpair_iscompleted(pair)) {
205 DEBUG_WARNING("set_state(%s): pair is already completed"
206 " [%H]\n",
207 trice_candpair_state2name(state),
208 trice_candpair_debug, pair);
209 }
210
211#if 0
212 trice_printf(pair->lcand->icem,
213 "%H new state \"%s\"\n",
214 trice_candpair_debug, pair,
215 trice_candpair_state2name(state));
216#endif
217
218 pair->state = state;
219}
220
221
222bool trice_candpair_iscompleted(const struct ice_candpair *cp)
223{
224 if (!cp)
225 return false;
226
227 return cp->state == ICE_CANDPAIR_FAILED ||
228 cp->state == ICE_CANDPAIR_SUCCEEDED;
229}
230
231
232/**
233 * Find the highest-priority candidate-pair in a given list, with
234 * optional match parameters
235 *
236 * @param lst List of candidate pairs
237 * @param lcand Local candidate (optional)
238 * @param rcand Remote candidate (optional)
239 *
240 * @return Matching candidate pair if found, otherwise NULL
241 *
242 * note: assume list is sorted by priority
243 */
244struct ice_candpair *trice_candpair_find(const struct list *lst,
245 const struct ice_lcand *lcand,
246 const struct ice_rcand *rcand)
247{
248 struct le *le;
249
250 for (le = list_head(lst); le; le = le->next) {
251
252 struct ice_candpair *cp = le->data;
253
254 if (!cp->lcand || !cp->rcand) {
255 DEBUG_WARNING("corrupt candpair %p\n", cp);
256 continue;
257 }
258
259 if (lcand && cp->lcand != lcand)
260 continue;
261
262 if (rcand && cp->rcand != rcand)
263 continue;
264
265 return cp;
266 }
267
268 return NULL;
269}
270
271
272/* find the first pair with a given state */
273struct ice_candpair *trice_candpair_find_state(const struct list *lst,
274 enum ice_candpair_state state)
275{
276 struct le *le;
277
278 for (le = list_head(lst); le; le = le->next) {
279
280 struct ice_candpair *cp = le->data;
281
282 if (cp->state != state)
283 continue;
284
285 return cp;
286 }
287
288 return NULL;
289}
290
291
292bool trice_candpair_cmp_fnd(const struct ice_candpair *cp1,
293 const struct ice_candpair *cp2)
294{
295 if (!cp1 || !cp2)
296 return false;
297
298 return 0 == strcmp(cp1->lcand->attr.foundation,
299 cp2->lcand->attr.foundation) &&
300 0 == strcmp(cp1->rcand->attr.foundation,
301 cp2->rcand->attr.foundation);
302}
303
304
305/* RFC 6544 -- 6.2. Forming the Check Lists
306
307 Local Remote
308 Candidate Candidate
309 ---------------------------
310 tcp-so tcp-so
311 tcp-active tcp-passive
312 tcp-passive tcp-active
313
314 */
315static bool tcptype_match(enum ice_tcptype loc, enum ice_tcptype rem)
316{
317 if (loc == ICE_TCP_SO && rem == ICE_TCP_SO) return true;
318 if (loc == ICE_TCP_ACTIVE && rem == ICE_TCP_PASSIVE) return true;
319 if (loc == ICE_TCP_PASSIVE && rem == ICE_TCP_ACTIVE) return true;
320
321 return false;
322}
323
324
325/* Replace server reflexive candidates by its base */
326static const struct sa *cand_srflx_addr(const struct ice_lcand *cand)
327{
328 if (ICE_CAND_TYPE_SRFLX == cand->attr.type)
329 return &cand->base_addr;
330 else
331 return &cand->attr.addr;
332}
333
334
335static struct ice_candpair *find_same_base_list(const struct list *lst,
336 const struct ice_lcand *lcand,
337 const struct ice_rcand *rcand)
338{
339 struct le *le;
340
341 for (le = list_head(lst); le; le = le->next) {
342
343 struct ice_candpair *cp = le->data;
344
345 if (cp->lcand->attr.compid == lcand->attr.compid
346 &&
347 cp->lcand->attr.proto == lcand->attr.proto
348 &&
349 sa_cmp(cand_srflx_addr(cp->lcand),
350 cand_srflx_addr(lcand), SA_ALL)
351 &&
352 sa_cmp(&cp->rcand->attr.addr,
353 &rcand->attr.addr, SA_ALL)) {
354
355 return cp;
356 }
357 }
358
359 return NULL;
360}
361
362
363/* look in both check-list and valid-list */
364static struct ice_candpair *find_same_base(struct trice *icem,
365 const struct ice_lcand *lcand,
366 const struct ice_rcand *rcand)
367{
368 struct ice_candpair *cp;
369
370 cp = find_same_base_list(&icem->checkl, lcand, rcand);
371 if (cp)
372 return cp;
373
374 cp = find_same_base_list(&icem->validl, lcand, rcand);
375 if (cp)
376 return cp;
377
378 return NULL;
379}
380
381
382/* Pair a local candidate with a remote candidate */
383static int create_pair(struct trice *icem, struct ice_lcand *lcand,
384 struct ice_rcand *rcand)
385{
386 struct ice_candpair *cpx;
387
388 if (lcand->attr.compid != rcand->attr.compid ||
389 lcand->attr.proto != rcand->attr.proto ||
390 sa_af(&lcand->attr.addr) != sa_af(&rcand->attr.addr)) {
391 return 0;
392 }
393
394 /*
395 * IPv6 link-local: only pair with IPv6 link-local addresses
396 * see: RFC5245bis, section 6.1.2.2
397 */
398 if (sa_af(&lcand->attr.addr) == AF_INET6 &&
399 sa_is_linklocal(&lcand->attr.addr) !=
400 sa_is_linklocal(&rcand->attr.addr)) {
401 return 0;
402 }
403
404 /* loopback pairing optimization: only pair with loopback addresses */
405 if (icem->conf.optimize_loopback_pairing &&
406 sa_is_loopback(&lcand->attr.addr) !=
407 sa_is_loopback(&rcand->attr.addr)) {
408 return 0;
409 }
410
411 cpx = find_same_base(icem, lcand, rcand);
412 if (cpx) {
413 trice_printf(icem,
414 "with: pair with same"
415 " base already exist"
416 " (%H)\n",
417 trice_candpair_debug, cpx);
418
419 return 0;
420 }
421
422 if (lcand->attr.proto == IPPROTO_TCP) {
423 if (!tcptype_match(lcand->attr.tcptype,
424 rcand->attr.tcptype))
425 return 0;
426 }
427
428 /* add sorted */
429 return trice_candpair_alloc(NULL, icem, lcand, rcand);
430}
431
432
433/* Pair a candidate with all other candidates of the opposite kind */
434int trice_candpair_with_local(struct trice *icem, struct ice_lcand *lcand)
435{
436 struct list *lst = &icem->rcandl;
437 struct le *le;
438 int err = 0;
439
440 if (icem->lrole == ICE_ROLE_UNKNOWN) {
441 DEBUG_WARNING("trice_candpair_with_local: invalid local role!"
442 "\n");
443 return EINVAL;
444 }
445
446 for (le = list_head(lst); le; le = le->next) {
447
448 struct ice_rcand *rcand = le->data;
449
450 err = create_pair(icem, lcand, rcand);
451 if (err)
452 goto out;
453 }
454
455 out:
456 return err;
457}
458
459
460/* Pair a candidate with all other candidates of the opposite kind */
461int trice_candpair_with_remote(struct trice *icem, struct ice_rcand *rcand)
462{
463 struct list *lst = &icem->lcandl;
464 struct le *le;
465 int err = 0;
466
467 if (icem->lrole == ICE_ROLE_UNKNOWN) {
468 DEBUG_WARNING("trice_candpair_with_remote: invalid local role!"
469 "\n");
470 return EINVAL;
471 }
472
473 for (le = list_head(lst); le; le = le->next) {
474
475 struct ice_lcand *lcand = le->data;
476
477 err = create_pair(icem, lcand, rcand);
478 if (err)
479 goto out;
480 }
481
482 out:
483 return err;
484}
485
486
487int trice_candpair_debug(struct re_printf *pf, const struct ice_candpair *cp)
488{
489 int err;
490
491 if (!cp)
492 return 0;
493
494 err = re_hprintf(pf, "{comp=%u} %10s {%c%c%c%c} %28H <---> %28H",
495 cp->lcand->attr.compid,
496 trice_candpair_state2name(cp->state),
497 cp->valid ? 'V' : ' ',
498 cp->nominated ? 'N' : ' ',
499 cp->estab ? 'E' : ' ',
500 cp->trigged ? 'T' : ' ',
501 trice_cand_print, cp->lcand,
502 trice_cand_print, cp->rcand);
503
504 if (cp->err)
505 err |= re_hprintf(pf, " (%m)", cp->err);
506
507 if (cp->scode)
508 err |= re_hprintf(pf, " [%u]", cp->scode);
509
510 return err;
511}
512
513
514int trice_candpairs_debug(struct re_printf *pf, bool ansi_output,
515 const struct list *list)
516{
517 struct le *le;
518 int err;
519
520 if (!list)
521 return 0;
522
523 err = re_hprintf(pf, " (%u)\n", list_count(list));
524
525 for (le = list->head; le && !err; le = le->next) {
526
527 const struct ice_candpair *cp = le->data;
528 bool ansi = false;
529
530 if (ansi_output) {
531 if (cp->state == ICE_CANDPAIR_SUCCEEDED) {
532 err |= re_hprintf(pf, "\x1b[32m");
533 ansi = true;
534 }
535 else if (cp->err || cp->scode) {
536 err |= re_hprintf(pf, "\x1b[31m");
537 ansi = true;
538 }
539 }
540
541 err |= re_hprintf(pf, " %H\n",
542 trice_candpair_debug, cp);
543
544 if (ansi)
545 err |= re_hprintf(pf, "\x1b[;m");
546 }
547
548 return err;
549}
550
551
552const char *trice_candpair_state2name(enum ice_candpair_state st)
553{
554 switch (st) {
555
556 case ICE_CANDPAIR_FROZEN: return "Frozen";
557 case ICE_CANDPAIR_WAITING: return "Waiting";
558 case ICE_CANDPAIR_INPROGRESS: return "InProgress";
559 case ICE_CANDPAIR_SUCCEEDED: return "Succeeded";
560 case ICE_CANDPAIR_FAILED: return "Failed";
561 default: return "???";
562 }
563}