Coverage Report

Created: 2026-03-21 06:16

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/rtpproxy/external/libre/src/ice/icesdp.c
Line
Count
Source
1
/**
2
 * @file icesdp.c  SDP Attributes for ICE
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_net.h>
15
#include <re_stun.h>
16
#include <re_ice.h>
17
#include "ice.h"
18
19
20
0
#define DEBUG_MODULE "icesdp"
21
#define DEBUG_LEVEL 5
22
#include <re_dbg.h>
23
24
25
const char ice_attr_cand[]        = "candidate";
26
const char ice_attr_remote_cand[] = "remote-candidates";
27
const char ice_attr_lite[]        = "ice-lite";
28
const char ice_attr_ufrag[]       = "ice-ufrag";
29
const char ice_attr_pwd[]         = "ice-pwd";
30
const char ice_attr_mismatch[]    = "ice-mismatch";
31
32
33
static const char rel_addr_str[] = "raddr";
34
static const char rel_port_str[] = "rport";
35
36
37
/* Encode SDP Attributes */
38
39
40
static const char *transp_name(enum ice_transp transp)
41
13.1k
{
42
13.1k
  switch (transp) {
43
44
13.1k
  case ICE_TRANSP_UDP: return "UDP";
45
0
  default:             return "???";
46
13.1k
  }
47
13.1k
}
48
49
50
static enum ice_transp transp_resolve(const struct pl *transp)
51
0
{
52
0
  if (!pl_strcasecmp(transp, "UDP"))
53
0
    return ICE_TRANSP_UDP;
54
55
0
  return ICE_TRANSP_NONE;
56
0
}
57
58
59
/**
60
 * Encode SDP candidate attribute
61
 *
62
 * @param pf    Print function
63
 * @param cand  Candidate to encode
64
 *
65
 * @return 0 if success, otherwise errorcode
66
 */
67
int ice_cand_encode(struct re_printf *pf, const struct ice_cand *cand)
68
13.1k
{
69
13.1k
  int err;
70
71
13.1k
  err = re_hprintf(pf, "%s %u %s %u %j %u typ %s",
72
13.1k
       cand->foundation, cand->compid,
73
13.1k
       transp_name(cand->transp), cand->prio,
74
13.1k
       &cand->addr, sa_port(&cand->addr),
75
13.1k
       ice_cand_type2name(cand->type));
76
77
13.1k
  if (sa_isset(&cand->rel, SA_ADDR))
78
0
    err |= re_hprintf(pf, " raddr %j", &cand->rel);
79
80
13.1k
  if (sa_isset(&cand->rel, SA_PORT))
81
0
    err |= re_hprintf(pf, " rport %u", sa_port(&cand->rel));
82
83
13.1k
  return err;
84
13.1k
}
85
86
87
/**
88
 * Check if remote candidates are available
89
 *
90
 * @param icem ICE Media object
91
 *
92
 * @return True if available, otherwise false
93
 */
94
bool ice_remotecands_avail(const struct icem *icem)
95
0
{
96
0
  if (!icem)
97
0
    return false;
98
99
0
  return icem->lrole == ICE_ROLE_CONTROLLING &&
100
0
    icem->state == ICE_CHECKLIST_COMPLETED;
101
0
}
102
103
104
/**
105
 * Encode the SDP "remote-candidates" Attribute
106
 *
107
 * @param pf   Print function
108
 * @param icem ICE Media object
109
 *
110
 * @return 0 if success, otherwise errorcode
111
 */
112
int ice_remotecands_encode(struct re_printf *pf, const struct icem *icem)
113
0
{
114
0
  struct le *le;
115
0
  int err = 0;
116
117
0
  if (!icem)
118
0
    return EINVAL;
119
120
0
  for (le = icem->rcandl.head; le && !err; le = le->next) {
121
122
0
    const struct ice_cand *rcand = le->data;
123
124
0
    err = re_hprintf(pf, "%s%d %j %u",
125
0
         icem->rcandl.head==le ? "" : " ",
126
0
         rcand->compid,
127
0
         &rcand->addr, sa_port(&rcand->addr));
128
0
  }
129
130
0
  return err;
131
0
}
132
133
134
/* Decode SDP Attributes */
135
136
137
static int ufrag_decode(struct icem *icem, const char *value)
138
0
{
139
0
  char *ufrag = NULL;
140
0
  int err;
141
142
0
  err = str_dup(&ufrag, value);
143
0
  if (err)
144
0
    return err;
145
146
0
  mem_deref(icem->rufrag);
147
0
  icem->rufrag = mem_ref(ufrag);
148
149
0
  mem_deref(ufrag);
150
151
0
  return 0;
152
0
}
153
154
155
static int pwd_decode(struct icem *icem, const char *value)
156
0
{
157
0
  char *pwd = NULL;
158
0
  int err;
159
160
0
  err = str_dup(&pwd, value);
161
0
  if (err)
162
0
    return err;
163
164
0
  mem_deref(icem->rpwd);
165
0
  icem->rpwd = mem_ref(pwd);
166
167
0
  mem_deref(pwd);
168
169
0
  return 0;
170
0
}
171
172
173
static int media_ufrag_decode(struct icem *icem, const char *value)
174
6.97k
{
175
6.97k
  icem->rufrag = mem_deref(icem->rufrag);
176
177
6.97k
  return str_dup(&icem->rufrag, value);
178
6.97k
}
179
180
181
static int media_pwd_decode(struct icem *icem, const char *value)
182
6.97k
{
183
6.97k
  icem->rpwd = mem_deref(icem->rpwd);
184
185
6.97k
  return str_dup(&icem->rpwd, value);
186
6.97k
}
187
188
189
static int cand_decode(struct icem *icem, const char *val)
190
0
{
191
0
  struct pl foundation, compid, transp, prio, addr, port, cand_type;
192
0
  struct pl extra = pl_null;
193
0
  struct sa caddr, rel_addr;
194
0
  char type[8];
195
0
  uint8_t cid;
196
0
  int err;
197
198
0
  sa_init(&rel_addr, AF_INET);
199
200
0
  err = re_regex(val, strlen(val),
201
0
           "[^ ]+ [0-9]+ [^ ]+ [0-9]+ [^ ]+ [0-9]+ typ [a-z]+[^]*",
202
0
           &foundation, &compid, &transp, &prio,
203
0
           &addr, &port, &cand_type, &extra);
204
0
  if (err)
205
0
    return err;
206
207
0
  if (ICE_TRANSP_NONE == transp_resolve(&transp)) {
208
0
    DEBUG_NOTICE("<%s> ignoring candidate with"
209
0
           " unknown transport=%r (%r:%r)\n",
210
0
           icem->name, &transp, &cand_type, &addr);
211
0
    return 0;
212
0
  }
213
214
0
  if (pl_isset(&extra)) {
215
216
0
    struct pl name, value;
217
218
    /* Loop through " SP attr SP value" pairs */
219
0
    while (!re_regex(extra.p, extra.l, " [^ ]+ [^ ]+",
220
0
         &name, &value)) {
221
222
0
      pl_advance(&extra, value.p + value.l - extra.p);
223
224
0
      if (0 == pl_strcasecmp(&name, rel_addr_str)) {
225
0
        err = sa_set(&rel_addr, &value,
226
0
               sa_port(&rel_addr));
227
0
        if (err)
228
0
          break;
229
0
      }
230
0
      else if (0 == pl_strcasecmp(&name, rel_port_str)) {
231
0
        sa_set_port(&rel_addr, pl_u32(&value));
232
0
      }
233
0
    }
234
0
  }
235
236
0
  err = sa_set(&caddr, &addr, pl_u32(&port));
237
0
  if (err)
238
0
    return err;
239
240
0
  cid = pl_u32(&compid);
241
242
  /* add only if not exist */
243
0
  if (icem_cand_find(&icem->rcandl, cid, &caddr))
244
0
    return 0;
245
246
0
  (void)pl_strcpy(&cand_type, type, sizeof(type));
247
248
0
  return icem_rcand_add(icem, ice_cand_name2type(type), cid,
249
0
            pl_u32(&prio), &caddr, &rel_addr, &foundation);
250
0
}
251
252
253
/**
254
 * Decode SDP session attributes
255
 *
256
 * @param icem  ICE Media object
257
 * @param name  Name of the SDP attribute
258
 * @param value Value of the SDP attribute (optional)
259
 *
260
 * @return 0 if success, otherwise errorcode
261
 */
262
int ice_sdp_decode(struct icem *icem, const char *name, const char *value)
263
0
{
264
0
  if (!icem)
265
0
    return EINVAL;
266
267
0
  if (0 == str_casecmp(name, ice_attr_lite)) {
268
0
    if (ICE_MODE_LITE == icem->lmode) {
269
0
      DEBUG_WARNING("we are lite, peer is also lite!\n");
270
0
      return EPROTO;
271
0
    }
272
0
    icem->rmode = ICE_MODE_LITE;
273
0
    icem->lrole = ICE_ROLE_CONTROLLING;
274
0
  }
275
0
  else if (0 == str_casecmp(name, ice_attr_ufrag))
276
0
    return ufrag_decode(icem, value);
277
0
  else if (0 == str_casecmp(name, ice_attr_pwd))
278
0
    return pwd_decode(icem, value);
279
280
0
  return 0;
281
0
}
282
283
284
/**
285
 * Decode SDP media attributes
286
 *
287
 * @param icem  ICE Media object
288
 * @param name  Name of the SDP attribute
289
 * @param value Value of the SDP attribute (optional)
290
 *
291
 * @return 0 if success, otherwise errorcode
292
 */
293
int icem_sdp_decode(struct icem *icem, const char *name, const char *value)
294
13.9k
{
295
13.9k
  if (!icem)
296
0
    return EINVAL;
297
298
13.9k
  if (0 == str_casecmp(name, ice_attr_cand))
299
0
    return cand_decode(icem, value);
300
13.9k
  else if (0 == str_casecmp(name, ice_attr_mismatch))
301
0
    icem->mismatch = true;
302
13.9k
  else if (0 == str_casecmp(name, ice_attr_ufrag))
303
6.97k
    return media_ufrag_decode(icem, value);
304
6.97k
  else if (0 == str_casecmp(name, ice_attr_pwd))
305
6.97k
    return media_pwd_decode(icem, value);
306
307
0
  return 0;
308
13.9k
}
309
310
311
static const char *ice_tcptype_name(enum ice_tcptype tcptype)
312
0
{
313
0
  switch (tcptype) {
314
315
0
  case ICE_TCP_ACTIVE:  return "active";
316
0
  case ICE_TCP_PASSIVE: return "passive";
317
0
  case ICE_TCP_SO:      return "so";
318
0
  default: return "???";
319
0
  }
320
0
}
321
322
323
static enum ice_tcptype ice_tcptype_resolve(const struct pl *pl)
324
0
{
325
0
  if (0 == pl_strcasecmp(pl, "active"))  return ICE_TCP_ACTIVE;
326
0
  if (0 == pl_strcasecmp(pl, "passive")) return ICE_TCP_PASSIVE;
327
0
  if (0 == pl_strcasecmp(pl, "so"))      return ICE_TCP_SO;
328
329
0
  return (enum ice_tcptype)-1;
330
0
}
331
332
333
int ice_cand_attr_encode(struct re_printf *pf,
334
       const struct ice_cand_attr *cand)
335
0
{
336
0
  int err = 0;
337
338
0
  if (!cand)
339
0
    return 0;
340
341
0
  err |= re_hprintf(pf, "%s %u %s %u %j %u typ %s",
342
0
        cand->foundation, cand->compid,
343
0
        net_proto2name(cand->proto), cand->prio,
344
0
        &cand->addr, sa_port(&cand->addr),
345
0
        ice_cand_type2name(cand->type));
346
347
0
  if (sa_isset(&cand->rel_addr, SA_ADDR))
348
0
    err |= re_hprintf(pf, " raddr %j", &cand->rel_addr);
349
350
0
  if (sa_isset(&cand->rel_addr, SA_PORT))
351
0
    err |= re_hprintf(pf, " rport %u", sa_port(&cand->rel_addr));
352
353
0
  if (cand->proto == IPPROTO_TCP) {
354
0
    err |= re_hprintf(pf, " tcptype %s",
355
0
          ice_tcptype_name(cand->tcptype));
356
0
  }
357
358
0
  return err;
359
0
}
360
361
362
int ice_cand_attr_decode(struct ice_cand_attr *cand, const char *val)
363
0
{
364
0
  struct pl pl_fnd, pl_compid, pl_transp, pl_prio, pl_addr, pl_port;
365
0
  struct pl pl_type, pl_raddr, pl_rport, pl_opt = PL_INIT;
366
0
  size_t len;
367
0
  char type[8];
368
0
  int err;
369
370
0
  if (!cand || !val)
371
0
    return EINVAL;
372
373
0
  memset(cand, 0, sizeof(*cand));
374
375
0
  len = str_len(val);
376
377
0
  err = re_regex(val, len,
378
0
           "[^ ]+ [0-9]+ [a-z]+ [0-9]+ [^ ]+ [0-9]+ typ [a-z]+"
379
0
           "[^]*",
380
0
           &pl_fnd, &pl_compid, &pl_transp, &pl_prio,
381
0
           &pl_addr, &pl_port, &pl_type, &pl_opt);
382
0
  if (err)
383
0
    return err;
384
385
0
  (void)pl_strcpy(&pl_fnd, cand->foundation, sizeof(cand->foundation));
386
387
0
  if (0 == pl_strcasecmp(&pl_transp, "UDP"))
388
0
    cand->proto = IPPROTO_UDP;
389
0
  else if (0 == pl_strcasecmp(&pl_transp, "TCP"))
390
0
    cand->proto = IPPROTO_TCP;
391
0
  else
392
0
    cand->proto = 0;
393
394
0
  err = sa_set(&cand->addr, &pl_addr, pl_u32(&pl_port));
395
0
  if (err)
396
0
    return err;
397
398
0
  cand->compid = pl_u32(&pl_compid);
399
0
  cand->prio   = pl_u32(&pl_prio);
400
401
0
  (void)pl_strcpy(&pl_type, type, sizeof(type));
402
403
0
  cand->type = ice_cand_name2type(type);
404
405
  /* optional */
406
407
0
  if (0 == re_regex(pl_opt.p, pl_opt.l, "raddr [^ ]+ rport [0-9]+",
408
0
        &pl_raddr, &pl_rport)) {
409
410
0
    err = sa_set(&cand->rel_addr, &pl_raddr, pl_u32(&pl_rport));
411
0
    if (err)
412
0
      return err;
413
0
  }
414
415
0
  if (cand->proto == IPPROTO_TCP) {
416
417
0
    struct pl tcptype;
418
419
0
    err = re_regex(pl_opt.p, pl_opt.l, "tcptype [^ ]+",
420
0
             &tcptype);
421
0
    if (err)
422
0
      return err;
423
424
0
    cand->tcptype = ice_tcptype_resolve(&tcptype);
425
0
  }
426
427
0
  return 0;
428
0
}