diff options
Diffstat (limited to 'pjnath/src/pjnath/ice_session.c')
-rw-r--r-- | pjnath/src/pjnath/ice_session.c | 409 |
1 files changed, 230 insertions, 179 deletions
diff --git a/pjnath/src/pjnath/ice_session.c b/pjnath/src/pjnath/ice_session.c index 05f39bc..30a40f6 100644 --- a/pjnath/src/pjnath/ice_session.c +++ b/pjnath/src/pjnath/ice_session.c @@ -1,4 +1,4 @@ -/* $Id: ice_session.c 3999 2012-03-30 07:10:13Z bennylp $ */ +/* $Id: ice_session.c 4365 2013-02-21 18:06:51Z bennylp $ */ /* * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com) * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org> @@ -97,6 +97,7 @@ static pj_uint8_t cand_type_prefs[4] = #endif }; +#define THIS_FILE "ice_session.c" #define CHECK_NAME_LEN 128 #define LOG4(expr) PJ_LOG(4,expr) #define LOG5(expr) PJ_LOG(4,expr) @@ -134,6 +135,7 @@ typedef struct timer_data static void on_timer(pj_timer_heap_t *th, pj_timer_entry *te); static void on_ice_complete(pj_ice_sess *ice, pj_status_t status); static void ice_keep_alive(pj_ice_sess *ice, pj_bool_t send_now); +static void ice_on_destroy(void *obj); static void destroy_ice(pj_ice_sess *ice, pj_status_t reason); static pj_status_t start_periodic_check(pj_timer_heap_t *th, @@ -288,6 +290,7 @@ static pj_status_t init_comp(pj_ice_sess *ice, /* Create STUN session for this candidate */ status = pj_stun_session_create(&ice->stun_cfg, NULL, &sess_cb, PJ_TRUE, + ice->grp_lock, &comp->stun_sess); if (status != PJ_SUCCESS) return status; @@ -332,6 +335,7 @@ PJ_DEF(pj_status_t) pj_ice_sess_create(pj_stun_config *stun_cfg, const pj_ice_sess_cb *cb, const pj_str_t *local_ufrag, const pj_str_t *local_passwd, + pj_grp_lock_t *grp_lock, pj_ice_sess **p_ice) { pj_pool_t *pool; @@ -359,13 +363,20 @@ PJ_DEF(pj_status_t) pj_ice_sess_create(pj_stun_config *stun_cfg, pj_ansi_snprintf(ice->obj_name, sizeof(ice->obj_name), name, ice); - status = pj_mutex_create_recursive(pool, ice->obj_name, - &ice->mutex); - if (status != PJ_SUCCESS) { - destroy_ice(ice, status); - return status; + if (grp_lock) { + ice->grp_lock = grp_lock; + } else { + status = pj_grp_lock_create(pool, NULL, &ice->grp_lock); + if (status != PJ_SUCCESS) { + pj_pool_release(pool); + return status; + } } + pj_grp_lock_add_ref(ice->grp_lock); + pj_grp_lock_add_handler(ice->grp_lock, pool, ice, + &ice_on_destroy); + pj_memcpy(&ice->cb, cb, sizeof(*cb)); pj_memcpy(&ice->stun_cfg, stun_cfg, sizeof(*stun_cfg)); @@ -444,6 +455,21 @@ PJ_DEF(pj_status_t) pj_ice_sess_set_options(pj_ice_sess *ice, /* + * Callback to really destroy the session + */ +static void ice_on_destroy(void *obj) +{ + pj_ice_sess *ice = (pj_ice_sess*) obj; + + if (ice->pool) { + pj_pool_t *pool = ice->pool; + ice->pool = NULL; + pj_pool_release(pool); + } + LOG4((THIS_FILE, "ICE session %p destroyed", ice)); +} + +/* * Destroy */ static void destroy_ice(pj_ice_sess *ice, @@ -452,21 +478,21 @@ static void destroy_ice(pj_ice_sess *ice, unsigned i; if (reason == PJ_SUCCESS) { - LOG4((ice->obj_name, "Destroying ICE session")); + LOG4((ice->obj_name, "Destroying ICE session %p", ice)); } - /* Let other callbacks finish */ - if (ice->mutex) { - pj_mutex_lock(ice->mutex); - pj_mutex_unlock(ice->mutex); - } + pj_grp_lock_acquire(ice->grp_lock); - if (ice->timer.id) { - pj_timer_heap_cancel(ice->stun_cfg.timer_heap, - &ice->timer); - ice->timer.id = PJ_FALSE; + if (ice->is_destroying) { + pj_grp_lock_release(ice->grp_lock); + return; } + ice->is_destroying = PJ_TRUE; + + pj_timer_heap_cancel_if_active(ice->stun_cfg.timer_heap, + &ice->timer, PJ_FALSE); + for (i=0; i<ice->comp_cnt; ++i) { if (ice->comp[i].stun_sess) { pj_stun_session_destroy(ice->comp[i].stun_sess); @@ -474,21 +500,12 @@ static void destroy_ice(pj_ice_sess *ice, } } - if (ice->clist.timer.id) { - pj_timer_heap_cancel(ice->stun_cfg.timer_heap, &ice->clist.timer); - ice->clist.timer.id = PJ_FALSE; - } + pj_timer_heap_cancel_if_active(ice->stun_cfg.timer_heap, + &ice->clist.timer, + PJ_FALSE); - if (ice->mutex) { - pj_mutex_destroy(ice->mutex); - ice->mutex = NULL; - } - - if (ice->pool) { - pj_pool_t *pool = ice->pool; - ice->pool = NULL; - pj_pool_release(pool); - } + pj_grp_lock_dec_ref(ice->grp_lock); + pj_grp_lock_release(ice->grp_lock); } @@ -701,13 +718,14 @@ PJ_DEF(pj_status_t) pj_ice_sess_add_cand(pj_ice_sess *ice, { pj_ice_sess_cand *lcand; pj_status_t status = PJ_SUCCESS; + char address[PJ_INET6_ADDRSTRLEN]; PJ_ASSERT_RETURN(ice && comp_id && foundation && addr && base_addr && addr_len, PJ_EINVAL); PJ_ASSERT_RETURN(comp_id <= ice->comp_cnt, PJ_EINVAL); - pj_mutex_lock(ice->mutex); + pj_grp_lock_acquire(ice->grp_lock); if (ice->lcand_cnt >= PJ_ARRAY_SIZE(ice->lcand)) { status = PJ_ETOOMANY; @@ -720,13 +738,14 @@ PJ_DEF(pj_status_t) pj_ice_sess_add_cand(pj_ice_sess *ice, lcand->type = type; pj_strdup(ice->pool, &lcand->foundation, foundation); lcand->prio = CALC_CAND_PRIO(ice, type, local_pref, lcand->comp_id); - pj_memcpy(&lcand->addr, addr, addr_len); - pj_memcpy(&lcand->base_addr, base_addr, addr_len); + pj_sockaddr_cp(&lcand->addr, addr); + pj_sockaddr_cp(&lcand->base_addr, base_addr); if (rel_addr == NULL) rel_addr = base_addr; pj_memcpy(&lcand->rel_addr, rel_addr, addr_len); - pj_ansi_strcpy(ice->tmp.txt, pj_inet_ntoa(lcand->addr.ipv4.sin_addr)); + pj_ansi_strcpy(ice->tmp.txt, pj_sockaddr_print(&lcand->addr, address, + sizeof(address), 0)); LOG4((ice->obj_name, "Candidate %d added: comp_id=%d, type=%s, foundation=%.*s, " "addr=%s:%d, base=%s:%d, prio=0x%x (%u)", @@ -736,9 +755,9 @@ PJ_DEF(pj_status_t) pj_ice_sess_add_cand(pj_ice_sess *ice, (int)lcand->foundation.slen, lcand->foundation.ptr, ice->tmp.txt, - (int)pj_ntohs(lcand->addr.ipv4.sin_port), - pj_inet_ntoa(lcand->base_addr.ipv4.sin_addr), - (int)pj_htons(lcand->base_addr.ipv4.sin_port), + pj_sockaddr_get_port(&lcand->addr), + pj_sockaddr_print(&lcand->base_addr, address, sizeof(address), 0), + pj_sockaddr_get_port(&lcand->base_addr), lcand->prio, lcand->prio)); if (p_cand_id) @@ -747,7 +766,7 @@ PJ_DEF(pj_status_t) pj_ice_sess_add_cand(pj_ice_sess *ice, ++ice->lcand_cnt; on_error: - pj_mutex_unlock(ice->mutex); + pj_grp_lock_release(ice->grp_lock); return status; } @@ -764,7 +783,7 @@ PJ_DEF(pj_status_t) pj_ice_sess_find_default_cand(pj_ice_sess *ice, *cand_id = -1; - pj_mutex_lock(ice->mutex); + pj_grp_lock_acquire(ice->grp_lock); /* First find in valid list if we have nominated pair */ for (i=0; i<ice->valid_list.count; ++i) { @@ -772,7 +791,7 @@ PJ_DEF(pj_status_t) pj_ice_sess_find_default_cand(pj_ice_sess *ice, if (check->lcand->comp_id == comp_id) { *cand_id = GET_LCAND_ID(check->lcand); - pj_mutex_unlock(ice->mutex); + pj_grp_lock_release(ice->grp_lock); return PJ_SUCCESS; } } @@ -784,7 +803,7 @@ PJ_DEF(pj_status_t) pj_ice_sess_find_default_cand(pj_ice_sess *ice, lcand->type == PJ_ICE_CAND_TYPE_RELAYED) { *cand_id = GET_LCAND_ID(lcand); - pj_mutex_unlock(ice->mutex); + pj_grp_lock_release(ice->grp_lock); return PJ_SUCCESS; } } @@ -797,7 +816,7 @@ PJ_DEF(pj_status_t) pj_ice_sess_find_default_cand(pj_ice_sess *ice, lcand->type == PJ_ICE_CAND_TYPE_PRFLX)) { *cand_id = GET_LCAND_ID(lcand); - pj_mutex_unlock(ice->mutex); + pj_grp_lock_release(ice->grp_lock); return PJ_SUCCESS; } } @@ -809,13 +828,13 @@ PJ_DEF(pj_status_t) pj_ice_sess_find_default_cand(pj_ice_sess *ice, lcand->type == PJ_ICE_CAND_TYPE_HOST) { *cand_id = GET_LCAND_ID(lcand); - pj_mutex_unlock(ice->mutex); + pj_grp_lock_release(ice->grp_lock); return PJ_SUCCESS; } } /* Still no candidate is found! :( */ - pj_mutex_unlock(ice->mutex); + pj_grp_lock_release(ice->grp_lock); pj_assert(!"Should have a candidate by now"); return PJ_EBUG; @@ -875,25 +894,24 @@ static const char *dump_check(char *buffer, unsigned bufsize, { const pj_ice_sess_cand *lcand = check->lcand; const pj_ice_sess_cand *rcand = check->rcand; - char laddr[PJ_INET6_ADDRSTRLEN]; + char laddr[PJ_INET6_ADDRSTRLEN], raddr[PJ_INET6_ADDRSTRLEN]; int len; PJ_CHECK_STACK(); - pj_ansi_strcpy(laddr, pj_inet_ntoa(lcand->addr.ipv4.sin_addr)); - - if (lcand->addr.addr.sa_family == pj_AF_INET()) { - len = pj_ansi_snprintf(buffer, bufsize, - "%d: [%d] %s:%d-->%s:%d", - (int)GET_CHECK_ID(clist, check), - check->lcand->comp_id, - laddr, (int)pj_ntohs(lcand->addr.ipv4.sin_port), - pj_inet_ntoa(rcand->addr.ipv4.sin_addr), - (int)pj_ntohs(rcand->addr.ipv4.sin_port)); - } else { - len = pj_ansi_snprintf(buffer, bufsize, "IPv6->IPv6"); - } + pj_ansi_strcpy(laddr, pj_sockaddr_print(&lcand->addr, laddr, + sizeof(laddr), 0)); + len = pj_ansi_snprintf(buffer, bufsize, + "%d: [%d] %s:%d-->%s:%d", + (int)GET_CHECK_ID(clist, check), + check->lcand->comp_id, + pj_sockaddr_print(&lcand->addr, laddr, + sizeof(laddr), 0), + pj_sockaddr_get_port(&lcand->addr), + pj_sockaddr_print(&rcand->addr, raddr, + sizeof(raddr), 0), + pj_sockaddr_get_port(&rcand->addr)); if (len < 0) len = 0; @@ -964,6 +982,7 @@ static void sort_checklist(pj_ice_sess *ice, pj_ice_sess_checklist *clist) } } + pj_assert(clist->count > 0); for (i=0; i<clist->count-1; ++i) { unsigned j, highest = i; @@ -996,32 +1015,6 @@ static void sort_checklist(pj_ice_sess *ice, pj_ice_sess_checklist *clist) } } -enum -{ - SOCKADDR_EQUAL = 0, - SOCKADDR_NOT_EQUAL = 1 -}; - -/* Utility: compare sockaddr. - * Returns 0 if equal. - */ -static int sockaddr_cmp(const pj_sockaddr *a1, const pj_sockaddr *a2) -{ - if (a1->addr.sa_family != a2->addr.sa_family) - return SOCKADDR_NOT_EQUAL; - - if (a1->addr.sa_family == pj_AF_INET()) { - return !(a1->ipv4.sin_addr.s_addr == a2->ipv4.sin_addr.s_addr && - a1->ipv4.sin_port == a2->ipv4.sin_port); - } else if (a1->addr.sa_family == pj_AF_INET6()) { - return pj_memcmp(&a1->ipv6, &a2->ipv6, sizeof(a1->ipv6)); - } else { - pj_assert(!"Invalid address family!"); - return SOCKADDR_NOT_EQUAL; - } -} - - /* Prune checklist, this must have been done after the checklist * is sorted. */ @@ -1053,7 +1046,7 @@ static pj_status_t prune_checklist(pj_ice_sess *ice, if (host->type != PJ_ICE_CAND_TYPE_HOST) continue; - if (sockaddr_cmp(&srflx->base_addr, &host->addr) == 0) { + if (pj_sockaddr_cmp(&srflx->base_addr, &host->addr) == 0) { /* Replace this SRFLX with its BASE */ clist->checks[i].lcand = host; break; @@ -1061,11 +1054,13 @@ static pj_status_t prune_checklist(pj_ice_sess *ice, } if (j==ice->lcand_cnt) { + char baddr[PJ_INET6_ADDRSTRLEN]; /* Host candidate not found this this srflx! */ LOG4((ice->obj_name, "Base candidate %s:%d not found for srflx candidate %d", - pj_inet_ntoa(srflx->base_addr.ipv4.sin_addr), - pj_ntohs(srflx->base_addr.ipv4.sin_port), + pj_sockaddr_print(&srflx->base_addr, baddr, + sizeof(baddr), 0), + pj_sockaddr_get_port(&srflx->base_addr), GET_LCAND_ID(clist->checks[i].lcand))); return PJNATH_EICENOHOSTCAND; } @@ -1093,7 +1088,7 @@ static pj_status_t prune_checklist(pj_ice_sess *ice, if ((licand == ljcand) && (ricand == rjcand)) { reason = "duplicate found"; } else if ((rjcand == ricand) && - (sockaddr_cmp(&ljcand->base_addr, + (pj_sockaddr_cmp(&ljcand->base_addr, &licand->base_addr)==0)) { reason = "equal base"; @@ -1124,14 +1119,20 @@ static void on_timer(pj_timer_heap_t *th, pj_timer_entry *te) { pj_ice_sess *ice = (pj_ice_sess*) te->user_data; enum timer_type type = (enum timer_type)te->id; - pj_bool_t has_mutex = PJ_TRUE; PJ_UNUSED_ARG(th); - pj_mutex_lock(ice->mutex); + pj_grp_lock_acquire(ice->grp_lock); te->id = TIMER_NONE; + if (ice->is_destroying) { + /* Stray timer, could happen when destroy is invoked while callback + * is pending. */ + pj_grp_lock_release(ice->grp_lock); + return; + } + switch (type) { case TIMER_CONTROLLED_WAIT_NOM: LOG4((ice->obj_name, @@ -1154,8 +1155,6 @@ static void on_timer(pj_timer_heap_t *th, pj_timer_entry *te) /* Release mutex in case app destroy us in the callback */ ice_status = ice->ice_status; on_ice_complete = ice->cb.on_ice_complete; - has_mutex = PJ_FALSE; - pj_mutex_unlock(ice->mutex); /* Notify app about ICE completion*/ if (on_ice_complete) @@ -1173,8 +1172,7 @@ static void on_timer(pj_timer_heap_t *th, pj_timer_entry *te) break; } - if (has_mutex) - pj_mutex_unlock(ice->mutex); + pj_grp_lock_release(ice->grp_lock); } /* Send keep-alive */ @@ -1232,8 +1230,10 @@ done: ice->comp_cnt; pj_time_val_normalize(&delay); - ice->timer.id = TIMER_KEEP_ALIVE; - pj_timer_heap_schedule(ice->stun_cfg.timer_heap, &ice->timer, &delay); + pj_timer_heap_schedule_w_grp_lock(ice->stun_cfg.timer_heap, + &ice->timer, &delay, + TIMER_KEEP_ALIVE, + ice->grp_lock); } else { pj_assert(!"Not expected any timer active"); @@ -1247,10 +1247,8 @@ static void on_ice_complete(pj_ice_sess *ice, pj_status_t status) ice->is_complete = PJ_TRUE; ice->ice_status = status; - if (ice->timer.id != TIMER_NONE) { - pj_timer_heap_cancel(ice->stun_cfg.timer_heap, &ice->timer); - ice->timer.id = TIMER_NONE; - } + pj_timer_heap_cancel_if_active(ice->stun_cfg.timer_heap, &ice->timer, + TIMER_NONE); /* Log message */ LOG4((ice->obj_name, "ICE process complete, status=%s", @@ -1263,9 +1261,10 @@ static void on_ice_complete(pj_ice_sess *ice, pj_status_t status) if (ice->cb.on_ice_complete) { pj_time_val delay = {0, 0}; - ice->timer.id = TIMER_COMPLETION_CALLBACK; - pj_timer_heap_schedule(ice->stun_cfg.timer_heap, - &ice->timer, &delay); + pj_timer_heap_schedule_w_grp_lock(ice->stun_cfg.timer_heap, + &ice->timer, &delay, + TIMER_COMPLETION_CALLBACK, + ice->grp_lock); } } } @@ -1493,10 +1492,11 @@ static pj_bool_t on_check_complete(pj_ice_sess *ice, delay.msec = ice->opt.controlled_agent_want_nom_timeout; pj_time_val_normalize(&delay); - ice->timer.id = TIMER_CONTROLLED_WAIT_NOM; - pj_timer_heap_schedule(ice->stun_cfg.timer_heap, - &ice->timer, - &delay); + pj_timer_heap_schedule_w_grp_lock( + ice->stun_cfg.timer_heap, + &ice->timer, &delay, + TIMER_CONTROLLED_WAIT_NOM, + ice->grp_lock); LOG5((ice->obj_name, "All checks have completed. Controlled agent now " @@ -1572,10 +1572,8 @@ static pj_bool_t on_check_complete(pj_ice_sess *ice, "Scheduling nominated check in %d ms", ice->opt.nominated_check_delay)); - if (ice->timer.id != TIMER_NONE) { - pj_timer_heap_cancel(ice->stun_cfg.timer_heap, &ice->timer); - ice->timer.id = TIMER_NONE; - } + pj_timer_heap_cancel_if_active(ice->stun_cfg.timer_heap, &ice->timer, + TIMER_NONE); /* All components have valid pair. Let connectivity checks run for * a little bit more time, then start our nominated check. @@ -1584,8 +1582,10 @@ static pj_bool_t on_check_complete(pj_ice_sess *ice, delay.msec = ice->opt.nominated_check_delay; pj_time_val_normalize(&delay); - ice->timer.id = TIMER_START_NOMINATED_CHECK; - pj_timer_heap_schedule(ice->stun_cfg.timer_heap, &ice->timer, &delay); + pj_timer_heap_schedule_w_grp_lock(ice->stun_cfg.timer_heap, + &ice->timer, &delay, + TIMER_START_NOMINATED_CHECK, + ice->grp_lock); return PJ_FALSE; } @@ -1615,7 +1615,7 @@ PJ_DEF(pj_status_t) pj_ice_sess_create_check_list( PJ_ASSERT_RETURN(rcand_cnt + ice->rcand_cnt <= PJ_ICE_MAX_CAND, PJ_ETOOMANY); - pj_mutex_lock(ice->mutex); + pj_grp_lock_acquire(ice->grp_lock); /* Save credentials */ username.ptr = buf; @@ -1663,7 +1663,7 @@ PJ_DEF(pj_status_t) pj_ice_sess_create_check_list( pj_ice_sess_check *chk = &clist->checks[clist->count]; if (clist->count >= PJ_ICE_MAX_CHECKS) { - pj_mutex_unlock(ice->mutex); + pj_grp_lock_release(ice->grp_lock); return PJ_ETOOMANY; } @@ -1688,13 +1688,20 @@ PJ_DEF(pj_status_t) pj_ice_sess_create_check_list( } } + /* This could happen if candidates have no matching address families */ + if (clist->count == 0) { + LOG4((ice->obj_name, "Error: no checklist can be created")); + pj_grp_lock_release(ice->grp_lock); + return PJ_ENOTFOUND; + } + /* Sort checklist based on priority */ sort_checklist(ice, clist); /* Prune the checklist */ status = prune_checklist(ice, clist); if (status != PJ_SUCCESS) { - pj_mutex_unlock(ice->mutex); + pj_grp_lock_release(ice->grp_lock); return status; } @@ -1721,7 +1728,7 @@ PJ_DEF(pj_status_t) pj_ice_sess_create_check_list( /* Log checklist */ dump_checklist("Checklist created:", ice, clist); - pj_mutex_unlock(ice->mutex); + pj_grp_lock_release(ice->grp_lock); return PJ_SUCCESS; } @@ -1809,7 +1816,8 @@ static pj_status_t perform_check(pj_ice_sess *ice, /* Initiate STUN transaction to send the request */ status = pj_stun_session_send_msg(comp->stun_sess, msg_data, PJ_FALSE, PJ_TRUE, &rcand->addr, - sizeof(pj_sockaddr_in), check->tdata); + pj_sockaddr_get_len(&rcand->addr), + check->tdata); if (status != PJ_SUCCESS) { check->tdata = NULL; pjnath_perror(ice->obj_name, "Error sending STUN request", status); @@ -1840,7 +1848,12 @@ static pj_status_t start_periodic_check(pj_timer_heap_t *th, ice = td->ice; clist = td->clist; - pj_mutex_lock(ice->mutex); + pj_grp_lock_acquire(ice->grp_lock); + + if (ice->is_destroying) { + pj_grp_lock_release(ice->grp_lock); + return PJ_SUCCESS; + } /* Set timer ID to FALSE first */ te->id = PJ_FALSE; @@ -1860,7 +1873,7 @@ static pj_status_t start_periodic_check(pj_timer_heap_t *th, if (check->state == PJ_ICE_SESS_CHECK_STATE_WAITING) { status = perform_check(ice, clist, i, ice->is_nominating); if (status != PJ_SUCCESS) { - pj_mutex_unlock(ice->mutex); + pj_grp_lock_release(ice->grp_lock); pj_log_pop_indent(); return status; } @@ -1880,7 +1893,7 @@ static pj_status_t start_periodic_check(pj_timer_heap_t *th, if (check->state == PJ_ICE_SESS_CHECK_STATE_FROZEN) { status = perform_check(ice, clist, i, ice->is_nominating); if (status != PJ_SUCCESS) { - pj_mutex_unlock(ice->mutex); + pj_grp_lock_release(ice->grp_lock); pj_log_pop_indent(); return status; } @@ -1897,12 +1910,12 @@ static pj_status_t start_periodic_check(pj_timer_heap_t *th, /* Schedule for next timer */ pj_time_val timeout = {0, PJ_ICE_TA_VAL}; - te->id = PJ_TRUE; pj_time_val_normalize(&timeout); - pj_timer_heap_schedule(th, te, &timeout); + pj_timer_heap_schedule_w_grp_lock(th, te, &timeout, PJ_TRUE, + ice->grp_lock); } - pj_mutex_unlock(ice->mutex); + pj_grp_lock_release(ice->grp_lock); pj_log_pop_indent(); return PJ_SUCCESS; } @@ -1922,8 +1935,8 @@ static void start_nominated_check(pj_ice_sess *ice) /* Stop our timer if it's active */ if (ice->timer.id == TIMER_START_NOMINATED_CHECK) { - pj_timer_heap_cancel(ice->stun_cfg.timer_heap, &ice->timer); - ice->timer.id = TIMER_NONE; + pj_timer_heap_cancel_if_active(ice->stun_cfg.timer_heap, &ice->timer, + TIMER_NONE); } /* For each component, set the check state of valid check with @@ -1951,18 +1964,15 @@ static void start_nominated_check(pj_ice_sess *ice) } /* And (re)start the periodic check */ - if (ice->clist.timer.id) { - pj_timer_heap_cancel(ice->stun_cfg.timer_heap, &ice->clist.timer); - ice->clist.timer.id = PJ_FALSE; - } + pj_timer_heap_cancel_if_active(ice->stun_cfg.timer_heap, + &ice->clist.timer, PJ_FALSE); - ice->clist.timer.id = PJ_TRUE; delay.sec = delay.msec = 0; - status = pj_timer_heap_schedule(ice->stun_cfg.timer_heap, - &ice->clist.timer, &delay); - if (status != PJ_SUCCESS) { - ice->clist.timer.id = PJ_FALSE; - } else { + status = pj_timer_heap_schedule_w_grp_lock(ice->stun_cfg.timer_heap, + &ice->clist.timer, &delay, + PJ_TRUE, + ice->grp_lock); + if (status == PJ_SUCCESS) { LOG5((ice->obj_name, "Periodic timer rescheduled..")); } @@ -2012,7 +2022,7 @@ PJ_DEF(pj_status_t) pj_ice_sess_start_check(pj_ice_sess *ice) PJ_ASSERT_RETURN(ice->clist.count > 0, PJ_EINVALIDOP); /* Lock session */ - pj_mutex_lock(ice->mutex); + pj_grp_lock_acquire(ice->grp_lock); LOG4((ice->obj_name, "Starting ICE check..")); pj_log_push_indent(); @@ -2042,7 +2052,7 @@ PJ_DEF(pj_status_t) pj_ice_sess_start_check(pj_ice_sess *ice) } if (i == clist->count) { pj_assert(!"Unable to find checklist for component 1"); - pj_mutex_unlock(ice->mutex); + pj_grp_lock_release(ice->grp_lock); pj_log_pop_indent(); return PJNATH_EICEINCOMPID; } @@ -2096,15 +2106,15 @@ PJ_DEF(pj_status_t) pj_ice_sess_start_check(pj_ice_sess *ice) * instead to reduce stack usage: * return start_periodic_check(ice->stun_cfg.timer_heap, &clist->timer); */ - clist->timer.id = PJ_TRUE; delay.sec = delay.msec = 0; - status = pj_timer_heap_schedule(ice->stun_cfg.timer_heap, - &clist->timer, &delay); + status = pj_timer_heap_schedule_w_grp_lock(ice->stun_cfg.timer_heap, + &clist->timer, &delay, + PJ_TRUE, ice->grp_lock); if (status != PJ_SUCCESS) { clist->timer.id = PJ_FALSE; } - pj_mutex_unlock(ice->mutex); + pj_grp_lock_release(ice->grp_lock); pj_log_pop_indent(); return status; } @@ -2125,9 +2135,22 @@ static pj_status_t on_stun_send_msg(pj_stun_session *sess, stun_data *sd = (stun_data*) pj_stun_session_get_user_data(sess); pj_ice_sess *ice = sd->ice; pj_ice_msg_data *msg_data = (pj_ice_msg_data*) token; + pj_status_t status; - return (*ice->cb.on_tx_pkt)(ice, sd->comp_id, msg_data->transport_id, - pkt, pkt_size, dst_addr, addr_len); + pj_grp_lock_acquire(ice->grp_lock); + + if (ice->is_destroying) { + /* Stray retransmit timer that could happen while + * we're being destroyed */ + pj_grp_lock_release(ice->grp_lock); + return PJ_EINVALIDOP; + } + + status = (*ice->cb.on_tx_pkt)(ice, sd->comp_id, msg_data->transport_id, + pkt, pkt_size, dst_addr, addr_len); + + pj_grp_lock_release(ice->grp_lock); + return status; } @@ -2162,7 +2185,13 @@ static void on_stun_request_complete(pj_stun_session *stun_sess, pj_assert(tdata == check->tdata); check->tdata = NULL; - pj_mutex_lock(ice->mutex); + pj_grp_lock_acquire(ice->grp_lock); + + if (ice->is_destroying) { + /* Not sure if this is possible but just in case */ + pj_grp_lock_release(ice->grp_lock); + return; + } /* Init lcand to NULL. lcand will be found from the mapped address * found in the response. @@ -2213,7 +2242,7 @@ static void on_stun_request_complete(pj_stun_session *stun_sess, perform_check(ice, clist, msg_data->data.req.ckid, check->nominated || ice->is_nominating); pj_log_pop_indent(); - pj_mutex_unlock(ice->mutex); + pj_grp_lock_release(ice->grp_lock); return; } @@ -2228,7 +2257,7 @@ static void on_stun_request_complete(pj_stun_session *stun_sess, check_set_state(ice, check, PJ_ICE_SESS_CHECK_STATE_FAILED, status); on_check_complete(ice, check); pj_log_pop_indent(); - pj_mutex_unlock(ice->mutex); + pj_grp_lock_release(ice->grp_lock); return; } @@ -2241,7 +2270,8 @@ static void on_stun_request_complete(pj_stun_session *stun_sess, * the response match the source IP address and port that the Binding * Request was sent from. */ - if (sockaddr_cmp(&check->rcand->addr, (const pj_sockaddr*)src_addr) != 0) { + if (pj_sockaddr_cmp(&check->rcand->addr, (const pj_sockaddr*)src_addr)!=0) + { status = PJNATH_EICEINSRCADDR; LOG4((ice->obj_name, "Check %s%s: connectivity check FAILED: source address mismatch", @@ -2252,7 +2282,7 @@ static void on_stun_request_complete(pj_stun_session *stun_sess, check_set_state(ice, check, PJ_ICE_SESS_CHECK_STATE_FAILED, status); on_check_complete(ice, check); pj_log_pop_indent(); - pj_mutex_unlock(ice->mutex); + pj_grp_lock_release(ice->grp_lock); return; } @@ -2285,14 +2315,14 @@ static void on_stun_request_complete(pj_stun_session *stun_sess, check_set_state(ice, check, PJ_ICE_SESS_CHECK_STATE_FAILED, PJNATH_ESTUNNOMAPPEDADDR); on_check_complete(ice, check); - pj_mutex_unlock(ice->mutex); + pj_grp_lock_release(ice->grp_lock); return; } /* Find local candidate that matches the XOR-MAPPED-ADDRESS */ pj_assert(lcand == NULL); for (i=0; i<ice->lcand_cnt; ++i) { - if (sockaddr_cmp(&xaddr->sockaddr, &ice->lcand[i].addr) == 0) { + if (pj_sockaddr_cmp(&xaddr->sockaddr, &ice->lcand[i].addr) == 0) { /* Match */ lcand = &ice->lcand[i]; break; @@ -2328,12 +2358,13 @@ static void on_stun_request_complete(pj_stun_session *stun_sess, &xaddr->sockaddr, &check->lcand->base_addr, &check->lcand->base_addr, - sizeof(pj_sockaddr_in), &cand_id); + pj_sockaddr_get_len(&xaddr->sockaddr), + &cand_id); if (status != PJ_SUCCESS) { check_set_state(ice, check, PJ_ICE_SESS_CHECK_STATE_FAILED, status); on_check_complete(ice, check); - pj_mutex_unlock(ice->mutex); + pj_grp_lock_release(ice->grp_lock); return; } @@ -2393,11 +2424,11 @@ static void on_stun_request_complete(pj_stun_session *stun_sess, */ if (on_check_complete(ice, check)) { /* ICE complete! */ - pj_mutex_unlock(ice->mutex); + pj_grp_lock_release(ice->grp_lock); return; } - pj_mutex_unlock(ice->mutex); + pj_grp_lock_release(ice->grp_lock); } @@ -2438,7 +2469,12 @@ static pj_status_t on_stun_rx_request(pj_stun_session *sess, sd = (stun_data*) pj_stun_session_get_user_data(sess); ice = sd->ice; - pj_mutex_lock(ice->mutex); + pj_grp_lock_acquire(ice->grp_lock); + + if (ice->is_destroying) { + pj_grp_lock_release(ice->grp_lock); + return PJ_EINVALIDOP; + } /* * Note: @@ -2453,7 +2489,7 @@ static pj_status_t on_stun_rx_request(pj_stun_session *sess, pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_PRIORITY, 0); if (prio_attr == NULL) { LOG5((ice->obj_name, "Received Binding request with no PRIORITY")); - pj_mutex_unlock(ice->mutex); + pj_grp_lock_release(ice->grp_lock); return PJ_SUCCESS; } @@ -2498,7 +2534,7 @@ static pj_status_t on_stun_rx_request(pj_stun_session *sess, pj_stun_session_respond(sess, rdata, PJ_STUN_SC_ROLE_CONFLICT, NULL, token, PJ_TRUE, src_addr, src_addr_len); - pj_mutex_unlock(ice->mutex); + pj_grp_lock_release(ice->grp_lock); return PJ_SUCCESS; } @@ -2510,7 +2546,7 @@ static pj_status_t on_stun_rx_request(pj_stun_session *sess, pj_stun_session_respond(sess, rdata, PJ_STUN_SC_ROLE_CONFLICT, NULL, token, PJ_TRUE, src_addr, src_addr_len); - pj_mutex_unlock(ice->mutex); + pj_grp_lock_release(ice->grp_lock); return PJ_SUCCESS; } else { /* Switch role to controlled */ @@ -2525,7 +2561,7 @@ static pj_status_t on_stun_rx_request(pj_stun_session *sess, */ status = pj_stun_session_create_res(sess, rdata, 0, NULL, &tdata); if (status != PJ_SUCCESS) { - pj_mutex_unlock(ice->mutex); + pj_grp_lock_release(ice->grp_lock); return status; } @@ -2562,7 +2598,7 @@ static pj_status_t on_stun_rx_request(pj_stun_session *sess, rcheck->comp_id = sd->comp_id; rcheck->transport_id = ((pj_ice_msg_data*)token)->transport_id; rcheck->src_addr_len = src_addr_len; - pj_memcpy(&rcheck->src_addr, src_addr, src_addr_len); + pj_sockaddr_cp(&rcheck->src_addr, src_addr); rcheck->use_candidate = (uc_attr != NULL); rcheck->priority = prio_attr->value; rcheck->role_attr = role_attr; @@ -2577,7 +2613,7 @@ static pj_status_t on_stun_rx_request(pj_stun_session *sess, handle_incoming_check(ice, rcheck); } - pj_mutex_unlock(ice->mutex); + pj_grp_lock_release(ice->grp_lock); return PJ_SUCCESS; } @@ -2600,7 +2636,7 @@ static void handle_incoming_check(pj_ice_sess *ice, * the request. */ for (i=0; i<ice->rcand_cnt; ++i) { - if (sockaddr_cmp(&rcheck->src_addr, &ice->rcand[i].addr)==0) + if (pj_sockaddr_cmp(&rcheck->src_addr, &ice->rcand[i].addr)==0) break; } @@ -2610,6 +2646,7 @@ static void handle_incoming_check(pj_ice_sess *ice, * candidate. */ if (i == ice->rcand_cnt) { + char raddr[PJ_INET6_ADDRSTRLEN]; if (ice->rcand_cnt >= PJ_ICE_MAX_CAND) { LOG4((ice->obj_name, "Unable to add new peer reflexive candidate: too many " @@ -2621,7 +2658,7 @@ static void handle_incoming_check(pj_ice_sess *ice, rcand->comp_id = (pj_uint8_t)rcheck->comp_id; rcand->type = PJ_ICE_CAND_TYPE_PRFLX; rcand->prio = rcheck->priority; - pj_memcpy(&rcand->addr, &rcheck->src_addr, rcheck->src_addr_len); + pj_sockaddr_cp(&rcand->addr, &rcheck->src_addr); /* Foundation is random, unique from other foundation */ rcand->foundation.ptr = (char*) pj_pool_alloc(ice->pool, 36); @@ -2630,9 +2667,9 @@ static void handle_incoming_check(pj_ice_sess *ice, rcand->foundation.ptr); LOG4((ice->obj_name, - "Added new remote candidate from the request: %s:%d", - pj_inet_ntoa(rcand->addr.ipv4.sin_addr), - (int)pj_ntohs(rcand->addr.ipv4.sin_port))); + "Added new remote candidate from the request: %s:%d", + pj_sockaddr_print(&rcand->addr, raddr, sizeof(raddr), 0), + pj_sockaddr_get_port(&rcand->addr))); } else { /* Remote candidate found */ @@ -2649,7 +2686,7 @@ static void handle_incoming_check(pj_ice_sess *ice, for (i=0; i<ice->clist.count; ++i) { pj_ice_sess_check *c = &ice->clist.checks[i]; if (/*c->lcand == lcand ||*/ - sockaddr_cmp(&c->lcand->base_addr, &lcand->base_addr)==0) + pj_sockaddr_cmp(&c->lcand->base_addr, &lcand->base_addr)==0) { lcand = c->lcand; break; @@ -2732,7 +2769,7 @@ static void handle_incoming_check(pj_ice_sess *ice, LOG5((ice->obj_name, "Triggered check for check %d not performed " "because it's in progress. Retransmitting", i)); pj_log_push_indent(); - pj_stun_session_retransmit_req(comp->stun_sess, c->tdata); + pj_stun_session_retransmit_req(comp->stun_sess, c->tdata, PJ_FALSE); pj_log_pop_indent(); } else if (c->state == PJ_ICE_SESS_CHECK_STATE_SUCCEEDED) { @@ -2866,18 +2903,23 @@ PJ_DEF(pj_status_t) pj_ice_sess_send_data(pj_ice_sess *ice, return PJNATH_EICEINCOMPID; } - pj_mutex_lock(ice->mutex); + pj_grp_lock_acquire(ice->grp_lock); + + if (ice->is_destroying) { + pj_grp_lock_release(ice->grp_lock); + return PJ_EINVALIDOP; + } comp = find_comp(ice, comp_id); if (comp == NULL) { status = PJNATH_EICEINCOMPID; - pj_mutex_unlock(ice->mutex); + pj_grp_lock_release(ice->grp_lock); goto on_return; } if (comp->valid_check == NULL) { status = PJNATH_EICEINPROGRESS; - pj_mutex_unlock(ice->mutex); + pj_grp_lock_release(ice->grp_lock); goto on_return; } @@ -2886,12 +2928,14 @@ PJ_DEF(pj_status_t) pj_ice_sess_send_data(pj_ice_sess *ice, pj_sockaddr_cp(&addr, &comp->valid_check->rcand->addr); /* Release the mutex now to avoid deadlock (see ticket #1451). */ - pj_mutex_unlock(ice->mutex); + pj_grp_lock_release(ice->grp_lock); + + PJ_RACE_ME(5); status = (*ice->cb.on_tx_pkt)(ice, comp_id, transport_id, data, data_len, &addr, - sizeof(pj_sockaddr_in)); + pj_sockaddr_get_len(&addr)); on_return: return status; @@ -2913,11 +2957,16 @@ PJ_DEF(pj_status_t) pj_ice_sess_on_rx_pkt(pj_ice_sess *ice, PJ_ASSERT_RETURN(ice, PJ_EINVAL); - pj_mutex_lock(ice->mutex); + pj_grp_lock_acquire(ice->grp_lock); + + if (ice->is_destroying) { + pj_grp_lock_release(ice->grp_lock); + return PJ_EINVALIDOP; + } comp = find_comp(ice, comp_id); if (comp == NULL) { - pj_mutex_unlock(ice->mutex); + pj_grp_lock_release(ice->grp_lock); return PJNATH_EICEINCOMPID; } @@ -2930,7 +2979,7 @@ PJ_DEF(pj_status_t) pj_ice_sess_on_rx_pkt(pj_ice_sess *ice, } if (msg_data == NULL) { pj_assert(!"Invalid transport ID"); - pj_mutex_unlock(ice->mutex); + pj_grp_lock_release(ice->grp_lock); return PJ_EINVAL; } @@ -2950,12 +2999,14 @@ PJ_DEF(pj_status_t) pj_ice_sess_on_rx_pkt(pj_ice_sess *ice, LOG4((ice->obj_name, "Error processing incoming message: %s", ice->tmp.errmsg)); } - pj_mutex_unlock(ice->mutex); + pj_grp_lock_release(ice->grp_lock); } else { /* Not a STUN packet. Call application's callback instead, but release * the mutex now or otherwise we may get deadlock. */ - pj_mutex_unlock(ice->mutex); + pj_grp_lock_release(ice->grp_lock); + + PJ_RACE_ME(5); (*ice->cb.on_rx_data)(ice, comp_id, transport_id, pkt, pkt_size, src_addr, src_addr_len); |