more ICE fixes

This commit is contained in:
Richard Aas 2011-01-19 09:44:20 +00:00
parent e8fdeec394
commit f35510eb22
14 changed files with 367 additions and 207 deletions

View file

@ -15,8 +15,8 @@ enum ice_compid {
};
enum ice_nomination {
NOMINATION_REGULAR = 0,
NOMINATION_AGGRESSIVE
ICE_NOMINATION_REGULAR = 0,
ICE_NOMINATION_AGGRESSIVE
};
struct ice;

View file

@ -13,6 +13,9 @@ VENDORID 0
CAPABILITY NetworkServices
#endif
MACRO HAVE_SYS_TIME_H
MACRO HAVE_UNISTD_H
SOURCEPATH .
SOURCE dll.cpp
@ -28,7 +31,6 @@ SOURCE icem.c
SOURCE icesdp.c
SOURCE icestr.c
SOURCE stunsrv.c
SOURCE triggq.c
SOURCE util.c
SOURCEPATH ..\..\src\natbd

View file

@ -11,6 +11,7 @@
#include <re_list.h>
#include <re_tmr.h>
#include <re_sa.h>
#include <re_sys.h>
#include <re_stun.h>
#include <re_turn.h>
#include <re_ice.h>
@ -169,6 +170,37 @@ int icem_rcand_add(struct icem *icem, enum cand_type type, uint8_t compid,
}
int icem_rcand_add_prflx(struct cand **rcp, struct icem *icem, uint8_t compid,
uint32_t prio, const struct sa *addr)
{
struct cand *rcand;
int err;
if (!icem || !addr)
return EINVAL;
rcand = mem_zalloc(sizeof(*rcand), cand_destructor);
if (!rcand)
return ENOMEM;
list_append(&icem->rcandl, &rcand->le, rcand);
rcand->type = CAND_TYPE_PRFLX;
rcand->compid = compid;
rcand->prio = prio;
rcand->addr = *addr;
err = re_sdprintf(&rcand->foundation, "%08x", rand_u32());
if (err)
mem_deref(rcand);
else if (rcp)
*rcp = rcand;
return err;
}
struct cand *icem_cand_find(const struct list *lst, uint8_t compid,
const struct sa *addr)
{

View file

@ -26,7 +26,6 @@ static void candpair_destructor(void *data)
struct candpair *cp = data;
list_unlink(&cp->le);
list_unlink(&cp->le_tq);
mem_deref(cp->ct_conn);
@ -35,6 +34,17 @@ static void candpair_destructor(void *data)
}
static bool sort_handler(struct le *le1, struct le *le2, void *arg)
{
const struct candpair *cp1 = le1->data;
const struct candpair *cp2 = le2->data;
(void)arg;
return cp1->pprio >= cp2->pprio;
}
static void candpair_set_pprio(struct candpair *cp)
{
uint32_t g, d;
@ -52,6 +62,27 @@ static void candpair_set_pprio(struct candpair *cp)
}
/**
* Add candidate pair to list, sorted by pair priority (highest is first)
*/
static void list_add_sorted(struct list *list, struct candpair *cp)
{
struct le *le;
/* find our slot */
for (le = list_tail(list); le; le = le->prev) {
struct candpair *cp0 = le->data;
if (cp->pprio < cp0->pprio) {
list_insert_after(list, le, &cp->le, cp);
return;
}
}
list_prepend(list, &cp->le, cp);
}
int icem_candpair_alloc(struct candpair **cpp, struct icem *icem,
struct cand *lcand, struct cand *rcand)
{
@ -69,18 +100,18 @@ int icem_candpair_alloc(struct candpair **cpp, struct icem *icem,
if (!cp)
return ENOMEM;
list_append(&icem->checkl, &cp->le, cp);
cp->icem = icem;
cp->comp = comp;
cp->lcand = mem_ref(lcand);
cp->rcand = mem_ref(rcand);
cp->state = CANDPAIR_FROZEN;
cp->rtt = -1;
cp->ertt = -1;
cp->def = comp->def_lcand == lcand && comp->def_rcand == rcand;
candpair_set_pprio(cp);
list_add_sorted(&icem->checkl, cp);
if (cpp)
*cpp = cp;
@ -88,14 +119,39 @@ int icem_candpair_alloc(struct candpair **cpp, struct icem *icem,
}
static bool sort_handler(struct le *le1, struct le *le2, void *arg)
int icem_candpair_clone(struct candpair **cpp, struct candpair *cp0,
struct cand *lcand, struct cand *rcand)
{
const struct candpair *cp1 = le1->data;
const struct candpair *cp2 = le2->data;
struct candpair *cp;
(void)arg;
if (!cp0)
return EINVAL;
return cp1->pprio >= cp2->pprio;
cp = mem_zalloc(sizeof(*cp), candpair_destructor);
if (!cp)
return ENOMEM;
cp->icem = cp0->icem;
cp->comp = cp0->comp;
cp->lcand = mem_ref(lcand ? lcand : cp0->lcand);
cp->rcand = mem_ref(rcand ? rcand : cp0->rcand);
cp->def = cp0->def;
cp->valid = cp0->valid;
cp->nominated = cp0->nominated;
cp->use_cand = cp0->use_cand;
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;
list_add_sorted(&cp0->icem->checkl, cp);
if (cpp)
*cpp = cp;
return 0;
}
@ -117,7 +173,7 @@ void icem_candpair_prio_order(struct list *lst)
void icem_candpair_move(struct candpair *cp, struct list *list)
{
list_unlink(&cp->le);
list_append(list, &cp->le, cp);
list_add_sorted(list, cp);
}
@ -128,8 +184,6 @@ void icem_candpair_cancel(struct candpair *cp)
return;
cp->ct_conn = mem_deref(cp->ct_conn);
icem_conncheck_continue(cp->icem);
}
@ -142,8 +196,8 @@ void icem_candpair_make_valid(struct candpair *cp)
cp->scode = 0;
cp->valid = true;
if (cp->tick_sent)
cp->rtt = (int)(tmr_jiffies() - cp->tick_sent);
if (cp->usec_sent)
cp->ertt = (long)(ice_get_usec() - cp->usec_sent);
icem_candpair_set_state(cp, CANDPAIR_SUCCEEDED);
icem_candpair_move(cp, &cp->icem->validl);
@ -168,12 +222,14 @@ void icem_candpair_set_state(struct candpair *cp, enum candpair_state state)
return;
if (cp->state != state) {
icecomp_printf(cp->comp, "FSM: %10s ===> %-10s\n",
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;
}
cp->state = state;
}
@ -196,9 +252,6 @@ void icem_candpairs_flush(struct list *lst, enum cand_type type, uint8_t id)
if (cp->lcand->type != type)
continue;
/* also remove the local candidate */
mem_deref(cp->lcand);
mem_deref(cp);
}
}
@ -320,18 +373,19 @@ 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%c} %28H <---> %28H",
err = re_hprintf(pf, "{%u} %10s {%c%c%c%c} %22llu %28H <---> %28H",
cp->lcand->compid,
ice_candpair_state2name(cp->state),
cp->def ? 'D' : ' ',
cp->valid ? 'V' : ' ',
cp->nominated ? 'N' : ' ',
cp->use_cand ? 'U' : ' ',
cp->pprio,
icem_cand_print, cp->lcand,
icem_cand_print, cp->rcand);
if (cp->rtt != -1)
err |= re_hprintf(pf, " RTT=%dms", cp->rtt);
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));

View file

@ -21,6 +21,9 @@
#include <re_dbg.h>
/**
* Forming Candidate Pairs
*/
static int candpairs_form(struct icem *icem)
{
struct le *le;
@ -72,7 +75,9 @@ static void *unique_handler(struct le *le1, struct le *le2)
}
/** Pruning the Pairs */
/**
* Pruning the Pairs
*/
static void candpair_prune(struct icem *icem)
{
/* The agent MUST prune the list.
@ -85,12 +90,15 @@ static void candpair_prune(struct icem *icem)
uint32_t n = ice_list_unique(&icem->checkl, unique_handler);
if (n > 0) {
DEBUG_NOTICE("pruned candidate pairs: %u\n", n);
DEBUG_NOTICE("%s: pruned candidate pairs: %u\n",
icem->name, n);
}
}
/** Computing States */
/**
* Computing States
*/
static void candpair_set_states(struct icem *icem)
{
struct le *le, *le2;
@ -205,10 +213,12 @@ static void concluding_ice(struct icem_comp *comp)
icem_comp_set_selected(comp, cp);
/* send STUN request with USE_CAND flag via triggered qeueue */
cp->use_cand = true;
icem_triggq_push(comp->icem, cp);
icem_conncheck_schedule_check(comp->icem);
if (comp->icem->ice->conf.nom == ICE_NOMINATION_REGULAR) {
/* send STUN request with USE_CAND flag via triggered qeueue */
cp->use_cand = true;
(void)icem_conncheck_send(cp, true);
icem_conncheck_schedule_check(comp->icem);
}
comp->concluded = true;
}
@ -234,8 +244,8 @@ void icem_checklist_update(struct icem *icem)
struct icem_comp *comp = le->data;
if (!icem_candpair_find_compid(&icem->validl, comp->id)) {
DEBUG_WARNING("no candidate pair for compid %u\n",
comp->id);
DEBUG_WARNING("%s: no candidate pair for compid %u\n",
icem->name, comp->id);
err = ENOENT;
break;
}

View file

@ -215,9 +215,14 @@ void icem_comp_set_default_rcand(struct icem_comp *comp, struct cand *rcand)
void icem_comp_set_selected(struct icem_comp *comp, struct candpair *cp)
{
if (!comp)
if (!comp || !cp)
return;
if (cp->state != CANDPAIR_SUCCEEDED) {
DEBUG_WARNING("set_selected: invalid state %s\n",
ice_candpair_state2name(cp->state));
}
mem_deref(comp->cp_sel);
comp->cp_sel = mem_ref(cp);
}

View file

@ -22,11 +22,15 @@
#include <re_dbg.h>
#define ICE_CONNCHECK_MULTIPLE 1
/** 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"
@ -42,10 +46,15 @@ static void pace_next(struct icem *icem)
}
/** Constructing a Valid Pair */
static void construct_valid_pair(struct icem *icem, struct candpair *cp,
const struct sa *mapped,
const struct sa *dest)
/**
* Constructing a Valid Pair
*
* @return The valid pair
*/
static struct candpair *construct_valid_pair(struct icem *icem,
struct candpair *cp,
const struct sa *mapped,
const struct sa *dest)
{
struct cand *lcand, *rcand;
struct candpair *cp2;
@ -53,13 +62,14 @@ static void construct_valid_pair(struct icem *icem, struct candpair *cp,
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;
return NULL;
}
if (!rcand) {
DEBUG_WARNING("no such remote candidate: %J\n", dest);
return;
return NULL;
}
/* New candidate? -- implicit success */
@ -81,22 +91,27 @@ static void construct_valid_pair(struct icem *icem, struct candpair *cp,
* This happens for UAs behind NAT where the original
* pair is of type 'host' and the implicit pair is 'srflx'
*/
icem_candpair_failed(cp, EINTR, 0);
if (icem_candpair_find(&icem->validl, lcand, rcand)) {
cp2 = icem_candpair_find(&icem->validl, lcand, rcand);
if (cp2) {
DEBUG_NOTICE("candpair already in VALID list\n");
return;
return cp2;
}
err = icem_candpair_alloc(&cp2, icem, lcand, rcand);
err = icem_candpair_clone(&cp2, cp, lcand, rcand);
if (err)
return;
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;
}
}
@ -108,9 +123,10 @@ static void handle_success(struct icem *icem, struct candpair *cp,
int err;
DEBUG_NOTICE("adding PRFLX Candidate: %J\n", addr);
icecomp_printf(cp->comp, "adding local PRFLX Candidate: %J\n",
addr);
err = icem_lcand_add(icem, cp->lcand->base,
err = icem_lcand_add(icem, cp->lcand,
CAND_TYPE_PRFLX, addr);
if (err) {
DEBUG_WARNING("failed to add PRFLX: %s\n",
@ -118,10 +134,19 @@ static void handle_success(struct icem *icem, struct candpair *cp,
}
}
construct_valid_pair(icem, cp, addr, &cp->rcand->addr);
cp = construct_valid_pair(icem, cp, addr, &cp->rcand->addr);
if (!cp) {
DEBUG_WARNING("no valid pair\n");
return;
}
if (icem->ice->lrole == ROLE_CONTROLLING && cp->use_cand)
cp->nominated = true;
icem_candpair_make_valid(cp);
icem_comp_set_selected(cp->comp, cp);
cp->nominated = true;
/* stop conncheck now -- conclude */
icem_conncheck_stop(icem);
}
@ -162,10 +187,12 @@ static void stunc_resp_handler(int err, uint16_t scode, const char *reason,
case 487: /* Role Conflict */
ice_switch_local_role(icem->ice);
icem_candpair_set_state(cp, CANDPAIR_WAITING);
icem_triggq_push(icem, cp);
(void)icem_conncheck_send(cp, true);
break;
default:
DEBUG_WARNING("%s: STUN Response: %u %s\n", icem->name,
scode, reason);
icem_candpair_failed(cp, err, scode);
break;
}
@ -175,12 +202,11 @@ static void stunc_resp_handler(int err, uint16_t scode, const char *reason,
}
static int send_req(struct candpair *cp)
int icem_conncheck_send(struct candpair *cp, bool trigged)
{
struct cand *lcand = cp->lcand;
struct icem *icem = cp->icem;
struct ice *ice = icem->ice;
struct icem_comp *comp;
char username_buf[64];
size_t presz = 0;
int use_cand = 0;
@ -188,10 +214,6 @@ static int send_req(struct candpair *cp)
uint16_t ctrl_attr;
int err = 0;
comp = icem_comp_find(icem, lcand->compid);
if (!comp)
return ENOENT;
icem_candpair_set_state(cp, CANDPAIR_INPROGRESS);
(void)re_snprintf(username_buf, sizeof(username_buf),
@ -205,7 +227,7 @@ static int send_req(struct candpair *cp)
case ROLE_CONTROLLING:
ctrl_attr = STUN_ATTR_CONTROLLING;
if (cp->use_cand || ice->conf.nom == NOMINATION_AGGRESSIVE)
if (cp->use_cand || ice->conf.nom == ICE_NOMINATION_AGGRESSIVE)
use_cand = 1;
break;
@ -218,10 +240,11 @@ static int send_req(struct candpair *cp)
}
#if ICE_TRACE
icecomp_printf(cp->comp, "Tx %H ---> %H (%s) %s\n",
icem_cand_print, cp->lcand, icem_cand_print, cp->rcand,
ice_candpair_state2name(cp->state),
use_cand ? "[USE]" : "");
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]" : "");
#endif
/* A connectivity check MUST utilize the STUN short term credential
@ -232,7 +255,7 @@ static int send_req(struct candpair *cp)
DEBUG_WARNING("no remote password!\n");
}
cp->tick_sent = tmr_jiffies();
cp->usec_sent = ice_get_usec();
if (cp->ct_conn) {
DEBUG_WARNING("send_req: CONNCHECK already Pending!\n");
@ -243,7 +266,7 @@ static int send_req(struct candpair *cp)
case CAND_TYPE_RELAY:
/* Creating Permissions for Relayed Candidates */
err = turnc_add_chan(comp->turnc, &cp->rcand->addr,
err = turnc_add_chan(cp->comp->turnc, &cp->rcand->addr,
NULL, NULL);
if (err) {
DEBUG_WARNING("add channel: %s\n", strerror(err));
@ -254,9 +277,10 @@ static int send_req(struct candpair *cp)
case CAND_TYPE_HOST:
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,
comp->sock, &cp->rcand->addr, presz,
cp->comp->sock, &cp->rcand->addr, presz,
STUN_METHOD_BINDING,
(uint8_t *)icem->rpwd, str_len(icem->rpwd),
true, stunc_resp_handler, cp,
@ -267,8 +291,8 @@ static int send_req(struct candpair *cp)
STUN_ATTR_USE_CAND, use_cand);
break;
case CAND_TYPE_PRFLX:
DEBUG_WARNING("cannot send conncheck from Peer Reflexive\n");
default:
DEBUG_WARNING("unknown candidate type %d\n", lcand->type);
err = EINVAL;
break;
}
@ -281,7 +305,7 @@ static void do_check(struct candpair *cp)
{
int err;
err = send_req(cp);
err = icem_conncheck_send(cp, false);
if (err) {
icem_candpair_failed(cp, err, 0);
return;
@ -290,19 +314,12 @@ static void do_check(struct candpair *cp)
/**
* 5.8. Scheduling Checks
* Scheduling Checks
*/
void icem_conncheck_schedule_check(struct icem *icem)
{
struct candpair *cp;
/* search in triggered check queue first */
cp = icem_triggq_pop(icem);
if (cp) {
do_check(cp);
return;
}
/* Find the highest priority pair in that check list that is in the
Waiting state. */
cp = icem_candpair_find_st(&icem->checkl, 0, CANDPAIR_WAITING);
@ -372,10 +389,11 @@ int icem_conncheck_start(struct icem *icem)
DEBUG_NOTICE("starting connectivity checks with %u candidate pairs\n",
list_count(&icem->checkl));
#if 0
re_printf("%H\n", icem_debug, icem);
(void)re_printf("%H\n", icem_debug, icem);
#endif
tmr_start(&icem->tmr_pace, 1, timeout, icem);
/* add some delay, to wait for call to be 'established' */
tmr_start(&icem->tmr_pace, 1000, timeout, icem);
return 0;
}
@ -386,3 +404,27 @@ void icem_conncheck_continue(struct icem *icem)
if (!tmr_isrunning(&icem->tmr_pace))
tmr_start(&icem->tmr_pace, 1, timeout, icem);
}
/**
* Stop checklist, cancel all connectivity checks
*/
void icem_conncheck_stop(struct icem *icem)
{
struct le *le;
icem->state = 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);
}
icem_checklist_update(icem);
}

View file

@ -23,7 +23,7 @@
static const struct ice_conf conf_default = {
NOMINATION_REGULAR,
ICE_NOMINATION_REGULAR,
ICE_DEFAULT_RTO_RTP,
ICE_DEFAULT_RC,
false

View file

@ -91,9 +91,8 @@ struct icem {
int nstun; /**< Number of pending STUN candidates */
struct list lcandl; /**< List of local candidates */
struct list rcandl; /**< List of remote candidates */
struct list checkl; /**< Check List of cand pairs */
struct list validl; /**< Valid List of cand pairs */
struct list triggl; /**< Triggered check-list */
struct list checkl; /**< Check List of cand pairs (sorted) */
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 */
@ -128,7 +127,6 @@ struct cand {
/** Defines a candidate pair */
struct candpair {
struct le le; /**< List element */
struct le le_tq; /**< Triggered queue element */
struct icem *icem; /**< Pointer to parent ICE media */
struct icem_comp *comp; /**< Pointer to media-stream component */
struct cand *lcand; /**< Local candidate */
@ -136,11 +134,11 @@ struct candpair {
bool def; /**< Default flag */
bool valid; /**< Valid flag */
bool nominated; /**< Nominated flag */
bool use_cand; /**< Use-candidate flag */
enum candpair_state state; /**< Candidate pair state */
uint64_t pprio; /**< Pair priority */
uint64_t tick_sent; /**< When connectivity request was sent */
int rtt; /**< Estimated Round-Trip Time in [ms] */
bool use_cand; /**< Use-candidate flag */
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 */
@ -156,6 +154,8 @@ int icem_lcand_add(struct icem *icem, struct cand *base, enum cand_type type,
int icem_rcand_add(struct icem *icem, enum cand_type type, uint8_t compid,
uint32_t prio, const struct sa *addr,
const struct sa *rel_addr, const struct pl *foundation);
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);
int icem_cands_debug(struct re_printf *pf, const struct list *lst);
@ -165,6 +165,8 @@ int icem_cand_print(struct re_printf *pf, const struct cand *c);
/* candpair */
int icem_candpair_alloc(struct candpair **cpp, struct icem *icem,
struct cand *lcand, struct cand *rcand);
int icem_candpair_clone(struct candpair **cpp, struct candpair *cp0,
struct cand *lcand, struct cand *rcand);
void icem_candpair_prio_order(struct list *lst);
void icem_candpair_move(struct candpair *cp, struct list *list);
void icem_candpair_cancel(struct candpair *cp);
@ -216,11 +218,8 @@ void icecomp_printf(struct icem_comp *comp, const char *fmt, ...);
int icem_conncheck_start(struct icem *icem);
void icem_conncheck_schedule_check(struct icem *icem);
void icem_conncheck_continue(struct icem *icem);
/* triggered check queue */
void icem_triggq_push(struct icem *icem, struct candpair *cp);
struct candpair *icem_triggq_pop(struct icem *icem);
void icem_conncheck_stop(struct icem *icem);
int icem_conncheck_send(struct candpair *cp, bool trigged);
/* icestr */
@ -239,3 +238,4 @@ uint32_t ice_calc_prio(enum cand_type type, uint16_t local, uint8_t compid);
uint64_t ice_calc_pair_prio(uint32_t g, uint32_t d);
void ice_switch_local_role(struct ice *ice);
uint32_t ice_list_unique(struct list *list, list_unique_h *uh);
uint64_t ice_get_usec(void);

View file

@ -33,7 +33,6 @@ static void icem_destructor(void *data)
list_flush(&icem->checkl);
list_flush(&icem->lcandl);
list_flush(&icem->rcandl);
list_flush(&icem->triggl);
mem_deref(icem->stun);
mem_deref(icem->rufrag);
@ -62,7 +61,6 @@ int icem_alloc(struct icem **icemp, struct ice *ice, int proto, int layer,
list_init(&icem->rcandl);
list_init(&icem->checkl);
list_init(&icem->validl);
list_init(&icem->triggl);
icem->ice = ice;
icem->layer = layer;
@ -280,8 +278,6 @@ int icem_debug(struct re_printf *pf, const struct icem *icem)
icem_candpairs_debug, &icem->checkl);
err |= re_hprintf(pf, " Valid list: %H",
icem_candpairs_debug, &icem->validl);
err |= re_hprintf(pf, " Triggered queue: %H",
icem_candpairs_debug, &icem->triggl);
for (le = icem->compl.head; le; le = le->next) {

View file

@ -15,5 +15,4 @@ SRCS += ice/icem.c
SRCS += ice/icesdp.c
SRCS += ice/icestr.c
SRCS += ice/stunsrv.c
SRCS += ice/triggq.c
SRCS += ice/util.c

View file

@ -25,51 +25,19 @@
static const char *sw = "ice stunsrv v" VERSION " (" ARCH "/" OS ")";
/** Learning Peer Reflexive Candidates */
static int learn_peer_reflexive(struct icem_comp *comp, const struct sa *src,
uint32_t prio)
{
struct icem *icem = comp->icem;
char foundation[8];
struct pl fnd;
/*
If the source transport address of the request does not match any
existing remote candidates, it represents a new peer reflexive remote
candidate. This candidate is constructed as follows:
*/
if (icem_cand_find(&icem->rcandl, comp->id, src))
return 0;
DEBUG_NOTICE("{%d} Adding Peer-Reflexive remote candidate: %J\n",
comp->id, src);
/*
The foundation of the candidate is set to an arbitrary value,
different from the foundation for all other remote candidates. If
any subsequent offer/answer exchanges contain this peer reflexive
candidate in the SDP, it will signal the actual foundation for the
candidate.
*/
rand_str(foundation, sizeof(foundation));
pl_set_str(&fnd, foundation);
return icem_rcand_add(icem, CAND_TYPE_PRFLX, comp->id, prio,
src, NULL, &fnd);
}
static void triggered_check(struct icem *icem, struct cand *lcand,
struct cand *rcand)
{
struct candpair *cp;
struct candpair *cp = NULL;
int err;
if (!lcand || !rcand)
return;
if (lcand && rcand)
cp = icem_candpair_find(&icem->checkl, lcand, rcand);
cp = icem_candpair_find(&icem->checkl, lcand, rcand);
if (cp) {
DEBUG_NOTICE("triggered_check: found CANDPAIR on checklist"
" in state: %s\n",
ice_candpair_state2name(cp->state));
switch (cp->state) {
@ -91,7 +59,10 @@ static void triggered_check(struct icem *icem, struct cand *lcand,
case CANDPAIR_FROZEN:
case CANDPAIR_WAITING:
icem_triggq_push(icem, cp);
err = icem_conncheck_send(cp, true);
if (err) {
DEBUG_WARNING("triggered check failed\n");
}
break;
case CANDPAIR_SUCCEEDED:
@ -102,7 +73,9 @@ static void triggered_check(struct icem *icem, struct cand *lcand,
else {
err = icem_candpair_alloc(&cp, icem, lcand, rcand);
if (err) {
DEBUG_WARNING("failed to allocate candpair\n");
DEBUG_WARNING("failed to allocate candpair:"
" lcand=%p rcand=%p (%s)\n",
lcand, rcand, strerror(err));
return;
}
@ -110,7 +83,7 @@ static void triggered_check(struct icem *icem, struct cand *lcand,
icem_candpair_set_state(cp, CANDPAIR_WAITING);
icem_triggq_push(icem, cp);
(void)icem_conncheck_send(cp, true);
}
}
@ -128,9 +101,33 @@ static struct candpair *lookup_candpair(struct icem *icem,
if (cp)
return cp;
cp = icem_candpair_find(&icem->triggl, 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;
}
@ -142,16 +139,49 @@ static void handle_stun(struct ice *ice, struct icem *icem,
{
struct cand *lcand = NULL, *rcand = NULL;
struct candpair *cp = NULL;
int err;
rcand = icem_cand_find(&icem->rcandl, comp->id, src);
if (rcand) {
cp = lookup_candpair(icem, rcand);
if (cp)
lcand = cp->lcand;
if (icem->state != CHECKLIST_RUNNING) {
DEBUG_WARNING("Checklist is not running \n");
}
/* 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: %s\n",
strerror(err));
return;
}
}
cp = lookup_candpair(icem, rcand);
if (cp)
lcand = cp->lcand;
else {
lcand = lookup_lcand(icem, comp->id);
}
if (!lcand) {
DEBUG_WARNING("%s: local candidate not found\n", icem->name);
}
/* 7.2.1.4. Triggered Checks */
if (ICE_MODE_FULL == ice->lmode)
triggered_check(icem, lcand, rcand);
if (!cp) {
DEBUG_NOTICE("candidate pair not found: remote=%J\n", src);
/* This can happen for Peer-Reflexive candidates */
cp = lookup_candpair(icem, rcand);
if (!cp) {
DEBUG_WARNING("candidate pair not found:"
" source=%J\n", src);
}
}
#if ICE_TRACE
@ -164,13 +194,6 @@ static void handle_stun(struct ice *ice, struct icem *icem,
(void)tunnel;
#endif
/* 7.2.1.3. Learning Peer Reflexive Candidates */
(void)learn_peer_reflexive(comp, src, prio);
/* 7.2.1.4. Triggered Checks */
if (ICE_MODE_FULL == ice->lmode)
triggered_check(icem, lcand, rcand);
/* 7.2.1.5. Updating the Nominated Flag */
if (use_cand) {
if (ice->lrole == ROLE_CONTROLLED) {
@ -185,12 +208,13 @@ static void handle_stun(struct ice *ice, struct icem *icem,
/* Cancel conncheck. Choose Selected Pair */
if (cp) {
icem_candpair_cancel(cp);
icem_comp_set_selected(comp, cp);
}
icem_candpair_make_valid(cp);
/* ICE should complete now .. */
icem_checklist_update(icem);
if (ice->conf.nom == ICE_NOMINATION_REGULAR) {
icem_candpair_cancel(cp);
icem_comp_set_selected(comp, cp);
}
}
}
}
@ -227,7 +251,14 @@ int icem_stund_recv(struct icem_comp *comp, const struct sa *src,
err = re_regex(attr->v.username, strlen(attr->v.username),
"[^:]+:[^]+", &lu, &ru);
if (err || pl_strcmp(&lu, ice->lufrag) || pl_strcmp(&ru, icem->rufrag))
if (err) {
DEBUG_WARNING("could not parse USERNAME attribute (%s)\n",
attr->v.username);
goto unauth;
}
if (pl_strcmp(&lu, ice->lufrag))
goto unauth;
if (str_len(icem->rufrag) && pl_strcmp(&ru, icem->rufrag))
goto unauth;
attr = stun_msg_attr(req, STUN_ATTR_CONTROLLED);

View file

@ -1,44 +0,0 @@
/**
* @file triggq.c ICE Triggered Check Queue
*
* Copyright (C) 2010 Creytiv.com
*/
#include <string.h>
#include <re_types.h>
#include <re_fmt.h>
#include <re_mem.h>
#include <re_mbuf.h>
#include <re_list.h>
#include <re_tmr.h>
#include <re_sa.h>
#include <re_stun.h>
#include <re_turn.h>
#include <re_ice.h>
#include "ice.h"
void icem_triggq_push(struct icem *icem, struct candpair *cp)
{
if (!icem || !cp)
return;
if (!list_contains(&icem->triggl, &cp->le_tq))
list_append(&icem->triggl, &cp->le_tq, cp);
}
struct candpair *icem_triggq_pop(struct icem *icem)
{
struct candpair *cp;
if (!icem)
return NULL;
cp = list_ledata(icem->triggl.head);
if (!cp)
return NULL;
list_unlink(&cp->le_tq);
return cp;
}

View file

@ -4,6 +4,14 @@
* Copyright (C) 2010 Creytiv.com
*/
#include <string.h>
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
#ifdef WIN32
#include <windows.h>
#else
#include <time.h>
#endif
#include <re_types.h>
#include <re_fmt.h>
#include <re_mem.h>
@ -129,3 +137,28 @@ uint32_t ice_list_unique(struct list *list, list_unique_h *uh)
return n;
}
/** Get time of day in [microseconds] */
uint64_t ice_get_usec(void)
{
uint64_t jfs;
#if defined(WIN32)
FILETIME ft;
ULARGE_INTEGER li;
GetSystemTimeAsFileTime(&ft);
li.LowPart = ft.dwLowDateTime;
li.HighPart = ft.dwHighDateTime;
jfs = li.QuadPart/10;
#else
struct timeval now;
if (0 != gettimeofday(&now, NULL))
return 0;
jfs = 1000000UL * now.tv_sec + now.tv_usec;
#endif
return jfs;
}