res_pjsip_refer/chan_sip: Fix INVITE with replaces transfer to ConfBridge
authorRichard Mudgett <rmudgett@digium.com>
Thu, 5 Apr 2018 23:33:40 +0000 (18:33 -0500)
committerRichard Mudgett <rmudgett@digium.com>
Fri, 6 Apr 2018 22:12:57 +0000 (16:12 -0600)
There is a problem when an INVITE-with-Replaces transfer targets a channel
in a ConfBridge.  The transfer will unconditionally swap out the
ConfBridge channel.  Unfortunately, the ConfBridge state will not be aware
of this change.  Unexpected behavior will happen as a result since
ConfBridge channels currently can only be replaced by a masquerade and not
normal bridge channel moves.

* We just need to pretend that the channel isn't in a bridge (like other
transfer methods already do) so the transfer channel will masquerade into
the ConfBridge channel.

Change-Id: I209beb0e748fa4f4b92a576f36afa8f495ba4c82

channels/chan_sip.c
include/asterisk/bridge.h
main/bridge.c
res/res_pjsip_refer.c

index 138021e..3891dad 100644 (file)
@@ -25886,10 +25886,7 @@ static int handle_invite_replaces(struct sip_pvt *p, struct sip_request *req,
 
        ast_raw_answer(c);
 
-       ast_channel_lock(replaces_chan);
-       bridge = ast_channel_get_bridge(replaces_chan);
-       ast_channel_unlock(replaces_chan);
-
+       bridge = ast_bridge_transfer_acquire_bridge(replaces_chan);
        if (bridge) {
                if (ast_bridge_impart(bridge, c, replaces_chan, NULL,
                        AST_BRIDGE_IMPART_CHAN_INDEPENDENT)) {
index 8d5c502..484d9a2 100644 (file)
@@ -945,6 +945,17 @@ void ast_bridge_remove_video_src(struct ast_bridge *bridge, struct ast_channel *
  */
 const char *ast_bridge_video_mode_to_string(enum ast_bridge_video_mode_type video_mode);
 
+/*!
+ * \brief Acquire the channel's bridge for transfer purposes.
+ * \since 13.21.0
+ *
+ * \param chan Channel involved in a transfer.
+ *
+ * \return The bridge the channel is in or NULL if it either isn't
+ * in a bridge or should not be considered to be in a bridge.
+ */
+struct ast_bridge *ast_bridge_transfer_acquire_bridge(struct ast_channel *chan);
+
 enum ast_transfer_result {
        /*! The transfer completed successfully */
        AST_BRIDGE_TRANSFER_SUCCESS,
index 1109c4b..21645ad 100644 (file)
@@ -4420,7 +4420,7 @@ static void set_transfer_variables_all(struct ast_channel *transferer, struct ao
        ao2_iterator_destroy(&iter);
 }
 
-static struct ast_bridge *acquire_bridge(struct ast_channel *chan)
+struct ast_bridge *ast_bridge_transfer_acquire_bridge(struct ast_channel *chan)
 {
        struct ast_bridge *bridge;
 
@@ -4461,7 +4461,7 @@ enum ast_transfer_result ast_bridge_transfer_blind(int is_external,
                return AST_BRIDGE_TRANSFER_FAIL;
        }
 
-       bridge = acquire_bridge(transferer);
+       bridge = ast_bridge_transfer_acquire_bridge(transferer);
        if (!bridge) {
                transfer_result = AST_BRIDGE_TRANSFER_INVALID;
                goto publish;
@@ -4708,8 +4708,8 @@ enum ast_transfer_result ast_bridge_transfer_attended(struct ast_channel *to_tra
        const char *app = NULL;
        int hangup_target = 0;
 
-       to_transferee_bridge = acquire_bridge(to_transferee);
-       to_target_bridge = acquire_bridge(to_transfer_target);
+       to_transferee_bridge = ast_bridge_transfer_acquire_bridge(to_transferee);
+       to_target_bridge = ast_bridge_transfer_acquire_bridge(to_transfer_target);
 
        transfer_msg = ast_attended_transfer_message_create(1, to_transferee, to_transferee_bridge,
                        to_transfer_target, to_target_bridge, NULL, NULL);
index 7d892f6..120203c 100644 (file)
@@ -917,10 +917,7 @@ static int invite_replaces(void *data)
        ast_channel_ref(invite->session->channel);
        invite->channel = invite->session->channel;
 
-       ast_channel_lock(invite->channel);
-       invite->bridge = ast_channel_get_bridge(invite->channel);
-       ast_channel_unlock(invite->channel);
-
+       invite->bridge = ast_bridge_transfer_acquire_bridge(invite->channel);
        return 0;
 }