Coverage Report

Created: 2026-01-10 06:11

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/rtpproxy/external/libre/src/ice/candpair.c
Line
Count
Source
1
/**
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_stun.h>
15
#include <re_ice.h>
16
#include "ice.h"
17
18
19
0
#define DEBUG_MODULE "cndpair"
20
#define DEBUG_LEVEL 5
21
#include <re_dbg.h>
22
23
24
static void candpair_destructor(void *arg)
25
0
{
26
0
  struct ice_candpair *cp = arg;
27
28
0
  list_unlink(&cp->le);
29
0
  mem_deref(cp->ct_conn);
30
0
  mem_deref(cp->lcand);
31
0
  mem_deref(cp->rcand);
32
0
}
33
34
35
static bool sort_handler(struct le *le1, struct le *le2, void *arg)
36
0
{
37
0
  const struct ice_candpair *cp1 = le1->data, *cp2 = le2->data;
38
0
  (void)arg;
39
40
0
  return cp1->pprio >= cp2->pprio;
41
0
}
42
43
44
static void candpair_set_pprio(struct ice_candpair *cp)
45
0
{
46
0
  uint32_t g, d;
47
48
0
  if (ICE_ROLE_CONTROLLING == cp->icem->lrole) {
49
0
    g = cp->lcand->prio;
50
0
    d = cp->rcand->prio;
51
0
  }
52
0
  else {
53
0
    g = cp->rcand->prio;
54
0
    d = cp->lcand->prio;
55
0
  }
56
57
0
  cp->pprio = ice_calc_pair_prio(g, d);
58
0
}
59
60
61
/**
62
 * Add candidate pair to list, sorted by pair priority (highest is first)
63
 */
64
static void list_add_sorted(struct list *list, struct ice_candpair *cp)
65
0
{
66
0
  struct le *le;
67
68
  /* find our slot */
69
0
  for (le = list_tail(list); le; le = le->prev) {
70
0
    struct ice_candpair *cp0 = le->data;
71
72
0
    if (cp->pprio < cp0->pprio) {
73
0
      list_insert_after(list, le, &cp->le, cp);
74
0
      return;
75
0
    }
76
0
  }
77
78
0
  list_prepend(list, &cp->le, cp);
79
0
}
80
81
82
int icem_candpair_alloc(struct ice_candpair **cpp, struct icem *icem,
83
      struct ice_cand *lcand, struct ice_cand *rcand)
84
0
{
85
0
  struct ice_candpair *cp;
86
0
  struct icem_comp *comp;
87
88
0
  if (!icem || !lcand || !rcand)
89
0
    return EINVAL;
90
91
0
  comp = icem_comp_find(icem, lcand->compid);
92
0
  if (!comp)
93
0
    return ENOENT;
94
95
0
  cp = mem_zalloc(sizeof(*cp), candpair_destructor);
96
0
  if (!cp)
97
0
    return ENOMEM;
98
99
0
  cp->icem  = icem;
100
0
  cp->comp  = comp;
101
0
  cp->lcand = mem_ref(lcand);
102
0
  cp->rcand = mem_ref(rcand);
103
0
  cp->state = ICE_CANDPAIR_FROZEN;
104
0
  cp->def   = comp->def_lcand == lcand && comp->def_rcand == rcand;
105
106
0
  candpair_set_pprio(cp);
107
108
0
  list_add_sorted(&icem->checkl, cp);
109
110
0
  if (cpp)
111
0
    *cpp = cp;
112
113
0
  return 0;
114
0
}
115
116
117
int icem_candpair_clone(struct ice_candpair **cpp, struct ice_candpair *cp0,
118
      struct ice_cand *lcand, struct ice_cand *rcand)
119
0
{
120
0
  struct ice_candpair *cp;
121
122
0
  if (!cp0)
123
0
    return EINVAL;
124
125
0
  cp = mem_zalloc(sizeof(*cp), candpair_destructor);
126
0
  if (!cp)
127
0
    return ENOMEM;
128
129
0
  cp->icem      = cp0->icem;
130
0
  cp->comp      = cp0->comp;
131
0
  cp->lcand     = mem_ref(lcand ? lcand : cp0->lcand);
132
0
  cp->rcand     = mem_ref(rcand ? rcand : cp0->rcand);
133
0
  cp->def       = cp0->def;
134
0
  cp->valid     = cp0->valid;
135
0
  cp->nominated = cp0->nominated;
136
0
  cp->state     = cp0->state;
137
0
  cp->pprio     = cp0->pprio;
138
0
  cp->err       = cp0->err;
139
0
  cp->scode     = cp0->scode;
140
141
0
  list_add_sorted(&cp0->icem->checkl, cp);
142
143
0
  if (cpp)
144
0
    *cpp = cp;
145
146
0
  return 0;
147
0
}
148
149
150
/**
151
 * Computing Pair Priority and Ordering Pairs
152
 *
153
 * @param lst Checklist (struct ice_candpair)
154
 */
155
void icem_candpair_prio_order(struct list *lst)
156
0
{
157
0
  struct le *le;
158
159
0
  for (le = list_head(lst); le; le = le->next) {
160
0
    struct ice_candpair *cp = le->data;
161
162
0
    candpair_set_pprio(cp);
163
0
  }
164
165
0
  list_sort(lst, sort_handler, NULL);
166
0
}
167
168
169
/* cancel transaction */
170
void icem_candpair_cancel(struct ice_candpair *cp)
171
0
{
172
0
  if (!cp)
173
0
    return;
174
175
0
  cp->ct_conn = mem_deref(cp->ct_conn);
176
0
}
177
178
179
void icem_candpair_make_valid(struct ice_candpair *cp)
180
0
{
181
0
  if (!cp)
182
0
    return;
183
184
0
  cp->err = 0;
185
0
  cp->scode = 0;
186
0
  cp->valid = true;
187
188
0
  icem_candpair_set_state(cp, ICE_CANDPAIR_SUCCEEDED);
189
190
0
  list_unlink(&cp->le);
191
0
  list_add_sorted(&cp->icem->validl, cp);
192
0
}
193
194
195
void icem_candpair_failed(struct ice_candpair *cp, int err, uint16_t scode)
196
0
{
197
0
  if (!cp)
198
0
    return;
199
200
0
  cp->err = err;
201
0
  cp->scode = scode;
202
0
  cp->valid = false;
203
204
0
  icem_candpair_set_state(cp, ICE_CANDPAIR_FAILED);
205
0
}
206
207
208
void icem_candpair_set_state(struct ice_candpair *cp,
209
           enum ice_candpair_state state)
210
0
{
211
0
  if (!cp)
212
0
    return;
213
0
  if (cp->state == state || icem_candpair_iscompleted(cp))
214
0
    return;
215
216
0
  icecomp_printf(cp->comp,
217
0
           "%5s <---> %5s  FSM:  %10s ===> %-10s\n",
218
0
           ice_cand_type2name(cp->lcand->type),
219
0
           ice_cand_type2name(cp->rcand->type),
220
0
           ice_candpair_state2name(cp->state),
221
0
           ice_candpair_state2name(state));
222
223
0
  cp->state = state;
224
0
}
225
226
227
/**
228
 * Delete all Candidate-Pairs where the Local candidate is of a given type
229
 *
230
 * @param lst     Checklist or Validlist
231
 * @param type    Candidate type
232
 * @param compid  Component ID
233
 */
234
void icem_candpairs_flush(struct list *lst, enum ice_cand_type type,
235
        unsigned compid)
236
0
{
237
0
  struct le *le = list_head(lst);
238
239
0
  while (le) {
240
241
0
    struct ice_candpair *cp = le->data;
242
243
0
    le = le->next;
244
245
0
    if (cp->lcand->compid != compid)
246
0
      continue;
247
248
0
    if (cp->lcand->type != type)
249
0
      continue;
250
251
0
    mem_deref(cp);
252
0
  }
253
0
}
254
255
256
bool icem_candpair_iscompleted(const struct ice_candpair *cp)
257
0
{
258
0
  if (!cp)
259
0
    return false;
260
261
0
  return cp->state == ICE_CANDPAIR_FAILED ||
262
0
    cp->state == ICE_CANDPAIR_SUCCEEDED;
263
0
}
264
265
266
/**
267
 * Compare local and remote candidates of two candidate pairs
268
 *
269
 * @param cp1  First Candidate pair
270
 * @param cp2  Second Candidate pair
271
 *
272
 * @return true if match
273
 */
274
bool icem_candpair_cmp(const struct ice_candpair *cp1,
275
           const struct ice_candpair *cp2)
276
0
{
277
0
  if (!sa_cmp(&cp1->lcand->addr, &cp2->lcand->addr, SA_ALL))
278
0
    return false;
279
280
0
  return sa_cmp(&cp1->rcand->addr, &cp2->rcand->addr, SA_ALL);
281
0
}
282
283
284
/**
285
 * Find the highest-priority candidate-pair in a given list, with
286
 * optional match parameters
287
 *
288
 * @param lst    List of candidate pairs
289
 * @param lcand  Local candidate (optional)
290
 * @param rcand  Remote candidate (optional)
291
 *
292
 * @return Matching candidate pair if found, otherwise NULL
293
 *
294
 * note: assume list is sorted by priority
295
 */
296
struct ice_candpair *icem_candpair_find(const struct list *lst,
297
            const struct ice_cand *lcand,
298
            const struct ice_cand *rcand)
299
0
{
300
0
  struct le *le;
301
302
0
  for (le = list_head(lst); le; le = le->next) {
303
304
0
    struct ice_candpair *cp = le->data;
305
306
0
    if (!cp->lcand || !cp->rcand) {
307
0
      DEBUG_WARNING("corrupt candpair %p\n", cp);
308
0
      continue;
309
0
    }
310
311
0
    if (lcand && cp->lcand != lcand)
312
0
      continue;
313
314
0
    if (rcand && cp->rcand != rcand)
315
0
      continue;
316
317
0
    return cp;
318
0
  }
319
320
0
  return NULL;
321
0
}
322
323
324
struct ice_candpair *icem_candpair_find_st(const struct list *lst,
325
             unsigned compid,
326
             enum ice_candpair_state state)
327
0
{
328
0
  struct le *le;
329
330
0
  for (le = list_head(lst); le; le = le->next) {
331
332
0
    struct ice_candpair *cp = le->data;
333
334
0
    if (compid && cp->lcand->compid != compid)
335
0
      continue;
336
337
0
    if (cp->state != state)
338
0
      continue;
339
340
0
    return cp;
341
0
  }
342
343
0
  return NULL;
344
0
}
345
346
347
struct ice_candpair *icem_candpair_find_compid(const struct list *lst,
348
             unsigned compid)
349
0
{
350
0
  struct le *le;
351
352
0
  for (le = list_head(lst); le; le = le->next) {
353
354
0
    struct ice_candpair *cp = le->data;
355
356
0
    if (cp->lcand->compid != compid)
357
0
      continue;
358
359
0
    return cp;
360
0
  }
361
362
0
  return NULL;
363
0
}
364
365
366
/**
367
 * Find a remote candidate in the checklist or validlist
368
 *
369
 * @param icem    ICE Media object
370
 * @param rcand   Remote candidate
371
 *
372
 * @return Candidate pair if found, otherwise NULL
373
 */
374
struct ice_candpair *icem_candpair_find_rcand(struct icem *icem,
375
            const struct ice_cand *rcand)
376
0
{
377
0
  struct ice_candpair *cp;
378
379
0
  cp = icem_candpair_find(&icem->checkl, NULL, rcand);
380
0
  if (cp)
381
0
    return cp;
382
383
0
  cp = icem_candpair_find(&icem->validl, NULL, rcand);
384
0
  if (cp)
385
0
    return cp;
386
387
0
  return NULL;
388
0
}
389
390
391
bool icem_candpair_cmp_fnd(const struct ice_candpair *cp1,
392
         const struct ice_candpair *cp2)
393
0
{
394
0
  if (!cp1 || !cp2)
395
0
    return false;
396
397
0
  return 0 == strcmp(cp1->lcand->foundation, cp2->lcand->foundation) &&
398
0
    0 == strcmp(cp1->rcand->foundation, cp2->rcand->foundation);
399
0
}
400
401
402
int icem_candpair_debug(struct re_printf *pf, const struct ice_candpair *cp)
403
0
{
404
0
  int err;
405
406
0
  if (!cp)
407
0
    return 0;
408
409
0
  err = re_hprintf(pf, "{comp=%u} %10s {%c%c%c} %28H <---> %28H",
410
0
       cp->lcand->compid,
411
0
       ice_candpair_state2name(cp->state),
412
0
       cp->def ? 'D' : ' ',
413
0
       cp->valid ? 'V' : ' ',
414
0
       cp->nominated ? 'N' : ' ',
415
0
       icem_cand_print, cp->lcand,
416
0
       icem_cand_print, cp->rcand);
417
418
0
  if (cp->err)
419
0
    err |= re_hprintf(pf, " (%m)", cp->err);
420
421
0
  if (cp->scode)
422
0
    err |= re_hprintf(pf, " [%u]", cp->scode);
423
424
0
  return err;
425
0
}
426
427
428
int icem_candpairs_debug(struct re_printf *pf, const struct list *list)
429
0
{
430
0
  struct le *le;
431
0
  int err;
432
433
0
  if (!list)
434
0
    return 0;
435
436
0
  err = re_hprintf(pf, " (%u)\n", list_count(list));
437
438
0
  for (le = list->head; le && !err; le = le->next) {
439
440
0
    const struct ice_candpair *cp = le->data;
441
0
    bool is_selected = (cp == cp->comp->cp_sel);
442
443
0
    err = re_hprintf(pf, "  %c  %H\n",
444
0
         is_selected ? '*' : ' ',
445
0
         icem_candpair_debug, cp);
446
0
  }
447
448
0
  return err;
449
0
}