chan_dahdi: Fix analog parking using flash-hook.
authorRichard Mudgett <rmudgett@digium.com>
Tue, 1 Oct 2013 21:19:13 +0000 (21:19 +0000)
committerRichard Mudgett <rmudgett@digium.com>
Tue, 1 Oct 2013 21:19:13 +0000 (21:19 +0000)
Transferring an analog call using a flash-hook to parking would fail to
park the call and result in an invalid ao2 object unref.

* Park the correct bridged channel.
........

Merged revisions 400236 from http://svn.asterisk.org/svn/asterisk/branches/12

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@400237 65c4cc65-6c06-0410-ace0-fbb531ad65f3

channels/chan_dahdi.c
channels/sig_analog.c

index f7cfa8c..853c5f4 100644 (file)
@@ -9722,16 +9722,34 @@ static void *analog_ss_thread(void *data)
                                getforward = 0;
                                memset(exten, 0, sizeof(exten));
                                len = 0;
-                       } else if ((p->transfer || p->canpark) && is_exten_parking &&
-                                               p->subs[SUB_THREEWAY].owner) {
-                               RAII_VAR(struct ast_bridge_channel *, bridge_channel, NULL, ao2_cleanup);
-                               /* This is a three way call, the main call being a real channel,
-                                       and we're parking the first call. */
-                               ast_channel_lock(chan);
-                               bridge_channel = ast_channel_get_bridge_channel(chan);
-                               ast_channel_unlock(chan);
-                               if (bridge_channel && !ast_parking_blind_transfer_park(bridge_channel, ast_channel_context(chan), exten)) {
-                                       ast_verb(3, "Parking call to '%s'\n", ast_channel_name(chan));
+                       } else if ((p->transfer || p->canpark) && is_exten_parking
+                               && p->subs[SUB_THREEWAY].owner) {
+                               struct ast_bridge_channel *bridge_channel;
+
+                               /*
+                                * This is a three way call, the main call being a real channel,
+                                * and we're parking the first call.
+                                */
+                               ast_channel_lock(p->subs[SUB_THREEWAY].owner);
+                               bridge_channel = ast_channel_get_bridge_channel(p->subs[SUB_THREEWAY].owner);
+                               ast_channel_unlock(p->subs[SUB_THREEWAY].owner);
+                               if (bridge_channel) {
+                                       if (!ast_parking_blind_transfer_park(bridge_channel, ast_channel_context(chan), exten)) {
+                                               /*
+                                                * Swap things around between the three-way and real call so we
+                                                * can hear where the channel got parked.
+                                                */
+                                               ast_mutex_lock(&p->lock);
+                                               p->owner = p->subs[SUB_THREEWAY].owner;
+                                               swap_subs(p, SUB_THREEWAY, SUB_REAL);
+                                               ast_mutex_unlock(&p->lock);
+
+                                               ast_verb(3, "%s: Parked call\n", ast_channel_name(chan));
+                                               ast_hangup(chan);
+                                               ao2_ref(bridge_channel, -1);
+                                               goto quit;
+                                       }
+                                       ao2_ref(bridge_channel, -1);
                                }
                                break;
                        } else if (p->hidecallerid && !strcmp(exten, "*82")) {
index d1ed673..bbf7a3c 100644 (file)
@@ -2245,18 +2245,35 @@ static void *__analog_ss_thread(void *data)
                                getforward = 0;
                                memset(exten, 0, sizeof(exten));
                                len = 0;
-                       } else if ((p->transfer || p->canpark) && is_exten_parking &&
-                                               p->subs[ANALOG_SUB_THREEWAY].owner) {
+                       } else if ((p->transfer || p->canpark) && is_exten_parking
+                               && p->subs[ANALOG_SUB_THREEWAY].owner) {
                                struct ast_bridge_channel *bridge_channel;
-                               /* This is a three way call, the main call being a real channel,
-                                       and we're parking the first call. */
-                               ast_channel_lock(chan);
-                               bridge_channel = ast_channel_get_bridge_channel(chan);
-                               ast_channel_unlock(chan);
-                               if (bridge_channel && !ast_parking_blind_transfer_park(bridge_channel, ast_channel_context(chan), exten)) {
-                                       ast_verb(3, "Parking call to '%s'\n", ast_channel_name(chan));
+
+                               /*
+                                * This is a three way call, the main call being a real channel,
+                                * and we're parking the first call.
+                                */
+                               ast_channel_lock(p->subs[ANALOG_SUB_THREEWAY].owner);
+                               bridge_channel = ast_channel_get_bridge_channel(p->subs[ANALOG_SUB_THREEWAY].owner);
+                               ast_channel_unlock(p->subs[ANALOG_SUB_THREEWAY].owner);
+                               if (bridge_channel) {
+                                       if (!ast_parking_blind_transfer_park(bridge_channel, ast_channel_context(chan), exten)) {
+                                               /*
+                                                * Swap things around between the three-way and real call so we
+                                                * can hear where the channel got parked.
+                                                */
+                                               analog_lock_private(p);
+                                               analog_set_new_owner(p, p->subs[ANALOG_SUB_THREEWAY].owner);
+                                               analog_swap_subs(p, ANALOG_SUB_THREEWAY, ANALOG_SUB_REAL);
+                                               analog_unlock_private(p);
+
+                                               ast_verb(3, "%s: Parked call\n", ast_channel_name(chan));
+                                               ast_hangup(chan);
+                                               ao2_ref(bridge_channel, -1);
+                                               goto quit;
+                                       }
+                                       ao2_ref(bridge_channel, -1);
                                }
-                               ao2_ref(bridge_channel, -1);
                                break;
                        } else if (!ast_strlen_zero(p->lastcid_num) && !strcmp(exten, "*60")) {
                                ast_verb(3, "Blacklisting number %s\n", p->lastcid_num);