[svn-commits] jrose: trunk r414403 - in /trunk: ./ channels/ include/asterisk/ main/ res/ r...

SVN commits to the Digium repositories svn-commits at lists.digium.com
Thu May 22 10:52:37 CDT 2014


Author: jrose
Date: Thu May 22 10:52:30 2014
New Revision: 414403

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=414403
Log:
res_pjsip_refer: Fix bugs involving Parking/PJSIP/transfers

PJSIP would never send the final 200 Notify for a blind transfer
when transferring to parking. This patch fixes that. In addition,
it fixes a reference leak when performing blind transfers to
non-bridging extensions.

Review: https://reviewboard.asterisk.org/r/3485/
........

Merged revisions 414400 from http://svn.asterisk.org/svn/asterisk/branches/12

Modified:
    trunk/   (props changed)
    trunk/channels/chan_dahdi.c
    trunk/channels/chan_mgcp.c
    trunk/channels/chan_sip.c
    trunk/channels/sig_analog.c
    trunk/include/asterisk/bridge.h
    trunk/include/asterisk/parking.h
    trunk/main/bridge.c
    trunk/main/bridge_basic.c
    trunk/main/parking.c
    trunk/res/parking/parking_applications.c
    trunk/res/parking/parking_bridge_features.c
    trunk/res/res_pjsip_refer.c

Propchange: trunk/
------------------------------------------------------------------------------
Binary property 'branch-12-merged' - no diff available.

Modified: trunk/channels/chan_dahdi.c
URL: http://svnview.digium.com/svn/asterisk/trunk/channels/chan_dahdi.c?view=diff&rev=414403&r1=414402&r2=414403
==============================================================================
--- trunk/channels/chan_dahdi.c (original)
+++ trunk/channels/chan_dahdi.c Thu May 22 10:52:30 2014
@@ -9741,7 +9741,7 @@
 				bridge_channel = ast_channel_get_bridge_channel(p->subs[SUB_THREEWAY].owner);
 				ast_channel_unlock(p->subs[SUB_THREEWAY].owner);
 				if (bridge_channel) {
-					if (!ast_parking_blind_transfer_park(bridge_channel, ast_channel_context(chan), exten)) {
+					if (!ast_parking_blind_transfer_park(bridge_channel, ast_channel_context(chan), exten, NULL, NULL)) {
 						/*
 						 * Swap things around between the three-way and real call so we
 						 * can hear where the channel got parked.

Modified: trunk/channels/chan_mgcp.c
URL: http://svnview.digium.com/svn/asterisk/trunk/channels/chan_mgcp.c?view=diff&rev=414403&r1=414402&r2=414403
==============================================================================
--- trunk/channels/chan_mgcp.c (original)
+++ trunk/channels/chan_mgcp.c Thu May 22 10:52:30 2014
@@ -3167,7 +3167,7 @@
 			ast_channel_lock(chan);
 			bridge_channel = ast_channel_get_bridge_channel(chan);
 			ast_channel_unlock(chan);
-			if (bridge_channel && !ast_parking_blind_transfer_park(bridge_channel, ast_channel_context(chan), p->dtmf_buf)) {
+			if (bridge_channel && !ast_parking_blind_transfer_park(bridge_channel, ast_channel_context(chan), p->dtmf_buf, NULL, NULL)) {
 				ast_verb(3, "Parking call to '%s'\n", ast_channel_name(chan));
 			}
 			break;

Modified: trunk/channels/chan_sip.c
URL: http://svnview.digium.com/svn/asterisk/trunk/channels/chan_sip.c?view=diff&rev=414403&r1=414402&r2=414403
==============================================================================
--- trunk/channels/chan_sip.c (original)
+++ trunk/channels/chan_sip.c Thu May 22 10:52:30 2014
@@ -26081,10 +26081,10 @@
  * \param user_data A blind_transfer_cb_data struct
  * \param transfer_type Unused
  */
-static void blind_transfer_cb(struct ast_channel *chan, void *user_data,
+static void blind_transfer_cb(struct ast_channel *chan, struct transfer_channel_data *user_data_wrapper,
 		enum ast_transfer_type transfer_type)
 {
-	struct blind_transfer_cb_data *cb_data = user_data;
+	struct blind_transfer_cb_data *cb_data = user_data_wrapper->data;
 
 	pbx_builtin_setvar_helper(chan, "SIPTRANSFER", "yes");
 	pbx_builtin_setvar_helper(chan, "SIPTRANSFER_REFERER", cb_data->referred_by);

Modified: trunk/channels/sig_analog.c
URL: http://svnview.digium.com/svn/asterisk/trunk/channels/sig_analog.c?view=diff&rev=414403&r1=414402&r2=414403
==============================================================================
--- trunk/channels/sig_analog.c (original)
+++ trunk/channels/sig_analog.c Thu May 22 10:52:30 2014
@@ -2259,7 +2259,7 @@
 				bridge_channel = ast_channel_get_bridge_channel(p->subs[ANALOG_SUB_THREEWAY].owner);
 				ast_channel_unlock(p->subs[ANALOG_SUB_THREEWAY].owner);
 				if (bridge_channel) {
-					if (!ast_parking_blind_transfer_park(bridge_channel, ast_channel_context(chan), exten)) {
+					if (!ast_parking_blind_transfer_park(bridge_channel, ast_channel_context(chan), exten, NULL, NULL)) {
 						/*
 						 * Swap things around between the three-way and real call so we
 						 * can hear where the channel got parked.

Modified: trunk/include/asterisk/bridge.h
URL: http://svnview.digium.com/svn/asterisk/trunk/include/asterisk/bridge.h?view=diff&rev=414403&r1=414402&r2=414403
==============================================================================
--- trunk/include/asterisk/bridge.h (original)
+++ trunk/include/asterisk/bridge.h Thu May 22 10:52:30 2014
@@ -904,6 +904,22 @@
 };
 
 /*!
+ * \brief AO2 object that wraps data for transfer_channel_cb
+ */
+struct transfer_channel_data {
+	void *data;    /*! Data to be used by the transfer_channel_cb -- note that this
+	                *  pointer is going to be pointing to something on the stack, so
+	                *  it must not be used at any point after returning from the
+	                *  transfer_channel_cb. */
+	int completed; /*! Initially 0, This will be set to 1 by either the transfer
+	                *  code or by transfer code hooks (e.g. parking) when the
+	                *  transfer is completed and any remaining actions have taken
+	                *  place (e.g. parking announcements). It will never be reset
+	                *  to 0. This is used for deferring progress for channel
+	                *  drivers that support deferred progress. */
+};
+
+/*!
  * \brief Callback function type called during blind transfers
  *
  * A caller of ast_bridge_transfer_blind() may wish to set data on
@@ -914,7 +930,7 @@
  * \param user_data User-provided data needed in the callback
  * \param transfer_type The type of transfer being completed
  */
-typedef void (*transfer_channel_cb)(struct ast_channel *chan, void *user_data,
+typedef void (*transfer_channel_cb)(struct ast_channel *chan, struct transfer_channel_data *user_data,
 		enum ast_transfer_type transfer_type);
 
 /*!

Modified: trunk/include/asterisk/parking.h
URL: http://svnview.digium.com/svn/asterisk/trunk/include/asterisk/parking.h?view=diff&rev=414403&r1=414402&r2=414403
==============================================================================
--- trunk/include/asterisk/parking.h (original)
+++ trunk/include/asterisk/parking.h Thu May 22 10:52:30 2014
@@ -24,6 +24,7 @@
  */
 
 #include "asterisk/stringfields.h"
+#include "asterisk/bridge.h"
 
 /*!
  * \brief The default parking application that Asterisk expects.
@@ -163,6 +164,8 @@
 	 * \param parker The \ref bridge_channel object that is initiating the parking
 	 * \param context The context to blind transfer to
 	 * \param exten The extension to blind transfer to
+	 * \param parked_channel_cb Execute the following function on the the channel that gets parked
+	 * \param parked_channel_data Data for the parked_channel_cb
 	 *
 	 * \note If the bridge \ref parker is in has more than one other occupant, the entire
 	 * bridge will be parked using a Local channel
@@ -172,7 +175,8 @@
 	 * \retval 0 on success
 	 * \retval non-zero on error
 	 */
-	int (* parking_blind_transfer_park)(struct ast_bridge_channel *parker, const char *context, const char *exten);
+	int (* parking_blind_transfer_park)(struct ast_bridge_channel *parker, const char *context,
+		const char *exten, transfer_channel_cb parked_channel_cb, struct transfer_channel_data *parked_channel_data);
 
 	/*!
 	 * \brief Perform a direct park on a channel in a bridge.
@@ -224,6 +228,9 @@
  * \param parker The \ref bridge_channel object that is initiating the parking
  * \param context The context to blind transfer to
  * \param exten The extension to blind transfer to
+ * \param exten The extension to blind transfer to
+ * \param parked_channel_cb Execute the following function on the the channel that gets parked
+ * \param parked_channel_data Data for the parked_channel_cb
  *
  * \note If the bridge \ref parker is in has more than one other occupant, the entire
  * bridge will be parked using a Local channel
@@ -233,7 +240,8 @@
  * \retval 0 on success
  * \retval non-zero on error
  */
-int ast_parking_blind_transfer_park(struct ast_bridge_channel *parker, const char *context, const char *exten);
+int ast_parking_blind_transfer_park(struct ast_bridge_channel *parker, const char *context,
+	const char *exten, transfer_channel_cb parked_channel_cb, struct transfer_channel_data *parked_channel_data);
 
 /*!
  * \brief Perform a direct park on a channel in a bridge.

Modified: trunk/main/bridge.c
URL: http://svnview.digium.com/svn/asterisk/trunk/main/bridge.c?view=diff&rev=414403&r1=414402&r2=414403
==============================================================================
--- trunk/main/bridge.c (original)
+++ trunk/main/bridge.c Thu May 22 10:52:30 2014
@@ -3718,7 +3718,7 @@
  */
 static enum ast_transfer_result blind_transfer_bridge(struct ast_channel *transferer,
 		struct ast_bridge *bridge, const char *exten, const char *context,
-		transfer_channel_cb new_channel_cb, void *user_data)
+		transfer_channel_cb new_channel_cb, struct transfer_channel_data *user_data_wrapper)
 {
 	struct ast_channel *local;
 	char chan_name[AST_MAX_EXTENSION + AST_MAX_CONTEXT + 2];
@@ -3734,7 +3734,7 @@
 	pbx_builtin_setvar_helper(local, BLINDTRANSFER, ast_channel_name(transferer));
 
 	if (new_channel_cb) {
-		new_channel_cb(local, user_data, AST_BRIDGE_TRANSFER_MULTI_PARTY);
+		new_channel_cb(local, user_data_wrapper, AST_BRIDGE_TRANSFER_MULTI_PARTY);
 	}
 
 	if (ast_call(local, chan_name, 0)) {
@@ -3968,7 +3968,9 @@
 	return transferee;
 }
 
-static enum ast_transfer_result try_parking(struct ast_channel *transferer, const char *context, const char *exten)
+static enum ast_transfer_result try_parking(struct ast_channel *transferer,
+	const char *context, const char *exten, transfer_channel_cb new_channel_cb,
+	struct transfer_channel_data *user_data_wrapper)
 {
 	RAII_VAR(struct ast_bridge_channel *, transferer_bridge_channel, NULL, ao2_cleanup);
 
@@ -3985,7 +3987,7 @@
 	}
 
 	if (ast_parking_blind_transfer_park(transferer_bridge_channel,
-		context, exten)) {
+		context, exten, new_channel_cb, user_data_wrapper)) {
 		return AST_BRIDGE_TRANSFER_FAIL;
 	}
 
@@ -4089,6 +4091,7 @@
 	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, ast_channel_cleanup);
+	RAII_VAR(struct transfer_channel_data *, user_data_wrapper, NULL, ao2_cleanup);
 	int do_bridge_transfer;
 	int transfer_prohibited;
 	enum ast_transfer_result transfer_result;
@@ -4106,13 +4109,24 @@
 		goto publish;
 	}
 
+	user_data_wrapper = ao2_alloc(sizeof(*user_data_wrapper), NULL);
+	if (!user_data_wrapper) {
+		transfer_result = AST_BRIDGE_TRANSFER_FAIL;
+		goto publish;
+	}
+
+	user_data_wrapper->data = user_data;
+
 	/* Take off hold if they are on hold. */
 	ast_bridge_channel_write_unhold(bridge_channel);
 
-	transfer_result = try_parking(transferer, context, exten);
+	transfer_result = try_parking(transferer, context, exten, new_channel_cb, user_data_wrapper);
 	if (transfer_result == AST_BRIDGE_TRANSFER_SUCCESS) {
 		goto publish;
 	}
+
+	/* Since parking didn't take control of the user_data_wrapper, we are just going to raise the completed flag now. */
+	user_data_wrapper->completed = 1;
 
 	{
 		SCOPED_LOCK(lock, bridge, ast_bridge_lock, ast_bridge_unlock);
@@ -4142,7 +4156,7 @@
 
 	if (do_bridge_transfer) {
 		transfer_result = blind_transfer_bridge(transferer, bridge, exten, context,
-				new_channel_cb, user_data);
+				new_channel_cb, user_data_wrapper);
 		goto publish;
 	}
 
@@ -4155,7 +4169,7 @@
 	}
 
 	if (bridge_channel_internal_queue_blind_transfer(transferee, exten, context,
-				new_channel_cb, user_data)) {
+				new_channel_cb, user_data_wrapper)) {
 		transfer_result = AST_BRIDGE_TRANSFER_FAIL;
 		goto publish;
 	}

Modified: trunk/main/bridge_basic.c
URL: http://svnview.digium.com/svn/asterisk/trunk/main/bridge_basic.c?view=diff&rev=414403&r1=414402&r2=414403
==============================================================================
--- trunk/main/bridge_basic.c (original)
+++ trunk/main/bridge_basic.c Thu May 22 10:52:30 2014
@@ -3145,10 +3145,10 @@
 	return 0;
 }
 
-static void blind_transfer_cb(struct ast_channel *new_channel, void *user_data,
+static void blind_transfer_cb(struct ast_channel *new_channel, struct transfer_channel_data *user_data_wrapper,
 		enum ast_transfer_type transfer_type)
 {
-	struct ast_channel *transferer_channel = user_data;
+	struct ast_channel *transferer_channel = user_data_wrapper->data;
 
 	if (transfer_type == AST_BRIDGE_TRANSFER_MULTI_PARTY) {
 		copy_caller_data(new_channel, transferer_channel);

Modified: trunk/main/parking.c
URL: http://svnview.digium.com/svn/asterisk/trunk/main/parking.c?view=diff&rev=414403&r1=414402&r2=414403
==============================================================================
--- trunk/main/parking.c (original)
+++ trunk/main/parking.c Thu May 22 10:52:30 2014
@@ -142,7 +142,9 @@
 	return table->parking_park_bridge_channel(parkee, parkee_uuid, parker_uuid, app_data);
 }
 
-int ast_parking_blind_transfer_park(struct ast_bridge_channel *parker, const char *context, const char *exten)
+int ast_parking_blind_transfer_park(struct ast_bridge_channel *parker,
+	const char *context, const char *exten, transfer_channel_cb parked_channel_cb,
+	struct transfer_channel_data *parked_channel_data)
 {
 	RAII_VAR(struct ast_parking_bridge_feature_fn_table *, table,
 		ao2_global_obj_ref(parking_provider), ao2_cleanup);
@@ -153,10 +155,10 @@
 
 	if (table->module_info) {
 		SCOPED_MODULE_USE(table->module_info->self);
-		return table->parking_blind_transfer_park(parker, context, exten);
-	}
-
-	return table->parking_blind_transfer_park(parker, context, exten);
+		return table->parking_blind_transfer_park(parker, context, exten, parked_channel_cb, parked_channel_data);
+	}
+
+	return table->parking_blind_transfer_park(parker, context, exten, parked_channel_cb, parked_channel_data);
 }
 
 int ast_parking_park_call(struct ast_bridge_channel *parker, char *exten, size_t length)

Modified: trunk/res/parking/parking_applications.c
URL: http://svnview.digium.com/svn/asterisk/trunk/res/parking/parking_applications.c?view=diff&rev=414403&r1=414402&r2=414403
==============================================================================
--- trunk/res/parking/parking_applications.c (original)
+++ trunk/res/parking/parking_applications.c Thu May 22 10:52:30 2014
@@ -516,6 +516,7 @@
 		if (!silence_announcements && !transferer) {
 			ast_stream_and_wait(chan, "pbx-parkingfailed", "");
 		}
+		publish_parked_call_failure(chan);
 		return 0;
 	}
 
@@ -523,6 +524,7 @@
 	res = ast_bridge_features_init(&chan_features);
 	if (res) {
 		ast_bridge_features_cleanup(&chan_features);
+		publish_parked_call_failure(chan);
 		return -1;
 	}
 

Modified: trunk/res/parking/parking_bridge_features.c
URL: http://svnview.digium.com/svn/asterisk/trunk/res/parking/parking_bridge_features.c?view=diff&rev=414403&r1=414402&r2=414403
==============================================================================
--- trunk/res/parking/parking_bridge_features.c (original)
+++ trunk/res/parking/parking_bridge_features.c Thu May 22 10:52:30 2014
@@ -49,6 +49,7 @@
 };
 
 struct parked_subscription_data {
+	struct transfer_channel_data *transfer_data;
 	char *parkee_uuid;
 	int hangup_after:1;
 	char parker_uuid[0];
@@ -89,7 +90,7 @@
 	const char *parkee_to_act_on = data->parkee_uuid;
 	char saynum_buf[16];
 	struct ast_channel_snapshot *parkee_snapshot = message->parkee;
-	RAII_VAR(struct ast_channel *, parker, NULL, ao2_cleanup);
+	RAII_VAR(struct ast_channel *, parker, NULL, ast_channel_cleanup);
 	RAII_VAR(struct ast_bridge_channel *, bridge_channel, NULL, ao2_cleanup);
 
 	if (strcmp(parkee_to_act_on, parkee_snapshot->uniqueid)) {
@@ -113,22 +114,35 @@
 		return;
 	}
 
+	/* This subscription callback will block for the duration of the announcement if
+	 * parked_subscription_data is tracking a transfer_channel_data struct. */
 	if (message->event_type == PARKED_CALL) {
 		/* queue the saynum on the bridge channel and hangup */
 		snprintf(saynum_buf, sizeof(saynum_buf), "%d %u", data->hangup_after, message->parkingspace);
-		ast_bridge_channel_queue_playfile(bridge_channel, say_parking_space, saynum_buf, NULL);
-		wipe_subscription_datastore(bridge_channel->chan);
-	}
-
-	if (message->event_type == PARKED_CALL_FAILED) {
-		ast_bridge_channel_queue_playfile(bridge_channel, NULL, "pbx-parkingfailed", NULL);
-		wipe_subscription_datastore(bridge_channel->chan);
+		if (!data->transfer_data) {
+			ast_bridge_channel_queue_playfile(bridge_channel, say_parking_space, saynum_buf, NULL);
+		} else {
+			ast_bridge_channel_queue_playfile_sync(bridge_channel, say_parking_space, saynum_buf, NULL);
+			data->transfer_data->completed = 1;
+		}
+		wipe_subscription_datastore(parker);
+	} else if (message->event_type == PARKED_CALL_FAILED) {
+		if (!data->transfer_data) {
+			ast_bridge_channel_queue_playfile(bridge_channel, NULL, "pbx-parkingfailed", NULL);
+		} else {
+			ast_bridge_channel_queue_playfile_sync(bridge_channel, NULL, "pbx-parkingfailed", NULL);
+			data->transfer_data->completed = 1;
+		}
+		wipe_subscription_datastore(parker);
 	}
 }
 
 static void parker_update_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message)
 {
 	if (stasis_subscription_final_message(sub, message)) {
+		struct parked_subscription_data *ps_data = data;
+		ao2_cleanup(ps_data->transfer_data);
+		ps_data->transfer_data = NULL;
 		ast_free(data);
 		return;
 	}
@@ -139,7 +153,8 @@
 	}
 }
 
-int create_parked_subscription(struct ast_channel *chan, const char *parkee_uuid, int hangup_after)
+static int create_parked_subscription_full(struct ast_channel *chan, const char *parkee_uuid, int hangup_after,
+	struct transfer_channel_data *parked_channel_data)
 {
 	struct ast_datastore *datastore;
 	struct parked_subscription_datastore *parked_datastore;
@@ -167,6 +182,11 @@
 		return -1;
 	}
 
+	if (parked_channel_data) {
+		subscription_data->transfer_data = parked_channel_data;
+		ao2_ref(parked_channel_data, +1);
+	}
+
 	subscription_data->hangup_after = hangup_after;
 	subscription_data->parkee_uuid = subscription_data->parker_uuid + parker_uuid_size;
 	strcpy(subscription_data->parkee_uuid, parkee_uuid);
@@ -183,6 +203,11 @@
 	ast_channel_unlock(chan);
 
 	return 0;
+}
+
+int create_parked_subscription(struct ast_channel *chan, const char *parkee_uuid, int hangup_after)
+{
+	return create_parked_subscription_full(chan, parkee_uuid, hangup_after, NULL);
 }
 
 /*!
@@ -191,7 +216,7 @@
  *        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 *context, const char *exten)
+static struct ast_channel *park_local_transfer(struct ast_channel *parker, const char *context, const char *exten, struct transfer_channel_data *parked_channel_data)
 {
 	char destination[AST_MAX_EXTENSION + AST_MAX_CONTEXT + 1];
 	struct ast_channel *parkee;
@@ -220,7 +245,11 @@
 	ast_channel_unlock(parkee);
 
 	/* We need to have the parker subscribe to the new local channel before hand. */
-	create_parked_subscription(parker, ast_channel_uniqueid(parkee_side_2), 1);
+	if (create_parked_subscription_full(parker, ast_channel_uniqueid(parkee_side_2), 1, parked_channel_data)) {
+		ast_channel_unref(parkee_side_2);
+		ast_hangup(parkee);
+		return NULL;
+	}
 
 	ast_bridge_set_transfer_variables(parkee_side_2, ast_channel_name(parker), 0);
 
@@ -272,14 +301,21 @@
  * \param bridge_channel The bridge_channel representing the channel performing the park
  * \param context The context to blind transfer to
  * \param exten The extension to blind transfer to
+ * \param parked_channel_cb Optional callback executed prior to sending the parked channel into the bridge
+ * \param parked_channel_data Data for the parked_channel_cb
  *
  * \retval 0 on success
  * \retval non-zero on error
  */
 static int parking_blind_transfer_park(struct ast_bridge_channel *bridge_channel,
-		const char *context, const char *exten)
+		const char *context, const char *exten, transfer_channel_cb parked_channel_cb,
+		struct transfer_channel_data *parked_channel_data)
 {
 	RAII_VAR(struct ast_bridge_channel *, other, NULL, ao2_cleanup);
+	RAII_VAR(struct ast_channel *, other_chan, NULL, ast_channel_cleanup);
+
+	struct ast_exten *e;
+	struct pbx_find_info find_info = { .stacklen = 0 };
 	int peer_count;
 
 	if (ast_strlen_zero(context) || ast_strlen_zero(exten)) {
@@ -299,6 +335,8 @@
 	if (peer_count == 2) {
 		other = ast_bridge_channel_peer(bridge_channel);
 		ao2_ref(other, +1);
+		other_chan = other->chan;
+		ast_channel_ref(other_chan);
 	}
 	ast_bridge_unlock(bridge_channel->bridge);
 
@@ -313,33 +351,47 @@
 	if (peer_count > 2) {
 		struct ast_channel *transfer_chan = NULL;
 
-		transfer_chan = park_local_transfer(bridge_channel->chan, context, exten);
+		transfer_chan = park_local_transfer(bridge_channel->chan, context, exten, parked_channel_data);
 		if (!transfer_chan) {
 			return -1;
 		}
+		ast_channel_ref(transfer_chan);
+
+		if (parked_channel_cb) {
+			parked_channel_cb(transfer_chan, parked_channel_data, AST_BRIDGE_TRANSFER_MULTI_PARTY);
+		}
 
 		if (ast_bridge_impart(bridge_channel->bridge, transfer_chan, NULL, NULL,
 			AST_BRIDGE_IMPART_CHAN_INDEPENDENT)) {
 			ast_hangup(transfer_chan);
+			ast_channel_unref(transfer_chan);
 			return -1;
 		}
+
+		ast_channel_unref(transfer_chan);
+
 		return 0;
 	}
 
 	/* Subscribe to park messages with the other channel entering */
-	if (create_parked_subscription(bridge_channel->chan, ast_channel_uniqueid(other->chan), 1)) {
-		return -1;
-	}
+	if (create_parked_subscription_full(bridge_channel->chan, ast_channel_uniqueid(other->chan), 1, parked_channel_data)) {
+		return -1;
+	}
+
+	if (parked_channel_cb) {
+		parked_channel_cb(other_chan, parked_channel_data, AST_BRIDGE_TRANSFER_SINGLE_PARTY);
+	}
+
+	e = pbx_find_extension(NULL, NULL, &find_info, context, exten, 1, NULL, NULL, E_MATCH);
 
 	/* Write the park frame with the intended recipient and other data out to the bridge. */
 	ast_bridge_channel_write_park(bridge_channel,
-		ast_channel_uniqueid(other->chan),
+		ast_channel_uniqueid(other_chan),
 		ast_channel_uniqueid(bridge_channel->chan),
-		NULL);
+		e ? ast_get_extension_app_data(e) : NULL);
 
 	return 0;
 }
-
 
 /*!
  * \internal
@@ -444,7 +496,7 @@
 	if (exten) {
 		ast_copy_string(exten, lot->cfg->parkext, length);
 	}
-	return parking_blind_transfer_park(parker, lot->cfg->parking_con, lot->cfg->parkext);
+	return parking_blind_transfer_park(parker, lot->cfg->parking_con, lot->cfg->parkext, NULL, NULL);
 }
 
 static int feature_park_call(struct ast_bridge_channel *bridge_channel, void *hook_pvt)

Modified: trunk/res/res_pjsip_refer.c
URL: http://svnview.digium.com/svn/asterisk/trunk/res/res_pjsip_refer.c?view=diff&rev=414403&r1=414402&r2=414403
==============================================================================
--- trunk/res/res_pjsip_refer.c (original)
+++ trunk/res/res_pjsip_refer.c Thu May 22 10:52:30 2014
@@ -55,6 +55,8 @@
 	struct ast_taskprocessor *serializer;
 	/*! \brief Stasis subscription for bridge events */
 	struct stasis_subscription *bridge_sub;
+	/*! \brief Reference to transfer_channel_data related to the refer */
+	struct transfer_channel_data *transfer_data;
 	/*! \brief Uniqueid of transferee channel */
 	char *transferee;
 };
@@ -165,6 +167,12 @@
 		return;
 	}
 
+	if (!progress->transfer_data->completed) {
+		/* We can't act on this message because the transfer_channel_data doesn't show that
+		 * the transfer is ready to progress */
+		return;
+	}
+
 	/* OMG the transferee is joining a bridge. His call got answered! */
 	notification = refer_progress_notification_alloc(progress, 200, PJSIP_EVSUB_STATE_TERMINATED);
 	if (notification) {
@@ -183,6 +191,11 @@
 
 	/* We only care about frames *to* the channel */
 	if (!f || (event != AST_FRAMEHOOK_EVENT_WRITE)) {
+		return f;
+	}
+
+	/* If the completed flag hasn't been raised, skip this pass. */
+	if (!progress->transfer_data->completed) {
 		return f;
 	}
 
@@ -240,6 +253,10 @@
 		ao2_cleanup(notification);
 	}
 
+	if (progress->bridge_sub) {
+		progress->bridge_sub = stasis_unsubscribe(progress->bridge_sub);
+	}
+
 	ao2_cleanup(progress);
 }
 
@@ -295,6 +312,8 @@
 	if (progress->bridge_sub) {
 		progress->bridge_sub = stasis_unsubscribe(progress->bridge_sub);
 	}
+
+	ao2_cleanup(progress->transfer_data);
 
 	ast_free(progress->transferee);
 	ast_taskprocessor_unreference(progress->serializer);
@@ -472,9 +491,10 @@
 };
 
 /*! \brief Blind transfer callback function */
-static void refer_blind_callback(struct ast_channel *chan, void *user_data, enum ast_transfer_type transfer_type)
-{
-	struct refer_blind *refer = user_data;
+static void refer_blind_callback(struct ast_channel *chan, struct transfer_channel_data *user_data_wrapper,
+	enum ast_transfer_type transfer_type)
+{
+	struct refer_blind *refer = user_data_wrapper->data;
 	pjsip_generic_string_hdr *referred_by;
 
 	static const pj_str_t str_referred_by = { "Referred-By", 11 };
@@ -502,6 +522,10 @@
 				refer_progress_notify(notification);
 			}
 		}
+
+		/* Progress needs a reference to the transfer_channel_data so that it can track the completed status of the transfer */
+		ao2_ref(user_data_wrapper, +1);
+		refer->progress->transfer_data = user_data_wrapper;
 
 		/* We need to bump the reference count up on the progress structure since it is in the frame hook now */
 		ao2_ref(refer->progress, +1);




More information about the svn-commits mailing list