static void handle_success(struct icem *icem, struct ice_candpair *cp, const struct sa *laddr) { if (!icem_cand_find(&icem->lcandl, cp->lcand->compid, laddr)) { int err; icecomp_printf(cp->comp, "adding local PRFLX Candidate: %J\n", laddr); err = icem_lcand_add(icem, cp->lcand, ICE_CAND_TYPE_PRFLX, laddr); if (err) { DEBUG_WARNING("failed to add PRFLX: %m\n", err); } } cp = construct_valid_pair(icem, cp, laddr, &cp->rcand->addr); if (!cp) { DEBUG_WARNING("{%s} no valid candidate pair for %J\n", icem->name, laddr); return; } icem_candpair_make_valid(cp); icem_comp_set_selected(cp->comp, cp); cp->nominated = true; #if 0 /* stop conncheck now -- conclude */ icem_conncheck_stop(icem, 0); #endif }
static void stun_resp_handler(int err, uint16_t scode, const char *reason, const struct stun_msg *msg, void *arg) { struct icem_comp *comp = arg; struct icem *icem = comp->icem; struct stun_attr *attr; struct cand *lcand; --icem->nstun; if (err || scode > 0) { DEBUG_WARNING("{%s.%u} STUN Request failed: %m\n", icem->name, comp->id, err); goto out; } lcand = icem_cand_find(&icem->lcandl, comp->id, NULL); if (!lcand) goto out; attr = stun_msg_attr(msg, STUN_ATTR_XOR_MAPPED_ADDR); if (!attr) attr = stun_msg_attr(msg, STUN_ATTR_MAPPED_ADDR); if (!attr) { DEBUG_WARNING("no Mapped Address in Response\n"); err = EPROTO; goto out; } err = icem_lcand_add(icem, lcand->base, CAND_TYPE_SRFLX, &attr->v.sa); out: call_gather_handler(err, icem, scode, reason); }
/* * 7.2.2. Additional Procedures for Lite Implementations */ static int handle_stun_lite(struct icem *icem, struct icem_comp *comp, const struct sa *src, bool use_cand) { struct cand *lcand, *rcand; struct candpair *cp; int err; if (!use_cand) return 0; rcand = icem_cand_find(&icem->rcandl, comp->id, src); if (!rcand) { DEBUG_WARNING("lite: could not find remote candidate\n"); return 0; } /* find the local host candidate with the same component */ lcand = icem_cand_find(&icem->lcandl, comp->id, NULL); if (!lcand) { DEBUG_WARNING("lite: could not find local candidate\n"); return 0; } /* search validlist for existing candpair's */ if (icem_candpair_find(&icem->validl, lcand, rcand)) return 0; err = icem_candpair_alloc(&cp, icem, lcand, rcand); if (err) { DEBUG_WARNING("lite: failed to created candidate pair\n"); return err; } icem_candpair_make_valid(cp); cp->nominated = true; return 0; }
static void turnc_handler(int err, uint16_t scode, const char *reason, const struct sa *relay, const struct sa *mapped, const struct stun_msg *msg, void *arg) { struct icem_comp *comp = arg; struct icem *icem = comp->icem; struct cand *lcand; (void)msg; --icem->nstun; /* TURN failed, so we destroy the client */ if (err || scode) { comp->turnc = mem_deref(comp->turnc); } if (err) { DEBUG_WARNING("{%s.%u} TURN Client error: %m\n", icem->name, comp->id, err); goto out; } if (scode) { DEBUG_WARNING("{%s.%u} TURN Client error: %u %s\n", icem->name, comp->id, scode, reason); err = send_binding_request(icem, comp); if (err) goto out; return; } lcand = icem_cand_find(&icem->lcandl, comp->id, NULL); if (!lcand) goto out; if (!sa_cmp(relay, &lcand->base->addr, SA_ALL)) { err = icem_lcand_add(icem, lcand->base, CAND_TYPE_RELAY, relay); } if (mapped) { err |= icem_lcand_add(icem, lcand->base, CAND_TYPE_SRFLX, mapped); } else { err |= send_binding_request(icem, comp); } out: call_gather_handler(err, icem, scode, reason); }
/** * Verifying ICE Support and set default remote candidate * * @param icem ICE Media * @param compid Component ID * @param raddr Address of default remote candidate * * @return True if ICE is supported, otherwise false */ bool icem_verify_support(struct icem *icem, unsigned compid, const struct sa *raddr) { struct ice_cand *rcand; bool match; if (!icem) return false; rcand = icem_cand_find(&icem->rcandl, compid, raddr); match = rcand != NULL; if (!match) icem->mismatch = true; if (rcand) { icem_comp_set_default_rcand(icem_comp_find(icem, compid), rcand); } return match; }
static int handle_stun(struct ice *ice, struct icem *icem, struct icem_comp *comp, const struct sa *src, uint32_t prio, bool use_cand, bool tunnel) { struct cand *lcand = NULL, *rcand; struct candpair *cp = NULL; int err; rcand = icem_cand_find(&icem->rcandl, comp->id, src); if (!rcand) { err = icem_rcand_add_prflx(&rcand, icem, comp->id, prio, src); if (err) return err; } cp = icem_candpair_find_rcand(icem, rcand); if (cp) lcand = cp->lcand; else lcand = icem_lcand_find_checklist(icem, comp->id); if (!lcand) { DEBUG_WARNING("{%s.%u} no local candidate" " (checklist=%u) (src=%J)\n", icem->name, comp->id, list_count(&icem->checkl), src); return 0; } if (ICE_MODE_FULL == ice->lmode) triggered_check(icem, lcand, rcand); if (!cp) { cp = icem_candpair_find_rcand(icem, rcand); if (!cp) { DEBUG_WARNING("{%s.%u} candidate pair not found:" " source=%J\n", icem->name, comp->id, src); return 0; } } #if ICE_TRACE icecomp_printf(comp, "Rx Binding Request from %J via %s" " (candpair=%s) %s\n", src, tunnel ? "Tunnel" : "Socket", cp ? ice_candpair_state2name(cp->state) : "n/a", use_cand ? "[USE]" : ""); #else (void)tunnel; #endif /* 7.2.1.5. Updating the Nominated Flag */ if (use_cand) { if (ice->lrole == ROLE_CONTROLLED) { if (cp->state == CANDPAIR_SUCCEEDED) { cp->nominated = true; icecomp_printf(comp, "setting NOMINATED" " flag on candpair [%H]\n", icem_candpair_debug, cp); } } /* Cancel conncheck. Choose Selected Pair */ icem_candpair_make_valid(cp); if (ice->conf.nom == ICE_NOMINATION_REGULAR) { icem_candpair_cancel(cp); icem_comp_set_selected(comp, cp); } } return 0; }
/** * Constructing a Valid Pair * * @return The valid pair */ static struct ice_candpair *construct_valid_pair(struct icem *icem, struct ice_candpair *cp, const struct sa *mapped, const struct sa *dest) { struct ice_cand *lcand, *rcand; struct ice_candpair *cp2; int err; lcand = icem_cand_find(&icem->lcandl, cp->lcand->compid, mapped); rcand = icem_cand_find(&icem->rcandl, cp->rcand->compid, dest); if (!lcand) { DEBUG_WARNING("no such local candidate: %J\n", mapped); return NULL; } if (!rcand) { DEBUG_WARNING("no such remote candidate: %J\n", dest); return NULL; } /* New candidate? -- implicit success */ if (lcand != cp->lcand || rcand != cp->rcand) { if (lcand != cp->lcand) { icecomp_printf(cp->comp, "New local candidate for mapped %J\n", mapped); } if (rcand != cp->rcand) { icecomp_printf(cp->comp, "New remote candidate for dest %J\n", dest); } /* The original candidate pair is set to 'Failed' because * the implicitly discovered pair is 'better'. * This happens for UAs behind NAT where the original * pair is of type 'host' and the implicit pair is 'srflx' */ icem_candpair_make_valid(cp); cp2 = icem_candpair_find(&icem->validl, lcand, rcand); if (cp2) return cp2; err = icem_candpair_clone(&cp2, cp, lcand, rcand); if (err) return NULL; icem_candpair_make_valid(cp2); /*icem_candpair_failed(cp, EINTR, 0);*/ return cp2; } else { /* Add to VALID LIST, the pair that generated the check */ icem_candpair_make_valid(cp); return cp; } }
static int cand_decode(struct icem *icem, const char *val) { struct pl foundation, compid, transp, prio, addr, port, cand_type; struct pl extra = pl_null; struct sa caddr, rel_addr; char type[8]; uint8_t cid; int err; sa_init(&rel_addr, AF_INET); err = re_regex(val, strlen(val), "[^ ]+ [0-9]+ [^ ]+ [0-9]+ [^ ]+ [0-9]+ typ [a-z]+[^]*", &foundation, &compid, &transp, &prio, &addr, &port, &cand_type, &extra); if (err) return err; if (ICE_TRANSP_NONE == transp_resolve(&transp)) { DEBUG_NOTICE("<%s> ignoring candidate with" " unknown transport=%r (%r:%r)\n", icem->name, &transp, &cand_type, &addr); return 0; } if (pl_isset(&extra)) { struct pl name, value; /* Loop through " SP attr SP value" pairs */ while (!re_regex(extra.p, extra.l, " [^ ]+ [^ ]+", &name, &value)) { pl_advance(&extra, value.p + value.l - extra.p); if (0 == pl_strcasecmp(&name, rel_addr_str)) { err = sa_set(&rel_addr, &value, sa_port(&rel_addr)); if (err) break; } else if (0 == pl_strcasecmp(&name, rel_port_str)) { sa_set_port(&rel_addr, pl_u32(&value)); } } } err = sa_set(&caddr, &addr, pl_u32(&port)); if (err) return err; cid = pl_u32(&compid); /* add only if not exist */ if (icem_cand_find(&icem->rcandl, cid, &caddr)) return 0; (void)pl_strcpy(&cand_type, type, sizeof(type)); return icem_rcand_add(icem, ice_cand_name2type(type), cid, pl_u32(&prio), &caddr, &rel_addr, &foundation); }