summaryrefslogtreecommitdiff
path: root/pjnath/src/pjnath/turn_session.c
diff options
context:
space:
mode:
Diffstat (limited to 'pjnath/src/pjnath/turn_session.c')
-rw-r--r--pjnath/src/pjnath/turn_session.c184
1 files changed, 94 insertions, 90 deletions
diff --git a/pjnath/src/pjnath/turn_session.c b/pjnath/src/pjnath/turn_session.c
index cbe8f5c..7031cd3 100644
--- a/pjnath/src/pjnath/turn_session.c
+++ b/pjnath/src/pjnath/turn_session.c
@@ -1,4 +1,4 @@
-/* $Id: turn_session.c 3844 2011-10-24 15:03:43Z bennylp $ */
+/* $Id: turn_session.c 4368 2013-02-21 21:53:28Z bennylp $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
@@ -112,8 +112,9 @@ struct pj_turn_session
pj_turn_session_cb cb;
void *user_data;
pj_stun_config stun_cfg;
+ pj_bool_t is_destroying;
- pj_lock_t *lock;
+ pj_grp_lock_t *grp_lock;
int busy;
pj_turn_state_t state;
@@ -161,6 +162,7 @@ struct pj_turn_session
*/
static void sess_shutdown(pj_turn_session *sess,
pj_status_t status);
+static void turn_sess_on_destroy(void *comp);
static void do_destroy(pj_turn_session *sess);
static void send_refresh(pj_turn_session *sess, int lifetime);
static pj_status_t stun_on_send_msg(pj_stun_session *sess,
@@ -236,6 +238,7 @@ PJ_DEF(pj_status_t) pj_turn_session_create( const pj_stun_config *cfg,
const char *name,
int af,
pj_turn_tp_type conn_type,
+ pj_grp_lock_t *grp_lock,
const pj_turn_session_cb *cb,
unsigned options,
void *user_data,
@@ -244,7 +247,6 @@ PJ_DEF(pj_status_t) pj_turn_session_create( const pj_stun_config *cfg,
pj_pool_t *pool;
pj_turn_session *sess;
pj_stun_session_cb stun_cb;
- pj_lock_t *null_lock;
pj_status_t status;
PJ_ASSERT_RETURN(cfg && cfg->pf && cb && p_sess, PJ_EINVAL);
@@ -281,13 +283,20 @@ PJ_DEF(pj_status_t) pj_turn_session_create( const pj_stun_config *cfg,
sess->perm_table = pj_hash_create(pool, PJ_TURN_PERM_HTABLE_SIZE);
/* Session lock */
- status = pj_lock_create_recursive_mutex(pool, sess->obj_name,
- &sess->lock);
- if (status != PJ_SUCCESS) {
- do_destroy(sess);
- return status;
+ if (grp_lock) {
+ sess->grp_lock = grp_lock;
+ } else {
+ status = pj_grp_lock_create(pool, NULL, &sess->grp_lock);
+ if (status != PJ_SUCCESS) {
+ pj_pool_release(pool);
+ return status;
+ }
}
+ pj_grp_lock_add_ref(sess->grp_lock);
+ pj_grp_lock_add_handler(sess->grp_lock, pool, sess,
+ &turn_sess_on_destroy);
+
/* Timer */
pj_timer_entry_init(&sess->timer, TIMER_NONE, sess, &on_timer_event);
@@ -297,7 +306,7 @@ PJ_DEF(pj_status_t) pj_turn_session_create( const pj_stun_config *cfg,
stun_cb.on_request_complete = &stun_on_request_complete;
stun_cb.on_rx_indication = &stun_on_rx_indication;
status = pj_stun_session_create(&sess->stun_cfg, sess->obj_name, &stun_cb,
- PJ_FALSE, &sess->stun);
+ PJ_FALSE, sess->grp_lock, &sess->stun);
if (status != PJ_SUCCESS) {
do_destroy(sess);
return status;
@@ -306,16 +315,6 @@ PJ_DEF(pj_status_t) pj_turn_session_create( const pj_stun_config *cfg,
/* Attach ourself to STUN session */
pj_stun_session_set_user_data(sess->stun, sess);
- /* Replace mutex in STUN session with a NULL mutex, since access to
- * STUN session is serialized.
- */
- status = pj_lock_create_null_mutex(pool, name, &null_lock);
- if (status != PJ_SUCCESS) {
- do_destroy(sess);
- return status;
- }
- pj_stun_session_set_lock(sess->stun, null_lock, PJ_TRUE);
-
/* Done */
PJ_LOG(4,(sess->obj_name, "TURN client session created"));
@@ -325,32 +324,9 @@ PJ_DEF(pj_status_t) pj_turn_session_create( const pj_stun_config *cfg,
}
-/* Destroy */
-static void do_destroy(pj_turn_session *sess)
+static void turn_sess_on_destroy(void *comp)
{
- /* Lock session */
- if (sess->lock) {
- pj_lock_acquire(sess->lock);
- }
-
- /* Cancel pending timer, if any */
- if (sess->timer.id != TIMER_NONE) {
- pj_timer_heap_cancel(sess->timer_heap, &sess->timer);
- sess->timer.id = TIMER_NONE;
- }
-
- /* Destroy STUN session */
- if (sess->stun) {
- pj_stun_session_destroy(sess->stun);
- sess->stun = NULL;
- }
-
- /* Destroy lock */
- if (sess->lock) {
- pj_lock_release(sess->lock);
- pj_lock_destroy(sess->lock);
- sess->lock = NULL;
- }
+ pj_turn_session *sess = (pj_turn_session*) comp;
/* Destroy pool */
if (sess->pool) {
@@ -363,6 +339,26 @@ static void do_destroy(pj_turn_session *sess)
}
}
+/* Destroy */
+static void do_destroy(pj_turn_session *sess)
+{
+ PJ_LOG(4,(sess->obj_name, "TURN session destroy request, ref_cnt=%d",
+ pj_grp_lock_get_ref(sess->grp_lock)));
+
+ pj_grp_lock_acquire(sess->grp_lock);
+ if (sess->is_destroying) {
+ pj_grp_lock_release(sess->grp_lock);
+ return;
+ }
+
+ sess->is_destroying = PJ_TRUE;
+ pj_timer_heap_cancel_if_active(sess->timer_heap, &sess->timer, TIMER_NONE);
+ pj_stun_session_destroy(sess->stun);
+
+ pj_grp_lock_dec_ref(sess->grp_lock);
+ pj_grp_lock_release(sess->grp_lock);
+}
+
/* Set session state */
static void set_state(pj_turn_session *sess, enum pj_turn_state_t state)
@@ -421,7 +417,10 @@ static void sess_shutdown(pj_turn_session *sess,
/* This may recursively call this function again with
* state==PJ_TURN_STATE_DEALLOCATED.
*/
+ /* No need to deallocate as we're already deallocating!
+ * See https://trac.pjsip.org/repos/ticket/1551
send_refresh(sess, 0);
+ */
break;
case PJ_TURN_STATE_DEALLOCATED:
case PJ_TURN_STATE_DESTROYING:
@@ -434,13 +433,11 @@ static void sess_shutdown(pj_turn_session *sess,
set_state(sess, PJ_TURN_STATE_DESTROYING);
- if (sess->timer.id != TIMER_NONE) {
- pj_timer_heap_cancel(sess->timer_heap, &sess->timer);
- sess->timer.id = TIMER_NONE;
- }
-
- sess->timer.id = TIMER_DESTROY;
- pj_timer_heap_schedule(sess->timer_heap, &sess->timer, &delay);
+ pj_timer_heap_cancel_if_active(sess->timer_heap, &sess->timer,
+ TIMER_NONE);
+ pj_timer_heap_schedule_w_grp_lock(sess->timer_heap, &sess->timer,
+ &delay, TIMER_DESTROY,
+ sess->grp_lock);
}
}
@@ -452,11 +449,11 @@ PJ_DEF(pj_status_t) pj_turn_session_shutdown(pj_turn_session *sess)
{
PJ_ASSERT_RETURN(sess, PJ_EINVAL);
- pj_lock_acquire(sess->lock);
+ pj_grp_lock_acquire(sess->grp_lock);
sess_shutdown(sess, PJ_SUCCESS);
- pj_lock_release(sess->lock);
+ pj_grp_lock_release(sess->grp_lock);
return PJ_SUCCESS;
}
@@ -550,9 +547,9 @@ PJ_DEF(pj_status_t) pj_turn_session_set_software_name( pj_turn_session *sess,
{
pj_status_t status;
- pj_lock_acquire(sess->lock);
+ pj_grp_lock_acquire(sess->grp_lock);
status = pj_stun_session_set_software_name(sess->stun, sw);
- pj_lock_release(sess->lock);
+ pj_grp_lock_release(sess->grp_lock);
return status;
}
@@ -573,7 +570,7 @@ PJ_DEF(pj_status_t) pj_turn_session_set_server( pj_turn_session *sess,
PJ_ASSERT_RETURN(sess && domain, PJ_EINVAL);
PJ_ASSERT_RETURN(sess->state == PJ_TURN_STATE_NULL, PJ_EINVALIDOP);
- pj_lock_acquire(sess->lock);
+ pj_grp_lock_acquire(sess->grp_lock);
/* See if "domain" contains just IP address */
tmp_addr.addr.sa_family = sess->af;
@@ -673,7 +670,7 @@ PJ_DEF(pj_status_t) pj_turn_session_set_server( pj_turn_session *sess,
}
on_return:
- pj_lock_release(sess->lock);
+ pj_grp_lock_release(sess->grp_lock);
return status;
}
@@ -687,11 +684,11 @@ PJ_DEF(pj_status_t) pj_turn_session_set_credential(pj_turn_session *sess,
PJ_ASSERT_RETURN(sess && cred, PJ_EINVAL);
PJ_ASSERT_RETURN(sess->stun, PJ_EINVALIDOP);
- pj_lock_acquire(sess->lock);
+ pj_grp_lock_acquire(sess->grp_lock);
pj_stun_session_set_credential(sess->stun, PJ_STUN_AUTH_LONG_TERM, cred);
- pj_lock_release(sess->lock);
+ pj_grp_lock_release(sess->grp_lock);
return PJ_SUCCESS;
}
@@ -712,7 +709,7 @@ PJ_DEF(pj_status_t) pj_turn_session_alloc(pj_turn_session *sess,
sess->state<=PJ_TURN_STATE_RESOLVED,
PJ_EINVALIDOP);
- pj_lock_acquire(sess->lock);
+ pj_grp_lock_acquire(sess->grp_lock);
if (param && param != &sess->alloc_param)
pj_turn_alloc_param_copy(sess->pool, &sess->alloc_param, param);
@@ -723,7 +720,7 @@ PJ_DEF(pj_status_t) pj_turn_session_alloc(pj_turn_session *sess,
PJ_LOG(4,(sess->obj_name, "Pending ALLOCATE in state %s",
state_names[sess->state]));
- pj_lock_release(sess->lock);
+ pj_grp_lock_release(sess->grp_lock);
return PJ_SUCCESS;
}
@@ -735,7 +732,7 @@ PJ_DEF(pj_status_t) pj_turn_session_alloc(pj_turn_session *sess,
status = pj_stun_session_create_req(sess->stun, PJ_STUN_ALLOCATE_REQUEST,
PJ_STUN_MAGIC, NULL, &tdata);
if (status != PJ_SUCCESS) {
- pj_lock_release(sess->lock);
+ pj_grp_lock_release(sess->grp_lock);
return status;
}
@@ -775,7 +772,7 @@ PJ_DEF(pj_status_t) pj_turn_session_alloc(pj_turn_session *sess,
set_state(sess, PJ_TURN_STATE_RESOLVED);
}
- pj_lock_release(sess->lock);
+ pj_grp_lock_release(sess->grp_lock);
return status;
}
@@ -796,14 +793,14 @@ PJ_DEF(pj_status_t) pj_turn_session_set_perm( pj_turn_session *sess,
PJ_ASSERT_RETURN(sess && addr_cnt && addr, PJ_EINVAL);
- pj_lock_acquire(sess->lock);
+ pj_grp_lock_acquire(sess->grp_lock);
/* Create a bare CreatePermission request */
status = pj_stun_session_create_req(sess->stun,
PJ_STUN_CREATE_PERM_REQUEST,
PJ_STUN_MAGIC, NULL, &tdata);
if (status != PJ_SUCCESS) {
- pj_lock_release(sess->lock);
+ pj_grp_lock_release(sess->grp_lock);
return status;
}
@@ -854,7 +851,7 @@ PJ_DEF(pj_status_t) pj_turn_session_set_perm( pj_turn_session *sess,
goto on_error;
}
- pj_lock_release(sess->lock);
+ pj_grp_lock_release(sess->grp_lock);
return PJ_SUCCESS;
on_error:
@@ -871,7 +868,7 @@ on_error:
if (perm->req_token == req_token)
invalidate_perm(sess, perm);
}
- pj_lock_release(sess->lock);
+ pj_grp_lock_release(sess->grp_lock);
return status;
}
@@ -942,7 +939,7 @@ PJ_DEF(pj_status_t) pj_turn_session_sendto( pj_turn_session *sess,
}
/* Lock session now */
- pj_lock_acquire(sess->lock);
+ pj_grp_lock_acquire(sess->grp_lock);
/* Lookup permission first */
perm = lookup_perm(sess, addr, pj_sockaddr_get_len(addr), PJ_FALSE);
@@ -957,7 +954,7 @@ PJ_DEF(pj_status_t) pj_turn_session_sendto( pj_turn_session *sess,
status = pj_turn_session_set_perm(sess, 1, (const pj_sockaddr*)addr,
0);
if (status != PJ_SUCCESS) {
- pj_lock_release(sess->lock);
+ pj_grp_lock_release(sess->grp_lock);
return status;
}
}
@@ -1032,7 +1029,7 @@ PJ_DEF(pj_status_t) pj_turn_session_sendto( pj_turn_session *sess,
}
on_return:
- pj_lock_release(sess->lock);
+ pj_grp_lock_release(sess->grp_lock);
return status;
}
@@ -1052,7 +1049,7 @@ PJ_DEF(pj_status_t) pj_turn_session_bind_channel(pj_turn_session *sess,
PJ_ASSERT_RETURN(sess && peer_adr && addr_len, PJ_EINVAL);
PJ_ASSERT_RETURN(sess->state == PJ_TURN_STATE_READY, PJ_EINVALIDOP);
- pj_lock_acquire(sess->lock);
+ pj_grp_lock_acquire(sess->grp_lock);
/* Create blank ChannelBind request */
status = pj_stun_session_create_req(sess->stun,
@@ -1095,7 +1092,7 @@ PJ_DEF(pj_status_t) pj_turn_session_bind_channel(pj_turn_session *sess,
tdata);
on_return:
- pj_lock_release(sess->lock);
+ pj_grp_lock_release(sess->grp_lock);
return status;
}
@@ -1118,7 +1115,7 @@ PJ_DEF(pj_status_t) pj_turn_session_on_rx_pkt(pj_turn_session *sess,
*/
/* Start locking the session */
- pj_lock_acquire(sess->lock);
+ pj_grp_lock_acquire(sess->grp_lock);
is_datagram = (sess->conn_type==PJ_TURN_TP_UDP);
@@ -1190,7 +1187,7 @@ PJ_DEF(pj_status_t) pj_turn_session_on_rx_pkt(pj_turn_session *sess,
}
on_return:
- pj_lock_release(sess->lock);
+ pj_grp_lock_release(sess->grp_lock);
return status;
}
@@ -1382,20 +1379,22 @@ static void on_allocate_success(pj_turn_session *sess,
/* Cancel existing keep-alive timer, if any */
pj_assert(sess->timer.id != TIMER_DESTROY);
-
- if (sess->timer.id != TIMER_NONE) {
- pj_timer_heap_cancel(sess->timer_heap, &sess->timer);
- sess->timer.id = TIMER_NONE;
+ if (sess->timer.id == TIMER_KEEP_ALIVE) {
+ pj_timer_heap_cancel_if_active(sess->timer_heap, &sess->timer,
+ TIMER_NONE);
}
/* Start keep-alive timer once allocation succeeds */
- timeout.sec = sess->ka_interval;
- timeout.msec = 0;
+ if (sess->state < PJ_TURN_STATE_DEALLOCATING) {
+ timeout.sec = sess->ka_interval;
+ timeout.msec = 0;
- sess->timer.id = TIMER_KEEP_ALIVE;
- pj_timer_heap_schedule(sess->timer_heap, &sess->timer, &timeout);
+ pj_timer_heap_schedule_w_grp_lock(sess->timer_heap, &sess->timer,
+ &timeout, TIMER_KEEP_ALIVE,
+ sess->grp_lock);
- set_state(sess, PJ_TURN_STATE_READY);
+ set_state(sess, PJ_TURN_STATE_READY);
+ }
}
/*
@@ -1945,7 +1944,7 @@ static void on_timer_event(pj_timer_heap_t *th, pj_timer_entry *e)
PJ_UNUSED_ARG(th);
- pj_lock_acquire(sess->lock);
+ pj_grp_lock_acquire(sess->grp_lock);
eid = (enum timer_id_t) e->id;
e->id = TIMER_NONE;
@@ -1956,6 +1955,11 @@ static void on_timer_event(pj_timer_heap_t *th, pj_timer_entry *e)
pj_bool_t resched = PJ_TRUE;
pj_bool_t pkt_sent = PJ_FALSE;
+ if (sess->state >= PJ_TURN_STATE_DEALLOCATING) {
+ /* Ignore if we're deallocating */
+ goto on_return;
+ }
+
pj_gettimeofday(&now);
/* Refresh allocation if it's time to do so */
@@ -2022,19 +2026,19 @@ static void on_timer_event(pj_timer_heap_t *th, pj_timer_entry *e)
delay.sec = sess->ka_interval;
delay.msec = 0;
- sess->timer.id = TIMER_KEEP_ALIVE;
- pj_timer_heap_schedule(sess->timer_heap, &sess->timer, &delay);
+ pj_timer_heap_schedule_w_grp_lock(sess->timer_heap, &sess->timer,
+ &delay, TIMER_KEEP_ALIVE,
+ sess->grp_lock);
}
- pj_lock_release(sess->lock);
-
} else if (eid == TIMER_DESTROY) {
/* Time to destroy */
- pj_lock_release(sess->lock);
do_destroy(sess);
} else {
pj_assert(!"Unknown timer event");
- pj_lock_release(sess->lock);
}
+
+on_return:
+ pj_grp_lock_release(sess->grp_lock);
}