]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
Merged revisions 318671 via svnmerge from
authorRichard Mudgett <rmudgett@digium.com>
Fri, 13 May 2011 01:09:40 +0000 (01:09 +0000)
committerRichard Mudgett <rmudgett@digium.com>
Fri, 13 May 2011 01:09:40 +0000 (01:09 +0000)
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

apps/app_directed_pickup.c
channels/chan_sip.c
res/res_features.c

index d591ca18003a17e2d2ed20a7053cafabd54a9b62..203ca2c635233d67b3d8f33dba1adb50def2864f 100644 (file)
@@ -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 */
index 8e92c7910190fd1f0b9f0674f548c67792aad588..9108d178cb21181cef07155871cd543550bdb6fe 100644 (file)
@@ -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;
index 66106e851df3ab1dbf6e70b7354f698da38678d9..20ccc5f80ceaf1a7527e4ca7fe134711a50f4fed 100644 (file)
@@ -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;
 }