re/src/ice/candpair.c
2011-01-19 09:44:20 +00:00

418 lines
7.5 KiB
C

/**
* @file candpair.c ICE Candidate Pairs
*
* 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_ice.h>
#include "ice.h"
#define DEBUG_MODULE "cndpair"
#define DEBUG_LEVEL 5
#include <re_dbg.h>
static void candpair_destructor(void *data)
{
struct candpair *cp = data;
list_unlink(&cp->le);
mem_deref(cp->ct_conn);
mem_deref(cp->lcand);
mem_deref(cp->rcand);
}
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;
if (ROLE_CONTROLLING == cp->icem->ice->lrole) {
g = cp->lcand->prio;
d = cp->rcand->prio;
}
else {
g = cp->rcand->prio;
d = cp->lcand->prio;
}
cp->pprio = ice_calc_pair_prio(g, d);
}
/**
* 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)
{
struct candpair *cp;
struct icem_comp *comp;
if (!icem || !lcand || !rcand)
return EINVAL;
comp = icem_comp_find(icem, lcand->compid);
if (!comp)
return ENOENT;
cp = mem_zalloc(sizeof(*cp), candpair_destructor);
if (!cp)
return ENOMEM;
cp->icem = icem;
cp->comp = comp;
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);
list_add_sorted(&icem->checkl, cp);
if (cpp)
*cpp = cp;
return 0;
}
int icem_candpair_clone(struct candpair **cpp, struct candpair *cp0,
struct cand *lcand, struct cand *rcand)
{
struct candpair *cp;
if (!cp0)
return EINVAL;
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;
}
/** Computing Pair Priority and Ordering Pairs */
void icem_candpair_prio_order(struct list *lst)
{
struct le *le;
for (le = list_head(lst); le; le = le->next) {
struct candpair *cp = le->data;
candpair_set_pprio(cp);
}
list_sort(lst, sort_handler, NULL);
}
void icem_candpair_move(struct candpair *cp, struct list *list)
{
list_unlink(&cp->le);
list_add_sorted(list, cp);
}
/* cancel transaction */
void icem_candpair_cancel(struct candpair *cp)
{
if (!cp)
return;
cp->ct_conn = mem_deref(cp->ct_conn);
}
void icem_candpair_make_valid(struct candpair *cp)
{
if (!cp)
return;
cp->err = 0;
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);
icem_candpair_move(cp, &cp->icem->validl);
}
void icem_candpair_failed(struct candpair *cp, int err, uint16_t scode)
{
if (!cp)
return;
cp->err = err;
cp->scode = scode;
icem_candpair_set_state(cp, CANDPAIR_FAILED);
}
void icem_candpair_set_state(struct candpair *cp, enum candpair_state state)
{
if (!cp)
return;
if (cp->state != state) {
icecomp_printf(cp->comp,
"%5s <---> %5s FSM: %10s ===> %-10s\n",
ice_cand_type2name(cp->lcand->type),
ice_cand_type2name(cp->rcand->type),
ice_candpair_state2name(cp->state),
ice_candpair_state2name(state));
cp->state = state;
}
}
/**
* Delete all Candidate-Pairs where the Local candidate is of a given type
*/
void icem_candpairs_flush(struct list *lst, enum cand_type type, uint8_t id)
{
struct le *le = list_head(lst);
while (le) {
struct candpair *cp = le->data;
le = le->next;
if (cp->lcand->compid != id)
continue;
if (cp->lcand->type != type)
continue;
mem_deref(cp);
}
}
bool icem_candpair_iscompleted(const struct candpair *cp)
{
if (!cp)
return false;
return cp->state == CANDPAIR_FAILED || cp->state == CANDPAIR_SUCCEEDED;
}
/**
* Compare local and remote candidates of two candidate pairs
*
* @return true if match
*/
bool icem_candpair_cmp(const struct candpair *cp1, const struct candpair *cp2)
{
if (!sa_cmp(&cp1->lcand->addr, &cp2->lcand->addr, SA_ALL))
return false;
return sa_cmp(&cp1->rcand->addr, &cp2->rcand->addr, SA_ALL);
}
/**
* Find the highest-priority candidate-pair in a given list, with
* optional match parameters
*
* note: assume list is sorted by priority
*/
struct candpair *icem_candpair_find(const struct list *lst,
const struct cand *lcand,
const struct cand *rcand)
{
struct le *le;
for (le = list_head(lst); le; le = le->next) {
struct candpair *cp = le->data;
if (!cp->lcand || !cp->rcand) {
DEBUG_WARNING("corrupt candpair %p\n", cp);
continue;
}
if (lcand && cp->lcand != lcand)
continue;
if (rcand && cp->rcand != rcand)
continue;
return cp;
}
return NULL;
}
struct candpair *icem_candpair_find_st(const struct list *lst, uint8_t compid,
enum candpair_state state)
{
struct le *le;
for (le = list_head(lst); le; le = le->next) {
struct candpair *cp = le->data;
if (compid && cp->lcand->compid != compid)
continue;
if (cp->state != state)
continue;
return cp;
}
return NULL;
}
struct candpair *icem_candpair_find_compid(const struct list *lst,
uint8_t compid)
{
struct le *le;
for (le = list_head(lst); le; le = le->next) {
struct candpair *cp = le->data;
if (cp->lcand->compid != compid)
continue;
return cp;
}
return NULL;
}
bool icem_candpair_cmp_fnd(const struct candpair *cp1,
const struct candpair *cp2)
{
if (!cp1 || !cp2)
return false;
return 0 == strcmp(cp1->lcand->foundation, cp2->lcand->foundation) &&
0 == strcmp(cp1->rcand->foundation, cp2->rcand->foundation);
}
int icem_candpair_debug(struct re_printf *pf, const struct candpair *cp)
{
int err;
if (!cp)
return 0;
err = re_hprintf(pf, "{%u} %10s {%c%c%c%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->ertt != -1)
err |= re_hprintf(pf, " ERTT = %.2fms", cp->ertt / 1000.0);
if (cp->err)
err |= re_hprintf(pf, " (%s)", strerror(cp->err));
if (cp->scode)
err |= re_hprintf(pf, " [%u]", cp->scode);
return err;
}
int icem_candpairs_debug(struct re_printf *pf, const struct list *list)
{
struct le *le;
int err;
if (!list)
return 0;
err = re_hprintf(pf, " (%u)\n", list_count(list));
for (le = list->head; le && !err; le = le->next) {
const struct candpair *cp = le->data;
err = re_hprintf(pf, " %H\n", icem_candpair_debug, cp);
}
return err;
}