diff options
-rw-r--r-- | pjlib/include/pj/timer.h | 9 | ||||
-rw-r--r-- | pjlib/src/pj/timer.c | 5 | ||||
-rw-r--r-- | pjsip/src/pjsip/sip_transaction.c | 15 |
3 files changed, 29 insertions, 0 deletions
diff --git a/pjlib/include/pj/timer.h b/pjlib/include/pj/timer.h index 59149385..df6155a8 100644 --- a/pjlib/include/pj/timer.h +++ b/pjlib/include/pj/timer.h @@ -213,6 +213,15 @@ PJ_DECL(pj_timer_entry*) pj_timer_entry_init( pj_timer_entry *entry, pj_timer_heap_callback *cb ); /** + * Queries whether a timer entry is currently running. + * + * @param entry The timer entry to query. + * + * @return PJ_TRUE if the timer is running. PJ_FALSE if not. + */ +PJ_DECL(pj_bool_t) pj_timer_entry_running( pj_timer_entry *entry ); + +/** * Schedule a timer entry which will expire AFTER the specified delay. * * @param ht The timer heap. diff --git a/pjlib/src/pj/timer.c b/pjlib/src/pj/timer.c index b9205c81..931a57fa 100644 --- a/pjlib/src/pj/timer.c +++ b/pjlib/src/pj/timer.c @@ -466,6 +466,11 @@ PJ_DEF(pj_timer_entry*) pj_timer_entry_init( pj_timer_entry *entry, return entry; } +PJ_DEF(pj_bool_t) pj_timer_entry_running( pj_timer_entry *entry ) +{ + return (entry->_timer_id >= 1); +} + #if PJ_TIMER_DEBUG static pj_status_t schedule_w_grp_lock_dbg(pj_timer_heap_t *ht, pj_timer_entry *entry, diff --git a/pjsip/src/pjsip/sip_transaction.c b/pjsip/src/pjsip/sip_transaction.c index ec189815..446617e2 100644 --- a/pjsip/src/pjsip/sip_transaction.c +++ b/pjsip/src/pjsip/sip_transaction.c @@ -2224,6 +2224,18 @@ static pj_status_t tsx_retransmit( pjsip_transaction *tsx, int resched) { pj_status_t status; + if (resched && pj_timer_entry_running(&tsx->retransmit_timer)) { + /* We've been asked to reschedule but the timer is already rerunning. + * This can only happen in a race condition where, between removing + * this retransmit timer from the heap and actually scheduling it, + * another thread has got in and rescheduled the timer itself. In + * this scenario, the transmission has already happened and so we + * should just quit out immediately, without either resending the + * message or restarting the timer. + */ + return PJ_SUCCESS; + } + PJ_ASSERT_RETURN(tsx->last_tx!=NULL, PJ_EBUG); PJ_LOG(5,(tsx->obj_name, "Retransmiting %s, count=%d, restart?=%d", @@ -2332,6 +2344,7 @@ static pj_status_t tsx_on_state_null( pjsip_transaction *tsx, * timeout. */ lock_timer(tsx); + tsx_cancel_timer( tsx, &tsx->timeout_timer ); tsx_schedule_timer( tsx, &tsx->timeout_timer, &timeout_timer_val, TIMEOUT_TIMER); unlock_timer(tsx); @@ -2677,6 +2690,7 @@ static pj_status_t tsx_on_state_proceeding_uas( pjsip_transaction *tsx, } lock_timer(tsx); + tsx_cancel_timer(tsx, &tsx->timeout_timer); tsx_schedule_timer( tsx, &tsx->timeout_timer, &timeout, TIMEOUT_TIMER); unlock_timer(tsx); @@ -2705,6 +2719,7 @@ static pj_status_t tsx_on_state_proceeding_uas( pjsip_transaction *tsx, * non-reliable transports, and zero for reliable transports. */ lock_timer(tsx); + tsx_cancel_timer(tsx, &tsx->timeout_timer); if (tsx->method.id == PJSIP_INVITE_METHOD) { /* Start timer H for INVITE */ tsx_schedule_timer(tsx, &tsx->timeout_timer, |