From c017d5e6a34fa7e8dc7ba089b5db2338f117c81b Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Fri, 26 Jul 2013 21:34:23 +0000 Subject: Remove the unsafe bridge parameter from ast_bridge_hook_callback's. Most hook callbacks did not need the bridge parameter. The pointer value could become invalid if the channel is moved to another bridge while it is executing. * Fixed some issues in feature_attended_transfer() as a result. * Reduce the bridge inhibit count in attended_transfer_properties_shutdown() after it has restored the bridge channel hooks. * Removed basic bridge requirement on feature_blind_transfer(). It does not require the basic bridge like feature_attended_transfer(). git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@395574 65c4cc65-6c06-0410-ace0-fbb531ad65f3 --- apps/app_agent_pool.c | 9 ++-- apps/app_bridgewait.c | 2 +- apps/app_confbridge.c | 4 +- apps/confbridge/conf_config_parser.c | 3 +- bridges/bridge_builtin_features.c | 14 ++++-- bridges/bridge_builtin_interval_features.c | 6 +-- include/asterisk/bridge_features.h | 19 ++++--- include/asterisk/parking.h | 11 ++-- main/bridge.c | 13 +++-- main/bridge_basic.c | 81 +++++++++++++++++------------- main/bridge_channel.c | 10 ++-- main/features.c | 3 +- main/parking.c | 6 +-- res/parking/parking_bridge_features.c | 15 +++--- 14 files changed, 103 insertions(+), 93 deletions(-) diff --git a/apps/app_agent_pool.c b/apps/app_agent_pool.c index 6ed2ccad1..6beb90a95 100644 --- a/apps/app_agent_pool.c +++ b/apps/app_agent_pool.c @@ -1078,12 +1078,11 @@ static void agent_connect_caller(struct ast_bridge_channel *bridge_channel, stru * The agent is in the new bridge so we can invoke the * mixmonitor hook to only start recording. */ - ast_bridge_features_do(AST_BRIDGE_BUILTIN_AUTOMIXMON, caller_bridge, - bridge_channel, &options); + ast_bridge_features_do(AST_BRIDGE_BUILTIN_AUTOMIXMON, bridge_channel, &options); } } -static int bridge_agent_hold_ack(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt) +static int bridge_agent_hold_ack(struct ast_bridge_channel *bridge_channel, void *hook_pvt) { struct agent_pvt *agent = hook_pvt; @@ -1101,7 +1100,7 @@ static int bridge_agent_hold_ack(struct ast_bridge *bridge, struct ast_bridge_ch return 0; } -static int bridge_agent_hold_heartbeat(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt) +static int bridge_agent_hold_heartbeat(struct ast_bridge_channel *bridge_channel, void *hook_pvt) { struct agent_pvt *agent = hook_pvt; int probation_timedout = 0; @@ -1709,7 +1708,7 @@ static void caller_abort_agent(struct agent_pvt *agent) ast_bridge_channel_unlock(logged); } -static int caller_safety_timeout(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt) +static int caller_safety_timeout(struct ast_bridge_channel *bridge_channel, void *hook_pvt) { struct agent_pvt *agent = hook_pvt; diff --git a/apps/app_bridgewait.c b/apps/app_bridgewait.c index bdfd87e62..5697a79d0 100644 --- a/apps/app_bridgewait.c +++ b/apps/app_bridgewait.c @@ -201,7 +201,7 @@ AST_APP_OPTIONS(bridgewait_opts, { AST_APP_OPTION_ARG('S', MUXFLAG_TIMEOUT, OPT_ARG_TIMEOUT), }); -static int bridgewait_timeout_callback(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt) +static int bridgewait_timeout_callback(struct ast_bridge_channel *bridge_channel, void *hook_pvt) { ast_verb(3, "Channel %s timed out.\n", ast_channel_name(bridge_channel->chan)); ast_bridge_channel_leave_bridge(bridge_channel, BRIDGE_CHANNEL_STATE_END); diff --git a/apps/app_confbridge.c b/apps/app_confbridge.c index 3b58a4d86..01060976d 100644 --- a/apps/app_confbridge.c +++ b/apps/app_confbridge.c @@ -1402,9 +1402,9 @@ static void conf_handle_talker_destructor(void *pvt_data) ast_free(pvt_data); } -static int conf_handle_talker_cb(struct ast_bridge_channel *bridge_channel, void *pvt_data, int talking) +static int conf_handle_talker_cb(struct ast_bridge_channel *bridge_channel, void *hook_pvt, int talking) { - const char *conf_name = pvt_data; + const char *conf_name = hook_pvt; struct confbridge_conference *conference = ao2_find(conference_bridges, conf_name, OBJ_KEY); struct ast_json *talking_extras; diff --git a/apps/confbridge/conf_config_parser.c b/apps/confbridge/conf_config_parser.c index 58431ca3c..984787cb2 100644 --- a/apps/confbridge/conf_config_parser.c +++ b/apps/confbridge/conf_config_parser.c @@ -2080,9 +2080,10 @@ static void menu_hook_destroy(void *hook_pvt) ast_free(pvt); } -static int menu_hook_callback(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt) +static int menu_hook_callback(struct ast_bridge_channel *bridge_channel, void *hook_pvt) { struct dtmf_menu_hook_pvt *pvt = hook_pvt; + return conf_handle_dtmf(bridge_channel, pvt->user, &pvt->menu_entry, pvt->menu); } diff --git a/bridges/bridge_builtin_features.c b/bridges/bridge_builtin_features.c index 324969f33..c22b83548 100644 --- a/bridges/bridge_builtin_features.c +++ b/bridges/bridge_builtin_features.c @@ -214,7 +214,7 @@ static void start_automonitor(struct ast_bridge_channel *bridge_channel, struct pbx_builtin_setvar_helper(peer_chan, "TOUCH_MONITOR_OUTPUT", touch_filename); } -static int feature_automonitor(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt) +static int feature_automonitor(struct ast_bridge_channel *bridge_channel, void *hook_pvt) { const char *start_message; const char *stop_message; @@ -226,7 +226,9 @@ static int feature_automonitor(struct ast_bridge *bridge, struct ast_bridge_chan RAII_VAR(struct ast_features_general_config *, features_cfg, NULL, ao2_cleanup); features_cfg = ast_get_chan_features_general_config(bridge_channel->chan); - peer_chan = ast_bridge_peer(bridge, bridge_channel->chan); + ast_bridge_channel_lock_bridge(bridge_channel); + peer_chan = ast_bridge_peer_nolock(bridge_channel->bridge, bridge_channel->chan); + ast_bridge_unlock(bridge_channel->bridge); if (!peer_chan) { ast_verb(3, "Cannot start AutoMonitor for %s - can not determine peer in bridge.\n", @@ -397,7 +399,7 @@ static void start_automixmonitor(struct ast_bridge_channel *bridge_channel, stru pbx_builtin_setvar_helper(peer_chan, "TOUCH_MIXMONITOR_OUTPUT", touch_filename); } -static int feature_automixmonitor(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt) +static int feature_automixmonitor(struct ast_bridge_channel *bridge_channel, void *hook_pvt) { static const char *mixmonitor_spy_type = "MixMonitor"; const char *stop_message; @@ -410,7 +412,9 @@ static int feature_automixmonitor(struct ast_bridge *bridge, struct ast_bridge_c RAII_VAR(struct ast_features_general_config *, features_cfg, NULL, ao2_cleanup); features_cfg = ast_get_chan_features_general_config(bridge_channel->chan); - peer_chan = ast_bridge_peer(bridge, bridge_channel->chan); + ast_bridge_channel_lock_bridge(bridge_channel); + peer_chan = ast_bridge_peer_nolock(bridge_channel->bridge, bridge_channel->chan); + ast_bridge_unlock(bridge_channel->bridge); if (!peer_chan) { ast_verb(3, "Cannot do AutoMixMonitor for %s - cannot determine peer in bridge.\n", @@ -476,7 +480,7 @@ static int feature_automixmonitor(struct ast_bridge *bridge, struct ast_bridge_c } /*! \brief Internal built in feature for hangup */ -static int feature_hangup(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt) +static int feature_hangup(struct ast_bridge_channel *bridge_channel, void *hook_pvt) { /* * This is very simple, we simply change the state on the diff --git a/bridges/bridge_builtin_interval_features.c b/bridges/bridge_builtin_interval_features.c index 4a091126b..6b8e91b1e 100644 --- a/bridges/bridge_builtin_interval_features.c +++ b/bridges/bridge_builtin_interval_features.c @@ -50,7 +50,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/stringfields.h" #include "asterisk/musiconhold.h" -static int bridge_features_duration_callback(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt) +static int bridge_features_duration_callback(struct ast_bridge_channel *bridge_channel, void *hook_pvt) { struct ast_bridge_features_limits *limits = hook_pvt; @@ -110,7 +110,7 @@ static void limits_interval_playback(struct ast_bridge_channel *bridge_channel, } } -static int bridge_features_connect_callback(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt) +static int bridge_features_connect_callback(struct ast_bridge_channel *bridge_channel, void *hook_pvt) { struct ast_bridge_features_limits *limits = hook_pvt; @@ -118,7 +118,7 @@ static int bridge_features_connect_callback(struct ast_bridge *bridge, struct as return -1; } -static int bridge_features_warning_callback(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt) +static int bridge_features_warning_callback(struct ast_bridge_channel *bridge_channel, void *hook_pvt) { struct ast_bridge_features_limits *limits = hook_pvt; diff --git a/include/asterisk/bridge_features.h b/include/asterisk/bridge_features.h index 3a4fd9444..0a3a21ede 100644 --- a/include/asterisk/bridge_features.h +++ b/include/asterisk/bridge_features.h @@ -118,7 +118,6 @@ struct ast_bridge_channel; /*! * \brief Hook callback type * - * \param bridge The bridge that the channel is part of * \param bridge_channel Channel executing the feature * \param hook_pvt Private data passed in when the hook was created * @@ -131,7 +130,7 @@ struct ast_bridge_channel; * \retval 0 Keep the callback hook. * \retval -1 Remove the callback hook. */ -typedef int (*ast_bridge_hook_callback)(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt); +typedef int (*ast_bridge_hook_callback)(struct ast_bridge_channel *bridge_channel, void *hook_pvt); /*! * \brief Hook pvt destructor callback @@ -143,17 +142,19 @@ typedef void (*ast_bridge_hook_pvt_destructor)(void *hook_pvt); /*! * \brief Talking indicator callback * - * \details This callback can be registered with the bridge in order - * to receive updates on when a bridge_channel has started and stopped - * talking + * \details + * This callback can be registered with the bridge channel in + * order to receive updates when the bridge_channel has started + * and stopped talking. * * \param bridge_channel Channel executing the feature + * \param hook_pvt Private data passed in when the hook was created * \param talking TRUE if the channel is now talking * * \retval 0 Keep the callback hook. * \retval -1 Remove the callback hook. */ -typedef int (*ast_bridge_talking_indicate_callback)(struct ast_bridge_channel *bridge_channel, void *pvt_data, int talking); +typedef int (*ast_bridge_talking_indicate_callback)(struct ast_bridge_channel *bridge_channel, void *hook_pvt, int talking); enum ast_bridge_hook_remove_flags { /*! The hook is removed when the channel is pulled from the bridge. */ @@ -357,6 +358,8 @@ int ast_bridge_features_unregister(enum ast_bridge_builtin_feature feature); * \brief Invoke a built in feature hook now. * * \param feature The feature to invoke + * \param bridge_channel Channel executing the feature + * \param hook_pvt Private data passed in when the hook was created * * \note This API call is only meant to be used by bridge * subclasses and hook callbacks to request a builtin feature @@ -368,10 +371,10 @@ int ast_bridge_features_unregister(enum ast_bridge_builtin_feature feature); * Example usage: * * \code - * ast_bridge_features_do(AST_BRIDGE_BUILTIN_ATTENDED_TRANSFER, bridge, bridge_channel, hook_pvt); + * ast_bridge_features_do(AST_BRIDGE_BUILTIN_ATTENDED_TRANSFER, bridge_channel, hook_pvt); * \endcode */ -int ast_bridge_features_do(enum ast_bridge_builtin_feature feature, struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt); +int ast_bridge_features_do(enum ast_bridge_builtin_feature feature, struct ast_bridge_channel *bridge_channel, void *hook_pvt); /*! * \brief Attach interval hooks to a bridge features structure diff --git a/include/asterisk/parking.h b/include/asterisk/parking.h index dd8a67bf2..4a721200a 100644 --- a/include/asterisk/parking.h +++ b/include/asterisk/parking.h @@ -111,8 +111,7 @@ void ast_bridge_channel_park(struct ast_bridge_channel *bridge_channel, const char *parker_uuid, const char *app_data); -typedef int (*ast_park_blind_xfer_fn)(struct ast_bridge *bridge, struct ast_bridge_channel *parker, - struct ast_exten *park_exten); +typedef int (*ast_park_blind_xfer_fn)(struct ast_bridge_channel *parker, struct ast_exten *park_exten); /*! * \brief install a callback for handling blind transfers to a parking extension @@ -132,15 +131,13 @@ void ast_uninstall_park_blind_xfer_func(void); * \brief use the installed park blind xfer func * \since 12 * - * \param bridge Bridge being transferred from - * \param bridge_channel Bridge channel initiating the transfer - * \param app_data arguments to the park application + * \param parker Bridge channel initiating the park + * \param park_exten Exten to blind transfer part to. * * \retval 0 on success * \retval -1 on failure */ -int ast_park_blind_xfer(struct ast_bridge *bridge, struct ast_bridge_channel *parker, - struct ast_exten *park_exten); +int ast_park_blind_xfer(struct ast_bridge_channel *parker, struct ast_exten *park_exten); typedef void (*ast_bridge_channel_park_fn)(struct ast_bridge_channel *parkee, const char *parkee_uuid, const char *parker_uuid, const char *app_data); diff --git a/main/bridge.c b/main/bridge.c index e3a00ed2e..0b4d95d5e 100644 --- a/main/bridge.c +++ b/main/bridge.c @@ -2675,7 +2675,7 @@ int ast_bridge_features_unregister(enum ast_bridge_builtin_feature feature) return 0; } -int ast_bridge_features_do(enum ast_bridge_builtin_feature feature, struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt) +int ast_bridge_features_do(enum ast_bridge_builtin_feature feature, struct ast_bridge_channel *bridge_channel, void *hook_pvt) { ast_bridge_hook_callback callback; @@ -2687,7 +2687,7 @@ int ast_bridge_features_do(enum ast_bridge_builtin_feature feature, struct ast_b if (!callback) { return -1; } - callback(bridge, bridge_channel, hook_pvt); + callback(bridge_channel, hook_pvt); return 0; } @@ -3777,8 +3777,7 @@ enum try_parking_result { PARKING_NOT_APPLICABLE, }; -static enum try_parking_result try_parking(struct ast_bridge *bridge, struct ast_channel *transferer, - const char *exten, const char *context) +static enum try_parking_result try_parking(struct ast_channel *transferer, const char *exten, const char *context) { RAII_VAR(struct ast_bridge_channel *, transferer_bridge_channel, NULL, ao2_cleanup); struct ast_exten *parking_exten; @@ -3793,7 +3792,7 @@ static enum try_parking_result try_parking(struct ast_bridge *bridge, struct ast parking_exten = ast_get_parking_exten(exten, NULL, context); if (parking_exten) { - return ast_park_blind_xfer(bridge, transferer_bridge_channel, parking_exten) == 0 ? + return ast_park_blind_xfer(transferer_bridge_channel, parking_exten) == 0 ? PARKING_SUCCESS : PARKING_FAILURE; } @@ -3871,7 +3870,7 @@ enum ast_transfer_result ast_bridge_transfer_blind(int is_external, RAII_VAR(struct ast_bridge *, bridge, NULL, ao2_cleanup); RAII_VAR(struct ast_bridge_channel *, bridge_channel, NULL, ao2_cleanup); RAII_VAR(struct ao2_container *, channels, NULL, ao2_cleanup); - RAII_VAR(struct ast_channel *, transferee, NULL, ao2_cleanup); + RAII_VAR(struct ast_channel *, transferee, NULL, ast_channel_cleanup); int do_bridge_transfer; int transfer_prohibited; enum try_parking_result parking_result; @@ -3893,7 +3892,7 @@ enum ast_transfer_result ast_bridge_transfer_blind(int is_external, /* Take off hold if they are on hold. */ ast_bridge_channel_write_unhold(bridge_channel); - parking_result = try_parking(bridge, transferer, exten, context); + parking_result = try_parking(transferer, exten, context); switch (parking_result) { case PARKING_SUCCESS: transfer_result = AST_BRIDGE_TRANSFER_SUCCESS; diff --git a/main/bridge_basic.c b/main/bridge_basic.c index 7eaf30eb9..10c4efb57 100644 --- a/main/bridge_basic.c +++ b/main/bridge_basic.c @@ -265,20 +265,19 @@ struct ast_flags *ast_bridge_features_ds_get(struct ast_channel *chan) * \brief Determine if we should dissolve the bridge from a hangup. * \since 12.0.0 * - * \param bridge The bridge that the channel is part of * \param bridge_channel Channel executing the feature * \param hook_pvt Private data passed in when the hook was created * * \retval 0 Keep the callback hook. * \retval -1 Remove the callback hook. */ -static int basic_hangup_hook(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt) +static int basic_hangup_hook(struct ast_bridge_channel *bridge_channel, void *hook_pvt) { int bridge_count = 0; struct ast_bridge_channel *iter; ast_bridge_channel_lock_bridge(bridge_channel); - AST_LIST_TRAVERSE(&bridge->channels, iter, entry) { + AST_LIST_TRAVERSE(&bridge_channel->bridge->channels, iter, entry) { if (iter != bridge_channel && iter->state == BRIDGE_CHANNEL_STATE_WAIT) { ++bridge_count; } @@ -1069,7 +1068,6 @@ static const char *get_transfer_context(struct ast_channel *transferer, const ch /*! * \brief Allocate and initialize attended transfer properties * - * \param transferee_bridge The bridge where the transfer was initiated * \param transferer The channel performing the attended transfer * \param context Suggestion for what context the transfer target extension can be found in * @@ -1077,8 +1075,7 @@ static const char *get_transfer_context(struct ast_channel *transferer, const ch * \retval non-NULL Newly allocated properties */ static struct attended_transfer_properties *attended_transfer_properties_alloc( - struct ast_bridge *transferee_bridge, struct ast_channel *transferer, - const char *context) + struct ast_channel *transferer, const char *context) { struct attended_transfer_properties *props; char *tech; @@ -1162,9 +1159,9 @@ static void attended_transfer_properties_shutdown(struct attended_transfer_prope ast_debug(1, "Shutting down attended transfer %p\n", props); if (props->transferee_bridge) { - ast_bridge_merge_inhibit(props->transferee_bridge, -1); bridge_basic_change_personality(props->transferee_bridge, BRIDGE_BASIC_PERSONALITY_NORMAL, NULL); + ast_bridge_merge_inhibit(props->transferee_bridge, -1); } if (props->target_bridge) { @@ -2145,7 +2142,7 @@ static int fail_enter(struct attended_transfer_properties *props) * * Sends a stimulus to the attended transfer monitor thread that the abort sequence has been pressed */ -static int atxfer_abort(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt) +static int atxfer_abort(struct ast_bridge_channel *bridge_channel, void *hook_pvt) { struct attended_transfer_properties *props = hook_pvt; @@ -2159,7 +2156,7 @@ static int atxfer_abort(struct ast_bridge *bridge, struct ast_bridge_channel *br * * Sends a stimulus to the attended transfer monitor thread that the complete sequence has been pressed */ -static int atxfer_complete(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt) +static int atxfer_complete(struct ast_bridge_channel *bridge_channel, void *hook_pvt) { struct attended_transfer_properties *props = hook_pvt; @@ -2173,7 +2170,7 @@ static int atxfer_complete(struct ast_bridge *bridge, struct ast_bridge_channel * * Sends a stimulus to the attended transfer monitor thread that the threeway sequence has been pressed */ -static int atxfer_threeway(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt) +static int atxfer_threeway(struct ast_bridge_channel *bridge_channel, void *hook_pvt) { struct attended_transfer_properties *props = hook_pvt; @@ -2187,7 +2184,7 @@ static int atxfer_threeway(struct ast_bridge *bridge, struct ast_bridge_channel * * Sends a stimulus to the attended transfer monitor thread that the swap sequence has been pressed */ -static int atxfer_swap(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt) +static int atxfer_swap(struct ast_bridge_channel *bridge_channel, void *hook_pvt) { struct attended_transfer_properties *props = hook_pvt; @@ -2201,7 +2198,7 @@ static int atxfer_swap(struct ast_bridge *bridge, struct ast_bridge_channel *bri * * Sends a stimulus to the attended transfer monitor thread that the transferer has hung up. */ -static int atxfer_transferer_hangup(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt) +static int atxfer_transferer_hangup(struct ast_bridge_channel *bridge_channel, void *hook_pvt) { struct attended_transfer_properties *props = hook_pvt; @@ -2622,48 +2619,64 @@ static struct ast_channel *dial_transfer(struct ast_channel *caller, const char * an attended transfer. For more information about attended transfer * progress, see documentation on the transfer state machine. * - * \param bridge Bridge where attended transfer DTMF sequence was entered * \param bridge_channel The channel that pressed the attended transfer DTMF sequence * \param hook_pvt Structure with further information about the attended transfer */ -static int feature_attended_transfer(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt) +static int feature_attended_transfer(struct ast_bridge_channel *bridge_channel, void *hook_pvt) { struct ast_bridge_features_attended_transfer *attended_transfer = hook_pvt; struct attended_transfer_properties *props; + struct ast_bridge *bridge; char destination[AST_MAX_EXTENSION + AST_MAX_CONTEXT + 1]; char exten[AST_MAX_EXTENSION] = ""; pthread_t thread; + /* Inhibit the bridge before we do anything else. */ + bridge = ast_bridge_channel_merge_inhibit(bridge_channel, +1); + if (strcmp(bridge->v_table->name, "basic")) { - ast_log(LOG_ERROR, "Attended transfer attempted on unsupported bridge type '%s'\n", bridge->v_table->name); + ast_log(LOG_ERROR, "Attended transfer attempted on unsupported bridge type '%s'.\n", + bridge->v_table->name); + ast_bridge_merge_inhibit(bridge, -1); + ao2_ref(bridge, -1); return 0; } - if (bridge->inhibit_merge) { - ast_log(LOG_ERROR, "Unable to perform attended transfer since bridge '%s' does not permit merging.\n", bridge->uniqueid); + /* Was the bridge inhibited before we inhibited it? */ + if (1 < bridge->inhibit_merge) { + /* + * The peer likely initiated attended transfer at the same time + * and we lost the race. + */ + ast_verb(3, "Channel %s: Bridge '%s' does not permit merging at this time.\n", + ast_channel_name(bridge_channel->chan), bridge->uniqueid); + ast_bridge_merge_inhibit(bridge, -1); + ao2_ref(bridge, -1); return 0; } - props = attended_transfer_properties_alloc(bridge, bridge_channel->chan, - attended_transfer ? attended_transfer->context : NULL); - + props = attended_transfer_properties_alloc(bridge_channel->chan, + attended_transfer ? attended_transfer->context : NULL); if (!props) { - ast_log(LOG_ERROR, "Unable to allocate control structure for performing attended transfer\n"); + ast_log(LOG_ERROR, "Unable to allocate control structure for performing attended transfer.\n"); + ast_bridge_merge_inhibit(bridge, -1); + ao2_ref(bridge, -1); return 0; } + props->transferee_bridge = bridge; + if (add_transferer_role(props->transferer, attended_transfer)) { - ast_log(LOG_ERROR, "Unable to set transferer bridge role properly\n"); + ast_log(LOG_ERROR, "Unable to set transferrer bridge role.\n"); attended_transfer_properties_shutdown(props); return 0; } ast_bridge_channel_write_hold(bridge_channel, NULL); - props->transferee_bridge = ast_bridge_channel_merge_inhibit(bridge_channel, +1); /* Grab the extension to transfer to */ if (grab_transfer(bridge_channel->chan, exten, sizeof(exten), props->context)) { - ast_log(LOG_WARNING, "Unable to acquire target extension for attended transfer\n"); + ast_log(LOG_WARNING, "Unable to acquire target extension for attended transfer.\n"); ast_bridge_channel_write_unhold(bridge_channel); attended_transfer_properties_shutdown(props); return 0; @@ -2679,7 +2692,7 @@ static int feature_attended_transfer(struct ast_bridge *bridge, struct ast_bridg /* Get a channel that is the destination we wish to call */ props->transfer_target = dial_transfer(bridge_channel->chan, destination); if (!props->transfer_target) { - ast_log(LOG_ERROR, "Unable to request outbound channel for attended transfer target\n"); + ast_log(LOG_ERROR, "Unable to request outbound channel for attended transfer target.\n"); ast_stream_and_wait(props->transferer, props->failsound, AST_DIGIT_NONE); ast_bridge_channel_write_unhold(bridge_channel); attended_transfer_properties_shutdown(props); @@ -2690,7 +2703,7 @@ static int feature_attended_transfer(struct ast_bridge *bridge, struct ast_bridg /* Create a bridge to use to talk to the person we are calling */ props->target_bridge = ast_bridge_basic_new(); if (!props->target_bridge) { - ast_log(LOG_ERROR, "Unable to create bridge for attended transfer target\n"); + ast_log(LOG_ERROR, "Unable to create bridge for attended transfer target.\n"); ast_stream_and_wait(props->transferer, props->failsound, AST_DIGIT_NONE); ast_bridge_channel_write_unhold(bridge_channel); ast_hangup(props->transfer_target); @@ -2701,7 +2714,7 @@ static int feature_attended_transfer(struct ast_bridge *bridge, struct ast_bridg ast_bridge_merge_inhibit(props->target_bridge, +1); if (attach_framehook(props, props->transfer_target)) { - ast_log(LOG_ERROR, "Unable to attach framehook to transfer target\n"); + ast_log(LOG_ERROR, "Unable to attach framehook to transfer target.\n"); ast_stream_and_wait(props->transferer, props->failsound, AST_DIGIT_NONE); ast_bridge_channel_write_unhold(bridge_channel); ast_hangup(props->transfer_target); @@ -2716,7 +2729,7 @@ static int feature_attended_transfer(struct ast_bridge *bridge, struct ast_bridg BRIDGE_BASIC_PERSONALITY_ATXFER, props); if (ast_call(props->transfer_target, destination, 0)) { - ast_log(LOG_ERROR, "Unable to place outbound call to transfer target\n"); + ast_log(LOG_ERROR, "Unable to place outbound call to transfer target.\n"); ast_stream_and_wait(bridge_channel->chan, props->failsound, AST_DIGIT_NONE); ast_bridge_channel_write_unhold(bridge_channel); ast_hangup(props->transfer_target); @@ -2731,16 +2744,17 @@ static int feature_attended_transfer(struct ast_bridge *bridge, struct ast_bridg */ ast_channel_ref(props->transfer_target); if (ast_bridge_impart(props->target_bridge, props->transfer_target, NULL, NULL, 1)) { - ast_log(LOG_ERROR, "Unable to place transfer target into bridge\n"); + ast_log(LOG_ERROR, "Unable to place transfer target into bridge.\n"); ast_stream_and_wait(bridge_channel->chan, props->failsound, AST_DIGIT_NONE); ast_bridge_channel_write_unhold(bridge_channel); ast_hangup(props->transfer_target); + props->transfer_target = NULL; attended_transfer_properties_shutdown(props); return 0; } if (ast_pthread_create_detached(&thread, NULL, attended_transfer_monitor_thread, props)) { - ast_log(LOG_ERROR, "Unable to create monitoring thread for attended transfer\n"); + ast_log(LOG_ERROR, "Unable to create monitoring thread for attended transfer.\n"); ast_stream_and_wait(bridge_channel->chan, props->failsound, AST_DIGIT_NONE); ast_bridge_channel_write_unhold(bridge_channel); attended_transfer_properties_shutdown(props); @@ -2764,18 +2778,13 @@ static void blind_transfer_cb(struct ast_channel *new_channel, void *user_data, } /*! \brief Internal built in feature for blind transfers */ -static int feature_blind_transfer(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt) +static int feature_blind_transfer(struct ast_bridge_channel *bridge_channel, void *hook_pvt) { char exten[AST_MAX_EXTENSION] = ""; struct ast_bridge_features_blind_transfer *blind_transfer = hook_pvt; const char *context; char *goto_on_blindxfr; - if (strcmp(bridge->v_table->name, "basic")) { - ast_log(LOG_ERROR, "Blind transfer attempted on unsupported bridge type '%s'\n", bridge->v_table->name); - return 0; - } - ast_bridge_channel_write_hold(bridge_channel, NULL); ast_channel_lock(bridge_channel->chan); diff --git a/main/bridge_channel.c b/main/bridge_channel.c index cec3d1ad1..f887ef576 100644 --- a/main/bridge_channel.c +++ b/main/bridge_channel.c @@ -283,7 +283,7 @@ static void bridge_channel_handle_hangup(struct ast_bridge_channel *bridge_chann if (hook->type != AST_BRIDGE_HOOK_TYPE_HANGUP) { continue; } - remove_me = hook->callback(bridge_channel->bridge, bridge_channel, hook->hook_pvt); + remove_me = hook->callback(bridge_channel, hook->hook_pvt); if (remove_me) { ast_debug(1, "Hangup hook %p is being removed from %p(%s)\n", hook, bridge_channel, ast_channel_name(bridge_channel->chan)); @@ -916,8 +916,7 @@ static void bridge_channel_handle_interval(struct ast_bridge_channel *bridge_cha ast_debug(1, "Executing hook %p on %p(%s)\n", hook, bridge_channel, ast_channel_name(bridge_channel->chan)); - interval = hook->generic.callback(bridge_channel->bridge, bridge_channel, - hook->generic.hook_pvt); + interval = hook->generic.callback(bridge_channel, hook->generic.hook_pvt); ast_heap_wrlock(interval_hooks); if (ast_heap_peek(interval_hooks, hook->timer.heap_index) != hook @@ -1053,8 +1052,7 @@ static void bridge_channel_feature(struct ast_bridge_channel *bridge_channel) if (hook) { int remove_me; - remove_me = hook->generic.callback(bridge_channel->bridge, bridge_channel, - hook->generic.hook_pvt); + remove_me = hook->generic.callback(bridge_channel, hook->generic.hook_pvt); if (remove_me) { ast_debug(1, "DTMF hook %p is being removed from %p(%s)\n", hook, bridge_channel, ast_channel_name(bridge_channel->chan)); @@ -1782,7 +1780,7 @@ static void bridge_channel_event_join_leave(struct ast_bridge_channel *bridge_ch ast_indicate(bridge_channel->chan, AST_CONTROL_SRCUPDATE); do { if (hook->type == type) { - hook->callback(bridge_channel->bridge, bridge_channel, hook->hook_pvt); + hook->callback(bridge_channel, hook->hook_pvt); ao2_unlink(features->other_hooks, hook); } ao2_ref(hook, -1); diff --git a/main/features.c b/main/features.c index 417f18c66..56e47fb91 100644 --- a/main/features.c +++ b/main/features.c @@ -1842,14 +1842,13 @@ struct dynamic_dtmf_hook_data { * \brief Activated dynamic DTMF feature hook. * \since 12.0.0 * - * \param bridge The bridge that the channel is part of * \param bridge_channel Channel executing the feature * \param hook_pvt Private data passed in when the hook was created * * \retval 0 Keep the callback hook. * \retval -1 Remove the callback hook. */ -static int dynamic_dtmf_hook_trip(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt) +static int dynamic_dtmf_hook_trip(struct ast_bridge_channel *bridge_channel, void *hook_pvt) { struct dynamic_dtmf_hook_data *pvt = hook_pvt; int (*run_it)(struct ast_bridge_channel *bridge_channel, ast_bridge_custom_callback_fn callback, const void *payload, size_t payload_size); diff --git a/main/parking.c b/main/parking.c index 820cffdea..710a3c8c7 100644 --- a/main/parking.c +++ b/main/parking.c @@ -147,12 +147,12 @@ void ast_uninstall_bridge_channel_park_func(void) ast_bridge_channel_park_func = NULL; } -int ast_park_blind_xfer(struct ast_bridge *bridge, struct ast_bridge_channel *parker, - struct ast_exten *park_exten) +int ast_park_blind_xfer(struct ast_bridge_channel *parker, struct ast_exten *park_exten) { static int warned = 0; + if (ast_park_blind_xfer_func) { - return ast_park_blind_xfer_func(bridge, parker, park_exten); + return ast_park_blind_xfer_func(parker, park_exten); } if (warned++ % 10 == 0) { diff --git a/res/parking/parking_bridge_features.c b/res/parking/parking_bridge_features.c index 1d9e3dada..e44a7695b 100644 --- a/res/parking/parking_bridge_features.c +++ b/res/parking/parking_bridge_features.c @@ -183,7 +183,7 @@ static int create_parked_subscription(struct ast_channel *chan, const char *park /*! * \internal * \brief Helper function that creates an outgoing channel and returns it immediately. This function is nearly - * identical to the dial_transfer function in bridge_builtin_features.c, however it doesn't swap the + * identical to the dial_transfer function in bridge_basic.c, however it doesn't swap the * local channel and the channel that instigated the park. */ static struct ast_channel *park_local_transfer(struct ast_channel *parker, const char *exten, const char *context) @@ -242,7 +242,7 @@ static struct ast_channel *park_local_transfer(struct ast_channel *parker, const return parkee; } -static int park_feature_helper(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, struct ast_exten *park_exten) +static int park_feature_helper(struct ast_bridge_channel *bridge_channel, struct ast_exten *park_exten) { RAII_VAR(struct ast_channel *, other, NULL, ao2_cleanup); RAII_VAR(struct parking_lot *, lot, NULL, ao2_cleanup); @@ -251,7 +251,9 @@ static int park_feature_helper(struct ast_bridge *bridge, struct ast_bridge_chan RAII_VAR(struct ao2_container *, bridge_peers, NULL, ao2_cleanup); struct ao2_iterator iter; - bridge_peers = ast_bridge_peers(bridge); + ast_bridge_channel_lock_bridge(bridge_channel); + bridge_peers = ast_bridge_peers_nolock(bridge_channel->bridge); + ast_bridge_unlock(bridge_channel->bridge); if (ao2_container_count(bridge_peers) < 2) { /* There is nothing to do if there is no one to park. */ @@ -357,20 +359,19 @@ static void park_bridge_channel(struct ast_bridge_channel *bridge_channel, const } } -static int feature_park(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt) +static int feature_park(struct ast_bridge_channel *bridge_channel, void *hook_pvt) { - park_feature_helper(bridge, bridge_channel, NULL); + park_feature_helper(bridge_channel, NULL); return 0; } /*! \internal * \brief Interval hook. Pulls a parked call from the parking bridge after the timeout is passed and sets the resolution to timeout. * - * \param bridge Which bridge the channel was parked in * \param bridge_channel bridge channel this interval hook is being executed on * \param hook_pvt A pointer to the parked_user struct associated with the channel is stuffed in here */ -static int parking_duration_callback(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt) +static int parking_duration_callback(struct ast_bridge_channel *bridge_channel, void *hook_pvt) { struct parked_user *user = hook_pvt; struct ast_channel *chan = user->chan; -- cgit v1.2.3