]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
bridge: Fix returning to dialplan when executing Bridge() from AMI.
authorJoshua Colp <jcolp@digium.com>
Sun, 30 Apr 2017 21:40:16 +0000 (21:40 +0000)
committerJoshua Colp <jcolp@digium.com>
Thu, 4 May 2017 21:39:59 +0000 (16:39 -0500)
When using the Bridge AMI action on the same channel multiple times
it was possible for the channel to return to the wrong location in
the dialplan if the other party hung up. This happened because the
priority of the channel was not preserved across each action
invocation and it would fail to move on to the next priority in
other cases.

This change makes it so that the priority of a channel is preserved
when taking control of it from another thread and it is incremented
as appropriate such that the priority reflects where the channel
should next be executed in the dialplan, not where it may or may not
currently be.

The Bridge AMI action was also changed to ensure that it too
starts the channels at the next location in the dialplan.

ASTERISK-24529

Change-Id: I52406669cf64208aef7252a65b63ade31fbf7a5a

include/asterisk/channel.h
main/channel.c
main/features.c

index 219e5a28ee20dc8074116914052fcb74cb7f29b6..3acd07774b3364d83f5be5ca66db1f6239646211 100644 (file)
@@ -4513,6 +4513,9 @@ struct ast_bridge_channel *ast_channel_get_bridge_channel(struct ast_channel *ch
  *
  * \note absolutely _NO_ channel locks should be held before calling this function.
  *
+ * \note The dialplan location on the returned channel is where the channel
+ * should be started in the dialplan if it is returned to it.
+ *
  * \param yankee The channel to gain control of
  * \retval NULL Could not gain control of the channel
  * \retval non-NULL The channel
index ea83ebf1fa32e1ce595b873c78cba4127be2ab4f..8e7d142bba81a8c1031da491ef4d8c0034be608b 100644 (file)
@@ -10682,6 +10682,7 @@ struct ast_channel *ast_channel_yank(struct ast_channel *yankee)
                char *context;
                char *name;
                int amaflags;
+               int priority;
                struct ast_format *readformat;
                struct ast_format *writeformat;
        } my_vars = { 0, };
@@ -10692,6 +10693,16 @@ struct ast_channel *ast_channel_yank(struct ast_channel *yankee)
        my_vars.context = ast_strdupa(ast_channel_context(yankee));
        my_vars.name = ast_strdupa(ast_channel_name(yankee));
        my_vars.amaflags = ast_channel_amaflags(yankee);
+       my_vars.priority = ast_channel_priority(yankee);
+       /* The priority as returned by ast_channel_yank is where the channel
+        * should go if the dialplan is executed on it. If the channel is
+        * already executing dialplan then the priority currently set is
+        * where it is currently. We increment it so it becomes where it should
+        * execute.
+        */
+       if (ast_test_flag(ast_channel_flags(yankee), AST_FLAG_IN_AUTOLOOP)) {
+               my_vars.priority++;
+       }
        my_vars.writeformat = ao2_bump(ast_channel_writeformat(yankee));
        my_vars.readformat = ao2_bump(ast_channel_readformat(yankee));
        ast_channel_unlock(yankee);
@@ -10711,6 +10722,7 @@ struct ast_channel *ast_channel_yank(struct ast_channel *yankee)
        ast_channel_set_writeformat(yanked_chan, my_vars.writeformat);
        ao2_cleanup(my_vars.readformat);
        ao2_cleanup(my_vars.writeformat);
+       ast_channel_priority_set(yanked_chan, my_vars.priority);
 
        ast_channel_unlock(yanked_chan);
 
index 0af5a78e3c32d4d7d16913b529b4f1c8053c5f9c..0e52ea0f4ff159e6ccdacaa0750a84e4489b5285 100644 (file)
@@ -784,7 +784,7 @@ static int action_bridge(struct mansession *s, const struct message *m)
        chana_exten = ast_strdupa(ast_channel_exten(chana));
        chana_context = ast_strdupa(ast_channel_context(chana));
        chana_priority = ast_channel_priority(chana);
-       if (!ast_test_flag(ast_channel_flags(chana), AST_FLAG_IN_AUTOLOOP)) {
+       if (ast_test_flag(ast_channel_flags(chana), AST_FLAG_IN_AUTOLOOP)) {
                chana_priority++;
        }
        ast_channel_unlock(chana);
@@ -800,7 +800,7 @@ static int action_bridge(struct mansession *s, const struct message *m)
        chanb_exten = ast_strdupa(ast_channel_exten(chanb));
        chanb_context = ast_strdupa(ast_channel_context(chanb));
        chanb_priority = ast_channel_priority(chanb);
-       if (!ast_test_flag(ast_channel_flags(chanb), AST_FLAG_IN_AUTOLOOP)) {
+       if (ast_test_flag(ast_channel_flags(chanb), AST_FLAG_IN_AUTOLOOP)) {
                chanb_priority++;
        }
        ast_channel_unlock(chanb);
@@ -811,7 +811,7 @@ static int action_bridge(struct mansession *s, const struct message *m)
                return 0;
        }
 
-       ast_bridge_set_after_go_on(chana, chana_context, chana_exten, chana_priority, NULL);
+       ast_bridge_set_after_goto(chana, chana_context, chana_exten, chana_priority);
        if (ast_bridge_add_channel(bridge, chana, NULL, playtone & PLAYTONE_CHANNEL1, xfer_cfg_a ? xfer_cfg_a->xfersound : NULL)) {
                snprintf(buf, sizeof(buf), "Unable to add Channel1 to bridge: %s", ast_channel_name(chana));
                astman_send_error(s, m, buf);
@@ -819,7 +819,7 @@ static int action_bridge(struct mansession *s, const struct message *m)
                return 0;
        }
 
-       ast_bridge_set_after_go_on(chanb, chanb_context, chanb_exten, chanb_priority, NULL);
+       ast_bridge_set_after_goto(chanb, chanb_context, chanb_exten, chanb_priority);
        if (ast_bridge_add_channel(bridge, chanb, NULL, playtone & PLAYTONE_CHANNEL2, xfer_cfg_b ? xfer_cfg_b->xfersound : NULL)) {
                snprintf(buf, sizeof(buf), "Unable to add Channel2 to bridge: %s", ast_channel_name(chanb));
                astman_send_error(s, m, buf);