summaryrefslogtreecommitdiff
path: root/main/bridge_basic.c
diff options
context:
space:
mode:
authorRichard Mudgett <rmudgett@digium.com>2014-12-22 21:18:22 +0000
committerRichard Mudgett <rmudgett@digium.com>2014-12-22 21:18:22 +0000
commit7a356232bdf2cd231766459f476f5f0885981878 (patch)
treefc43cd982545cddffa054e43fef007ac7d2777b2 /main/bridge_basic.c
parentfca0be57d9207ba9ceef650cf79802f031f036d3 (diff)
DTMF atxfer: Setup recall channels as if the transferee initiated the call.
After the initial DTMF atxfer call attempt to the transfer target fails to answer during a blonde transfer, the recall callback channels do not get setup with information from the initial transferrer channel. As a result, the recall callback to the transferrer does not have callid, channel variables, datastores, accountcode, peeraccount, COLP, and CLID setup. A similar situation happens with the recall callback to the transfer target but it is less visible. The recall callback to the transfer target does not have callid, channel variables, datastores, accountcode, peeraccount, and COLP setup. * Added missing information to the recall callback channels before initiating the call. callid, channel variables, datastores, accountcode, peeraccount, COLP, and CLID * Set callid of the transferrer channel on the DTMF atxfer controller thread attended_transfer_monitor_thread(). * Added missing channel unlocks and props unref to off nominal paths in attended_transfer_properties_alloc(). ASTERISK-23841 #close Reported by: Richard Mudgett Review: https://reviewboard.asterisk.org/r/4259/ git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/13@430034 65c4cc65-6c06-0410-ace0-fbb531ad65f3
Diffstat (limited to 'main/bridge_basic.c')
-rw-r--r--main/bridge_basic.c108
1 files changed, 106 insertions, 2 deletions
diff --git a/main/bridge_basic.c b/main/bridge_basic.c
index b5305a61f..48b791d9d 100644
--- a/main/bridge_basic.c
+++ b/main/bridge_basic.c
@@ -45,6 +45,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/app.h"
#include "asterisk/dial.h"
#include "asterisk/stasis_bridges.h"
+#include "asterisk/stasis_channels.h"
#include "asterisk/features.h"
#include "asterisk/format_cache.h"
#include "asterisk/test.h"
@@ -1347,6 +1348,8 @@ struct attended_transfer_properties {
struct ast_dial *dial;
/*! The bridging features the transferer has available */
struct ast_flags transferer_features;
+ /*! Saved transferer connected line data for recalling the transferer. */
+ struct ast_party_connected_line original_transferer_colp;
};
static void attended_transfer_properties_destructor(void *obj)
@@ -1361,6 +1364,7 @@ static void attended_transfer_properties_destructor(void *obj)
ast_channel_cleanup(props->transferer);
ast_channel_cleanup(props->transfer_target);
ast_channel_cleanup(props->recall_target);
+ ast_party_connected_line_free(&props->original_transferer_colp);
ast_string_field_free_memory(props);
ast_cond_destroy(&props->cond);
}
@@ -1428,6 +1432,7 @@ static struct attended_transfer_properties *attended_transfer_properties_alloc(
xfer_cfg = ast_get_chan_features_xfer_config(props->transferer);
if (!xfer_cfg) {
ast_log(LOG_ERROR, "Unable to get transfer configuration from channel %s\n", ast_channel_name(props->transferer));
+ ast_channel_unlock(props->transferer);
ao2_ref(props, -1);
return NULL;
}
@@ -1443,11 +1448,20 @@ static struct attended_transfer_properties *attended_transfer_properties_alloc(
ast_string_field_set(props, failsound, xfer_cfg->xferfailsound);
ast_string_field_set(props, xfersound, xfer_cfg->xfersound);
+ /*
+ * Save the transferee's party information for any recall calls.
+ * This is the only piece of information needed that gets overwritten
+ * on the transferer channel by the inital call to the transfer target.
+ */
+ ast_party_connected_line_copy(&props->original_transferer_colp,
+ ast_channel_connected(props->transferer));
+
tech = ast_strdupa(ast_channel_name(props->transferer));
addr = strchr(tech, '/');
if (!addr) {
ast_log(LOG_ERROR, "Transferer channel name does not follow typical channel naming format (tech/address)\n");
- ast_channel_unref(props->transferer);
+ ast_channel_unlock(props->transferer);
+ ao2_ref(props, -1);
return NULL;
}
*addr++ = '\0';
@@ -2331,10 +2345,50 @@ static void recall_callback(struct ast_dial *dial)
}
}
+/*!
+ * \internal
+ * \brief Setup common things to transferrer and transfer_target recall channels.
+ *
+ * \param recall Channel for recalling a party.
+ * \param transferer Channel supplying recall information.
+ *
+ * \details
+ * Setup callid, variables, datastores, accountcode, and peeraccount.
+ *
+ * \pre Both channels are locked on entry.
+ *
+ * \pre COLP and CLID on the recall channel are setup by the caller but not
+ * explicitly published yet.
+ *
+ * \return Nothing
+ */
+static void common_recall_channel_setup(struct ast_channel *recall, struct ast_channel *transferer)
+{
+ struct ast_callid *callid;
+
+ callid = ast_read_threadstorage_callid();
+ if (callid) {
+ ast_channel_callid_set(recall, callid);
+ ast_callid_unref(callid);
+ }
+
+ ast_channel_inherit_variables(transferer, recall);
+ ast_channel_datastore_inherit(transferer, recall);
+
+ /*
+ * Stage a snapshot to ensure that a snapshot is always done
+ * on the recall channel so earler COLP and CLID setup will
+ * get published.
+ */
+ ast_channel_stage_snapshot(recall);
+ ast_channel_req_accountcodes(recall, transferer, AST_CHANNEL_REQUESTOR_REPLACEMENT);
+ ast_channel_stage_snapshot_done(recall);
+}
static int recalling_enter(struct attended_transfer_properties *props)
{
RAII_VAR(struct ast_format_cap *, cap, ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT), ao2_cleanup);
+ struct ast_channel *recall;
if (!cap) {
return -1;
@@ -2360,7 +2414,26 @@ static int recalling_enter(struct attended_transfer_properties *props)
return -1;
}
- ast_dial_set_state_callback(props->dial, &recall_callback);
+ /*
+ * Setup callid, variables, datastores, accountcode, peeraccount,
+ * COLP, and CLID on the recalled transferrer.
+ */
+ recall = ast_dial_get_channel(props->dial, 0);
+ if (!recall) {
+ return -1;
+ }
+ ast_channel_lock_both(recall, props->transferer);
+
+ ast_party_caller_copy(ast_channel_caller(recall),
+ ast_channel_caller(props->transferer));
+ ast_party_connected_line_copy(ast_channel_connected(recall),
+ &props->original_transferer_colp);
+
+ common_recall_channel_setup(recall, props->transferer);
+ ast_channel_unlock(recall);
+ ast_channel_unlock(props->transferer);
+
+ ast_dial_set_state_callback(props->dial, recall_callback);
ao2_ref(props, +1);
ast_dial_set_user_data(props->dial, props);
@@ -2487,6 +2560,20 @@ static int retransfer_enter(struct attended_transfer_properties *props)
return -1;
}
+ /*
+ * Setup callid, variables, datastores, accountcode, peeraccount,
+ * and COLP on the recalled transfer target.
+ */
+ ast_channel_lock_both(props->recall_target, props->transferer);
+
+ ast_party_connected_line_copy(ast_channel_connected(props->recall_target),
+ &props->original_transferer_colp);
+ ast_party_id_reset(&ast_channel_connected(props->recall_target)->priv);
+
+ common_recall_channel_setup(props->recall_target, props->recall_target);
+ ast_channel_unlock(props->recall_target);
+ ast_channel_unlock(props->transferer);
+
if (ast_call(props->recall_target, destination, 0)) {
ast_log(LOG_ERROR, "Unable to place outbound call to recall target\n");
ast_hangup(props->recall_target);
@@ -2881,6 +2968,18 @@ static enum attended_transfer_stimulus wait_for_stimulus(struct attended_transfe
static void *attended_transfer_monitor_thread(void *data)
{
struct attended_transfer_properties *props = data;
+ struct ast_callid *callid;
+
+ /*
+ * Set thread callid to the transferer's callid because we
+ * are doing all this on that channel's behalf.
+ */
+ ast_channel_lock(props->transferer);
+ callid = ast_channel_callid(props->transferer);
+ ast_channel_unlock(props->transferer);
+ if (callid) {
+ ast_callid_threadassoc_add(callid);
+ }
for (;;) {
enum attended_transfer_stimulus stimulus;
@@ -2913,6 +3012,11 @@ static void *attended_transfer_monitor_thread(void *data)
attended_transfer_properties_shutdown(props);
+ if (callid) {
+ ast_callid_unref(callid);
+ ast_callid_threadassoc_remove();
+ }
+
return NULL;
}