void icem_candpair_set_state(struct candpair *cp, enum candpair_state state) { if (!cp) return; if (cp->state != state) { icecomp_printf(cp->comp, "%5s <---> %5s FSM: %10s ===> %-10s\n", ice_cand_type2name(cp->lcand->type), ice_cand_type2name(cp->rcand->type), ice_candpair_state2name(cp->state), ice_candpair_state2name(state)); cp->state = state; } }
int icem_candpair_debug(struct re_printf *pf, const struct candpair *cp) { int err; if (!cp) return 0; err = re_hprintf(pf, "{%u} %10s {%c%c%c} %28H <---> %28H", cp->lcand->compid, ice_candpair_state2name(cp->state), cp->def ? 'D' : ' ', cp->valid ? 'V' : ' ', cp->nominated ? 'N' : ' ', icem_cand_print, cp->lcand, icem_cand_print, cp->rcand); if (cp->ertt != -1) err |= re_hprintf(pf, " ERTT = %.2fms", cp->ertt / 1000.0); if (cp->err) err |= re_hprintf(pf, " (%s)", strerror(cp->err)); if (cp->scode) err |= re_hprintf(pf, " [%u]", cp->scode); return err; }
void icem_comp_set_selected(struct icem_comp *comp, struct candpair *cp) { if (!comp || !cp) return; if (cp->state != CANDPAIR_SUCCEEDED) { DEBUG_WARNING("{%s.%u} set_selected: invalid state %s\n", comp->icem->name, comp->id, ice_candpair_state2name(cp->state)); } mem_deref(comp->cp_sel); comp->cp_sel = mem_ref(cp); }
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; }
int icem_conncheck_send(struct ice_candpair *cp, bool use_cand, bool trigged) { struct ice_cand *lcand = cp->lcand; struct icem *icem = cp->icem; char username_buf[64]; size_t presz = 0; uint32_t prio_prflx; uint16_t ctrl_attr; int err = 0; icem_candpair_set_state(cp, ICE_CANDPAIR_INPROGRESS); (void)re_snprintf(username_buf, sizeof(username_buf), "%s:%s", icem->rufrag, icem->lufrag); /* PRIORITY and USE-CANDIDATE */ prio_prflx = ice_cand_calc_prio(ICE_CAND_TYPE_PRFLX, 0, lcand->compid); switch (icem->lrole) { case ICE_ROLE_CONTROLLING: ctrl_attr = STUN_ATTR_CONTROLLING; if (icem->conf.nom == ICE_NOMINATION_AGGRESSIVE) use_cand = true; break; case ICE_ROLE_CONTROLLED: ctrl_attr = STUN_ATTR_CONTROLLED; break; default: return EINVAL; } #if ICE_TRACE icecomp_printf(cp->comp, "Tx %H ---> %H (%s) %s %s\n", icem_cand_print, cp->lcand, icem_cand_print, cp->rcand, ice_candpair_state2name(cp->state), use_cand ? "[USE]" : "", trigged ? "[Trigged]" : ""); #else (void)trigged; #endif /* A connectivity check MUST utilize the STUN short term credential mechanism. */ /* The password is equal to the password provided by the peer */ if (!icem->rpwd) { DEBUG_WARNING("no remote password!\n"); } if (cp->ct_conn) { DEBUG_WARNING("send_req: CONNCHECK already Pending!\n"); return EBUSY; } switch (lcand->type) { case ICE_CAND_TYPE_RELAY: /* Creating Permissions for Relayed Candidates */ err = turnc_add_chan(cp->comp->turnc, &cp->rcand->addr, NULL, NULL); if (err) { DEBUG_WARNING("add channel: %m\n", err); break; } presz = 4; /*@fallthrough@*/ case ICE_CAND_TYPE_HOST: case ICE_CAND_TYPE_SRFLX: case ICE_CAND_TYPE_PRFLX: cp->ct_conn = mem_deref(cp->ct_conn); err = stun_request(&cp->ct_conn, icem->stun, icem->proto, cp->comp->sock, &cp->rcand->addr, presz, STUN_METHOD_BINDING, (uint8_t *)icem->rpwd, str_len(icem->rpwd), true, stunc_resp_handler, cp, 4, STUN_ATTR_USERNAME, username_buf, STUN_ATTR_PRIORITY, &prio_prflx, ctrl_attr, &icem->tiebrk, STUN_ATTR_USE_CAND, use_cand ? &use_cand : 0); break; default: DEBUG_WARNING("unknown candidate type %d\n", lcand->type); err = EINVAL; break; } return err; }