more ICE fixes
This commit is contained in:
parent
e8fdeec394
commit
f35510eb22
14 changed files with 367 additions and 207 deletions
|
@ -15,8 +15,8 @@ enum ice_compid {
|
|||
};
|
||||
|
||||
enum ice_nomination {
|
||||
NOMINATION_REGULAR = 0,
|
||||
NOMINATION_AGGRESSIVE
|
||||
ICE_NOMINATION_REGULAR = 0,
|
||||
ICE_NOMINATION_AGGRESSIVE
|
||||
};
|
||||
|
||||
struct ice;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
|
||||
|
||||
static const struct ice_conf conf_default = {
|
||||
NOMINATION_REGULAR,
|
||||
ICE_NOMINATION_REGULAR,
|
||||
ICE_DEFAULT_RTO_RTP,
|
||||
ICE_DEFAULT_RC,
|
||||
false
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) {
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue