diff options
author | Benny Prijono <bennylp@teluu.com> | 2007-06-27 12:52:35 +0000 |
---|---|---|
committer | Benny Prijono <bennylp@teluu.com> | 2007-06-27 12:52:35 +0000 |
commit | 95c98b95136c97f511beed1636379b909b3181d0 (patch) | |
tree | 8688810d2fd2525e0ec1c4d2aa14fd12302e3986 /pjsip/src/pjsip-simple/evsub.c | |
parent | b1b10d6b468b110bf996eafec5a9875a9f917c7a (diff) |
Ticket #346: deadlock in event subscription when SUBSCRIBE is followed immediately with UN-SUBSCRIBE
git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@1395 74dad513-b988-da41-8d7b-12977e46ad98
Diffstat (limited to 'pjsip/src/pjsip-simple/evsub.c')
-rw-r--r-- | pjsip/src/pjsip-simple/evsub.c | 47 |
1 files changed, 45 insertions, 2 deletions
diff --git a/pjsip/src/pjsip-simple/evsub.c b/pjsip/src/pjsip-simple/evsub.c index 326afa8a..61a268d7 100644 --- a/pjsip/src/pjsip-simple/evsub.c +++ b/pjsip/src/pjsip-simple/evsub.c @@ -1210,6 +1210,23 @@ on_return: } +/* Callback to be called to terminate transaction. */ +static void terminate_timer_cb(pj_timer_heap_t *timer_heap, + struct pj_timer_entry *entry) +{ + pj_str_t *key; + pjsip_transaction *tsx; + + PJ_UNUSED_ARG(timer_heap); + + key = (pj_str_t*)entry->user_data; + tsx = pjsip_tsx_layer_find_tsx(key, PJ_FALSE); + /* Chance of race condition here */ + if (tsx) { + pjsip_tsx_terminate(tsx, PJSIP_SC_REQUEST_UPDATED); + } +} + /* * Attach subscription session to newly created transaction, if appropriate. @@ -1375,6 +1392,10 @@ static pjsip_evsub *on_new_transaction( pjsip_transaction *tsx, if (sub->pending_sub && sub->pending_sub->state < PJSIP_TSX_STATE_COMPLETED) { + pj_timer_entry *timer; + pj_str_t *key; + pj_time_val timeout = {0, 0}; + PJ_LOG(4,(sub->obj_name, "Cancelling pending subscription request")); @@ -1382,7 +1403,22 @@ static pjsip_evsub *on_new_transaction( pjsip_transaction *tsx, * When transaction handler (below) see this status code, it * will ignore the transaction. */ - pjsip_tsx_terminate(sub->pending_sub, PJSIP_SC_REQUEST_UPDATED); + /* This unfortunately may cause deadlock, because at the moment + * we are holding dialog's mutex. If a response to this + * transaction is in progress in another thread, that thread + * will deadlock when trying to acquire dialog mutex, because + * it is holding the transaction mutex. + * + * So the solution is to register timer to kill this transaction. + */ + //pjsip_tsx_terminate(sub->pending_sub, PJSIP_SC_REQUEST_UPDATED); + timer = PJ_POOL_ZALLOC_T(dlg->pool, pj_timer_entry); + key = PJ_POOL_ALLOC_T(dlg->pool, pj_str_t); + pj_strdup(dlg->pool, key, &sub->pending_sub->transaction_key); + timer->cb = &terminate_timer_cb; + timer->user_data = key; + + pjsip_endpt_schedule_timer(dlg->endpt, timer, &timeout); } sub->pending_sub = tsx; @@ -1499,8 +1535,15 @@ static void on_tsx_state_uac( pjsip_evsub *sub, pjsip_transaction *tsx, } /* Clear pending subscription */ - if (tsx == sub->pending_sub) + if (tsx == sub->pending_sub) { sub->pending_sub = NULL; + } else if (sub->pending_sub != NULL) { + /* This SUBSCRIBE transaction has been "renewed" with another + * SUBSCRIBE, so we can just ignore this. For example, user + * sent SUBSCRIBE followed immediately with UN-SUBSCRIBE. + */ + return; + } /* Handle authentication. */ if (tsx->status_code==401 || tsx->status_code==407) { |