diff options
author | Jenkins2 <jenkins2@gerrit.asterisk.org> | 2018-03-01 08:44:21 -0600 |
---|---|---|
committer | Gerrit Code Review <gerrit2@gerrit.digium.api> | 2018-03-01 08:44:21 -0600 |
commit | 97485eefaf14e433457ea9c73947a55aaa4bdbf8 (patch) | |
tree | 77709bb1b5e072e5ffea87077170a880ea3f584e /res | |
parent | 53ed437db3f37d941538ec1bf0ff96c422c7bef5 (diff) | |
parent | bb9c1938a019744ffa02dcd2779b97cd9240e182 (diff) |
Merge "res_pjsip_refer.c: Fix attended transfer race condition crash."
Diffstat (limited to 'res')
-rw-r--r-- | res/res_pjsip_refer.c | 32 |
1 files changed, 24 insertions, 8 deletions
diff --git a/res/res_pjsip_refer.c b/res/res_pjsip_refer.c index 5e0141b09..7d892f653 100644 --- a/res/res_pjsip_refer.c +++ b/res/res_pjsip_refer.c @@ -468,10 +468,20 @@ static struct refer_attended *refer_attended_alloc(struct ast_sip_session *trans return attended; } -static int defer_termination_cancel(void *data) +static int session_end_if_deferred_task(void *data) { struct ast_sip_session *session = data; + ast_sip_session_end_if_deferred(session); + ao2_ref(session, -1); + return 0; +} + +static int defer_termination_cancel_task(void *data) +{ + struct ast_sip_session *session = data; + + ast_sip_session_end_if_deferred(session); ast_sip_session_defer_termination_cancel(session); ao2_ref(session, -1); return 0; @@ -513,6 +523,7 @@ static int refer_attended_task(void *data) { struct refer_attended *attended = data; int response; + int (*task_cb)(void *data); if (attended->transferer_second->channel) { ast_debug(3, "Performing a REFER attended transfer - Transferer #1: %s Transferer #2: %s\n", @@ -543,13 +554,18 @@ static int refer_attended_task(void *data) } } - ast_sip_session_end_if_deferred(attended->transferer); - if (response != 200) { - if (!ast_sip_push_task(attended->transferer->serializer, - defer_termination_cancel, attended->transferer)) { - /* Gave the ref to the pushed task. */ - attended->transferer = NULL; - } + if (response == 200) { + task_cb = session_end_if_deferred_task; + } else { + task_cb = defer_termination_cancel_task; + } + if (!ast_sip_push_task(attended->transferer->serializer, + task_cb, attended->transferer)) { + /* Gave the ref to the pushed task. */ + attended->transferer = NULL; + } else { + /* Do this anyway even though it is the wrong serializer. */ + ast_sip_session_end_if_deferred(attended->transferer); } ao2_ref(attended, -1); |