[svn-commits] rmudgett: branch 1.8 r363428 - /branches/1.8/main/features.c

SVN commits to the Digium repositories svn-commits at lists.digium.com
Tue Apr 24 20:21:48 CDT 2012


Author: rmudgett
Date: Tue Apr 24 20:21:43 2012
New Revision: 363428

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=363428
Log:
Fix recalled party B feature flags for a failed DTMF atxfer.

1) B calls A with Dial option T
2) B DTMF atxfer to C
3) B hangs up
4) C does not answer
5) B is called back
6) B answers
7) B cannot initiate transfers anymore

* Add dial features datastore to recalled party B channel that is a copy
of the original party B channel's dial features datastore.

* Extracted add_features_datastore() from add_features_datastores().

* Renamed struct ast_dial_features features_caller and features_callee
members to my_features and peer_features respectively.  These better names
eliminate the need for some explanatory comments.

* Simplified code accessing the struct ast_dial_features datastore.

(closes issue ASTERISK-19383)
Reported by: lgfsantos

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=363428&r1=363427&r2=363428
==============================================================================
--- branches/1.8/main/features.c (original)
+++ branches/1.8/main/features.c Tue Apr 24 20:21:43 2012
@@ -643,9 +643,10 @@
 
 static pthread_t parking_thread;
 struct ast_dial_features {
-	struct ast_flags features_caller;
-	struct ast_flags features_callee;
-	int is_caller;
+	/*! Channel's feature flags. */
+	struct ast_flags my_features;
+	/*! Bridge peer's feature flags. */
+	struct ast_flags peer_features;
 };
 
 #if defined(ATXFER_NULL_TECH)
@@ -749,7 +750,52 @@
  	.destroy = dial_features_destroy,
  	.duplicate = dial_features_duplicate,
 };
- 
+
+/*!
+ * \internal
+ * \brief Set the features datastore if it doesn't exist.
+ *
+ * \param chan Channel to add features datastore
+ * \param my_features The channel's feature flags
+ * \param peer_features The channel's bridge peer feature flags
+ *
+ * \retval TRUE if features datastore already existed.
+ */
+static int add_features_datastore(struct ast_channel *chan, const struct ast_flags *my_features, const struct ast_flags *peer_features)
+{
+	struct ast_datastore *datastore;
+	struct ast_dial_features *dialfeatures;
+
+	ast_channel_lock(chan);
+	datastore = ast_channel_datastore_find(chan, &dial_features_info, NULL);
+	ast_channel_unlock(chan);
+	if (datastore) {
+		/* Already exists. */
+		return 1;
+	}
+
+	/* Create a new datastore with specified feature flags. */
+	datastore = ast_datastore_alloc(&dial_features_info, NULL);
+	if (!datastore) {
+		ast_log(LOG_WARNING, "Unable to create channel features datastore.\n");
+		return 0;
+	}
+	dialfeatures = ast_calloc(1, sizeof(*dialfeatures));
+	if (!dialfeatures) {
+		ast_log(LOG_WARNING, "Unable to allocate memory for feature flags.\n");
+		ast_datastore_free(datastore);
+		return 0;
+	}
+	ast_copy_flags(&dialfeatures->my_features, my_features, AST_FLAGS_ALL);
+	ast_copy_flags(&dialfeatures->peer_features, peer_features, AST_FLAGS_ALL);
+	datastore->inheritance = DATASTORE_INHERIT_FOREVER;
+	datastore->data = dialfeatures;
+	ast_channel_lock(chan);
+	ast_channel_datastore_add(chan, datastore);
+	ast_channel_unlock(chan);
+	return 0;
+}
+
 /* Forward declarations */
 static struct ast_parkinglot *parkinglot_addref(struct ast_parkinglot *parkinglot);
 static void parkinglot_unref(struct ast_parkinglot *parkinglot);
@@ -2442,7 +2488,7 @@
 	int l;
 	struct ast_party_connected_line connected_line;
 	struct ast_datastore *features_datastore;
-	struct ast_dial_features *dialfeatures = NULL;
+	struct ast_dial_features *dialfeatures;
 	char *transferer_tech;
 	char *transferer_name;
 	char *transferer_name_orig;
@@ -2492,7 +2538,13 @@
 		return xfer_park_call_helper(transferee, transferer, park_exten);
 	}
 
-	/* Append context to dialed transfer number. */
+	/*
+	 * Append context to dialed transfer number.
+	 *
+	 * NOTE: The local channel needs the /n flag so party C will use
+	 * the feature flags set by the dialplan when calling that
+	 * party.
+	 */
 	snprintf(xferto + l, sizeof(xferto) - l, "@%s/n", transferer_real_context);
 
 	/* If we are performing an attended transfer and we have two channels involved then
@@ -2645,7 +2697,31 @@
 					atxfernoanswertimeout, &outstate, transferer->language);
 				ast_debug(2, "Dial party B result: newchan:%d, outstate:%d\n",
 					!!newchan, outstate);
-				if (newchan || ast_check_hangup(transferee)) {
+				if (newchan) {
+					/*
+					 * We have recalled party B (newchan).  We need to give this
+					 * call leg the same feature flags as the original party B call
+					 * leg.
+					 */
+					ast_channel_lock(transferer);
+					features_datastore = ast_channel_datastore_find(transferer,
+						&dial_features_info, NULL);
+					if (features_datastore && (dialfeatures = features_datastore->data)) {
+						struct ast_flags my_features = { 0 };
+						struct ast_flags peer_features = { 0 };
+
+						ast_copy_flags(&my_features, &dialfeatures->my_features,
+							AST_FLAGS_ALL);
+						ast_copy_flags(&peer_features, &dialfeatures->peer_features,
+							AST_FLAGS_ALL);
+						ast_channel_unlock(transferer);
+						add_features_datastore(newchan, &my_features, &peer_features);
+					} else {
+						ast_channel_unlock(transferer);
+					}
+					break;
+				}
+				if (ast_check_hangup(transferee)) {
 					break;
 				}
 
@@ -2744,32 +2820,25 @@
 		return -1;
 	}
 
-	ast_channel_lock(newchan);
-	if ((features_datastore = ast_channel_datastore_find(newchan, &dial_features_info, NULL))) {
-		dialfeatures = features_datastore->data;
-	}
-	ast_channel_unlock(newchan);
-
-	if (dialfeatures) {
-		/* newchan should always be the callee and shows up as callee in dialfeatures, but for some reason
-		   I don't currently understand, the abilities of newchan seem to be stored on the caller side */
-		ast_copy_flags(&(config->features_callee), &(dialfeatures->features_caller), AST_FLAGS_ALL);
-		dialfeatures = NULL;
-	}
-
-	ast_channel_lock(xferchan);
-	if ((features_datastore = ast_channel_datastore_find(xferchan, &dial_features_info, NULL))) {
-		dialfeatures = features_datastore->data;
-	}
-	ast_channel_unlock(xferchan);
-
-	if (dialfeatures) {
-		ast_copy_flags(&(config->features_caller), &(dialfeatures->features_caller), AST_FLAGS_ALL);
-	}
-
 	tobj->chan = newchan;
 	tobj->peer = xferchan;
 	tobj->bconfig = *config;
+
+	ast_channel_lock(newchan);
+	features_datastore = ast_channel_datastore_find(newchan, &dial_features_info, NULL);
+	if (features_datastore && (dialfeatures = features_datastore->data)) {
+		ast_copy_flags(&tobj->bconfig.features_callee, &dialfeatures->my_features,
+			AST_FLAGS_ALL);
+	}
+	ast_channel_unlock(newchan);
+
+	ast_channel_lock(xferchan);
+	features_datastore = ast_channel_datastore_find(xferchan, &dial_features_info, NULL);
+	if (features_datastore && (dialfeatures = features_datastore->data)) {
+		ast_copy_flags(&tobj->bconfig.features_caller, &dialfeatures->my_features,
+			AST_FLAGS_ALL);
+	}
+	ast_channel_unlock(xferchan);
 
 	if (tobj->bconfig.end_bridge_callback_data_fixup) {
 		tobj->bconfig.end_bridge_callback_data_fixup(&tobj->bconfig, tobj->peer, tobj->chan);
@@ -3749,60 +3818,16 @@
 
 static void add_features_datastores(struct ast_channel *caller, struct ast_channel *callee, struct ast_bridge_config *config)
 {
-	struct ast_datastore *ds_callee_features = NULL, *ds_caller_features = NULL;
-	struct ast_dial_features *callee_features = NULL, *caller_features = NULL;
-
-	ast_channel_lock(caller);
-	ds_caller_features = ast_channel_datastore_find(caller, &dial_features_info, NULL);
-	ast_channel_unlock(caller);
-	if (!ds_caller_features) {
-		if (!(ds_caller_features = ast_datastore_alloc(&dial_features_info, NULL))) {
-			ast_log(LOG_WARNING, "Unable to create channel datastore for caller features. Aborting!\n");
-			return;
-		}
-		if (!(caller_features = ast_calloc(1, sizeof(*caller_features)))) {
-			ast_log(LOG_WARNING, "Unable to allocate memory for callee feature flags. Aborting!\n");
-			ast_datastore_free(ds_caller_features);
-			return;
-		}
-		ds_caller_features->inheritance = DATASTORE_INHERIT_FOREVER;
-		caller_features->is_caller = 1;
-		ast_copy_flags(&(caller_features->features_callee), &(config->features_callee), AST_FLAGS_ALL);
-		ast_copy_flags(&(caller_features->features_caller), &(config->features_caller), AST_FLAGS_ALL);
-		ds_caller_features->data = caller_features;
-		ast_channel_lock(caller);
-		ast_channel_datastore_add(caller, ds_caller_features);
-		ast_channel_unlock(caller);
-	} else {
-		/* If we don't return here, then when we do a builtin_atxfer we will copy the disconnect
-		 * flags over from the atxfer to the caller */
+	if (add_features_datastore(caller, &config->features_caller, &config->features_callee)) {
+		/*
+		 * If we don't return here, then when we do a builtin_atxfer we
+		 * will copy the disconnect flags over from the atxfer to the
+		 * callee (Party C).
+		 */
 		return;
 	}
 
-	ast_channel_lock(callee);
-	ds_callee_features = ast_channel_datastore_find(callee, &dial_features_info, NULL);
-	ast_channel_unlock(callee);
-	if (!ds_callee_features) {
-		if (!(ds_callee_features = ast_datastore_alloc(&dial_features_info, NULL))) {
-			ast_log(LOG_WARNING, "Unable to create channel datastore for callee features. Aborting!\n");
-			return;
-		}
-		if (!(callee_features = ast_calloc(1, sizeof(*callee_features)))) {
-			ast_log(LOG_WARNING, "Unable to allocate memory for callee feature flags. Aborting!\n");
-			ast_datastore_free(ds_callee_features);
-			return;
-		}
-		ds_callee_features->inheritance = DATASTORE_INHERIT_FOREVER;
-		callee_features->is_caller = 0;
-		ast_copy_flags(&(callee_features->features_callee), &(config->features_caller), AST_FLAGS_ALL);
-		ast_copy_flags(&(callee_features->features_caller), &(config->features_callee), AST_FLAGS_ALL);
-		ds_callee_features->data = callee_features;
-		ast_channel_lock(callee);
-		ast_channel_datastore_add(callee, ds_callee_features);
-		ast_channel_unlock(callee);
-	}
-
-	return;
+	add_features_datastore(callee, &config->features_callee, &config->features_caller);
 }
 
 static void clear_dialed_interfaces(struct ast_channel *chan)
@@ -4630,8 +4655,8 @@
 					char buf[MAX_DIAL_FEATURE_OPTIONS] = {0,};
 
 					snprintf(returnexten, sizeof(returnexten), "%s,30,%s", peername,
-						callback_dialoptions(&(dialfeatures->features_callee),
-							&(dialfeatures->features_caller), buf, sizeof(buf)));
+						callback_dialoptions(&dialfeatures->peer_features,
+							&dialfeatures->my_features, buf, sizeof(buf)));
 				} else { /* Existing default */
 					ast_log(LOG_NOTICE, "Dial features not found on %s, using default!\n",
 						chan->name);
@@ -5170,7 +5195,7 @@
 
 	if (peer) {
 		struct ast_datastore *features_datastore;
-		struct ast_dial_features *dialfeatures = NULL;
+		struct ast_dial_features *dialfeatures;
 
 		/* Play a courtesy to the source(s) configured to prefix the bridge connecting */
 		if (!ast_strlen_zero(courtesytone)) {
@@ -5214,20 +5239,10 @@
 
 		/* Get datastore for peer and apply it's features to the callee side of the bridge config */
 		ast_channel_lock(peer);
-		if ((features_datastore = ast_channel_datastore_find(peer, &dial_features_info, NULL))) {
-			dialfeatures = features_datastore->data;
-		}
-
-		/*
-		 * When the datastores for both caller and callee are created,
-		 * both the callee and caller channels use the features_caller
-		 * flag variable to represent themselves.  With that said, the
-		 * config.features_callee flags should be copied from the
-		 * datastore's caller feature flags regardless if peer was a
-		 * callee or caller.
-		 */
-		if (dialfeatures) {
-			ast_copy_flags(&(config.features_callee), &(dialfeatures->features_caller), AST_FLAGS_ALL);
+		features_datastore = ast_channel_datastore_find(peer, &dial_features_info, NULL);
+		if (features_datastore && (dialfeatures = features_datastore->data)) {
+			ast_copy_flags(&config.features_callee, &dialfeatures->my_features,
+				AST_FLAGS_ALL);
 		}
 		ast_channel_unlock(peer);
 




More information about the svn-commits mailing list