[asterisk-commits] jpeeler: branch 1.4 r173211 - /branches/1.4/res/res_features.c

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Tue Feb 3 15:57:01 CST 2009


Author: jpeeler
Date: Tue Feb  3 15:57:01 2009
New Revision: 173211

URL: http://svn.digium.com/svn-view/asterisk?view=rev&rev=173211
Log:
Parking attempts made to one end of a bridge no longer will hang up due to a
parking failure.

Parking attempts made using either one-touch, or doing either a blind or 
assisted transfer to the parking extension now keep up the bridge instead of
hanging up the attempted parked party. Normal causes for the parking attempt
to fail includes the specific specified extension (via PARKINGEXTEN) not being 
available or if all the parking spaces are currently in use. To avoid having
to reverse a masquerade park_space_reserve was made to provide foresight if
a parking attempt will succeed and if so reserve the parking space.

(closes issue #13494)
Reported by: mdu113

Reviewed by Russell: http://reviewboard.digium.com/r/133/


Modified:
    branches/1.4/res/res_features.c

Modified: branches/1.4/res/res_features.c
URL: http://svn.digium.com/svn-view/asterisk/branches/1.4/res/res_features.c?view=diff&rev=173211&r1=173210&r2=173211
==============================================================================
--- branches/1.4/res/res_features.c (original)
+++ branches/1.4/res/res_features.c Tue Feb  3 15:57:01 2009
@@ -72,6 +72,14 @@
 #define AST_MAX_WATCHERS 256
 #define MAX_DIAL_FEATURE_OPTIONS 30
 
+#define FEATURE_RETURN_HANGUP                  -1
+#define FEATURE_RETURN_SUCCESSBREAK             0
+#define FEATURE_RETURN_PASSDIGITS               21
+#define FEATURE_RETURN_STOREDIGITS              22
+#define FEATURE_RETURN_SUCCESS                  23
+#define FEATURE_RETURN_KEEPTRYING               24
+#define FEATURE_RETURN_PARKFAILED               25
+
 enum {
 	AST_FEATURE_FLAG_NEEDSDTMF = (1 << 0),
 	AST_FEATURE_FLAG_ONPEER =    (1 << 1),
@@ -338,16 +346,15 @@
 		return AST_DEVICE_INUSE;
 }
 
-static int park_call_full(struct ast_channel *chan, struct ast_channel *peer, int timeout, int *extout, const char *orig_chan_name)
+static struct parkeduser *park_space_reserve(struct ast_channel *chan)
 {
 	struct parkeduser *pu, *cur;
-	int i, x = -1, parking_range, parkingnum_copy;
-	struct ast_context *con;
+	int i, parking_space = -1, parking_range;
 	const char *parkingexten;
-	
+
 	/* Allocate memory for parking data */
 	if (!(pu = ast_calloc(1, sizeof(*pu)))) 
-		return -1;
+		return NULL;
 
 	/* Lock parking lot */
 	ast_mutex_lock(&parking_lock);
@@ -360,28 +367,28 @@
 		 * limitation here.  If extout was not numeric, we could permit
 		 * arbitrary non-numeric extensions.
 		 */
-		if (sscanf(parkingexten, "%d", &x) != 1 || x < 0) {
+		if (sscanf(parkingexten, "%d", &parking_space) != 1 || parking_space < 0) {
 			ast_log(LOG_WARNING, "PARKINGEXTEN does not indicate a valid parking slot: '%s'.\n", parkingexten);
 			ast_mutex_unlock(&parking_lock);
 			free(pu);
-			return 1;	/* Continue execution if possible */
-		}
-		snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", x);
+			return NULL;
+		}
+		snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", parking_space);
 
 		if (ast_exists_extension(NULL, parking_con, pu->parkingexten, 1, NULL)) {
 			ast_mutex_unlock(&parking_lock);
+			ast_log(LOG_WARNING, "Requested parking extension already exists: %s@%s\n", parkingexten, parking_con);
 			free(pu);
-			ast_log(LOG_WARNING, "Requested parking extension already exists: %s@%s\n", parkingexten, parking_con);
-			return 1;	/* Continue execution if possible */
+			return NULL;
 		}
 	} else {
 		/* Select parking space within range */
 		parking_range = parking_stop - parking_start+1;
 		for (i = 0; i < parking_range; i++) {
-			x = (i + parking_offset) % parking_range + parking_start;
+			parking_space = (i + parking_offset) % parking_range + parking_start;
 			cur = parkinglot;
 			while(cur) {
-				if (cur->parkingnum == x) 
+				if (cur->parkingnum == parking_space) 
 					break;
 				cur = cur->next;
 			}
@@ -391,15 +398,37 @@
 
 		if (!(i < parking_range)) {
 			ast_log(LOG_WARNING, "No more parking spaces\n");
+			ast_mutex_unlock(&parking_lock);
 			free(pu);
-			ast_mutex_unlock(&parking_lock);
-			return -1;
+			return NULL;
 		}
 		/* Set pointer for next parking */
 		if (parkfindnext) 
-			parking_offset = x - parking_start + 1;
-		snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", x);
-	}
+			parking_offset = parking_space - parking_start + 1;
+		snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", parking_space);
+	}
+	
+	pu->notquiteyet = 1;
+	pu->parkingnum = parking_space;
+	pu->next = parkinglot;
+	parkinglot = pu;
+	ast_mutex_unlock(&parking_lock);
+
+	return pu;
+}
+
+static int park_call_full(struct ast_channel *chan, struct ast_channel *peer, int timeout, int *extout, const char *orig_chan_name, struct parkeduser *pu)
+{
+	struct ast_context *con;
+	int parkingnum_copy;
+	
+	/* Get a valid space if not already done */
+	if (pu == NULL)
+		pu = park_space_reserve(chan);
+	if (pu == NULL)
+		return 1; /* Continue execution if possible */
+
+	snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", pu->parkingnum);
 	
 	chan->appl = "Parked Call";
 	chan->data = NULL; 
@@ -414,10 +443,9 @@
 	}
 	
 	pu->start = ast_tvnow();
-	pu->parkingnum = x;
 	pu->parkingtime = (timeout > 0) ? timeout : parkingtime;
 	if (extout)
-		*extout = x;
+		*extout = pu->parkingnum;
 
 	if (peer) { 
 		/* This is so ugly that it hurts, but implementing get_base_channel() on local channels
@@ -449,12 +477,12 @@
 	ast_copy_string(pu->context, S_OR(chan->macrocontext, chan->context), sizeof(pu->context));
 	ast_copy_string(pu->exten, S_OR(chan->macroexten, chan->exten), sizeof(pu->exten));
 	pu->priority = chan->macropriority ? chan->macropriority : chan->priority;
-	pu->next = parkinglot;
-	parkinglot = pu;
 	parkingnum_copy = pu->parkingnum;
-	/* If parking a channel directly, don't quite yet get parking running on it */
-	if (peer == chan) 
-		pu->notquiteyet = 1;
+
+	/* If parking a channel directly (peer == chan), don't quite yet get parking running on it.
+     * All parking lot entires are put into the parking lot with notquiteyet on. */
+	if (peer != chan) 
+		pu->notquiteyet = 0;
 
 	if (option_verbose > 1) 
 		ast_verbose(VERBOSE_PREFIX_2 "Parked %s on %d@%s. Will timeout back to extension [%s] %s, %d in %d seconds\n", pu->chan->name, pu->parkingnum, parking_con, pu->context, pu->exten, pu->priority, (pu->parkingtime/1000));
@@ -488,7 +516,6 @@
 		}
 	}
 
-	ast_mutex_unlock(&parking_lock);
 	/* Wake up the (presumably select()ing) thread */
 	pthread_kill(parking_thread, SIGURG);
 
@@ -517,14 +544,20 @@
 	after these channels too */
 int ast_park_call(struct ast_channel *chan, struct ast_channel *peer, int timeout, int *extout)
 {
-	return park_call_full(chan, peer, timeout, extout, NULL);
+	return park_call_full(chan, peer, timeout, extout, NULL, NULL);
 }
 
 static int masq_park_call(struct ast_channel *rchan, struct ast_channel *peer, int timeout, int *extout, int play_announcement, const char *orig_chan_name)
 {
 	struct ast_channel *chan;
 	struct ast_frame *f;
+	struct parkeduser *pu;
 	int park_status;
+
+	if ((pu = park_space_reserve(rchan)) == NULL) {
+		ast_stream_and_wait(peer, "beeperr", peer->language, "");
+		return FEATURE_RETURN_PARKFAILED;
+	}
 
 	/* Make a new, fake channel that we'll use to masquerade in the real one */
 	if (!(chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, rchan->accountcode, rchan->exten, rchan->context, rchan->amaflags, "Parked/%s",rchan->name))) {
@@ -553,7 +586,7 @@
 		orig_chan_name = ast_strdupa(chan->name);
 	}
 
-	park_status = park_call_full(chan, peer, timeout, extout, orig_chan_name);
+	park_status = park_call_full(chan, peer, timeout, extout, orig_chan_name, pu);
 	if (park_status == 1) {
 		/* would be nice to play: "invalid parking extension" */
 		ast_hangup(chan);
@@ -572,12 +605,6 @@
 {
 	return masq_park_call(rchan, peer, timeout, extout, 1, orig_chan_name);
 }
-#define FEATURE_RETURN_HANGUP                  -1
-#define FEATURE_RETURN_SUCCESSBREAK             0
-#define FEATURE_RETURN_PASSDIGITS               21
-#define FEATURE_RETURN_STOREDIGITS              22
-#define FEATURE_RETURN_SUCCESS                  23
-#define FEATURE_RETURN_KEEPTRYING               24
 
 #define FEATURE_SENSE_CHAN	(1 << 0)
 #define FEATURE_SENSE_PEER	(1 << 1)
@@ -624,8 +651,8 @@
 		res = ast_safe_sleep(chan, 1000);
 
 	if (!res) { /* one direction used to call park_call.... */
-		masq_park_call_announce(parkee, parker, 0, NULL, orig_chan_name);
-		res = 0; /* PBX should hangup zombie channel */
+		res = masq_park_call_announce(parkee, parker, 0, NULL, orig_chan_name);
+		/* PBX should hangup zombie channel if a masquerade actually occurred (res=0) */
 	}
 
 	ast_module_user_remove(u);
@@ -751,6 +778,7 @@
 	char xferto[256];
 	int res;
 	const char *orig_chan_name;
+	int parkstatus = 0;
 
 	set_peers(&transferer, &transferee, peer, chan, sense);
 	orig_chan_name = ast_strdupa(transferer->name);
@@ -780,13 +808,13 @@
 		res = finishup(transferee);
 		if (res)
 			res = -1;
-		else if (!masq_park_call_announce(transferee, transferer, 0, NULL, orig_chan_name)) {	/* success */
+		else if (!(parkstatus = masq_park_call_announce(transferee, transferer, 0, NULL, orig_chan_name))) {	/* success */
 			/* We return non-zero, but tell the PBX not to hang the channel when
 			   the thread dies -- We have to be careful now though.  We are responsible for 
 			   hanging up the channel, else it will never be hung up! */
 			return 0;
 		} else {
-			ast_log(LOG_WARNING, "Unable to park call %s\n", transferee->name);
+			ast_log(LOG_WARNING, "Unable to park call %s, parkstatus=%d\n", transferee->name, parkstatus);
 		}
 		/*! \todo XXX Maybe we should have another message here instead of invalid extension XXX */
 	} else if (ast_exists_extension(transferee, transferer_real_context, xferto, 1, transferer->cid.cid_num)) {
@@ -825,7 +853,7 @@
 		if (option_verbose > 2)	
 			ast_verbose(VERBOSE_PREFIX_3 "Unable to find extension '%s' in context '%s'\n", xferto, transferer_real_context);
 	}
-	if (ast_stream_and_wait(transferer, xferfailsound, transferer->language, AST_DIGIT_ANY) < 0 ) {
+	if (parkstatus != FEATURE_RETURN_PARKFAILED && ast_stream_and_wait(transferer, xferfailsound, transferer->language, AST_DIGIT_ANY) < 0 ) {
 		finishup(transferee);
 		return -1;
 	}
@@ -1213,6 +1241,9 @@
 		    !ast_strlen_zero(builtin_features[x].exten)) {
 			/* Feature is up for consideration */
 			if (!strcmp(builtin_features[x].exten, code)) {
+				if (option_debug > 2) {
+					ast_log(LOG_DEBUG, "Feature detected: fname=%s sname=%s exten=%s\n", builtin_features[x].fname, builtin_features[x].sname, builtin_features[x].exten);
+				}
 				res = builtin_features[x].operation(chan, peer, config, code, sense, NULL);
 				feature_detected = 1;
 				break;




More information about the asterisk-commits mailing list