From 3429c9de5efede907dc34ebb4cda555081961e94 Mon Sep 17 00:00:00 2001 From: Mark Michelson Date: Tue, 18 Nov 2008 18:25:55 +0000 Subject: [PATCH] Fix a crash in the end_bridge_callback of app_dial and app_followme which would occur at the end of an attended transfer. The error occurred because we initially stored a pointer to an ast_channel which then was hung up due to a masquerade. This commit adds a "fixup" callback to the bridge_config structure to allow for end_bridge_callback_data to be changed in the case that a new channel pointer is needed for the end_bridge_callback. git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/1.4@157305 65c4cc65-6c06-0410-ace0-fbb531ad65f3 --- apps/app_dial.c | 5 +++++ apps/app_followme.c | 6 ++++++ channels/chan_local.c | 8 +++++++- include/asterisk/channel.h | 4 ++++ res/res_features.c | 4 ++++ 5 files changed, 26 insertions(+), 1 deletion(-) diff --git a/apps/app_dial.c b/apps/app_dial.c index 5192217f11..1782e13f14 100644 --- a/apps/app_dial.c +++ b/apps/app_dial.c @@ -857,6 +857,10 @@ static void end_bridge_callback (void *data) ast_channel_unlock(chan); } +static void end_bridge_callback_data_fixup(struct ast_bridge_config *bconfig, struct ast_channel *originator, struct ast_channel *terminator) { + bconfig->end_bridge_callback_data = originator; +} + static int dial_exec_full(struct ast_channel *chan, void *data, struct ast_flags *peerflags, int *continue_exec) { int res = -1; @@ -1795,6 +1799,7 @@ static int dial_exec_full(struct ast_channel *chan, void *data, struct ast_flags config.start_sound = start_sound; config.end_bridge_callback = end_bridge_callback; config.end_bridge_callback_data = chan; + config.end_bridge_callback_data_fixup = end_bridge_callback_data_fixup; if (moh) { moh = 0; ast_moh_stop(chan); diff --git a/apps/app_followme.c b/apps/app_followme.c index 3de1a46080..fca6facc2e 100644 --- a/apps/app_followme.c +++ b/apps/app_followme.c @@ -935,6 +935,11 @@ static void end_bridge_callback (void *data) ast_channel_unlock(chan); } +static void end_bridge_callback_data_fixup(struct ast_bridge_config *bconfig, struct ast_channel *originator, struct ast_channel *terminator) +{ + bconfig->end_bridge_callback_data = originator; +} + static int app_exec(struct ast_channel *chan, void *data) { struct fm_args targs; @@ -1057,6 +1062,7 @@ static int app_exec(struct ast_channel *chan, void *data) config.end_bridge_callback = end_bridge_callback; config.end_bridge_callback_data = chan; + config.end_bridge_callback_data_fixup = end_bridge_callback_data_fixup; ast_moh_stop(caller); /* Be sure no generators are left on it */ diff --git a/channels/chan_local.c b/channels/chan_local.c index d879cb006f..cbe4c6f201 100644 --- a/channels/chan_local.c +++ b/channels/chan_local.c @@ -254,7 +254,7 @@ static void check_bridge(struct local_pvt *p, int isoutbound) if (!p->chan->_bridge->_softhangup) { if (!ast_mutex_trylock(&p->owner->lock)) { if (!p->owner->_softhangup) { - if(p->owner->monitor && !p->chan->_bridge->monitor) { + if (p->owner->monitor && !p->chan->_bridge->monitor) { /* If a local channel is being monitored, we don't want a masquerade * to cause the monitor to go away. Since the masquerade swaps the monitors, * pre-swapping the monitors before the masquerade will ensure that the monitor @@ -264,6 +264,12 @@ static void check_bridge(struct local_pvt *p, int isoutbound) p->owner->monitor = p->chan->_bridge->monitor; p->chan->_bridge->monitor = tmp; } + if (p->chan->audiohooks) { + struct ast_audiohook_list *audiohooks_swapper; + audiohooks_swapper = p->chan->audiohooks; + p->chan->audiohooks = p->owner->audiohooks; + p->owner->audiohooks = audiohooks_swapper; + } ast_channel_masquerade(p->owner, p->chan->_bridge); ast_set_flag(p, LOCAL_ALREADY_MASQED); } diff --git a/include/asterisk/channel.h b/include/asterisk/channel.h index be08873aef..ea4dac2bc3 100644 --- a/include/asterisk/channel.h +++ b/include/asterisk/channel.h @@ -542,6 +542,10 @@ struct ast_bridge_config { unsigned int flags; void (* end_bridge_callback)(void *); /*!< A callback that is called after a bridge attempt */ void *end_bridge_callback_data; /*!< Data passed to the callback */ + /*! If the end_bridge_callback_data refers to a channel which no longer is going to + * exist when the end_bridge_callback is called, then it needs to be fixed up properly + */ + void (*end_bridge_callback_data_fixup)(struct ast_bridge_config *bconfig, struct ast_channel *originator, struct ast_channel *terminator); }; struct chanmon; diff --git a/res/res_features.c b/res/res_features.c index 816e1630fe..a5c3dc9b52 100644 --- a/res/res_features.c +++ b/res/res_features.c @@ -982,6 +982,10 @@ static int builtin_atxfer(struct ast_channel *chan, struct ast_channel *peer, st tobj->peer = xferchan; tobj->bconfig = *config; + if (tobj->bconfig.end_bridge_callback_data_fixup) { + tobj->bconfig.end_bridge_callback_data_fixup(&tobj->bconfig, tobj->peer, tobj->chan); + } + if (ast_stream_and_wait(newchan, xfersound, newchan->language, "")) ast_log(LOG_WARNING, "Failed to play transfer sound!\n"); ast_bridge_call_thread_launch(tobj); -- 2.47.3