diff --git a/src/ice/connchk.c b/src/ice/connchk.c index 17a5662fa..e9809e688 100644 --- a/src/ice/connchk.c +++ b/src/ice/connchk.c @@ -400,6 +400,14 @@ static void pace_timeout(void *arg) } +static void rcand_wait_timeout(void *arg) +{ + struct icem *icem = arg; + + icem_conncheck_start(icem); +} + + /** * Scheduling Checks * @@ -414,6 +422,13 @@ int icem_conncheck_start(struct icem *icem) if (!icem) return EINVAL; + if (icem->rcand_wait) { + icem_printf(icem, "conncheck_start: " + "waiting mDNS for remote candidate...\n"); + tmr_start(&icem->tmr_rcand, 100, rcand_wait_timeout, icem); + return 0; + } + err = icem_checklist_form(icem); if (err) return err; diff --git a/src/ice/ice.h b/src/ice/ice.h index b26b41437..ab684428d 100644 --- a/src/ice/ice.h +++ b/src/ice/ice.h @@ -59,6 +59,7 @@ struct icem { bool rmode_lite; /**< Remote mode is Lite */ enum ice_role lrole; /**< Local role */ struct tmr tmr_pace; /**< Timer for pacing STUN requests */ + struct tmr tmr_rcand; /**< Timer for remote candidate wait */ int proto; /**< Transport protocol */ int layer; /**< Protocol layer */ enum ice_checkl_state state; /**< State of the checklist */ @@ -70,6 +71,7 @@ struct icem { ice_connchk_h *chkh; /**< Connectivity check handler */ void *arg; /**< Handler argument */ char name[32]; /**< Name of the media stream */ + bool rcand_wait; /**< Waiting for remote candidate */ }; /** Defines a candidate */ diff --git a/src/ice/icem.c b/src/ice/icem.c index 8173e2003..3679a3e35 100644 --- a/src/ice/icem.c +++ b/src/ice/icem.c @@ -51,6 +51,7 @@ static void icem_destructor(void *data) { struct icem *icem = data; + tmr_cancel(&icem->tmr_rcand); tmr_cancel(&icem->tmr_pace); list_flush(&icem->compl); list_flush(&icem->validl); @@ -105,6 +106,7 @@ int icem_alloc(struct icem **icemp, enum ice_role role, int proto, int layer, icem->conf = conf_default; tmr_init(&icem->tmr_pace); + tmr_init(&icem->tmr_rcand); list_init(&icem->lcandl); list_init(&icem->rcandl); list_init(&icem->checkl); diff --git a/src/ice/icesdp.c b/src/ice/icesdp.c index b8ca88571..3a37ab07c 100644 --- a/src/ice/icesdp.c +++ b/src/ice/icesdp.c @@ -3,6 +3,10 @@ * * Copyright (C) 2010 Creytiv.com */ +#ifndef WIN32 +#include +#endif + #include #include #include @@ -14,6 +18,7 @@ #include #include #include +#include #include "ice.h" @@ -34,6 +39,19 @@ static const char rel_addr_str[] = "raddr"; static const char rel_port_str[] = "rport"; +struct rcand { + struct icem *icem; + enum ice_cand_type type; + unsigned cid; + uint32_t prio; + uint32_t port; + struct sa caddr; + struct sa rel_addr; + struct pl foundation; + char domain[128]; +}; + + /* Encode SDP Attributes */ @@ -186,6 +204,62 @@ static int media_pwd_decode(struct icem *icem, const char *value) } +static int getaddr_rcand(void *arg) +{ + struct rcand *rcand = arg; + struct addrinfo *res, *res0 = NULL; + int err; + + err = getaddrinfo(rcand->domain, NULL, NULL, &res0); + if (err) + return EADDRNOTAVAIL; + + for (res = res0; res; res = res->ai_next) { + + err = sa_set_sa(&rcand->caddr, res->ai_addr); + if (err) + continue; + + break; + } + + sa_set_port(&rcand->caddr, rcand->port); + + freeaddrinfo(res); + + return 0; +} + + +static void delayed_rcand(int err, void *arg) +{ + struct rcand *rcand = arg; + + if (err) + goto out; + + /* add only if not exist */ + if (icem_cand_find(&rcand->icem->rcandl, rcand->cid, &rcand->caddr)) + goto out; + + icem_rcand_add(rcand->icem, rcand->type, rcand->cid, rcand->prio, + &rcand->caddr, &rcand->rel_addr, &rcand->foundation); + +out: + rcand->icem->rcand_wait = false; + mem_deref(rcand); +} + + +static void rcand_dealloc(void *arg) +{ + struct rcand *rcand = arg; + + mem_deref(rcand->icem); + mem_deref((char *)rcand->foundation.p); +} + + static int cand_decode(struct icem *icem, const char *val) { struct pl foundation, compid, transp, prio, addr, port, cand_type; @@ -233,18 +307,45 @@ static int cand_decode(struct icem *icem, const char *val) } } + (void)pl_strcpy(&cand_type, type, sizeof(type)); + cid = pl_u32(&compid); + + /* check for mdns .local address */ + if (pl_strstr(&addr, ".local") != NULL) { + /* try non blocking getaddr mdns resolution */ + icem_printf(icem, "mDNS remote cand: %r\n", &addr); + struct rcand *rcand = + mem_zalloc(sizeof(struct rcand), rcand_dealloc); + if (!rcand) + return ENOMEM; + + rcand->icem = mem_ref(icem); + rcand->type = ice_cand_name2type(type); + rcand->cid = cid; + rcand->prio = pl_u32(&prio); + rcand->port = pl_u32(&port); + rcand->rel_addr = rel_addr; + + pl_dup(&rcand->foundation, &foundation); + (void)pl_strcpy(&addr, rcand->domain, sizeof(rcand->domain)); + + icem->rcand_wait = true; + + err = re_thread_async(getaddr_rcand, delayed_rcand, rcand); + if (err) + mem_deref(rcand); + + return err; + } + err = sa_set(&caddr, &addr, pl_u32(&port)); if (err) return err; - cid = pl_u32(&compid); - /* add only if not exist */ if (icem_cand_find(&icem->rcandl, cid, &caddr)) return 0; - (void)pl_strcpy(&cand_type, type, sizeof(type)); - return icem_rcand_add(icem, ice_cand_name2type(type), cid, pl_u32(&prio), &caddr, &rel_addr, &foundation); }