From 0c03eab9626a3262d6b4f122ceaca29e7d390bbc Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Thu, 5 Apr 2018 18:33:40 -0500 Subject: res_pjsip_refer/chan_sip: Fix INVITE with replaces transfer to ConfBridge 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 | 5 +---- include/asterisk/bridge.h | 11 +++++++++++ main/bridge.c | 8 ++++---- res/res_pjsip_refer.c | 5 +---- 4 files changed, 17 insertions(+), 12 deletions(-) diff --git a/channels/chan_sip.c b/channels/chan_sip.c index 138021e82..3891dada6 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -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)) { diff --git a/include/asterisk/bridge.h b/include/asterisk/bridge.h index 8d5c50211..484d9a2f5 100644 --- a/include/asterisk/bridge.h +++ b/include/asterisk/bridge.h @@ -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, diff --git a/main/bridge.c b/main/bridge.c index 1109c4b76..21645adae 100644 --- a/main/bridge.c +++ b/main/bridge.c @@ -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); diff --git a/res/res_pjsip_refer.c b/res/res_pjsip_refer.c index 7d892f653..120203c95 100644 --- a/res/res_pjsip_refer.c +++ b/res/res_pjsip_refer.c @@ -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; } -- cgit v1.2.3