From d93f9bf7b4be0e61a0ae77c8938aec7b5f532da6 Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Mon, 24 Sep 2012 19:15:24 +0000 Subject: [PATCH] Fix a deadlock caused by a race condition between removing a hint and reloading the dialplan and subscribing to the removed hint. If conditions were right it was possible for both the PBX core and chan_sip to deadlock by both having a lock that the other wants. In the case of the PBX core it had the contexts lock and wanted a SIP dialog lock, while in the case of chan_sip it had the SIP dialog lock and wanted the contexts lock. This fix unlocks the SIP dialog before getting the extension state so that the other thread will not block on trying to lock it. Once the extension state is retrieved the SIP dialog is locked again and life carries on. As the SIP dialog is reference counted it is not possible for it to go away after unlocking. (closes issue ASTERISK-20437) Reported by: jhutchins git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/1.8@373438 65c4cc65-6c06-0410-ace0-fbb531ad65f3 --- channels/chan_sip.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/channels/chan_sip.c b/channels/chan_sip.c index 4456147a5c..cc691ab7b8 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -12896,6 +12896,11 @@ static int transmit_state_notify(struct sip_pvt *p, int state, int full, int tim struct sip_request req; const struct cfsubscription_types *subscriptiontype; + /* If the subscription has not yet been accepted do not send a NOTIFY */ + if (!ast_test_flag(&p->flags[1], SIP_PAGE2_DIALOG_ESTABLISHED)) { + return 0; + } + memset(from, 0, sizeof(from)); memset(to, 0, sizeof(to)); @@ -25134,8 +25139,11 @@ static int handle_request_subscribe(struct sip_pvt *p, struct sip_request *req, unref_peer(peer, "release a peer ref now that MWI is sent"); } } else if (p->subscribed != CALL_COMPLETION) { - if ((firststate = ast_extension_state(NULL, p->context, p->exten)) < 0) { + sip_pvt_unlock(p); + firststate = ast_extension_state(NULL, p->context, p->exten); + sip_pvt_lock(p); + if (firststate < 0) { ast_log(LOG_NOTICE, "Got SUBSCRIBE for extension %s@%s from %s, but there is no hint for that extension.\n", p->exten, p->context, ast_sockaddr_stringify(&p->sa)); transmit_response(p, "404 Not found", req); pvt_set_needdestroy(p, "no extension for SUBSCRIBE"); -- 2.47.3