[asterisk-commits] rmudgett: branch 1.8 r369282 - /branches/1.8/main/features.c
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Fri Jun 22 19:04:33 CDT 2012
Author: rmudgett
Date: Fri Jun 22 19:04:31 2012
New Revision: 369282
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=369282
Log:
Fix Bridge application and AMI Bridge action error handling.
* Fix AMI Bridge action disconnecting the AMI link on error.
* Fix AMI Bridge action and Bridge application not checking if their
masquerades were successful.
* Fix Bridge application running the h-exten when it should not.
* Made do_bridge_masquerade() return if the masquerade was successful so
the Bridge application and AMI Bridge action could deal with it correctly.
* Made bridge_call_thread_launch() hangup the passed in channels if the
bridge_call_thread fails to start. Those channels would have been
orphaned.
* Made builtin_atxfer() check the success of the transfer masquerade
setup.
Modified:
branches/1.8/main/features.c
Modified: branches/1.8/main/features.c
URL: http://svnview.digium.com/svn/asterisk/branches/1.8/main/features.c?view=diff&rev=369282&r1=369281&r2=369282
==============================================================================
--- branches/1.8/main/features.c (original)
+++ branches/1.8/main/features.c Fri Jun 22 19:04:31 2012
@@ -933,8 +933,9 @@
ast_clear_flag(xferchan, AST_FLAGS_ALL);
ast_channel_clear_softhangup(xferchan, AST_SOFTHANGUP_ALL);
- if (ast_do_masquerade(xferchan) || ast_pbx_start(xferchan)) {
- /* Failed to do masquerade or could not start PBX. */
+ ast_do_masquerade(xferchan);
+ if (ast_pbx_start(xferchan)) {
+ /* Failed to start PBX. */
ast_hangup(xferchan);
}
}
@@ -955,7 +956,6 @@
static void *bridge_call_thread(void *data)
{
struct ast_bridge_thread_obj *tobj = data;
- int res;
tobj->chan->appl = !tobj->return_to_pbx ? "Transferred Call" : "ManagerBridge";
tobj->chan->data = tobj->peer->name;
@@ -967,8 +967,7 @@
if (tobj->return_to_pbx) {
if (!ast_check_hangup(tobj->peer)) {
ast_log(LOG_VERBOSE, "putting peer %s into PBX again\n", tobj->peer->name);
- res = ast_pbx_start(tobj->peer);
- if (res != AST_PBX_SUCCESS) {
+ if (ast_pbx_start(tobj->peer)) {
ast_log(LOG_WARNING, "FAILED continuing PBX on peer %s\n", tobj->peer->name);
ast_hangup(tobj->peer);
}
@@ -977,8 +976,7 @@
}
if (!ast_check_hangup(tobj->chan)) {
ast_log(LOG_VERBOSE, "putting chan %s into PBX again\n", tobj->chan->name);
- res = ast_pbx_start(tobj->chan);
- if (res != AST_PBX_SUCCESS) {
+ if (ast_pbx_start(tobj->chan)) {
ast_log(LOG_WARNING, "FAILED continuing PBX on chan %s\n", tobj->chan->name);
ast_hangup(tobj->chan);
}
@@ -1001,7 +999,7 @@
*
* Create thread and attributes, call bridge_call_thread
*/
-static void bridge_call_thread_launch(void *data)
+static void bridge_call_thread_launch(struct ast_bridge_thread_obj *data)
{
pthread_t thread;
pthread_attr_t attr;
@@ -1010,7 +1008,9 @@
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
if (ast_pthread_create(&thread, &attr, bridge_call_thread, data)) {
- ast_log(LOG_WARNING, "Failed to create thread for parked call.\n");
+ ast_hangup(data->chan);
+ ast_hangup(data->peer);
+ ast_log(LOG_ERROR, "Failed to create bridge_call_thread.\n");
}
pthread_attr_destroy(&attr);
memset(&sched, 0, sizeof(sched));
@@ -2809,7 +2809,12 @@
xferchan->readformat = transferee->readformat;
xferchan->writeformat = transferee->writeformat;
- ast_channel_masquerade(xferchan, transferee);
+ if (ast_channel_masquerade(xferchan, transferee)) {
+ ast_hangup(xferchan);
+ ast_hangup(newchan);
+ ast_party_connected_line_free(&connected_line);
+ return -1;
+ }
ast_explicit_goto(xferchan, transferee->context, transferee->exten, transferee->priority);
xferchan->_state = AST_STATE_UP;
ast_clear_flag(xferchan, AST_FLAGS_ALL);
@@ -6799,11 +6804,14 @@
* \brief Actual bridge
* \param chan
* \param tmpchan
- *
+ *
* Stop hold music, lock both channels, masq channels,
* after bridge return channel to next priority.
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
*/
-static void do_bridge_masquerade(struct ast_channel *chan, struct ast_channel *tmpchan)
+static int do_bridge_masquerade(struct ast_channel *chan, struct ast_channel *tmpchan)
{
ast_moh_stop(chan);
ast_channel_lock_both(chan, tmpchan);
@@ -6813,28 +6821,30 @@
ast_channel_unlock(chan);
ast_channel_unlock(tmpchan);
- ast_channel_masquerade(tmpchan, chan);
-
- /* must be done without any channel locks held */
+ /* Masquerade setup and execution must be done without any channel locks held */
+ if (ast_channel_masquerade(tmpchan, chan)) {
+ return -1;
+ }
ast_do_masquerade(tmpchan);
/* when returning from bridge, the channel will continue at the next priority */
ast_explicit_goto(tmpchan, chan->context, chan->exten, chan->priority + 1);
+
+ return 0;
}
/*!
* \brief Bridge channels together
* \param s
* \param m
- *
- * Make sure valid channels were specified,
+ *
+ * Make sure valid channels were specified,
* send errors if any of the channels could not be found/locked, answer channels if needed,
- * create the placeholder channels and grab the other channels
- * make the channels compatible, send error if we fail doing so
+ * create the placeholder channels and grab the other channels
+ * make the channels compatible, send error if we fail doing so
* setup the bridge thread object and start the bridge.
- *
- * \retval 0 on success or on incorrect use.
- * \retval 1 on failure to bridge channels.
+ *
+ * \retval 0
*/
static int action_bridge(struct mansession *s, const struct message *m)
{
@@ -6844,6 +6854,7 @@
struct ast_channel *chana = NULL, *chanb = NULL, *chans[2];
struct ast_channel *tmpchana = NULL, *tmpchanb = NULL;
struct ast_bridge_thread_obj *tobj = NULL;
+ char buf[256];
/* make sure valid channels were specified */
if (ast_strlen_zero(channela) || ast_strlen_zero(channelb)) {
@@ -6853,10 +6864,7 @@
/* Start with chana */
chana = ast_channel_get_by_name_prefix(channela, strlen(channela));
-
- /* send errors if any of the channels could not be found/locked */
if (!chana) {
- char buf[256];
snprintf(buf, sizeof(buf), "Channel1 does not exists: %s", channela);
astman_send_error(s, m, buf);
return 0;
@@ -6871,21 +6879,25 @@
NULL, NULL, chana->linkedid, 0, "Bridge/%s", chana->name))) {
astman_send_error(s, m, "Unable to create temporary channel!");
chana = ast_channel_unref(chana);
- return 1;
- }
-
- do_bridge_masquerade(chana, tmpchana);
+ return 0;
+ }
+
+ if (do_bridge_masquerade(chana, tmpchana)) {
+ snprintf(buf, sizeof(buf), "Unable to masquerade channel %s!", channela);
+ astman_send_error(s, m, buf);
+ ast_hangup(tmpchana);
+ chana = ast_channel_unref(chana);
+ return 0;
+ }
chana = ast_channel_unref(chana);
/* now do chanb */
chanb = ast_channel_get_by_name_prefix(channelb, strlen(channelb));
- /* send errors if any of the channels could not be found/locked */
if (!chanb) {
- char buf[256];
snprintf(buf, sizeof(buf), "Channel2 does not exists: %s", channelb);
+ astman_send_error(s, m, buf);
ast_hangup(tmpchana);
- astman_send_error(s, m, buf);
return 0;
}
@@ -6899,10 +6911,17 @@
astman_send_error(s, m, "Unable to create temporary channels!");
ast_hangup(tmpchana);
chanb = ast_channel_unref(chanb);
- return 1;
- }
-
- do_bridge_masquerade(chanb, tmpchanb);
+ return 0;
+ }
+
+ if (do_bridge_masquerade(chanb, tmpchanb)) {
+ snprintf(buf, sizeof(buf), "Unable to masquerade channel %s!", channelb);
+ astman_send_error(s, m, buf);
+ ast_hangup(tmpchana);
+ ast_hangup(tmpchanb);
+ chanb = ast_channel_unref(chanb);
+ return 0;
+ }
chanb = ast_channel_unref(chanb);
@@ -6912,7 +6931,7 @@
astman_send_error(s, m, "Could not make channels compatible for manager bridge");
ast_hangup(tmpchana);
ast_hangup(tmpchanb);
- return 1;
+ return 0;
}
/* setup the bridge thread object and start the bridge */
@@ -6921,7 +6940,7 @@
astman_send_error(s, m, "Unable to spawn a new bridge thread");
ast_hangup(tmpchana);
ast_hangup(tmpchanb);
- return 1;
+ return 0;
}
tobj->chan = tmpchana;
@@ -7497,7 +7516,7 @@
* \brief Bridge channels
* \param chan
* \param data channel to bridge with.
- *
+ *
* Split data, check we aren't bridging with ourself, check valid channel,
* answer call if not already, check compatible channels, setup bridge config
* now bridge call, if transfered party hangs up return to PBX extension.
@@ -7515,7 +7534,7 @@
AST_APP_ARG(dest_chan);
AST_APP_ARG(options);
);
-
+
if (ast_strlen_zero(data)) {
ast_log(LOG_WARNING, "Bridge require at least 1 argument specifying the other end of the bridge\n");
return -1;
@@ -7530,11 +7549,11 @@
if (!strcmp(chan->name, args.dest_chan)) {
ast_log(LOG_WARNING, "Unable to bridge channel %s with itself\n", chan->name);
ast_manager_event(chan, EVENT_FLAG_CALL, "BridgeExec",
- "Response: Failed\r\n"
- "Reason: Unable to bridge channel to itself\r\n"
- "Channel1: %s\r\n"
- "Channel2: %s\r\n",
- chan->name, args.dest_chan);
+ "Response: Failed\r\n"
+ "Reason: Unable to bridge channel to itself\r\n"
+ "Channel1: %s\r\n"
+ "Channel2: %s\r\n",
+ chan->name, args.dest_chan);
pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "LOOP");
return 0;
}
@@ -7542,20 +7561,15 @@
/* make sure we have a valid end point */
if (!(current_dest_chan = ast_channel_get_by_name_prefix(args.dest_chan,
strlen(args.dest_chan)))) {
- ast_log(LOG_WARNING, "Bridge failed because channel %s does not exists or we "
- "cannot get its lock\n", args.dest_chan);
+ ast_log(LOG_WARNING, "Bridge failed because channel %s does not exist\n",
+ args.dest_chan);
ast_manager_event(chan, EVENT_FLAG_CALL, "BridgeExec",
- "Response: Failed\r\n"
- "Reason: Cannot grab end point\r\n"
- "Channel1: %s\r\n"
- "Channel2: %s\r\n", chan->name, args.dest_chan);
+ "Response: Failed\r\n"
+ "Reason: Channel2 does not exist\r\n"
+ "Channel1: %s\r\n"
+ "Channel2: %s\r\n", chan->name, args.dest_chan);
pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "NONEXISTENT");
return 0;
- }
-
- /* answer the channel if needed */
- if (current_dest_chan->_state != AST_STATE_UP) {
- ast_answer(current_dest_chan);
}
/* try to allocate a place holder where current_dest_chan will be placed */
@@ -7563,13 +7577,45 @@
NULL, NULL, current_dest_chan->linkedid, 0, "Bridge/%s", current_dest_chan->name))) {
ast_log(LOG_WARNING, "Cannot create placeholder channel for chan %s\n", args.dest_chan);
ast_manager_event(chan, EVENT_FLAG_CALL, "BridgeExec",
- "Response: Failed\r\n"
- "Reason: cannot create placeholder\r\n"
- "Channel1: %s\r\n"
- "Channel2: %s\r\n", chan->name, args.dest_chan);
- }
-
- do_bridge_masquerade(current_dest_chan, final_dest_chan);
+ "Response: Failed\r\n"
+ "Reason: Cannot create placeholder channel\r\n"
+ "Channel1: %s\r\n"
+ "Channel2: %s\r\n", chan->name, args.dest_chan);
+ pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "FAILURE");
+ ast_channel_unref(current_dest_chan);
+ return 0;
+ }
+
+ if (ast_test_flag(&opts, OPT_DURATION_LIMIT)
+ && !ast_strlen_zero(opt_args[OPT_ARG_DURATION_LIMIT])
+ && ast_bridge_timelimit(chan, &bconfig, opt_args[OPT_ARG_DURATION_LIMIT], &calldurationlimit)) {
+ ast_manager_event(chan, EVENT_FLAG_CALL, "BridgeExec",
+ "Response: Failed\r\n"
+ "Reason: Cannot setup bridge time limit\r\n"
+ "Channel1: %s\r\n"
+ "Channel2: %s\r\n", chan->name, args.dest_chan);
+ ast_hangup(final_dest_chan);
+ pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "FAILURE");
+ current_dest_chan = ast_channel_unref(current_dest_chan);
+ goto done;
+ }
+
+ if (do_bridge_masquerade(current_dest_chan, final_dest_chan)) {
+ ast_manager_event(chan, EVENT_FLAG_CALL, "BridgeExec",
+ "Response: Failed\r\n"
+ "Reason: Cannot masquerade channels\r\n"
+ "Channel1: %s\r\n"
+ "Channel2: %s\r\n", chan->name, args.dest_chan);
+ ast_hangup(final_dest_chan);
+ pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "FAILURE");
+ current_dest_chan = ast_channel_unref(current_dest_chan);
+ goto done;
+ }
+
+ /* answer the channel if needed */
+ if (final_dest_chan->_state != AST_STATE_UP) {
+ ast_answer(final_dest_chan);
+ }
chans[0] = current_dest_chan;
chans[1] = final_dest_chan;
@@ -7579,21 +7625,26 @@
if (ast_channel_make_compatible(chan, final_dest_chan) < 0) {
ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, final_dest_chan->name);
ast_manager_event_multichan(EVENT_FLAG_CALL, "BridgeExec", 2, chans,
- "Response: Failed\r\n"
- "Reason: Could not make channels compatible for bridge\r\n"
- "Channel1: %s\r\n"
- "Channel2: %s\r\n", chan->name, final_dest_chan->name);
- ast_hangup(final_dest_chan); /* may be we should return this channel to the PBX? */
+ "Response: Failed\r\n"
+ "Reason: Could not make channels compatible for bridge\r\n"
+ "Channel1: %s\r\n"
+ "Channel2: %s\r\n", chan->name, final_dest_chan->name);
+
+ /* Maybe we should return this channel to the PBX? */
+ ast_hangup(final_dest_chan);
+
pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "INCOMPATIBLE");
current_dest_chan = ast_channel_unref(current_dest_chan);
- return 0;
+ goto done;
}
/* Report that the bridge will be successfull */
ast_manager_event_multichan(EVENT_FLAG_CALL, "BridgeExec", 2, chans,
- "Response: Success\r\n"
- "Channel1: %s\r\n"
- "Channel2: %s\r\n", chan->name, final_dest_chan->name);
+ "Response: Success\r\n"
+ "Channel1: %s\r\n"
+ "Channel2: %s\r\n", chan->name, final_dest_chan->name);
+
+ current_dest_chan = ast_channel_unref(current_dest_chan);
/* we have 2 valid channels to bridge, now it is just a matter of setting up the bridge config and starting the bridge */
if (ast_test_flag(&opts, BRIDGE_OPT_PLAYTONE) && !ast_strlen_zero(xfersound)) {
@@ -7601,13 +7652,6 @@
if (ast_waitstream(final_dest_chan, "") < 0)
ast_log(LOG_WARNING, "Failed to play courtesy tone on %s\n", final_dest_chan->name);
}
- }
-
- current_dest_chan = ast_channel_unref(current_dest_chan);
-
- if (ast_test_flag(&opts, OPT_DURATION_LIMIT) && !ast_strlen_zero(opt_args[OPT_ARG_DURATION_LIMIT])) {
- if (ast_bridge_timelimit(chan, &bconfig, opt_args[OPT_ARG_DURATION_LIMIT], &calldurationlimit))
- goto done;
}
if (ast_test_flag(&opts, OPT_CALLEE_TRANSFER))
@@ -7620,41 +7664,47 @@
ast_set_flag(&(bconfig.features_caller), AST_FEATURE_DISCONNECT);
if (ast_test_flag(&opts, OPT_CALLEE_MONITOR))
ast_set_flag(&(bconfig.features_callee), AST_FEATURE_AUTOMON);
- if (ast_test_flag(&opts, OPT_CALLER_MONITOR))
+ if (ast_test_flag(&opts, OPT_CALLER_MONITOR))
ast_set_flag(&(bconfig.features_caller), AST_FEATURE_AUTOMON);
if (ast_test_flag(&opts, OPT_CALLEE_PARK))
ast_set_flag(&(bconfig.features_callee), AST_FEATURE_PARKCALL);
if (ast_test_flag(&opts, OPT_CALLER_PARK))
ast_set_flag(&(bconfig.features_caller), AST_FEATURE_PARKCALL);
+ /*
+ * Don't let the after-bridge code run the h-exten. We want to
+ * continue in the dialplan.
+ */
+ ast_set_flag(chan, AST_FLAG_BRIDGE_HANGUP_DONT);
ast_bridge_call(chan, final_dest_chan, &bconfig);
- /* the bridge has ended, set BRIDGERESULT to SUCCESS. If the other channel has not been hung up, return it to the PBX */
+ /* The bridge has ended, set BRIDGERESULT to SUCCESS. */
pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "SUCCESS");
- if (!ast_check_hangup(final_dest_chan) && !ast_test_flag(&opts, OPT_CALLEE_KILL)) {
- ast_debug(1, "starting new PBX in %s,%s,%d for chan %s\n",
- final_dest_chan->context, final_dest_chan->exten,
- final_dest_chan->priority, final_dest_chan->name);
-
- if (ast_pbx_start(final_dest_chan) != AST_PBX_SUCCESS) {
- ast_log(LOG_WARNING, "FAILED continuing PBX on dest chan %s\n", final_dest_chan->name);
+
+ /* If the other channel has not been hung up, return it to the PBX */
+ if (!ast_check_hangup(final_dest_chan)) {
+ if (!ast_test_flag(&opts, OPT_CALLEE_KILL)) {
+ ast_debug(1, "starting new PBX in %s,%s,%d for chan %s\n",
+ final_dest_chan->context, final_dest_chan->exten,
+ final_dest_chan->priority, final_dest_chan->name);
+
+ if (ast_pbx_start(final_dest_chan)) {
+ ast_log(LOG_WARNING, "FAILED continuing PBX on dest chan %s\n", final_dest_chan->name);
+ ast_hangup(final_dest_chan);
+ } else {
+ ast_debug(1, "SUCCESS continuing PBX on chan %s\n", final_dest_chan->name);
+ }
+ } else {
ast_hangup(final_dest_chan);
- } else
- ast_debug(1, "SUCCESS continuing PBX on chan %s\n", final_dest_chan->name);
+ }
} else {
- ast_debug(1, "hangup chan %s since the other endpoint has hung up or the x flag was passed\n", final_dest_chan->name);
+ ast_debug(1, "chan %s was hungup\n", final_dest_chan->name);
ast_hangup(final_dest_chan);
}
done:
- if (bconfig.warning_sound) {
- ast_free((char *)bconfig.warning_sound);
- }
- if (bconfig.end_sound) {
- ast_free((char *)bconfig.end_sound);
- }
- if (bconfig.start_sound) {
- ast_free((char *)bconfig.start_sound);
- }
+ ast_free((char *) bconfig.warning_sound);
+ ast_free((char *) bconfig.end_sound);
+ ast_free((char *) bconfig.start_sound);
return 0;
}
More information about the asterisk-commits
mailing list