ice: many improvements and fixes
This commit is contained in:
parent
f6e4ccd88b
commit
5af1657c55
12 changed files with 256 additions and 235 deletions
|
@ -64,6 +64,7 @@ int icem_gather_relay(struct icem *icem, const struct sa *stun_srv,
|
|||
bool icem_verify_support(struct icem *icem, uint8_t compid,
|
||||
const struct sa *raddr);
|
||||
int icem_conncheck_start(struct icem *icem);
|
||||
void icem_conncheck_stop(struct icem *icem, int err);
|
||||
int icem_add_chan(struct icem *icem, uint8_t compid, const struct sa *raddr);
|
||||
bool icem_mismatch(const struct icem *icem);
|
||||
void icem_update(struct icem *icem);
|
||||
|
|
|
@ -188,7 +188,14 @@ int icem_rcand_add_prflx(struct cand **rcp, struct icem *icem, uint8_t compid,
|
|||
rcand->addr = *addr;
|
||||
|
||||
err = re_sdprintf(&rcand->foundation, "%08x", rand_u32());
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
icecomp_printf(icem_comp_find(icem, compid),
|
||||
"added PeerReflexive remote candidate"
|
||||
" with priority %u (%J)\n", prio, addr);
|
||||
|
||||
out:
|
||||
if (err)
|
||||
mem_deref(rcand);
|
||||
else if (rcp)
|
||||
|
@ -220,6 +227,34 @@ struct cand *icem_cand_find(const struct list *lst, uint8_t compid,
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* Find the highest priority LCAND on the check-list of type HOST/RELAY
|
||||
*/
|
||||
struct cand *icem_lcand_find_checklist(const struct icem *icem, uint8_t compid)
|
||||
{
|
||||
struct le *le;
|
||||
|
||||
for (le = icem->checkl.head; le; le = le->next) {
|
||||
struct candpair *cp = le->data;
|
||||
|
||||
if (cp->lcand->compid != compid)
|
||||
continue;
|
||||
|
||||
switch (cp->lcand->type) {
|
||||
|
||||
case CAND_TYPE_HOST:
|
||||
case CAND_TYPE_RELAY:
|
||||
return cp->lcand;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
int icem_cands_debug(struct re_printf *pf, const struct list *lst)
|
||||
{
|
||||
struct le *le;
|
||||
|
|
|
@ -101,7 +101,6 @@ int icem_candpair_alloc(struct candpair **cpp, struct icem *icem,
|
|||
cp->lcand = mem_ref(lcand);
|
||||
cp->rcand = mem_ref(rcand);
|
||||
cp->state = CANDPAIR_FROZEN;
|
||||
cp->ertt = -1;
|
||||
cp->def = comp->def_lcand == lcand && comp->def_rcand == rcand;
|
||||
|
||||
candpair_set_pprio(cp);
|
||||
|
@ -136,8 +135,6 @@ int icem_candpair_clone(struct candpair **cpp, struct candpair *cp0,
|
|||
cp->nominated = cp0->nominated;
|
||||
cp->state = cp0->state;
|
||||
cp->pprio = cp0->pprio;
|
||||
cp->usec_sent = cp0->usec_sent;
|
||||
cp->ertt = cp0->ertt;
|
||||
cp->err = cp0->err;
|
||||
cp->scode = cp0->scode;
|
||||
|
||||
|
@ -184,9 +181,6 @@ void icem_candpair_make_valid(struct candpair *cp)
|
|||
cp->scode = 0;
|
||||
cp->valid = true;
|
||||
|
||||
if (cp->usec_sent)
|
||||
cp->ertt = (long)(ice_get_usec() - cp->usec_sent);
|
||||
|
||||
icem_candpair_set_state(cp, CANDPAIR_SUCCEEDED);
|
||||
|
||||
list_unlink(&cp->le);
|
||||
|
@ -211,16 +205,17 @@ void icem_candpair_set_state(struct candpair *cp, enum candpair_state state)
|
|||
{
|
||||
if (!cp)
|
||||
return;
|
||||
if (cp->state == state || icem_candpair_iscompleted(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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -355,6 +350,26 @@ struct candpair *icem_candpair_find_compid(const struct list *lst,
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* Find a remote candidate in the checklist or validlist
|
||||
*/
|
||||
struct candpair *icem_candpair_find_rcand(struct icem *icem,
|
||||
const struct cand *rcand)
|
||||
{
|
||||
struct candpair *cp;
|
||||
|
||||
cp = icem_candpair_find(&icem->checkl, NULL, rcand);
|
||||
if (cp)
|
||||
return cp;
|
||||
|
||||
cp = icem_candpair_find(&icem->validl, NULL, rcand);
|
||||
if (cp)
|
||||
return cp;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
bool icem_candpair_cmp_fnd(const struct candpair *cp1,
|
||||
const struct candpair *cp2)
|
||||
{
|
||||
|
@ -373,7 +388,7 @@ int icem_candpair_debug(struct re_printf *pf, const struct candpair *cp)
|
|||
if (!cp)
|
||||
return 0;
|
||||
|
||||
err = re_hprintf(pf, "{%u} %10s {%c%c%c} %28H <---> %28H",
|
||||
err = re_hprintf(pf, "{comp=%u} %10s {%c%c%c} %28H <---> %28H",
|
||||
cp->lcand->compid,
|
||||
ice_candpair_state2name(cp->state),
|
||||
cp->def ? 'D' : ' ',
|
||||
|
@ -382,9 +397,6 @@ int icem_candpair_debug(struct re_printf *pf, const struct candpair *cp)
|
|||
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, " (%m)", cp->err);
|
||||
|
||||
|
@ -408,8 +420,11 @@ int icem_candpairs_debug(struct re_printf *pf, const struct list *list)
|
|||
for (le = list->head; le && !err; le = le->next) {
|
||||
|
||||
const struct candpair *cp = le->data;
|
||||
bool is_selected = (cp == cp->comp->cp_sel);
|
||||
|
||||
err = re_hprintf(pf, " %H\n", icem_candpair_debug, cp);
|
||||
err = re_hprintf(pf, " %c %H\n",
|
||||
is_selected ? '*' : ' ',
|
||||
icem_candpair_debug, cp);
|
||||
}
|
||||
|
||||
return err;
|
||||
|
|
|
@ -32,6 +32,11 @@ static int candpairs_form(struct icem *icem)
|
|||
if (list_isempty(&icem->lcandl))
|
||||
return ENOENT;
|
||||
|
||||
if (list_isempty(&icem->rcandl)) {
|
||||
DEBUG_WARNING("%s: no remote candidates\n", icem->name);
|
||||
return ENOENT;
|
||||
}
|
||||
|
||||
for (le = icem->lcandl.head; le; le = le->next) {
|
||||
|
||||
struct cand *lcand = le->data;
|
||||
|
@ -47,7 +52,9 @@ static int candpairs_form(struct icem *icem)
|
|||
if (sa_af(&lcand->addr) != sa_af(&rcand->addr))
|
||||
continue;
|
||||
|
||||
err |= icem_candpair_alloc(NULL, icem, lcand, rcand);
|
||||
err = icem_candpair_alloc(NULL, icem, lcand, rcand);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -62,10 +69,14 @@ static const struct sa *cand_srflx_addr(const struct cand *c)
|
|||
}
|
||||
|
||||
|
||||
/* return: NULL to keep, pointer to remove object */
|
||||
static void *unique_handler(struct le *le1, struct le *le2)
|
||||
{
|
||||
struct candpair *cp1 = le1->data, *cp2 = le2->data;
|
||||
|
||||
if (cp1->comp->id != cp2->comp->id)
|
||||
return NULL;
|
||||
|
||||
if (!sa_cmp(cand_srflx_addr(cp1->lcand),
|
||||
cand_srflx_addr(cp2->lcand), SA_ALL) ||
|
||||
!sa_cmp(&cp1->rcand->addr, &cp2->rcand->addr, SA_ALL))
|
||||
|
@ -236,9 +247,11 @@ static void concluding_ice(struct icem_comp *comp)
|
|||
void icem_checklist_update(struct icem *icem)
|
||||
{
|
||||
struct le *le;
|
||||
bool compl;
|
||||
int err = 0;
|
||||
|
||||
if (!iscompleted(icem))
|
||||
compl = iscompleted(icem);
|
||||
if (!compl)
|
||||
return;
|
||||
|
||||
/*
|
||||
|
@ -268,9 +281,10 @@ void icem_checklist_update(struct icem *icem)
|
|||
|
||||
icem->state = err ? CHECKLIST_FAILED : CHECKLIST_COMPLETED;
|
||||
|
||||
if (icem->chkh)
|
||||
if (icem->chkh) {
|
||||
icem->chkh(err, icem->ice->lrole == ROLE_CONTROLLING,
|
||||
icem->arg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -27,27 +27,6 @@
|
|||
enum {COMPID_MIN = 1, COMPID_MAX = 255};
|
||||
|
||||
|
||||
#if 0
|
||||
/* for debugging */
|
||||
static bool helper_send_handler(int *err, struct sa *dst,
|
||||
struct mbuf *mb, void *arg)
|
||||
{
|
||||
struct icem_comp *comp = arg;
|
||||
|
||||
(void)comp;
|
||||
(void)err;
|
||||
(void)dst;
|
||||
(void)mb;
|
||||
|
||||
re_printf("{id=%d} ......... UDP send %u bytes to %J via %s\n",
|
||||
comp->id, mbuf_get_left(mb), dst,
|
||||
(mb->pos && comp->turnc) ? "tunnel" : "socket");
|
||||
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static bool helper_recv_handler(struct sa *src, struct mbuf *mb, void *arg)
|
||||
{
|
||||
struct icem_comp *comp = arg;
|
||||
|
@ -73,7 +52,7 @@ static bool helper_recv_handler(struct sa *src, struct mbuf *mb, void *arg)
|
|||
break;
|
||||
|
||||
default:
|
||||
(void)stun_ctrans_recv(icem->stun, msg, &ua);
|
||||
(void)stun_ctrans_recv(icem->ice->stun, msg, &ua);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -155,8 +134,7 @@ int icem_comp_alloc(struct icem_comp **cp, struct icem *icem, int id,
|
|||
comp->icem = icem;
|
||||
|
||||
err = udp_register_helper(&comp->uh, sock, icem->layer,
|
||||
NULL, /*helper_send_handler*/
|
||||
helper_recv_handler, comp);
|
||||
NULL, helper_recv_handler, comp);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
|
@ -290,6 +268,6 @@ void icecomp_printf(struct icem_comp *comp, const char *fmt, ...)
|
|||
return;
|
||||
|
||||
va_start(ap, fmt);
|
||||
(void)re_printf("{%s.%u} %v", comp->icem->name, comp->id, fmt, &ap);
|
||||
(void)re_printf("{%11s.%u} %v", comp->icem->name, comp->id, fmt, &ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
|
|
@ -21,26 +21,16 @@
|
|||
#include <re_dbg.h>
|
||||
|
||||
|
||||
/** Enable multiple parallel connectivity checks */
|
||||
#define ICE_CONNCHECK_MULTIPLE 0
|
||||
|
||||
|
||||
static void pace_next(struct icem *icem)
|
||||
{
|
||||
if (icem->state != CHECKLIST_RUNNING)
|
||||
return;
|
||||
|
||||
#if 0
|
||||
re_printf("\n");
|
||||
re_printf("---> Pace next check: checklist=%u validlist=%u"
|
||||
" triggq=%u\n",
|
||||
list_count(&icem->checkl),
|
||||
list_count(&icem->validl),
|
||||
list_count(&icem->triggl));
|
||||
#endif
|
||||
|
||||
icem_conncheck_schedule_check(icem);
|
||||
|
||||
if (icem->state == CHECKLIST_FAILED)
|
||||
return;
|
||||
|
||||
icem_checklist_update(icem);
|
||||
}
|
||||
|
||||
|
@ -91,6 +81,8 @@ static struct candpair *construct_valid_pair(struct icem *icem,
|
|||
* 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;
|
||||
|
@ -100,7 +92,7 @@ static struct candpair *construct_valid_pair(struct icem *icem,
|
|||
return NULL;
|
||||
|
||||
icem_candpair_make_valid(cp2);
|
||||
icem_candpair_failed(cp, EINTR, 0);
|
||||
/*icem_candpair_failed(cp, EINTR, 0);*/
|
||||
|
||||
return cp2;
|
||||
}
|
||||
|
@ -114,25 +106,26 @@ static struct candpair *construct_valid_pair(struct icem *icem,
|
|||
|
||||
|
||||
static void handle_success(struct icem *icem, struct candpair *cp,
|
||||
const struct sa *addr)
|
||||
const struct sa *laddr)
|
||||
{
|
||||
if (!icem_cand_find(&icem->lcandl, cp->lcand->compid, addr)) {
|
||||
if (!icem_cand_find(&icem->lcandl, cp->lcand->compid, laddr)) {
|
||||
|
||||
int err;
|
||||
|
||||
icecomp_printf(cp->comp, "adding local PRFLX Candidate: %J\n",
|
||||
addr);
|
||||
laddr);
|
||||
|
||||
err = icem_lcand_add(icem, cp->lcand,
|
||||
CAND_TYPE_PRFLX, addr);
|
||||
CAND_TYPE_PRFLX, laddr);
|
||||
if (err) {
|
||||
DEBUG_WARNING("failed to add PRFLX: %m\n", err);
|
||||
}
|
||||
}
|
||||
|
||||
cp = construct_valid_pair(icem, cp, addr, &cp->rcand->addr);
|
||||
cp = construct_valid_pair(icem, cp, laddr, &cp->rcand->addr);
|
||||
if (!cp) {
|
||||
DEBUG_WARNING("no valid pair\n");
|
||||
DEBUG_WARNING("{%s.%u} no valid candidate pair for %J\n",
|
||||
icem->name, cp->comp->id, laddr);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -141,8 +134,10 @@ static void handle_success(struct icem *icem, struct candpair *cp,
|
|||
|
||||
cp->nominated = true;
|
||||
|
||||
#if 0
|
||||
/* stop conncheck now -- conclude */
|
||||
icem_conncheck_stop(icem);
|
||||
icem_conncheck_stop(icem, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
@ -251,8 +246,6 @@ int icem_conncheck_send(struct candpair *cp, bool use_cand, bool trigged)
|
|||
DEBUG_WARNING("no remote password!\n");
|
||||
}
|
||||
|
||||
cp->usec_sent = ice_get_usec();
|
||||
|
||||
if (cp->ct_conn) {
|
||||
DEBUG_WARNING("send_req: CONNCHECK already Pending!\n");
|
||||
return EBUSY;
|
||||
|
@ -275,7 +268,7 @@ int icem_conncheck_send(struct candpair *cp, bool use_cand, bool trigged)
|
|||
case CAND_TYPE_SRFLX:
|
||||
case CAND_TYPE_PRFLX:
|
||||
cp->ct_conn = mem_deref(cp->ct_conn);
|
||||
err = stun_request(&cp->ct_conn, icem->stun, icem->proto,
|
||||
err = stun_request(&cp->ct_conn, ice->stun, icem->proto,
|
||||
cp->comp->sock, &cp->rcand->addr, presz,
|
||||
STUN_METHOD_BINDING,
|
||||
(uint8_t *)icem->rpwd, str_len(icem->rpwd),
|
||||
|
@ -284,7 +277,8 @@ int icem_conncheck_send(struct candpair *cp, bool use_cand, bool trigged)
|
|||
STUN_ATTR_USERNAME, username_buf,
|
||||
STUN_ATTR_PRIORITY, &prio_prflx,
|
||||
ctrl_attr, &ice->tiebrk,
|
||||
STUN_ATTR_USE_CAND, use_cand);
|
||||
STUN_ATTR_USE_CAND,
|
||||
use_cand ? &use_cand : 0);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -297,6 +291,20 @@ int icem_conncheck_send(struct candpair *cp, bool use_cand, bool trigged)
|
|||
}
|
||||
|
||||
|
||||
static void abort_ice(struct icem *icem, int err)
|
||||
{
|
||||
icem->state = CHECKLIST_FAILED;
|
||||
tmr_cancel(&icem->tmr_pace);
|
||||
|
||||
if (icem->chkh) {
|
||||
icem->chkh(err, icem->ice->lrole == ROLE_CONTROLLING,
|
||||
icem->arg);
|
||||
}
|
||||
|
||||
icem->chkh = NULL;
|
||||
}
|
||||
|
||||
|
||||
static void do_check(struct candpair *cp)
|
||||
{
|
||||
int err;
|
||||
|
@ -304,7 +312,10 @@ static void do_check(struct candpair *cp)
|
|||
err = icem_conncheck_send(cp, false, false);
|
||||
if (err) {
|
||||
icem_candpair_failed(cp, err, 0);
|
||||
return;
|
||||
|
||||
if (err == ENOMEM) {
|
||||
abort_ice(cp->icem, err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -342,20 +353,16 @@ void icem_conncheck_schedule_check(struct icem *icem)
|
|||
|
||||
/* Terminate the timer for that check list. */
|
||||
|
||||
#if 0
|
||||
icem->state = CHECKLIST_COMPLETED;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static void timeout(void *arg)
|
||||
static void pace_timeout(void *arg)
|
||||
{
|
||||
struct icem *icem = arg;
|
||||
|
||||
#if ICE_CONNCHECK_MULTIPLE
|
||||
if (icem->state == CHECKLIST_RUNNING) {
|
||||
tmr_start(&icem->tmr_pace, 100, timeout, icem);
|
||||
}
|
||||
#endif
|
||||
|
||||
pace_next(icem);
|
||||
}
|
||||
|
||||
|
@ -379,12 +386,12 @@ int icem_conncheck_start(struct icem *icem)
|
|||
|
||||
icem->state = CHECKLIST_RUNNING;
|
||||
|
||||
DEBUG_NOTICE("%s: starting connectivity checks"
|
||||
" with %u candidate pairs\n",
|
||||
icem->name, list_count(&icem->checkl));
|
||||
icem_printf(icem, "starting connectivity checks"
|
||||
" with %u candidate pairs\n",
|
||||
list_count(&icem->checkl));
|
||||
|
||||
/* add some delay, to wait for call to be 'established' */
|
||||
tmr_start(&icem->tmr_pace, 1000, timeout, icem);
|
||||
tmr_start(&icem->tmr_pace, 10, pace_timeout, icem);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -393,28 +400,28 @@ int icem_conncheck_start(struct icem *icem)
|
|||
void icem_conncheck_continue(struct icem *icem)
|
||||
{
|
||||
if (!tmr_isrunning(&icem->tmr_pace))
|
||||
tmr_start(&icem->tmr_pace, 1, timeout, icem);
|
||||
tmr_start(&icem->tmr_pace, 1, pace_timeout, icem);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Stop checklist, cancel all connectivity checks
|
||||
*/
|
||||
void icem_conncheck_stop(struct icem *icem)
|
||||
void icem_conncheck_stop(struct icem *icem, int err)
|
||||
{
|
||||
struct le *le;
|
||||
|
||||
icem->state = CHECKLIST_COMPLETED;
|
||||
icem->state = err ? CHECKLIST_FAILED : CHECKLIST_COMPLETED;
|
||||
|
||||
tmr_cancel(&icem->tmr_pace);
|
||||
|
||||
for (le = icem->checkl.head; le; le = le->next) {
|
||||
struct candpair *cp = le->data;
|
||||
|
||||
icem_candpair_cancel(cp);
|
||||
|
||||
if (cp->state != CANDPAIR_SUCCEEDED)
|
||||
icem_candpair_failed(cp, EINTR, 0);
|
||||
if (!icem_candpair_iscompleted(cp)) {
|
||||
icem_candpair_cancel(cp);
|
||||
icem_candpair_failed(cp, ECANCELED, 0);
|
||||
}
|
||||
}
|
||||
|
||||
icem_checklist_update(icem);
|
||||
|
|
|
@ -96,7 +96,7 @@ static int send_binding_request(struct icem *icem, struct icem_comp *comp)
|
|||
if (comp->ct_gath)
|
||||
return EALREADY;
|
||||
|
||||
err = stun_request(&comp->ct_gath, icem->stun, icem->proto,
|
||||
err = stun_request(&comp->ct_gath, icem->ice->stun, icem->proto,
|
||||
comp->sock, &icem->stun_srv, 0,
|
||||
STUN_METHOD_BINDING,
|
||||
NULL, false, 0,
|
||||
|
@ -173,8 +173,8 @@ static int cand_gather_relayed(struct icem *icem, struct icem_comp *comp,
|
|||
if (comp->turnc)
|
||||
return EALREADY;
|
||||
|
||||
err = turnc_alloc(&comp->turnc, stun_conf(icem->stun), icem->proto,
|
||||
comp->sock, layer, &icem->stun_srv,
|
||||
err = turnc_alloc(&comp->turnc, stun_conf(icem->ice->stun),
|
||||
icem->proto, comp->sock, layer, &icem->stun_srv,
|
||||
username, password,
|
||||
60, turnc_handler, comp);
|
||||
if (err)
|
||||
|
@ -195,6 +195,12 @@ static int start_gathering(struct icem *icem, const struct sa *stun_srv,
|
|||
if (icem->ice->lmode != ICE_MODE_FULL)
|
||||
return EINVAL;
|
||||
|
||||
if (list_isempty(&icem->compl)) {
|
||||
DEBUG_WARNING("gathering: no components for"
|
||||
" mediastream '%s'\n", icem->name);
|
||||
return ENOENT;
|
||||
}
|
||||
|
||||
sa_cpy(&icem->stun_srv, stun_srv);
|
||||
|
||||
/* for each component */
|
||||
|
|
|
@ -50,6 +50,7 @@ static void ice_destructor(void *arg)
|
|||
struct ice *ice = arg;
|
||||
|
||||
list_flush(&ice->ml);
|
||||
mem_deref(ice->stun);
|
||||
}
|
||||
|
||||
|
||||
|
@ -65,6 +66,7 @@ static void ice_destructor(void *arg)
|
|||
int ice_alloc(struct ice **icep, enum ice_mode mode, bool offerer)
|
||||
{
|
||||
struct ice *ice;
|
||||
int err = 0;
|
||||
|
||||
if (!icep)
|
||||
return EINVAL;
|
||||
|
@ -84,9 +86,24 @@ int ice_alloc(struct ice **icep, enum ice_mode mode, bool offerer)
|
|||
|
||||
ice_determine_role(ice, offerer);
|
||||
|
||||
*icep = ice;
|
||||
if (ICE_MODE_FULL == ice->lmode) {
|
||||
|
||||
return 0;
|
||||
err = stun_alloc(&ice->stun, NULL, NULL, NULL);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
/* Update STUN Transport */
|
||||
stun_conf(ice->stun)->rto = ice->conf.rto;
|
||||
stun_conf(ice->stun)->rc = ice->conf.rc;
|
||||
}
|
||||
|
||||
out:
|
||||
if (err)
|
||||
mem_deref(ice);
|
||||
else
|
||||
*icep = ice;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
|
@ -166,6 +183,8 @@ int ice_debug(struct re_printf *pf, const struct ice *ice)
|
|||
for (le = ice->ml.head; le; le = le->next)
|
||||
err |= icem_debug(pf, le->data);
|
||||
|
||||
err |= stun_debug(pf, ice->stun);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
|
@ -64,6 +64,7 @@ struct ice {
|
|||
struct list ml; /**< Media list (struct icem) */
|
||||
uint64_t tiebrk; /**< Tie-break value for roleconflict */
|
||||
struct ice_conf conf; /**< ICE Configuration */
|
||||
struct stun *stun; /**< STUN Transport */
|
||||
};
|
||||
|
||||
/** Defines a media-stream component */
|
||||
|
@ -95,7 +96,6 @@ struct icem {
|
|||
struct list validl; /**< Valid List of cand pairs (sorted) */
|
||||
bool mismatch; /**< ICE mismatch flag */
|
||||
struct tmr tmr_pace; /**< Timer for pacing STUN requests */
|
||||
struct stun *stun; /**< STUN Transport */
|
||||
int proto; /**< Transport protocol */
|
||||
int layer; /**< Protocol layer */
|
||||
enum checkl_state state; /**< State of the checklist */
|
||||
|
@ -136,8 +136,6 @@ struct candpair {
|
|||
bool nominated; /**< Nominated flag */
|
||||
enum candpair_state state; /**< Candidate pair state */
|
||||
uint64_t pprio; /**< Pair priority */
|
||||
uint64_t usec_sent; /**< When connectivity request was sent */
|
||||
long ertt; /**< Estimated Round-Trip Time in [usec]*/
|
||||
struct stun_ctrans *ct_conn; /**< STUN Transaction for conncheck */
|
||||
int err; /**< Saved error code, if failed */
|
||||
uint16_t scode; /**< Saved STUN code, if failed */
|
||||
|
@ -157,6 +155,8 @@ int icem_rcand_add_prflx(struct cand **rcp, struct icem *icem, uint8_t compid,
|
|||
uint32_t prio, const struct sa *addr);
|
||||
struct cand *icem_cand_find(const struct list *lst, uint8_t compid,
|
||||
const struct sa *addr);
|
||||
struct cand *icem_lcand_find_checklist(const struct icem *icem,
|
||||
uint8_t compid);
|
||||
int icem_cands_debug(struct re_printf *pf, const struct list *lst);
|
||||
int icem_cand_print(struct re_printf *pf, const struct cand *c);
|
||||
|
||||
|
@ -183,6 +183,8 @@ struct candpair *icem_candpair_find_st(const struct list *lst, uint8_t compid,
|
|||
enum candpair_state state);
|
||||
struct candpair *icem_candpair_find_compid(const struct list *lst,
|
||||
uint8_t compid);
|
||||
struct candpair *icem_candpair_find_rcand(struct icem *icem,
|
||||
const struct cand *rcand);
|
||||
int icem_candpair_debug(struct re_printf *pf, const struct candpair *cp);
|
||||
int icem_candpairs_debug(struct re_printf *pf, const struct list *list);
|
||||
|
||||
|
@ -194,6 +196,7 @@ int icem_stund_recv(struct icem_comp *comp, const struct sa *src,
|
|||
|
||||
/* ICE media */
|
||||
void icem_cand_redund_elim(struct icem *icem);
|
||||
void icem_printf(struct icem *icem, const char *fmt, ...);
|
||||
|
||||
|
||||
/* Checklist */
|
||||
|
@ -215,7 +218,6 @@ void icecomp_printf(struct icem_comp *comp, const char *fmt, ...);
|
|||
/* conncheck */
|
||||
void icem_conncheck_schedule_check(struct icem *icem);
|
||||
void icem_conncheck_continue(struct icem *icem);
|
||||
void icem_conncheck_stop(struct icem *icem);
|
||||
int icem_conncheck_send(struct candpair *cp, bool use_cand, bool trigged);
|
||||
|
||||
|
||||
|
|
|
@ -32,7 +32,6 @@ static void icem_destructor(void *data)
|
|||
list_flush(&icem->checkl);
|
||||
list_flush(&icem->lcandl);
|
||||
list_flush(&icem->rcandl);
|
||||
mem_deref(icem->stun);
|
||||
mem_deref(icem->rufrag);
|
||||
mem_deref(icem->rpwd);
|
||||
}
|
||||
|
@ -82,17 +81,6 @@ int icem_alloc(struct icem **icemp, struct ice *ice, int proto, int layer,
|
|||
icem->chkh = chkh;
|
||||
icem->arg = arg;
|
||||
|
||||
if (ICE_MODE_FULL == ice->lmode) {
|
||||
|
||||
err = stun_alloc(&icem->stun, NULL, NULL, NULL);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
/* Update STUN Transport */
|
||||
stun_conf(icem->stun)->rto = ice->conf.rto;
|
||||
stun_conf(icem->stun)->rc = ice->conf.rc;
|
||||
}
|
||||
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
|
@ -190,25 +178,27 @@ static void *unique_handler(struct le *le1, struct le *le2)
|
|||
/** Eliminating Redundant Candidates */
|
||||
void icem_cand_redund_elim(struct icem *icem)
|
||||
{
|
||||
uint32_t n = ice_list_unique(&icem->lcandl, unique_handler);
|
||||
uint32_t n;
|
||||
|
||||
n = ice_list_unique(&icem->lcandl, unique_handler);
|
||||
if (n > 0) {
|
||||
DEBUG_NOTICE("%s: redundant candidates eliminated: %u\n",
|
||||
icem->name, n);
|
||||
icem_printf(icem, "redundant candidates eliminated: %u\n", n);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the Default Candidate
|
||||
* Get the Default Local Candidate
|
||||
*
|
||||
* @param icem ICE Media object
|
||||
* @param compid Component ID
|
||||
*
|
||||
* @return Default Candidate address if set, otherwise NULL
|
||||
* @return Default Local Candidate address if set, otherwise NULL
|
||||
*/
|
||||
const struct sa *icem_cand_default(struct icem *icem, uint8_t compid)
|
||||
{
|
||||
const struct icem_comp *comp = icem_comp_find(icem, compid);
|
||||
|
||||
if (!comp || !comp->def_lcand)
|
||||
return NULL;
|
||||
|
||||
|
@ -347,7 +337,6 @@ bool icem_mismatch(const struct icem *icem)
|
|||
*/
|
||||
int icem_debug(struct re_printf *pf, const struct icem *icem)
|
||||
{
|
||||
struct le *le;
|
||||
int err = 0;
|
||||
|
||||
if (!icem)
|
||||
|
@ -365,18 +354,6 @@ int icem_debug(struct re_printf *pf, const struct icem *icem)
|
|||
err |= re_hprintf(pf, " Valid list: %H",
|
||||
icem_candpairs_debug, &icem->validl);
|
||||
|
||||
for (le = icem->compl.head; le; le = le->next) {
|
||||
|
||||
const struct icem_comp *comp = le->data;
|
||||
|
||||
if (comp->cp_sel) {
|
||||
err |= re_hprintf(pf, " Selected: %H\n",
|
||||
icem_candpair_debug, comp->cp_sel);
|
||||
}
|
||||
}
|
||||
|
||||
err |= stun_debug(pf, icem->stun);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -392,3 +369,16 @@ struct list *icem_lcandl(const struct icem *icem)
|
|||
{
|
||||
return icem ? (struct list *)&icem->lcandl : NULL;
|
||||
}
|
||||
|
||||
|
||||
void icem_printf(struct icem *icem, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
if (!icem || !icem->ice->conf.debug)
|
||||
return;
|
||||
|
||||
va_start(ap, fmt);
|
||||
(void)re_printf("{%11s. } %v", icem->name, fmt, &ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
|
|
@ -215,7 +215,9 @@ static int cand_decode(struct icem *icem, const char *val)
|
|||
return err;
|
||||
|
||||
if (ICE_TRANSP_NONE == transp_resolve(&transp)) {
|
||||
DEBUG_WARNING("transport not supported: %r\n", &transp);
|
||||
DEBUG_NOTICE("<%s> ignoring candidate with"
|
||||
" unknown transport=%r (%r:%r)\n",
|
||||
icem->name, &transp, &cand_type, &addr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -35,11 +35,10 @@ static void triggered_check(struct icem *icem, struct cand *lcand,
|
|||
cp = icem_candpair_find(&icem->checkl, lcand, rcand);
|
||||
|
||||
if (cp) {
|
||||
DEBUG_NOTICE("{%s.%u} triggered_check: found CANDPAIR on"
|
||||
" checklist in state: %s [%H]\n",
|
||||
icem->name, cp->comp->id,
|
||||
ice_candpair_state2name(cp->state),
|
||||
icem_candpair_debug, cp);
|
||||
icecomp_printf(cp->comp,
|
||||
"triggered_check: found CandidatePair on"
|
||||
" checklist in state: %H\n",
|
||||
icem_candpair_debug, cp);
|
||||
|
||||
switch (cp->state) {
|
||||
|
||||
|
@ -73,6 +72,8 @@ static void triggered_check(struct icem *icem, struct cand *lcand,
|
|||
}
|
||||
}
|
||||
else {
|
||||
|
||||
#if 0
|
||||
err = icem_candpair_alloc(&cp, icem, lcand, rcand);
|
||||
if (err) {
|
||||
DEBUG_WARNING("failed to allocate candpair:"
|
||||
|
@ -86,108 +87,51 @@ static void triggered_check(struct icem *icem, struct cand *lcand,
|
|||
icem_candpair_set_state(cp, CANDPAIR_WAITING);
|
||||
|
||||
(void)icem_conncheck_send(cp, false, true);
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static struct candpair *lookup_candpair(struct icem *icem,
|
||||
const struct cand *rcand)
|
||||
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 candpair *cp;
|
||||
|
||||
cp = icem_candpair_find(&icem->checkl, NULL, rcand);
|
||||
if (cp)
|
||||
return cp;
|
||||
|
||||
cp = icem_candpair_find(&icem->validl, NULL, rcand);
|
||||
if (cp)
|
||||
return cp;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Find the highest priority LCAND on the check-list of type HOST/RELAY
|
||||
*/
|
||||
static struct cand *lookup_lcand(struct icem *icem, uint8_t compid)
|
||||
{
|
||||
struct le *le;
|
||||
|
||||
for (le = icem->checkl.head; le; le = le->next) {
|
||||
struct candpair *cp = le->data;
|
||||
|
||||
if (cp->lcand->compid != compid)
|
||||
continue;
|
||||
|
||||
switch (cp->lcand->type) {
|
||||
|
||||
case CAND_TYPE_HOST:
|
||||
case CAND_TYPE_RELAY:
|
||||
return cp->lcand;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static void 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 = NULL;
|
||||
struct cand *lcand = NULL, *rcand;
|
||||
struct candpair *cp = NULL;
|
||||
int err;
|
||||
|
||||
if (icem->state != CHECKLIST_RUNNING) {
|
||||
DEBUG_WARNING("{%s.%u} src=%J Checklist is not running (%s)\n",
|
||||
icem->name, comp->id, src,
|
||||
ice_checkl_state2name(icem->state));
|
||||
return;
|
||||
}
|
||||
|
||||
/* 7.2.1.3. Learning Peer Reflexive Candidates */
|
||||
rcand = icem_cand_find(&icem->rcandl, comp->id, src);
|
||||
if (!rcand) {
|
||||
|
||||
icecomp_printf(comp, "Adding PRFLX remote candidate: %J\n",
|
||||
src);
|
||||
|
||||
err = icem_rcand_add_prflx(&rcand, icem, comp->id, prio, src);
|
||||
if (err) {
|
||||
DEBUG_WARNING("icem_rcand_add_prflx: %m\n", err);
|
||||
return;
|
||||
}
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
cp = lookup_candpair(icem, rcand);
|
||||
cp = icem_candpair_find_rcand(icem, rcand);
|
||||
if (cp)
|
||||
lcand = cp->lcand;
|
||||
else {
|
||||
lcand = lookup_lcand(icem, comp->id);
|
||||
}
|
||||
else
|
||||
lcand = icem_lcand_find_checklist(icem, comp->id);
|
||||
|
||||
if (!lcand) {
|
||||
DEBUG_WARNING("{%s.%u} no local candidate (checkl=%u)\n",
|
||||
DEBUG_WARNING("{%s.%u} no local candidate"
|
||||
" (checklist=%u) (src=%J)\n",
|
||||
icem->name, comp->id,
|
||||
list_count(&icem->checkl));
|
||||
list_count(&icem->checkl), src);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 7.2.1.4. Triggered Checks */
|
||||
if (ICE_MODE_FULL == ice->lmode)
|
||||
triggered_check(icem, lcand, rcand);
|
||||
|
||||
if (!cp) {
|
||||
cp = lookup_candpair(icem, rcand);
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -204,25 +148,39 @@ static void handle_stun(struct ice *ice, struct icem *icem,
|
|||
/* 7.2.1.5. Updating the Nominated Flag */
|
||||
if (use_cand) {
|
||||
if (ice->lrole == ROLE_CONTROLLED) {
|
||||
if (cp && cp->state == CANDPAIR_SUCCEEDED) {
|
||||
DEBUG_NOTICE("{%s.%u} setting NOMINATED"
|
||||
" flag on candpair [%H]\n",
|
||||
icem->name, comp->id,
|
||||
icem_candpair_debug, cp);
|
||||
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 */
|
||||
if (cp) {
|
||||
icem_candpair_make_valid(cp);
|
||||
icem_candpair_make_valid(cp);
|
||||
|
||||
if (ice->conf.nom == ICE_NOMINATION_REGULAR) {
|
||||
icem_candpair_cancel(cp);
|
||||
icem_comp_set_selected(comp, cp);
|
||||
}
|
||||
if (ice->conf.nom == ICE_NOMINATION_REGULAR) {
|
||||
icem_candpair_cancel(cp);
|
||||
icem_comp_set_selected(comp, cp);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int stunsrv_ereply(struct icem_comp *comp, const struct sa *src,
|
||||
size_t presz, const struct stun_msg *req,
|
||||
uint16_t scode, const char *reason)
|
||||
{
|
||||
struct icem *icem = comp->icem;
|
||||
struct ice *ice = icem->ice;
|
||||
|
||||
return stun_ereply(icem->proto, comp->sock, src, presz, req,
|
||||
scode, reason,
|
||||
(uint8_t *)ice->lpwd, strlen(ice->lpwd), true, 1,
|
||||
STUN_ATTR_SOFTWARE, sw);
|
||||
}
|
||||
|
||||
|
||||
|
@ -297,7 +255,10 @@ int icem_stund_recv(struct icem_comp *comp, const struct sa *src,
|
|||
if (attr)
|
||||
use_cand = true;
|
||||
|
||||
handle_stun(ice, icem, comp, src, prio_prflx, use_cand, presz > 0);
|
||||
err = handle_stun(ice, icem, comp, src, prio_prflx,
|
||||
use_cand, presz > 0);
|
||||
if (err)
|
||||
goto badmsg;
|
||||
|
||||
return stun_reply(icem->proto, comp->sock, src, presz, req,
|
||||
(uint8_t *)ice->lpwd, strlen(ice->lpwd), true, 2,
|
||||
|
@ -305,20 +266,11 @@ int icem_stund_recv(struct icem_comp *comp, const struct sa *src,
|
|||
STUN_ATTR_SOFTWARE, sw);
|
||||
|
||||
badmsg:
|
||||
return stun_ereply(icem->proto, comp->sock, src, presz, req,
|
||||
400, "Bad Request",
|
||||
(uint8_t *)ice->lpwd, strlen(ice->lpwd), true, 1,
|
||||
STUN_ATTR_SOFTWARE, sw);
|
||||
return stunsrv_ereply(comp, src, presz, req, 400, "Bad Request");
|
||||
|
||||
unauth:
|
||||
return stun_ereply(icem->proto, comp->sock, src, presz, req,
|
||||
401, "Unauthorized",
|
||||
(uint8_t *)ice->lpwd, strlen(ice->lpwd), true, 1,
|
||||
STUN_ATTR_SOFTWARE, sw);
|
||||
return stunsrv_ereply(comp, src, presz, req, 401, "Unauthorized");
|
||||
|
||||
conflict:
|
||||
return stun_ereply(icem->proto, comp->sock, src, presz, req,
|
||||
487, "Role Conflict",
|
||||
(uint8_t *)ice->lpwd, strlen(ice->lpwd), true, 1,
|
||||
STUN_ATTR_SOFTWARE, sw);
|
||||
return stunsrv_ereply(comp, src, presz, req, 487, "Role Conflict");
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue