[asterisk-commits] dvossel: branch 1.6.0 r177227 - in /branches/1.6.0: ./ main/features.c

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Wed Feb 18 16:55:56 CST 2009


Author: dvossel
Date: Wed Feb 18 16:55:56 2009
New Revision: 177227

URL: http://svn.digium.com/svn-view/asterisk?view=rev&rev=177227
Log:
Merged revisions 177226 via svnmerge from 
https://origsvn.digium.com/svn/asterisk/trunk

........
  r177226 | dvossel | 2009-02-18 16:51:38 -0600 (Wed, 18 Feb 2009) | 9 lines
  
  Locking issue in action_bridge and bridge_exec
  
  action_bridge() and bridge_exec() both search for the channels to bridge to, and then immediately drop the lock.  Instead, they should hold the lock until the masquerade is complete.  This will guarantee the channel remains and prevent any other weirdness from occurring.  In action_bridge() some more weirdness comes into play.  Both channels are needlessly locked at the same time and perform the exact same logic.  It makes sense from a coding organizational standpoint, but could cause a theoretical deadlock so I split the code up.  There is an issue associated with this, but since its a rather complicated thing to reproduce I'm not certain this alone will close it.
  
  issue# 14296
  Review: http://reviewboard.digium.com/r/167/
........

Modified:
    branches/1.6.0/   (props changed)
    branches/1.6.0/main/features.c

Propchange: branches/1.6.0/
------------------------------------------------------------------------------
Binary property 'trunk-merged' - no diff available.

Modified: branches/1.6.0/main/features.c
URL: http://svn.digium.com/svn-view/asterisk/branches/1.6.0/main/features.c?view=diff&rev=177227&r1=177226&r2=177227
==============================================================================
--- branches/1.6.0/main/features.c (original)
+++ branches/1.6.0/main/features.c Wed Feb 18 16:55:56 2009
@@ -3491,55 +3491,69 @@
 	struct ast_bridge_thread_obj *tobj = NULL;
 
 	/* make sure valid channels were specified */
-	if (!ast_strlen_zero(channela) && !ast_strlen_zero(channelb)) {
-		chana = ast_get_channel_by_name_prefix_locked(channela, strlen(channela));
-		chanb = ast_get_channel_by_name_prefix_locked(channelb, strlen(channelb));
-		if (chana)
-			ast_channel_unlock(chana);
-		if (chanb)
-			ast_channel_unlock(chanb);
-
-		/* 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;
-		}
-		if (!chanb) {
-			char buf[256];
-			snprintf(buf, sizeof(buf), "Channel2 does not exists: %s", channelb);
-			astman_send_error(s, m, buf);
-			return 0;
-		}
-	} else {
+	if (ast_strlen_zero(channela) || ast_strlen_zero(channelb)) {
 		astman_send_error(s, m, "Missing channel parameter in request");
+		return 0;
+	}
+
+	/* The same code must be executed for chana and chanb.  To avoid a
+	 * theoretical deadlock, this code is separated so both chana and chanb will
+	 * not hold locks at the same time. */
+
+	/* Start with chana */
+	chana = ast_get_channel_by_name_prefix_locked(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;
 	}
 
 	/* Answer the channels if needed */
 	if (chana->_state != AST_STATE_UP)
 		ast_answer(chana);
-	if (chanb->_state != AST_STATE_UP)
-		ast_answer(chanb);
 
 	/* create the placeholder channels and grab the other channels */
 	if (!(tmpchana = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, 
 		NULL, NULL, 0, "Bridge/%s", chana->name))) {
 		astman_send_error(s, m, "Unable to create temporary channel!");
+		ast_channel_unlock(chana);
 		return 1;
 	}
 
+	do_bridge_masquerade(chana, tmpchana);
+	ast_channel_unlock(chana);
+	chana = NULL;
+
+	/* now do chanb */
+	chanb = ast_get_channel_by_name_prefix_locked(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);
+		ast_hangup(tmpchana);
+		astman_send_error(s, m, buf);
+		return 0;
+	}
+
+	/* Answer the channels if needed */
+	if (chanb->_state != AST_STATE_UP)
+		ast_answer(chanb);
+
+	/* create the placeholder channels and grab the other channels */
 	if (!(tmpchanb = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, 
 		NULL, NULL, 0, "Bridge/%s", chanb->name))) {
 		astman_send_error(s, m, "Unable to create temporary channels!");
-		ast_channel_free(tmpchana);
+		ast_hangup(tmpchana);
+		ast_channel_unlock(chanb);
 		return 1;
 	}
-
-	do_bridge_masquerade(chana, tmpchana);
 	do_bridge_masquerade(chanb, tmpchanb);
-	
+	ast_channel_unlock(chanb);
+	chanb = NULL;
+
 	/* make the channels compatible, send error if we fail doing so */
 	if (ast_channel_make_compatible(tmpchana, tmpchanb)) {
 		ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for manager bridge\n", tmpchana->name, tmpchanb->name);
@@ -3561,7 +3575,7 @@
 	tobj->chan = tmpchana;
 	tobj->peer = tmpchanb;
 	tobj->return_to_pbx = 1;
-	
+
 	if (ast_true(playtone)) {
 		if (!ast_strlen_zero(xfersound) && !ast_streamfile(tmpchanb, xfersound, tmpchanb->language)) {
 			if (ast_waitstream(tmpchanb, "") < 0)
@@ -3877,7 +3891,6 @@
 		pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "NONEXISTENT");
 		return 0;
 	}
-	ast_channel_unlock(current_dest_chan);
 
 	/* answer the channel if needed */
 	if (current_dest_chan->_state != AST_STATE_UP)
@@ -3894,6 +3907,8 @@
 					"Channel2: %s\r\n", chan->name, args.dest_chan);
 	}
 	do_bridge_masquerade(current_dest_chan, final_dest_chan);
+
+	ast_channel_unlock(current_dest_chan);
 
 	/* now current_dest_chan is a ZOMBIE and with softhangup set to 1 and final_dest_chan is our end point */
 	/* try to make compatible, send error if we fail */




More information about the asterisk-commits mailing list