James Kuszmaul | 82f6c04 | 2021-01-17 11:30:16 -0800 | [diff] [blame^] | 1 | /** |
| 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 | |
| 26 | static 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 */ |
| 40 | static 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 | |
| 51 | static 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 | |
| 89 | int 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 | |
| 116 | int 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 | |
| 139 | int 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 | |
| 171 | int 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 | |
| 210 | struct 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 | */ |
| 240 | struct 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 | |
| 266 | struct ice_cand *icem_lcand_base(struct ice_cand *lcand) |
| 267 | { |
| 268 | return lcand ? lcand->base : NULL; |
| 269 | } |
| 270 | |
| 271 | |
| 272 | const struct sa *icem_lcand_addr(const struct ice_cand *cand) |
| 273 | { |
| 274 | return cand ? &cand->addr : NULL; |
| 275 | } |
| 276 | |
| 277 | |
| 278 | int 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 | |
| 303 | int 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 | |
| 319 | enum ice_cand_type icem_cand_type(const struct ice_cand *cand) |
| 320 | { |
| 321 | return cand ? cand->type : (enum ice_cand_type)-1; |
| 322 | } |