From: Richard Mudgett Date: Fri, 13 May 2011 01:09:40 +0000 (+0000) Subject: Merged revisions 318671 via svnmerge from X-Git-Tag: 1.4.42-rc1~4 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=2f024e45446b1cf2dcce107663324e1c58a933ba;p=thirdparty%2Fasterisk.git Merged revisions 318671 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 * The applicable fixes for v1.4 are the SIP deadlock and the in progress masquerade check for multiple parties trying to pickup the same call. issue18654_v1.4.patch uploaded by rmudgett (license 664) * Backported to v1.6.2. issue18654_v1.6.2.patch uploaded by rmudgett (license 664) ........ r318671 | alecdavis | 2011-05-13 10:52:08 +1200 (Fri, 13 May 2011) | 30 lines Fix directed group pickup feature code *8 with pickupsounds enabled Since 1.6.2, the new pickupsound and pickupfailsound in features.conf cause many issues. 1). chan_sip:handle_request_invite() shouldn't be playing out the fail/success audio, as it has 'netlock' locked. 2). dialplan applications for directed_pickups shouldn't beep. 3). feature code for directed pickup should beep on success/failure if configured. Created a sip_pickup() thread to handle the pickup and playout the audio, spawned from handle_request_invite. Moved app_directed:pickup_do() to features:ast_do_pickup(). Functions below, all now use the new ast_do_pickup() app_directed_pickup.c: pickup_by_channel() pickup_by_exten() pickup_by_mark() pickup_by_part() features.c: ast_pickup_call() (closes issue #18654) Reported by: Docent Patches: ast_do_pickup_1.8_trunk.diff.txt uploaded by alecdavis (license 585) Tested by: lmadsen, francesco_r, amilcar, isis242, alecdavis, irroot, rymkus, loloski, rmudgett Review: https://reviewboard.asterisk.org/r/1185/ ........ git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/1.4@318734 65c4cc65-6c06-0410-ace0-fbb531ad65f3 --- diff --git a/apps/app_directed_pickup.c b/apps/app_directed_pickup.c index d591ca1800..203ca2c635 100644 --- a/apps/app_directed_pickup.c +++ b/apps/app_directed_pickup.c @@ -54,39 +54,45 @@ static const char *descrip = "10@PICKUPMARK, this application tries to find a channel which has defined a channel variable with the same content\n" "as \"extension\"."; -/* Perform actual pickup between two channels */ +/*! + * \internal + * \brief Perform actual pickup between two channels. + * \note Must remain in sync with same function in res/res_features.c. + */ static int pickup_do(struct ast_channel *chan, struct ast_channel *target) { - int res = 0; - if (option_debug) ast_log(LOG_DEBUG, "Call pickup on '%s' by '%s'\n", target->name, chan->name); - if ((res = ast_answer(chan))) { + if (ast_answer(chan)) { ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name); return -1; } - if ((res = ast_queue_control(chan, AST_CONTROL_ANSWER))) { + if (ast_queue_control(chan, AST_CONTROL_ANSWER)) { ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name); return -1; } - if ((res = ast_channel_masquerade(target, chan))) { + if (ast_channel_masquerade(target, chan)) { ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, target->name); return -1; } - return res; + return 0; } /* Helper function that determines whether a channel is capable of being picked up */ static int can_pickup(struct ast_channel *chan) { - if (!chan->pbx && (chan->_state == AST_STATE_RINGING || chan->_state == AST_STATE_RING || chan->_state == AST_STATE_DOWN)) + if (!chan->pbx && !chan->masq && + !ast_test_flag(chan, AST_FLAG_ZOMBIE) && + (chan->_state == AST_STATE_RINGING || + chan->_state == AST_STATE_RING || + chan->_state == AST_STATE_DOWN)) { return 1; - else - return 0; + } + return 0; } /* Attempt to pick up specified extension with context */ diff --git a/channels/chan_sip.c b/channels/chan_sip.c index 8e92c79101..9108d178cb 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -15867,6 +15867,7 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int /* Unlock locks so ast_hangup can do its magic */ ast_mutex_unlock(&c->lock); + *nounlock = 1; ast_mutex_unlock(&p->lock); ast_hangup(c); ast_mutex_lock(&p->lock); @@ -15875,7 +15876,9 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int } else { /* Pickup call in call group */ ast_channel_unlock(c); *nounlock = 1; + ast_mutex_unlock(&p->lock); if (ast_pickup_call(c)) { + ast_mutex_lock(&p->lock); ast_log(LOG_NOTICE, "Nothing to pick up for %s\n", p->callid); if (ast_test_flag(req, SIP_PKT_IGNORE)) transmit_response(p, "503 Unavailable", req); /* OEJ - Right answer? */ @@ -15886,13 +15889,11 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int ast_mutex_unlock(&p->lock); c->hangupcause = AST_CAUSE_CALL_REJECTED; } else { - ast_mutex_unlock(&p->lock); - ast_setstate(c, AST_STATE_DOWN); c->hangupcause = AST_CAUSE_NORMAL_CLEARING; } - p->invitestate = INV_COMPLETED; ast_hangup(c); ast_mutex_lock(&p->lock); + p->invitestate = INV_COMPLETED; c = NULL; } break; diff --git a/res/res_features.c b/res/res_features.c index 66106e851d..20ccc5f80c 100644 --- a/res/res_features.c +++ b/res/res_features.c @@ -3374,6 +3374,34 @@ static int manager_park(struct mansession *s, const struct message *m) } +/*! + * \internal + * \brief Perform actual pickup between two channels. + * \note Must remain in sync with same function in apps/app_directed_pickup.c. + */ +static int pickup_do(struct ast_channel *chan, struct ast_channel *target) +{ + if (option_debug) + ast_log(LOG_DEBUG, "Call pickup on '%s' by '%s'\n", target->name, chan->name); + + if (ast_answer(chan)) { + ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name); + return -1; + } + + if (ast_queue_control(chan, AST_CONTROL_ANSWER)) { + ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name); + return -1; + } + + if (ast_channel_masquerade(target, chan)) { + ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, target->name); + return -1; + } + + return 0; +} + int ast_pickup_call(struct ast_channel *chan) { struct ast_channel *cur = NULL; @@ -3385,27 +3413,21 @@ int ast_pickup_call(struct ast_channel *chan) (chan->pickupgroup & cur->callgroup) && ((cur->_state == AST_STATE_RINGING) || (cur->_state == AST_STATE_RING)) && - !cur->masq) { + !cur->masq && + !ast_test_flag(cur, AST_FLAG_ZOMBIE)) { break; } ast_channel_unlock(cur); } if (cur) { - if (option_debug) - ast_log(LOG_DEBUG, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name); - res = ast_answer(chan); - if (res) - ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name); - res = ast_queue_control(chan, AST_CONTROL_ANSWER); - if (res) - ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name); - res = ast_channel_masquerade(cur, chan); - if (res) - ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, cur->name); /* Done */ + res = pickup_do(chan, cur); + if (res) { + ast_log(LOG_WARNING, "pickup %s failed by %s\n", cur->name, chan->name); + } ast_channel_unlock(cur); } else { if (option_debug) - ast_log(LOG_DEBUG, "No call pickup possible...\n"); + ast_log(LOG_DEBUG, "No call pickup possible... for %s\n", chan->name); } return res; }