From 477dea46616c0a6b79706f10349aaf9a87832e0e Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Thu, 22 Aug 2013 21:09:52 +0000 Subject: Bridge API: Set a cause code on a channel when it is ejected from a bridge. The cause code needs to be passed from the disconnecting channel to the bridge peers if the disconnecting channel dissolves the bridge. * Made the call to an app_agent_pool agent disconnect with the busy cause code if the agent does not ack the call in time or hangs up before acking the call. (closes issue ASTERISK-22042) Reported by: Matt Jordan Review: https://reviewboard.asterisk.org/r/2772/ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@397472 65c4cc65-6c06-0410-ace0-fbb531ad65f3 --- apps/app_agent_pool.c | 45 ++++++++++++++++++++++++++++----------------- apps/app_bridgewait.c | 10 ++++++---- apps/app_confbridge.c | 2 +- apps/app_dial.c | 1 - 4 files changed, 35 insertions(+), 23 deletions(-) (limited to 'apps') diff --git a/apps/app_agent_pool.c b/apps/app_agent_pool.c index d4446ceb5..cb5e0ce17 100644 --- a/apps/app_agent_pool.c +++ b/apps/app_agent_pool.c @@ -49,6 +49,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/astobj2.h" #include "asterisk/stringfields.h" #include "asterisk/stasis_channels.h" +#include "asterisk/causes.h" /*** DOCUMENTATION @@ -760,7 +761,7 @@ static void agent_pvt_destructor(void *vdoomed) ast_party_connected_line_free(&doomed->waiting_colp); if (doomed->caller_bridge) { - ast_bridge_destroy(doomed->caller_bridge); + ast_bridge_destroy(doomed->caller_bridge, AST_CAUSE_USER_BUSY); doomed->caller_bridge = NULL; } if (doomed->logged) { @@ -1019,15 +1020,17 @@ static void agent_connect_caller(struct ast_bridge_channel *bridge_channel, stru if (!caller_bridge) { /* Reset agent. */ - ast_bridge_channel_leave_bridge(bridge_channel, BRIDGE_CHANNEL_STATE_END); + ast_bridge_channel_leave_bridge(bridge_channel, BRIDGE_CHANNEL_STATE_END, + AST_CAUSE_NORMAL_CLEARING); return; } res = ast_bridge_move(caller_bridge, bridge_channel->bridge, bridge_channel->chan, NULL, 0); if (res) { /* Reset agent. */ - ast_bridge_destroy(caller_bridge); - ast_bridge_channel_leave_bridge(bridge_channel, BRIDGE_CHANNEL_STATE_END); + ast_bridge_destroy(caller_bridge, AST_CAUSE_USER_BUSY); + ast_bridge_channel_leave_bridge(bridge_channel, BRIDGE_CHANNEL_STATE_END, + AST_CAUSE_NORMAL_CLEARING); return; } ast_bridge_channel_write_control_data(bridge_channel, AST_CONTROL_ANSWER, NULL, 0); @@ -1122,13 +1125,15 @@ static int bridge_agent_hold_heartbeat(struct ast_bridge_channel *bridge_channel if (deferred_logoff) { ast_debug(1, "Agent %s: Deferred logoff.\n", agent->username); - ast_bridge_channel_leave_bridge(bridge_channel, BRIDGE_CHANNEL_STATE_END); + ast_bridge_channel_leave_bridge(bridge_channel, BRIDGE_CHANNEL_STATE_END, + AST_CAUSE_NORMAL_CLEARING); } else if (probation_timedout) { ast_debug(1, "Agent %s: Login complete.\n", agent->username); agent_devstate_changed(agent->username); } else if (ack_timedout) { ast_debug(1, "Agent %s: Ack call timeout.\n", agent->username); - ast_bridge_channel_leave_bridge(bridge_channel, BRIDGE_CHANNEL_STATE_END); + ast_bridge_channel_leave_bridge(bridge_channel, BRIDGE_CHANNEL_STATE_END, + AST_CAUSE_NORMAL_CLEARING); } else if (wrapup_timedout) { ast_debug(1, "Agent %s: Wrapup timeout. Ready for new call.\n", agent->username); agent_devstate_changed(agent->username); @@ -1233,7 +1238,8 @@ static int bridge_agent_hold_push(struct ast_bridge *self, struct ast_bridge_cha * agent will have some slightly different behavior in corner * cases. */ - ast_bridge_channel_leave_bridge(bridge_channel, BRIDGE_CHANNEL_STATE_END); + ast_bridge_channel_leave_bridge(bridge_channel, BRIDGE_CHANNEL_STATE_END, + AST_CAUSE_NORMAL_CLEARING); return 0; } @@ -1455,7 +1461,7 @@ static void agent_logout(struct agent_pvt *agent) agent_devstate_changed(agent->username); if (caller_bridge) { - ast_bridge_destroy(caller_bridge); + ast_bridge_destroy(caller_bridge, AST_CAUSE_USER_BUSY); } send_agent_logoff(logged, agent->username, time_logged_in); @@ -1479,6 +1485,7 @@ static void agent_run(struct agent_pvt *agent, struct ast_channel *logged) struct ast_bridge_features features; if (ast_bridge_features_init(&features)) { + ast_channel_hangupcause_set(logged, AST_CAUSE_NORMAL_CLEARING); goto agent_run_cleanup; } for (;;) { @@ -1488,6 +1495,8 @@ static void agent_run(struct agent_pvt *agent, struct ast_channel *logged) struct ast_bridge *holding; struct ast_bridge *caller_bridge; + ast_channel_hangupcause_set(logged, AST_CAUSE_NORMAL_CLEARING); + holding = ao2_global_obj_ref(agent_holding); if (!holding) { ast_debug(1, "Agent %s: Someone destroyed the agent holding bridge.\n", @@ -1535,7 +1544,7 @@ static void agent_run(struct agent_pvt *agent, struct ast_channel *logged) agent_unlock(agent); ao2_ref(cfg_old, -1); if (caller_bridge) { - ast_bridge_destroy(caller_bridge); + ast_bridge_destroy(caller_bridge, AST_CAUSE_USER_BUSY); } if (agent->state == AGENT_STATE_LOGGING_OUT @@ -1661,13 +1670,14 @@ static void caller_abort_agent(struct agent_pvt *agent) agent->caller_bridge = NULL; agent_unlock(agent); if (caller_bridge) { - ast_bridge_destroy(caller_bridge); + ast_bridge_destroy(caller_bridge, AST_CAUSE_USER_BUSY); } return; } /* Kick the agent out of the holding bridge to reset it. */ - ast_bridge_channel_leave_bridge_nolock(logged, BRIDGE_CHANNEL_STATE_END); + ast_bridge_channel_leave_bridge_nolock(logged, BRIDGE_CHANNEL_STATE_END, + AST_CAUSE_NORMAL_CLEARING); ast_bridge_channel_unlock(logged); } @@ -1677,7 +1687,8 @@ static int caller_safety_timeout(struct ast_bridge_channel *bridge_channel, void if (agent->state == AGENT_STATE_CALL_PRESENT) { ast_verb(3, "Agent '%s' did not respond. Safety timeout.\n", agent->username); - ast_bridge_channel_leave_bridge(bridge_channel, BRIDGE_CHANNEL_STATE_END); + ast_bridge_channel_leave_bridge(bridge_channel, BRIDGE_CHANNEL_STATE_END, + AST_CAUSE_USER_BUSY); caller_abort_agent(agent); } @@ -1829,7 +1840,7 @@ static int agent_request_exec(struct ast_channel *chan, const char *data) case AGENT_STATE_LOGGING_OUT: agent_unlock(agent); ast_party_connected_line_free(&connected); - ast_bridge_destroy(caller_bridge); + ast_bridge_destroy(caller_bridge, 0); ast_bridge_features_cleanup(&caller_features); ast_verb(3, "Agent '%s' not logged in.\n", agent->username); pbx_builtin_setvar_helper(chan, "AGENT_STATUS", "NOT_LOGGED_IN"); @@ -1843,7 +1854,7 @@ static int agent_request_exec(struct ast_channel *chan, const char *data) default: agent_unlock(agent); ast_party_connected_line_free(&connected); - ast_bridge_destroy(caller_bridge); + ast_bridge_destroy(caller_bridge, 0); ast_bridge_features_cleanup(&caller_features); ast_verb(3, "Agent '%s' is busy.\n", agent->username); pbx_builtin_setvar_helper(chan, "AGENT_STATUS", "BUSY"); @@ -1855,7 +1866,7 @@ static int agent_request_exec(struct ast_channel *chan, const char *data) logged = agent_bridge_channel_get_lock(agent); if (!logged) { ast_party_connected_line_free(&connected); - ast_bridge_destroy(caller_bridge); + ast_bridge_destroy(caller_bridge, 0); ast_bridge_features_cleanup(&caller_features); ast_verb(3, "Agent '%s' not logged in.\n", agent->username); pbx_builtin_setvar_helper(chan, "AGENT_STATUS", "NOT_LOGGED_IN"); @@ -1870,7 +1881,7 @@ static int agent_request_exec(struct ast_channel *chan, const char *data) ast_bridge_channel_unlock(logged); ao2_ref(logged, -1); if (res) { - ast_bridge_destroy(caller_bridge); + ast_bridge_destroy(caller_bridge, 0); ast_bridge_features_cleanup(&caller_features); ast_verb(3, "Agent '%s': Failed to alert the agent.\n", agent->username); pbx_builtin_setvar_helper(chan, "AGENT_STATUS", "ERROR"); @@ -2499,7 +2510,7 @@ static int unload_module(void) /* Destroy agent holding bridge. */ holding = ao2_global_obj_replace(agent_holding, NULL); if (holding) { - ast_bridge_destroy(holding); + ast_bridge_destroy(holding, 0); } destroy_config(); diff --git a/apps/app_bridgewait.c b/apps/app_bridgewait.c index 36747056e..8e615f05f 100644 --- a/apps/app_bridgewait.c +++ b/apps/app_bridgewait.c @@ -48,6 +48,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/bridge.h" #include "asterisk/musiconhold.h" #include "asterisk/astobj2.h" +#include "asterisk/causes.h" /*** DOCUMENTATION @@ -127,8 +128,9 @@ struct wait_bridge_wrapper { static void wait_bridge_wrapper_destructor(void *obj) { struct wait_bridge_wrapper *wrapper = obj; + if (wrapper->bridge) { - ast_bridge_destroy(wrapper->bridge); + ast_bridge_destroy(wrapper->bridge, 0); } } @@ -204,7 +206,8 @@ AST_APP_OPTIONS(bridgewait_opts, { 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); + ast_bridge_channel_leave_bridge(bridge_channel, BRIDGE_CHANNEL_STATE_END, + AST_CAUSE_NORMAL_CLEARING); return -1; } @@ -321,9 +324,8 @@ static struct wait_bridge_wrapper *wait_bridge_wrapper_alloc(const char *bridge_ bridge_wrapper = ao2_alloc_options(sizeof(*bridge_wrapper) + strlen(bridge_name) + 1, wait_bridge_wrapper_destructor, AO2_ALLOC_OPT_LOCK_NOLOCK); - if (!bridge_wrapper) { - ast_bridge_destroy(bridge); + ast_bridge_destroy(bridge, 0); return NULL; } diff --git a/apps/app_confbridge.c b/apps/app_confbridge.c index 79631225e..d9db7ab5b 100644 --- a/apps/app_confbridge.c +++ b/apps/app_confbridge.c @@ -892,7 +892,7 @@ static void destroy_conference_bridge(void *obj) /* Destroying a conference bridge is simple, all we have to do is destroy the bridging object */ if (conference->bridge) { - ast_bridge_destroy(conference->bridge); + ast_bridge_destroy(conference->bridge, 0); conference->bridge = NULL; } diff --git a/apps/app_dial.c b/apps/app_dial.c index 4397c5090..c053820dc 100644 --- a/apps/app_dial.c +++ b/apps/app_dial.c @@ -3024,7 +3024,6 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast ast_channel_setoption(chan, AST_OPTION_OPRMODE, &oprmode, sizeof(oprmode), 0); } -/* BUGBUG bridge needs to set hangup cause on chan when peer breaks the bridge. */ setup_peer_after_bridge_goto(chan, peer, &opts, opt_args); res = ast_bridge_call(chan, peer, &config); } -- cgit v1.2.3