Remove ICE Session object (#56)
* ice: export enum ice_candpair_state this is related to the work of merging 2 ice-stacks into 1: https://github.com/creytiv/re/wiki/ICE-Stacks-merge * ice: remove ice session (struct ice) * ice: remove list, cleanup * ice: use local role instead of offerer
This commit is contained in:
parent
dfd952d858
commit
a1f84fe762
13 changed files with 217 additions and 371 deletions
|
@ -45,6 +45,15 @@ enum ice_tcptype {
|
|||
ICE_TCP_SO /**< Simultaneous-open TCP client/server */
|
||||
};
|
||||
|
||||
/** Candidate pair states */
|
||||
enum ice_candpair_state {
|
||||
ICE_CANDPAIR_FROZEN = 0, /**< Frozen state (default) */
|
||||
ICE_CANDPAIR_WAITING, /**< Waiting to become highest on list */
|
||||
ICE_CANDPAIR_INPROGRESS, /**< In-Progress state;transac. in progress */
|
||||
ICE_CANDPAIR_SUCCEEDED, /**< Succeeded state; successful result */
|
||||
ICE_CANDPAIR_FAILED /**< Failed state; check failed */
|
||||
};
|
||||
|
||||
struct ice;
|
||||
struct icem;
|
||||
|
||||
|
@ -61,22 +70,15 @@ typedef void (ice_gather_h)(int err, uint16_t scode, const char *reason,
|
|||
typedef void (ice_connchk_h)(int err, bool update, void *arg);
|
||||
|
||||
|
||||
/* ICE Session */
|
||||
int ice_alloc(struct ice **icep, enum ice_mode mode, bool offerer);
|
||||
struct ice_conf *ice_conf(struct ice *ice);
|
||||
void ice_set_conf(struct ice *ice, const struct ice_conf *conf);
|
||||
void ice_set_offerer(struct ice *ice, bool offerer);
|
||||
int ice_sdp_decode(struct ice *ice, const char *name, const char *value);
|
||||
int ice_conncheck_start(struct ice *ice);
|
||||
int ice_debug(struct re_printf *pf, const struct ice *ice);
|
||||
struct list *ice_medialist(const struct ice *ice);
|
||||
const char *ice_ufrag(const struct ice *ice);
|
||||
const char *ice_pwd(const struct ice *ice);
|
||||
|
||||
|
||||
/* ICE Media */
|
||||
int icem_alloc(struct icem **icemp, struct ice *ice, int proto, int layer,
|
||||
int icem_alloc(struct icem **icemp, enum ice_mode mode,
|
||||
enum ice_role role, int proto, int layer,
|
||||
uint64_t tiebrk, const char *lufrag, const char *lpwd,
|
||||
ice_gather_h *gh, ice_connchk_h *chkh, void *arg);
|
||||
struct ice_conf *icem_conf(struct icem *icem);
|
||||
enum ice_role icem_local_role(const struct icem *icem);
|
||||
void icem_set_conf(struct icem *icem, const struct ice_conf *conf);
|
||||
void icem_set_role(struct icem *icem, enum ice_role role);
|
||||
void icem_set_name(struct icem *icem, const char *name);
|
||||
int icem_comp_add(struct icem *icem, unsigned compid, void *sock);
|
||||
int icem_cand_add(struct icem *icem, unsigned compid, uint16_t lprio,
|
||||
|
@ -92,6 +94,7 @@ void icem_conncheck_stop(struct icem *icem, int err);
|
|||
int icem_add_chan(struct icem *icem, unsigned compid, const struct sa *raddr);
|
||||
bool icem_mismatch(const struct icem *icem);
|
||||
void icem_update(struct icem *icem);
|
||||
int ice_sdp_decode(struct icem *ice, const char *name, const char *value);
|
||||
int icem_sdp_decode(struct icem *icem, const char *name, const char *value);
|
||||
int icem_debug(struct re_printf *pf, const struct icem *icem);
|
||||
struct list *icem_lcandl(const struct icem *icem);
|
||||
|
@ -100,6 +103,7 @@ struct list *icem_checkl(const struct icem *icem);
|
|||
struct list *icem_validl(const struct icem *icem);
|
||||
const struct sa *icem_cand_default(struct icem *icem, unsigned compid);
|
||||
const struct sa *icem_selected_laddr(const struct icem *icem, unsigned compid);
|
||||
void ice_candpair_set_states(struct icem *icem);
|
||||
|
||||
|
||||
struct ice_cand;
|
||||
|
@ -119,6 +123,7 @@ extern const char ice_attr_ufrag[];
|
|||
const char *ice_cand_type2name(enum ice_cand_type type);
|
||||
enum ice_cand_type ice_cand_name2type(const char *name);
|
||||
const char *ice_role2name(enum ice_role role);
|
||||
const char *ice_candpair_state2name(enum ice_candpair_state st);
|
||||
|
||||
|
||||
uint32_t ice_cand_calc_prio(enum ice_cand_type type, uint16_t local,
|
||||
|
|
|
@ -45,7 +45,7 @@ static void candpair_set_pprio(struct ice_candpair *cp)
|
|||
{
|
||||
uint32_t g, d;
|
||||
|
||||
if (ICE_ROLE_CONTROLLING == cp->icem->ice->lrole) {
|
||||
if (ICE_ROLE_CONTROLLING == cp->icem->lrole) {
|
||||
g = cp->lcand->prio;
|
||||
d = cp->rcand->prio;
|
||||
}
|
||||
|
|
|
@ -110,7 +110,7 @@ static void candpair_prune(struct icem *icem)
|
|||
/**
|
||||
* Computing States
|
||||
*/
|
||||
static void candpair_set_states(struct icem *icem)
|
||||
void ice_candpair_set_states(struct icem *icem)
|
||||
{
|
||||
struct le *le, *le2;
|
||||
|
||||
|
@ -161,7 +161,7 @@ int icem_checklist_form(struct icem *icem)
|
|||
if (!icem)
|
||||
return EINVAL;
|
||||
|
||||
if (ICE_MODE_LITE == icem->ice->lmode) {
|
||||
if (ICE_MODE_LITE == icem->lmode) {
|
||||
DEBUG_WARNING("%s: Checklist: only valid for full-mode\n",
|
||||
icem->name);
|
||||
return EINVAL;
|
||||
|
@ -182,10 +182,6 @@ int icem_checklist_form(struct icem *icem)
|
|||
/* 4. prune the pairs */
|
||||
candpair_prune(icem);
|
||||
|
||||
/* 5. set the pair states -- first media stream only */
|
||||
if (icem->ice->ml.head->data == icem)
|
||||
candpair_set_states(icem);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -230,7 +226,7 @@ static void concluding_ice(struct icem_comp *comp)
|
|||
|
||||
icem_comp_set_selected(comp, cp);
|
||||
|
||||
if (comp->icem->ice->conf.nom == ICE_NOMINATION_REGULAR) {
|
||||
if (comp->icem->conf.nom == ICE_NOMINATION_REGULAR) {
|
||||
|
||||
/* send STUN request with USE_CAND flag via triggered qeueue */
|
||||
(void)icem_conncheck_send(cp, true, true);
|
||||
|
@ -282,7 +278,7 @@ void icem_checklist_update(struct icem *icem)
|
|||
icem->state = err ? ICE_CHECKLIST_FAILED : ICE_CHECKLIST_COMPLETED;
|
||||
|
||||
if (icem->chkh) {
|
||||
icem->chkh(err, icem->ice->lrole == ICE_ROLE_CONTROLLING,
|
||||
icem->chkh(err, icem->lrole == ICE_ROLE_CONTROLLING,
|
||||
icem->arg);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -52,7 +52,7 @@ static bool helper_recv_handler(struct sa *src, struct mbuf *mb, void *arg)
|
|||
break;
|
||||
|
||||
default:
|
||||
(void)stun_ctrans_recv(icem->ice->stun, msg, &ua);
|
||||
(void)stun_ctrans_recv(icem->stun, msg, &ua);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -266,7 +266,7 @@ void icecomp_printf(struct icem_comp *comp, const char *fmt, ...)
|
|||
{
|
||||
va_list ap;
|
||||
|
||||
if (!comp || !comp->icem->ice->conf.debug)
|
||||
if (!comp || !comp->icem->conf.debug)
|
||||
return;
|
||||
|
||||
va_start(ap, fmt);
|
||||
|
|
|
@ -187,7 +187,7 @@ static void stunc_resp_handler(int err, uint16_t scode, const char *reason,
|
|||
break;
|
||||
|
||||
case 487: /* Role Conflict */
|
||||
ice_switch_local_role(icem->ice);
|
||||
ice_switch_local_role(icem);
|
||||
(void)icem_conncheck_send(cp, false, true);
|
||||
break;
|
||||
|
||||
|
@ -207,7 +207,6 @@ int icem_conncheck_send(struct ice_candpair *cp, bool use_cand, bool trigged)
|
|||
{
|
||||
struct ice_cand *lcand = cp->lcand;
|
||||
struct icem *icem = cp->icem;
|
||||
struct ice *ice = icem->ice;
|
||||
char username_buf[64];
|
||||
size_t presz = 0;
|
||||
uint32_t prio_prflx;
|
||||
|
@ -217,17 +216,17 @@ int icem_conncheck_send(struct ice_candpair *cp, bool use_cand, bool trigged)
|
|||
icem_candpair_set_state(cp, ICE_CANDPAIR_INPROGRESS);
|
||||
|
||||
(void)re_snprintf(username_buf, sizeof(username_buf),
|
||||
"%s:%s", icem->rufrag, ice->lufrag);
|
||||
"%s:%s", icem->rufrag, icem->lufrag);
|
||||
|
||||
/* PRIORITY and USE-CANDIDATE */
|
||||
prio_prflx = ice_cand_calc_prio(ICE_CAND_TYPE_PRFLX, 0, lcand->compid);
|
||||
|
||||
switch (ice->lrole) {
|
||||
switch (icem->lrole) {
|
||||
|
||||
case ICE_ROLE_CONTROLLING:
|
||||
ctrl_attr = STUN_ATTR_CONTROLLING;
|
||||
|
||||
if (ice->conf.nom == ICE_NOMINATION_AGGRESSIVE)
|
||||
if (icem->conf.nom == ICE_NOMINATION_AGGRESSIVE)
|
||||
use_cand = true;
|
||||
break;
|
||||
|
||||
|
@ -279,7 +278,7 @@ int icem_conncheck_send(struct ice_candpair *cp, bool use_cand, bool trigged)
|
|||
case ICE_CAND_TYPE_SRFLX:
|
||||
case ICE_CAND_TYPE_PRFLX:
|
||||
cp->ct_conn = mem_deref(cp->ct_conn);
|
||||
err = stun_request(&cp->ct_conn, ice->stun, icem->proto,
|
||||
err = stun_request(&cp->ct_conn, icem->stun, icem->proto,
|
||||
cp->comp->sock, &cp->rcand->addr, presz,
|
||||
STUN_METHOD_BINDING,
|
||||
(uint8_t *)icem->rpwd, str_len(icem->rpwd),
|
||||
|
@ -287,7 +286,7 @@ int icem_conncheck_send(struct ice_candpair *cp, bool use_cand, bool trigged)
|
|||
4,
|
||||
STUN_ATTR_USERNAME, username_buf,
|
||||
STUN_ATTR_PRIORITY, &prio_prflx,
|
||||
ctrl_attr, &ice->tiebrk,
|
||||
ctrl_attr, &icem->tiebrk,
|
||||
STUN_ATTR_USE_CAND,
|
||||
use_cand ? &use_cand : 0);
|
||||
break;
|
||||
|
@ -308,7 +307,7 @@ static void abort_ice(struct icem *icem, int err)
|
|||
tmr_cancel(&icem->tmr_pace);
|
||||
|
||||
if (icem->chkh) {
|
||||
icem->chkh(err, icem->ice->lrole == ICE_ROLE_CONTROLLING,
|
||||
icem->chkh(err, icem->lrole == ICE_ROLE_CONTROLLING,
|
||||
icem->arg);
|
||||
}
|
||||
|
||||
|
@ -391,7 +390,7 @@ int icem_conncheck_start(struct icem *icem)
|
|||
if (!icem)
|
||||
return EINVAL;
|
||||
|
||||
if (ICE_MODE_FULL != icem->ice->lmode)
|
||||
if (ICE_MODE_FULL != icem->lmode)
|
||||
return EINVAL;
|
||||
|
||||
err = icem_checklist_form(icem);
|
||||
|
|
|
@ -97,7 +97,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->ice->stun, icem->proto,
|
||||
err = stun_request(&comp->ct_gath, icem->stun, icem->proto,
|
||||
comp->sock, &icem->stun_srv, 0,
|
||||
STUN_METHOD_BINDING,
|
||||
NULL, false, 0,
|
||||
|
@ -174,7 +174,7 @@ 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->ice->stun),
|
||||
err = turnc_alloc(&comp->turnc, stun_conf(icem->stun),
|
||||
icem->proto, comp->sock, layer, &icem->stun_srv,
|
||||
username, password,
|
||||
60, turnc_handler, comp);
|
||||
|
@ -193,7 +193,7 @@ static int start_gathering(struct icem *icem, const struct sa *stun_srv,
|
|||
struct le *le;
|
||||
int err = 0;
|
||||
|
||||
if (icem->ice->lmode != ICE_MODE_FULL)
|
||||
if (icem->lmode != ICE_MODE_FULL)
|
||||
return EINVAL;
|
||||
|
||||
if (list_isempty(&icem->compl)) {
|
||||
|
|
244
src/ice/ice.c
244
src/ice/ice.c
|
@ -1,245 +1 @@
|
|||
/**
|
||||
* @file ice.c Interactive Connectivity Establishment (ICE)
|
||||
*
|
||||
* Copyright (C) 2010 Creytiv.com
|
||||
*/
|
||||
#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_sys.h>
|
||||
#include <re_stun.h>
|
||||
#include <re_turn.h>
|
||||
#include <re_ice.h>
|
||||
#include "ice.h"
|
||||
|
||||
|
||||
/*
|
||||
* ICE Implementation as of RFC 5245
|
||||
*/
|
||||
|
||||
|
||||
static const struct ice_conf conf_default = {
|
||||
ICE_NOMINATION_REGULAR,
|
||||
ICE_DEFAULT_RTO_RTP,
|
||||
ICE_DEFAULT_RC,
|
||||
false
|
||||
};
|
||||
|
||||
|
||||
/** Determining Role */
|
||||
static void ice_determine_role(struct ice *ice, bool offerer)
|
||||
{
|
||||
if (!ice)
|
||||
return;
|
||||
|
||||
if (ice->lmode == ice->rmode)
|
||||
ice->lrole = offerer
|
||||
? ICE_ROLE_CONTROLLING : ICE_ROLE_CONTROLLED;
|
||||
else if (ice->lmode == ICE_MODE_FULL)
|
||||
ice->lrole = ICE_ROLE_CONTROLLING;
|
||||
else
|
||||
ice->lrole = ICE_ROLE_CONTROLLED;
|
||||
}
|
||||
|
||||
|
||||
static void ice_destructor(void *arg)
|
||||
{
|
||||
struct ice *ice = arg;
|
||||
|
||||
list_flush(&ice->ml);
|
||||
mem_deref(ice->stun);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Allocate a new ICE Session
|
||||
*
|
||||
* @param icep Pointer to allocated ICE Session object
|
||||
* @param mode ICE Mode; Full-mode or Lite-mode
|
||||
* @param offerer True if we are SDP offerer, otherwise false
|
||||
*
|
||||
* @return 0 if success, otherwise errorcode
|
||||
*/
|
||||
int ice_alloc(struct ice **icep, enum ice_mode mode, bool offerer)
|
||||
{
|
||||
struct ice *ice;
|
||||
int err = 0;
|
||||
|
||||
if (!icep)
|
||||
return EINVAL;
|
||||
|
||||
ice = mem_zalloc(sizeof(*ice), ice_destructor);
|
||||
if (!ice)
|
||||
return ENOMEM;
|
||||
|
||||
list_init(&ice->ml);
|
||||
|
||||
ice->conf = conf_default;
|
||||
ice->lmode = mode;
|
||||
ice->tiebrk = rand_u64();
|
||||
|
||||
rand_str(ice->lufrag, sizeof(ice->lufrag));
|
||||
rand_str(ice->lpwd, sizeof(ice->lpwd));
|
||||
|
||||
ice_determine_role(ice, offerer);
|
||||
|
||||
if (ICE_MODE_FULL == ice->lmode) {
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the ICE Configuration
|
||||
*
|
||||
* @param ice ICE Session
|
||||
*
|
||||
* @return ICE Configuration
|
||||
*/
|
||||
struct ice_conf *ice_conf(struct ice *ice)
|
||||
{
|
||||
return ice ? &ice->conf : NULL;
|
||||
}
|
||||
|
||||
|
||||
void ice_set_conf(struct ice *ice, const struct ice_conf *conf)
|
||||
{
|
||||
if (!ice || !conf)
|
||||
return;
|
||||
|
||||
ice->conf = *conf;
|
||||
|
||||
if (ice->stun) {
|
||||
|
||||
/* Update STUN Transport */
|
||||
stun_conf(ice->stun)->rto = ice->conf.rto;
|
||||
stun_conf(ice->stun)->rc = ice->conf.rc;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the offerer flag on the ICE Session
|
||||
*
|
||||
* @param ice ICE Session
|
||||
* @param offerer True if offerer, otherwise false
|
||||
*/
|
||||
void ice_set_offerer(struct ice *ice, bool offerer)
|
||||
{
|
||||
if (!ice)
|
||||
return;
|
||||
|
||||
ice_determine_role(ice, offerer);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Start the Connectivity checks on the ICE Session
|
||||
*
|
||||
* @param ice ICE Session
|
||||
*
|
||||
* @return 0 if success, otherwise errorcode
|
||||
*/
|
||||
int ice_conncheck_start(struct ice *ice)
|
||||
{
|
||||
struct le *le;
|
||||
int err = 0;
|
||||
|
||||
if (!ice)
|
||||
return EINVAL;
|
||||
|
||||
for (le = ice->ml.head; le; le = le->next)
|
||||
err |= icem_conncheck_start(le->data);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Print debug information for the ICE Session
|
||||
*
|
||||
* @param pf Print function for debug output
|
||||
* @param ice ICE Session
|
||||
*
|
||||
* @return 0 if success, otherwise errorcode
|
||||
*/
|
||||
int ice_debug(struct re_printf *pf, const struct ice *ice)
|
||||
{
|
||||
struct le *le;
|
||||
int err = 0;
|
||||
|
||||
if (!ice)
|
||||
return 0;
|
||||
|
||||
err |= re_hprintf(pf, " local_mode=%s, remote_mode=%s",
|
||||
ice_mode2name(ice->lmode),
|
||||
ice_mode2name(ice->rmode));
|
||||
err |= re_hprintf(pf, ", local_role=%s\n", ice_role2name(ice->lrole));
|
||||
err |= re_hprintf(pf, " local_ufrag=\"%s\" local_pwd=\"%s\"\n",
|
||||
ice->lufrag, ice->lpwd);
|
||||
|
||||
for (le = ice->ml.head; le; le = le->next)
|
||||
err |= icem_debug(pf, le->data);
|
||||
|
||||
err |= stun_debug(pf, ice->stun);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the list of ICE Media objects (struct icem) for the ICE Session
|
||||
*
|
||||
* @param ice ICE Session
|
||||
*
|
||||
* @return List of ICE Media objects
|
||||
*/
|
||||
struct list *ice_medialist(const struct ice *ice)
|
||||
{
|
||||
return ice ? (struct list *)&ice->ml : NULL;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the local Username fragment for the ICE Session
|
||||
*
|
||||
* @param ice ICE Session
|
||||
*
|
||||
* @return Local Username-fragment
|
||||
*/
|
||||
const char *ice_ufrag(const struct ice *ice)
|
||||
{
|
||||
return ice ? ice->lufrag : NULL;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the local password for the ICE Session
|
||||
*
|
||||
* @param ice ICE Session
|
||||
*
|
||||
* @return Local password
|
||||
*/
|
||||
const char *ice_pwd(const struct ice *ice)
|
||||
{
|
||||
return ice ? ice->lpwd : NULL;
|
||||
}
|
||||
|
|
|
@ -17,15 +17,6 @@ enum ice_checkl_state {
|
|||
ICE_CHECKLIST_FAILED
|
||||
};
|
||||
|
||||
/** Candidate pair states */
|
||||
enum ice_candpair_state {
|
||||
ICE_CANDPAIR_FROZEN = 0, /**< Frozen state (default) */
|
||||
ICE_CANDPAIR_WAITING, /**< Waiting to become highest on list */
|
||||
ICE_CANDPAIR_INPROGRESS, /**< In-Progress state;transac. in progress */
|
||||
ICE_CANDPAIR_SUCCEEDED, /**< Succeeded state; successful result */
|
||||
ICE_CANDPAIR_FAILED /**< Failed state; check failed */
|
||||
};
|
||||
|
||||
enum ice_transp {
|
||||
ICE_TRANSP_NONE = -1,
|
||||
ICE_TRANSP_UDP = IPPROTO_UDP
|
||||
|
@ -42,19 +33,6 @@ enum {
|
|||
};
|
||||
|
||||
|
||||
/** Defines an ICE session */
|
||||
struct ice {
|
||||
enum ice_mode lmode; /**< Local mode */
|
||||
enum ice_mode rmode; /**< Remote mode */
|
||||
enum ice_role lrole; /**< Local role */
|
||||
char lufrag[5]; /**< Local Username fragment */
|
||||
char lpwd[23]; /**< Local Password */
|
||||
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 */
|
||||
struct icem_comp {
|
||||
struct le le; /**< Linked-list element */
|
||||
|
@ -74,20 +52,26 @@ struct icem_comp {
|
|||
|
||||
/** Defines an ICE media-stream */
|
||||
struct icem {
|
||||
struct le le; /**< Linked-list element */
|
||||
struct ice *ice; /**< Pointer to parent ICE-session */
|
||||
struct ice_conf conf; /**< ICE Configuration */
|
||||
struct stun *stun; /**< STUN Transport */
|
||||
struct sa stun_srv; /**< STUN Server IP address and port */
|
||||
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 (sorted) */
|
||||
struct list validl; /**< Valid List of cand pairs (sorted) */
|
||||
uint64_t tiebrk; /**< Tie-break value for roleconflict */
|
||||
bool mismatch; /**< ICE mismatch flag */
|
||||
enum ice_mode lmode; /**< Local mode */
|
||||
enum ice_mode rmode; /**< Remote mode */
|
||||
enum ice_role lrole; /**< Local role */
|
||||
struct tmr tmr_pace; /**< Timer for pacing STUN requests */
|
||||
int proto; /**< Transport protocol */
|
||||
int layer; /**< Protocol layer */
|
||||
enum ice_checkl_state state; /**< State of the checklist */
|
||||
struct list compl; /**< ICE media components */
|
||||
char *lufrag; /**< Local Username fragment */
|
||||
char *lpwd; /**< Local Password */
|
||||
char *rufrag; /**< Remote Username fragment */
|
||||
char *rpwd; /**< Remote Password */
|
||||
ice_gather_h *gh; /**< Gather handler */
|
||||
|
@ -219,7 +203,6 @@ int icem_conncheck_send(struct ice_candpair *cp, bool use_cand, bool trigged);
|
|||
|
||||
/* icestr */
|
||||
const char *ice_mode2name(enum ice_mode mode);
|
||||
const char *ice_candpair_state2name(enum ice_candpair_state st);
|
||||
const char *ice_checkl_state2name(enum ice_checkl_state cst);
|
||||
|
||||
|
||||
|
@ -227,5 +210,5 @@ const char *ice_checkl_state2name(enum ice_checkl_state cst);
|
|||
typedef void * (list_unique_h)(struct le *le1, struct le *le2);
|
||||
|
||||
uint64_t ice_calc_pair_prio(uint32_t g, uint32_t d);
|
||||
void ice_switch_local_role(struct ice *ice);
|
||||
void ice_switch_local_role(struct icem *icem);
|
||||
uint32_t ice_list_unique(struct list *list, list_unique_h *uh);
|
||||
|
|
151
src/ice/icem.c
151
src/ice/icem.c
|
@ -21,44 +21,86 @@
|
|||
#include <re_dbg.h>
|
||||
|
||||
|
||||
/*
|
||||
* ICE Implementation as of RFC 5245
|
||||
*/
|
||||
|
||||
|
||||
static const struct ice_conf conf_default = {
|
||||
ICE_NOMINATION_REGULAR,
|
||||
ICE_DEFAULT_RTO_RTP,
|
||||
ICE_DEFAULT_RC,
|
||||
false
|
||||
};
|
||||
|
||||
|
||||
/** Determining Role */
|
||||
static void ice_determine_role(struct icem *icem, enum ice_role role)
|
||||
{
|
||||
if (!icem)
|
||||
return;
|
||||
|
||||
if (icem->lmode == icem->rmode)
|
||||
icem->lrole = role;
|
||||
else if (icem->lmode == ICE_MODE_FULL)
|
||||
icem->lrole = ICE_ROLE_CONTROLLING;
|
||||
else
|
||||
icem->lrole = ICE_ROLE_CONTROLLED;
|
||||
}
|
||||
|
||||
|
||||
static void icem_destructor(void *data)
|
||||
{
|
||||
struct icem *icem = data;
|
||||
|
||||
list_unlink(&icem->le);
|
||||
tmr_cancel(&icem->tmr_pace);
|
||||
list_flush(&icem->compl);
|
||||
list_flush(&icem->validl);
|
||||
list_flush(&icem->checkl);
|
||||
list_flush(&icem->lcandl);
|
||||
list_flush(&icem->rcandl);
|
||||
mem_deref(icem->lufrag);
|
||||
mem_deref(icem->lpwd);
|
||||
mem_deref(icem->rufrag);
|
||||
mem_deref(icem->rpwd);
|
||||
mem_deref(icem->stun);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add a new ICE Media object to the ICE Session
|
||||
*
|
||||
* @param icemp Pointer to allocated ICE Media object
|
||||
* @param ice ICE Session
|
||||
* @param proto Transport protocol
|
||||
* @param layer Protocol stack layer
|
||||
* @param gh Gather handler
|
||||
* @param chkh Connectivity check handler
|
||||
* @param arg Handler argument
|
||||
* @param icemp Pointer to allocated ICE Media object
|
||||
* @param mode ICE mode
|
||||
* @param role Local ICE role
|
||||
* @param proto Transport protocol
|
||||
* @param layer Protocol stack layer
|
||||
* @param tiebrk Tie-breaker value, must be same for all media streams
|
||||
* @param lufrag Local username fragment
|
||||
* @param lpwd Local password
|
||||
* @param gh Gather handler
|
||||
* @param chkh Connectivity check handler
|
||||
* @param arg Handler argument
|
||||
*
|
||||
* @return 0 if success, otherwise errorcode
|
||||
*/
|
||||
int icem_alloc(struct icem **icemp, struct ice *ice, int proto, int layer,
|
||||
ice_gather_h *gh, ice_connchk_h *chkh, void *arg)
|
||||
int icem_alloc(struct icem **icemp,
|
||||
enum ice_mode mode, enum ice_role role,
|
||||
int proto, int layer,
|
||||
uint64_t tiebrk, const char *lufrag, const char *lpwd,
|
||||
ice_gather_h *gh, ice_connchk_h *chkh, void *arg)
|
||||
{
|
||||
struct icem *icem;
|
||||
int err = 0;
|
||||
|
||||
if (!ice)
|
||||
if (!icemp || !tiebrk || !lufrag || !lpwd)
|
||||
return EINVAL;
|
||||
|
||||
if (str_len(lufrag) < 4 || str_len(lpwd) < 22) {
|
||||
DEBUG_WARNING("alloc: lufrag/lpwd is too short\n");
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
if (proto != IPPROTO_UDP)
|
||||
return EPROTONOSUPPORT;
|
||||
|
||||
|
@ -66,13 +108,14 @@ int icem_alloc(struct icem **icemp, struct ice *ice, int proto, int layer,
|
|||
if (!icem)
|
||||
return ENOMEM;
|
||||
|
||||
icem->conf = conf_default;
|
||||
|
||||
tmr_init(&icem->tmr_pace);
|
||||
list_init(&icem->lcandl);
|
||||
list_init(&icem->rcandl);
|
||||
list_init(&icem->checkl);
|
||||
list_init(&icem->validl);
|
||||
|
||||
icem->ice = ice;
|
||||
icem->layer = layer;
|
||||
icem->proto = proto;
|
||||
icem->state = ICE_CHECKLIST_NULL;
|
||||
|
@ -84,7 +127,26 @@ int icem_alloc(struct icem **icemp, struct ice *ice, int proto, int layer,
|
|||
if (err)
|
||||
goto out;
|
||||
|
||||
list_append(&ice->ml, &icem->le, icem);
|
||||
icem->lmode = mode;
|
||||
icem->tiebrk = tiebrk;
|
||||
|
||||
err |= str_dup(&icem->lufrag, lufrag);
|
||||
err |= str_dup(&icem->lpwd, lpwd);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
ice_determine_role(icem, role);
|
||||
|
||||
if (ICE_MODE_FULL == icem->lmode) {
|
||||
|
||||
err = stun_alloc(&icem->stun, NULL, NULL, NULL);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
/* Update STUN Transport */
|
||||
stun_conf(icem->stun)->rto = icem->conf.rto;
|
||||
stun_conf(icem->stun)->rc = icem->conf.rc;
|
||||
}
|
||||
|
||||
out:
|
||||
if (err)
|
||||
|
@ -96,6 +158,56 @@ int icem_alloc(struct icem **icemp, struct ice *ice, int proto, int layer,
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the ICE Configuration
|
||||
*
|
||||
* @param icem ICE Media object
|
||||
*
|
||||
* @return ICE Configuration
|
||||
*/
|
||||
struct ice_conf *icem_conf(struct icem *icem)
|
||||
{
|
||||
return icem ? &icem->conf : NULL;
|
||||
}
|
||||
|
||||
|
||||
enum ice_role icem_local_role(const struct icem *icem)
|
||||
{
|
||||
return icem ? icem->lrole : ICE_ROLE_UNKNOWN;
|
||||
}
|
||||
|
||||
|
||||
void icem_set_conf(struct icem *icem, const struct ice_conf *conf)
|
||||
{
|
||||
if (!icem || !conf)
|
||||
return;
|
||||
|
||||
icem->conf = *conf;
|
||||
|
||||
if (icem->stun) {
|
||||
|
||||
/* Update STUN Transport */
|
||||
stun_conf(icem->stun)->rto = icem->conf.rto;
|
||||
stun_conf(icem->stun)->rc = icem->conf.rc;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the local role on the ICE Session
|
||||
*
|
||||
* @param icem ICE Media object
|
||||
* @param role Local ICE role
|
||||
*/
|
||||
void icem_set_role(struct icem *icem, enum ice_role role)
|
||||
{
|
||||
if (!icem)
|
||||
return;
|
||||
|
||||
ice_determine_role(icem, role);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the name of the ICE Media object, used for debugging
|
||||
*
|
||||
|
@ -345,6 +457,13 @@ int icem_debug(struct re_printf *pf, const struct icem *icem)
|
|||
|
||||
err |= re_hprintf(pf, "----- ICE Media <%s> -----\n", icem->name);
|
||||
|
||||
err |= re_hprintf(pf, " local_mode=%s, remote_mode=%s",
|
||||
ice_mode2name(icem->lmode),
|
||||
ice_mode2name(icem->rmode));
|
||||
err |= re_hprintf(pf, ", local_role=%s\n", ice_role2name(icem->lrole));
|
||||
err |= re_hprintf(pf, " local_ufrag=\"%s\" local_pwd=\"%s\"\n",
|
||||
icem->lufrag, icem->lpwd);
|
||||
|
||||
err |= re_hprintf(pf, " Components: (%u)\n", list_count(&icem->compl));
|
||||
for (le = icem->compl.head; le; le = le->next) {
|
||||
struct icem_comp *comp = le->data;
|
||||
|
@ -362,6 +481,8 @@ int icem_debug(struct re_printf *pf, const struct icem *icem)
|
|||
err |= re_hprintf(pf, " Valid list: %H",
|
||||
icem_candpairs_debug, &icem->validl);
|
||||
|
||||
err |= stun_debug(pf, icem->stun);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -430,7 +551,7 @@ int icem_lite_set_default_candidates(struct icem *icem)
|
|||
struct le *le;
|
||||
int err = 0;
|
||||
|
||||
if (icem->ice->lmode != ICE_MODE_LITE)
|
||||
if (icem->lmode != ICE_MODE_LITE)
|
||||
return EINVAL;
|
||||
|
||||
for (le = icem->compl.head; le; le = le->next) {
|
||||
|
@ -448,7 +569,7 @@ void icem_printf(struct icem *icem, const char *fmt, ...)
|
|||
{
|
||||
va_list ap;
|
||||
|
||||
if (!icem || !icem->ice->conf.debug)
|
||||
if (!icem || !icem->conf.debug)
|
||||
return;
|
||||
|
||||
va_start(ap, fmt);
|
||||
|
|
|
@ -96,7 +96,7 @@ bool ice_remotecands_avail(const struct icem *icem)
|
|||
if (!icem)
|
||||
return false;
|
||||
|
||||
return icem->ice->lrole == ICE_ROLE_CONTROLLING &&
|
||||
return icem->lrole == ICE_ROLE_CONTROLLING &&
|
||||
icem->state == ICE_CHECKLIST_COMPLETED;
|
||||
}
|
||||
|
||||
|
@ -134,23 +134,17 @@ int ice_remotecands_encode(struct re_printf *pf, const struct icem *icem)
|
|||
/* Decode SDP Attributes */
|
||||
|
||||
|
||||
static int ufrag_decode(struct ice *ice, const char *value)
|
||||
static int ufrag_decode(struct icem *icem, const char *value)
|
||||
{
|
||||
char *ufrag = NULL;
|
||||
struct le *le;
|
||||
int err;
|
||||
|
||||
err = str_dup(&ufrag, value);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
for (le = ice->ml.head; le; le = le->next) {
|
||||
|
||||
struct icem *icem = le->data;
|
||||
|
||||
mem_deref(icem->rufrag);
|
||||
icem->rufrag = mem_ref(ufrag);
|
||||
}
|
||||
mem_deref(icem->rufrag);
|
||||
icem->rufrag = mem_ref(ufrag);
|
||||
|
||||
mem_deref(ufrag);
|
||||
|
||||
|
@ -158,23 +152,17 @@ static int ufrag_decode(struct ice *ice, const char *value)
|
|||
}
|
||||
|
||||
|
||||
static int pwd_decode(struct ice *ice, const char *value)
|
||||
static int pwd_decode(struct icem *icem, const char *value)
|
||||
{
|
||||
char *pwd = NULL;
|
||||
struct le *le;
|
||||
int err;
|
||||
|
||||
err = str_dup(&pwd, value);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
for (le = ice->ml.head; le; le = le->next) {
|
||||
|
||||
struct icem *icem = le->data;
|
||||
|
||||
mem_deref(icem->rpwd);
|
||||
icem->rpwd = mem_ref(pwd);
|
||||
}
|
||||
mem_deref(icem->rpwd);
|
||||
icem->rpwd = mem_ref(pwd);
|
||||
|
||||
mem_deref(pwd);
|
||||
|
||||
|
@ -265,29 +253,29 @@ static int cand_decode(struct icem *icem, const char *val)
|
|||
/**
|
||||
* Decode SDP session attributes
|
||||
*
|
||||
* @param ice ICE Session
|
||||
* @param icem ICE Media object
|
||||
* @param name Name of the SDP attribute
|
||||
* @param value Value of the SDP attribute (optional)
|
||||
*
|
||||
* @return 0 if success, otherwise errorcode
|
||||
*/
|
||||
int ice_sdp_decode(struct ice *ice, const char *name, const char *value)
|
||||
int ice_sdp_decode(struct icem *icem, const char *name, const char *value)
|
||||
{
|
||||
if (!ice)
|
||||
if (!icem)
|
||||
return EINVAL;
|
||||
|
||||
if (0 == str_casecmp(name, ice_attr_lite)) {
|
||||
if (ICE_MODE_LITE == ice->lmode) {
|
||||
if (ICE_MODE_LITE == icem->lmode) {
|
||||
DEBUG_WARNING("we are lite, peer is also lite!\n");
|
||||
return EPROTO;
|
||||
}
|
||||
ice->rmode = ICE_MODE_LITE;
|
||||
ice->lrole = ICE_ROLE_CONTROLLING;
|
||||
icem->rmode = ICE_MODE_LITE;
|
||||
icem->lrole = ICE_ROLE_CONTROLLING;
|
||||
}
|
||||
else if (0 == str_casecmp(name, ice_attr_ufrag))
|
||||
return ufrag_decode(ice, value);
|
||||
return ufrag_decode(icem, value);
|
||||
else if (0 == str_casecmp(name, ice_attr_pwd))
|
||||
return pwd_decode(ice, value);
|
||||
return pwd_decode(icem, value);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -10,7 +10,6 @@ SRCS += ice/chklist.c
|
|||
SRCS += ice/comp.c
|
||||
SRCS += ice/connchk.c
|
||||
SRCS += ice/gather.c
|
||||
SRCS += ice/ice.c
|
||||
SRCS += ice/icem.c
|
||||
SRCS += ice/icesdp.c
|
||||
SRCS += ice/icestr.c
|
||||
|
|
|
@ -92,7 +92,7 @@ static void triggered_check(struct icem *icem, struct ice_cand *lcand,
|
|||
/*
|
||||
* 7.2.1. Additional Procedures for Full Implementations
|
||||
*/
|
||||
static int handle_stun_full(struct ice *ice, struct icem *icem,
|
||||
static int handle_stun_full(struct icem *icem,
|
||||
struct icem_comp *comp, const struct sa *src,
|
||||
uint32_t prio, bool use_cand, bool tunnel)
|
||||
{
|
||||
|
@ -145,7 +145,7 @@ static int handle_stun_full(struct ice *ice, struct icem *icem,
|
|||
|
||||
/* 7.2.1.5. Updating the Nominated Flag */
|
||||
if (use_cand) {
|
||||
if (ice->lrole == ICE_ROLE_CONTROLLED &&
|
||||
if (icem->lrole == ICE_ROLE_CONTROLLED &&
|
||||
cp->state == ICE_CANDPAIR_SUCCEEDED) {
|
||||
|
||||
if (!cp->nominated) {
|
||||
|
@ -160,7 +160,7 @@ static int handle_stun_full(struct ice *ice, struct icem *icem,
|
|||
/* Cancel conncheck. Choose Selected Pair */
|
||||
icem_candpair_make_valid(cp);
|
||||
|
||||
if (ice->conf.nom == ICE_NOMINATION_REGULAR) {
|
||||
if (icem->conf.nom == ICE_NOMINATION_REGULAR) {
|
||||
icem_candpair_cancel(cp);
|
||||
icem_comp_set_selected(comp, cp);
|
||||
}
|
||||
|
@ -219,11 +219,10 @@ static int stunsrv_ereply(struct icem_comp *comp, const struct sa *src,
|
|||
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,
|
||||
(uint8_t *)icem->lpwd, strlen(icem->lpwd), true, 1,
|
||||
STUN_ATTR_SOFTWARE, sw);
|
||||
}
|
||||
|
||||
|
@ -232,7 +231,6 @@ int icem_stund_recv(struct icem_comp *comp, const struct sa *src,
|
|||
struct stun_msg *req, size_t presz)
|
||||
{
|
||||
struct icem *icem = comp->icem;
|
||||
struct ice *ice = icem->ice;
|
||||
struct stun_attr *attr;
|
||||
struct pl lu, ru;
|
||||
enum ice_role rrole = ICE_ROLE_UNKNOWN;
|
||||
|
@ -246,7 +244,7 @@ int icem_stund_recv(struct icem_comp *comp, const struct sa *src,
|
|||
if (err)
|
||||
return err;
|
||||
|
||||
err = stun_msg_chk_mi(req, (uint8_t *)ice->lpwd, strlen(ice->lpwd));
|
||||
err = stun_msg_chk_mi(req, (uint8_t *)icem->lpwd, strlen(icem->lpwd));
|
||||
if (err) {
|
||||
if (err == EBADMSG)
|
||||
goto unauth;
|
||||
|
@ -265,7 +263,7 @@ int icem_stund_recv(struct icem_comp *comp, const struct sa *src,
|
|||
attr->v.username);
|
||||
goto unauth;
|
||||
}
|
||||
if (pl_strcmp(&lu, ice->lufrag))
|
||||
if (pl_strcmp(&lu, icem->lufrag))
|
||||
goto unauth;
|
||||
if (str_isset(icem->rufrag) && pl_strcmp(&ru, icem->rufrag))
|
||||
goto unauth;
|
||||
|
@ -282,9 +280,9 @@ int icem_stund_recv(struct icem_comp *comp, const struct sa *src,
|
|||
tiebrk = attr->v.uint64;
|
||||
}
|
||||
|
||||
if (rrole == ice->lrole) {
|
||||
if (ice->tiebrk >= tiebrk)
|
||||
ice_switch_local_role(ice);
|
||||
if (rrole == icem->lrole) {
|
||||
if (icem->tiebrk >= tiebrk)
|
||||
ice_switch_local_role(icem);
|
||||
else
|
||||
goto conflict;
|
||||
}
|
||||
|
@ -299,8 +297,8 @@ int icem_stund_recv(struct icem_comp *comp, const struct sa *src,
|
|||
if (attr)
|
||||
use_cand = true;
|
||||
|
||||
if (ice->lmode == ICE_MODE_FULL) {
|
||||
err = handle_stun_full(ice, icem, comp, src, prio_prflx,
|
||||
if (icem->lmode == ICE_MODE_FULL) {
|
||||
err = handle_stun_full(icem, comp, src, prio_prflx,
|
||||
use_cand, presz > 0);
|
||||
}
|
||||
else {
|
||||
|
@ -311,7 +309,7 @@ int icem_stund_recv(struct icem_comp *comp, const struct sa *src,
|
|||
goto badmsg;
|
||||
|
||||
return stun_reply(icem->proto, comp->sock, src, presz, req,
|
||||
(uint8_t *)ice->lpwd, strlen(ice->lpwd), true, 2,
|
||||
(uint8_t *)icem->lpwd, strlen(icem->lpwd), true, 2,
|
||||
STUN_ATTR_XOR_MAPPED_ADDR, src,
|
||||
STUN_ATTR_SOFTWARE, sw);
|
||||
|
||||
|
|
|
@ -72,26 +72,27 @@ uint64_t ice_calc_pair_prio(uint32_t g, uint32_t d)
|
|||
}
|
||||
|
||||
|
||||
void ice_switch_local_role(struct ice *ice)
|
||||
void ice_switch_local_role(struct icem *icem)
|
||||
{
|
||||
enum ice_role new_role;
|
||||
struct le *le;
|
||||
|
||||
if (ICE_ROLE_CONTROLLING == ice->lrole)
|
||||
if (ICE_ROLE_CONTROLLING == icem->lrole)
|
||||
new_role = ICE_ROLE_CONTROLLED;
|
||||
else
|
||||
new_role = ICE_ROLE_CONTROLLING;
|
||||
|
||||
DEBUG_NOTICE("Switch local role from %s to %s\n",
|
||||
ice_role2name(ice->lrole), ice_role2name(new_role));
|
||||
ice_role2name(icem->lrole), ice_role2name(new_role));
|
||||
|
||||
ice->lrole = new_role;
|
||||
icem->lrole = new_role;
|
||||
|
||||
#if 0
|
||||
/* recompute pair priorities for all media streams */
|
||||
for (le = ice->ml.head; le; le = le->next) {
|
||||
struct icem *icem = le->data;
|
||||
for (le = icem->le.list->head; le; le = le->next) {
|
||||
icem = le->data;
|
||||
icem_candpair_prio_order(&icem->checkl);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue