ice: many improvements and fixes

This commit is contained in:
Richard Aas 2013-05-27 13:23:03 +00:00
parent f6e4ccd88b
commit 5af1657c55
12 changed files with 256 additions and 235 deletions

View file

@ -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);

View file

@ -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;

View file

@ -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;

View file

@ -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);
}
}

View file

@ -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);
}

View file

@ -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);

View file

@ -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 */

View file

@ -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;
}

View file

@ -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);

View file

@ -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);
}

View file

@ -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;
}

View file

@ -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");
}