blob: 5d4ee05c2258cbd24d054b4f62ca5f03d7a87ef2 [file] [log] [blame]
James Kuszmaul82f6c042021-01-17 11:30:16 -08001/**
2 * @file cand.c ICE Candidates
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_sys.h>
15#include <re_stun.h>
16#include <re_turn.h>
17#include <re_ice.h>
18#include "ice.h"
19
20
21#define DEBUG_MODULE "icecand"
22#define DEBUG_LEVEL 5
23#include <re_dbg.h>
24
25
26static void cand_destructor(void *arg)
27{
28 struct ice_cand *cand = arg;
29
30 list_unlink(&cand->le);
31 mem_deref(cand->foundation);
32 mem_deref(cand->ifname);
33
34 if (cand != cand->base)
35 mem_deref(cand->base);
36}
37
38
39/** Foundation is a hash of IP address and candidate type */
40static int compute_foundation(struct ice_cand *cand)
41{
42 uint32_t v;
43
44 v = sa_hash(&cand->addr, SA_ADDR);
45 v ^= cand->type;
46
47 return re_sdprintf(&cand->foundation, "%08x", v);
48}
49
50
51static int cand_alloc(struct ice_cand **candp, struct icem *icem,
52 enum ice_cand_type type, unsigned compid,
53 uint32_t prio, const char *ifname,
54 enum ice_transp transp, const struct sa *addr)
55{
56 struct ice_cand *cand;
57 int err;
58
59 if (!icem)
60 return EINVAL;
61
62 cand = mem_zalloc(sizeof(*cand), cand_destructor);
63 if (!cand)
64 return ENOMEM;
65
66 list_append(&icem->lcandl, &cand->le, cand);
67
68 cand->type = type;
69 cand->compid = compid;
70 cand->prio = prio;
71 cand->transp = transp;
72
73 sa_cpy(&cand->addr, addr);
74
75 err = compute_foundation(cand);
76
77 if (ifname)
78 err |= str_dup(&cand->ifname, ifname);
79
80 if (err)
81 mem_deref(cand);
82 else if (candp)
83 *candp = cand;
84
85 return err;
86}
87
88
89int icem_lcand_add_base(struct icem *icem, unsigned compid, uint16_t lprio,
90 const char *ifname, enum ice_transp transp,
91 const struct sa *addr)
92{
93 struct icem_comp *comp;
94 struct ice_cand *cand;
95 int err;
96
97 comp = icem_comp_find(icem, compid);
98 if (!comp)
99 return ENOENT;
100
101 err = cand_alloc(&cand, icem, ICE_CAND_TYPE_HOST, compid,
102 ice_cand_calc_prio(ICE_CAND_TYPE_HOST, lprio, compid),
103 ifname, transp, addr);
104 if (err)
105 return err;
106
107 /* the base is itself */
108 cand->base = cand;
109
110 sa_set_port(&cand->addr, comp->lport);
111
112 return 0;
113}
114
115
116int icem_lcand_add(struct icem *icem, struct ice_cand *base,
117 enum ice_cand_type type,
118 const struct sa *addr)
119{
120 struct ice_cand *cand;
121 int err;
122
123 if (!base)
124 return EINVAL;
125
126 err = cand_alloc(&cand, icem, type, base->compid,
127 ice_cand_calc_prio(type, 0, base->compid),
128 base->ifname, base->transp, addr);
129 if (err)
130 return err;
131
132 cand->base = mem_ref(base);
133 sa_cpy(&cand->rel, &base->addr);
134
135 return 0;
136}
137
138
139int icem_rcand_add(struct icem *icem, enum ice_cand_type type, unsigned compid,
140 uint32_t prio, const struct sa *addr,
141 const struct sa *rel_addr, const struct pl *foundation)
142{
143 struct ice_cand *rcand;
144 int err;
145
146 if (!icem || !foundation)
147 return EINVAL;
148
149 rcand = mem_zalloc(sizeof(*rcand), cand_destructor);
150 if (!rcand)
151 return ENOMEM;
152
153 list_append(&icem->rcandl, &rcand->le, rcand);
154
155 rcand->type = type;
156 rcand->compid = compid;
157 rcand->prio = prio;
158
159 sa_cpy(&rcand->addr, addr);
160 sa_cpy(&rcand->rel, rel_addr);
161
162 err = pl_strdup(&rcand->foundation, foundation);
163
164 if (err)
165 mem_deref(rcand);
166
167 return err;
168}
169
170
171int icem_rcand_add_prflx(struct ice_cand **rcp, struct icem *icem,
172 unsigned compid, uint32_t prio,
173 const struct sa *addr)
174{
175 struct ice_cand *rcand;
176 int err;
177
178 if (!icem || !addr)
179 return EINVAL;
180
181 rcand = mem_zalloc(sizeof(*rcand), cand_destructor);
182 if (!rcand)
183 return ENOMEM;
184
185 list_append(&icem->rcandl, &rcand->le, rcand);
186
187 rcand->type = ICE_CAND_TYPE_PRFLX;
188 rcand->compid = compid;
189 rcand->prio = prio;
190 rcand->addr = *addr;
191
192 err = re_sdprintf(&rcand->foundation, "%08x", rand_u32());
193 if (err)
194 goto out;
195
196 icecomp_printf(icem_comp_find(icem, compid),
197 "added PeerReflexive remote candidate"
198 " with priority %u (%J)\n", prio, addr);
199
200 out:
201 if (err)
202 mem_deref(rcand);
203 else if (rcp)
204 *rcp = rcand;
205
206 return err;
207}
208
209
210struct ice_cand *icem_cand_find(const struct list *lst, unsigned compid,
211 const struct sa *addr)
212{
213 struct le *le;
214
215 for (le = list_head(lst); le; le = le->next) {
216
217 struct ice_cand *cand = le->data;
218
219 if (compid && cand->compid != compid)
220 continue;
221
222 if (addr && !sa_cmp(&cand->addr, addr, SA_ALL))
223 continue;
224
225 return cand;
226 }
227
228 return NULL;
229}
230
231
232/**
233 * Find the highest priority LCAND on the check-list of type HOST/RELAY
234 *
235 * @param icem ICE Media object
236 * @param compid Component ID
237 *
238 * @return Local candidate if found, otherwise NULL
239 */
240struct ice_cand *icem_lcand_find_checklist(const struct icem *icem,
241 unsigned compid)
242{
243 struct le *le;
244
245 for (le = icem->checkl.head; le; le = le->next) {
246 struct ice_candpair *cp = le->data;
247
248 if (cp->lcand->compid != compid)
249 continue;
250
251 switch (cp->lcand->type) {
252
253 case ICE_CAND_TYPE_HOST:
254 case ICE_CAND_TYPE_RELAY:
255 return cp->lcand;
256
257 default:
258 break;
259 }
260 }
261
262 return NULL;
263}
264
265
266struct ice_cand *icem_lcand_base(struct ice_cand *lcand)
267{
268 return lcand ? lcand->base : NULL;
269}
270
271
272const struct sa *icem_lcand_addr(const struct ice_cand *cand)
273{
274 return cand ? &cand->addr : NULL;
275}
276
277
278int icem_cands_debug(struct re_printf *pf, const struct list *lst)
279{
280 struct le *le;
281 int err;
282
283 err = re_hprintf(pf, " (%u)\n", list_count(lst));
284
285 for (le = list_head(lst); le && !err; le = le->next) {
286
287 const struct ice_cand *cand = le->data;
288
289 err |= re_hprintf(pf, " {%u} fnd=%-2s prio=%08x %24H",
290 cand->compid, cand->foundation, cand->prio,
291 icem_cand_print, cand);
292
293 if (sa_isset(&cand->rel, SA_ADDR))
294 err |= re_hprintf(pf, " (rel-addr=%J)", &cand->rel);
295
296 err |= re_hprintf(pf, "\n");
297 }
298
299 return err;
300}
301
302
303int icem_cand_print(struct re_printf *pf, const struct ice_cand *cand)
304{
305 int err = 0;
306
307 if (!cand)
308 return 0;
309
310 if (cand->ifname)
311 err |= re_hprintf(pf, "%s:", cand->ifname);
312
313 err |= re_hprintf(pf, "%s:%J",
314 ice_cand_type2name(cand->type), &cand->addr);
315
316 return err;
317}
318
319enum ice_cand_type icem_cand_type(const struct ice_cand *cand)
320{
321 return cand ? cand->type : (enum ice_cand_type)-1;
322}