[svn-commits] rmudgett: branch 1.8 r341254 - in /branches/1.8: channels/ channels/sip/inclu...

SVN commits to the Digium repositories svn-commits at lists.digium.com
Tue Oct 18 16:03:09 CDT 2011


Author: rmudgett
Date: Tue Oct 18 16:03:04 2011
New Revision: 341254

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=341254
Log:
More parking issues.

* Fix potential deadlocks in SIP and IAX blind transfer to parking.

* Fix SIP, IAX, DAHDI analog, and MGCP channel drivers to respect the
parkext_exclusive option with transfers (Park(,,,,,exclusive_lot)
parameter).  Created ast_park_call_exten() and ast_masq_park_call_exten()
to maintian API compatibility.

* Made masq_park_call() handle a failed ast_channel_masquerade() setup.

* Reduced excessive struct parkeduser.peername[] size.

Modified:
    branches/1.8/channels/chan_dahdi.c
    branches/1.8/channels/chan_iax2.c
    branches/1.8/channels/chan_mgcp.c
    branches/1.8/channels/chan_sip.c
    branches/1.8/channels/sig_analog.c
    branches/1.8/channels/sip/include/sip.h
    branches/1.8/include/asterisk/features.h
    branches/1.8/main/features.c

Modified: branches/1.8/channels/chan_dahdi.c
URL: http://svnview.digium.com/svn/asterisk/branches/1.8/channels/chan_dahdi.c?view=diff&rev=341254&r1=341253&r2=341254
==============================================================================
--- branches/1.8/channels/chan_dahdi.c (original)
+++ branches/1.8/channels/chan_dahdi.c Tue Oct 18 16:03:04 2011
@@ -10239,7 +10239,8 @@
 						ast_bridged_channel(p->subs[SUB_THREEWAY].owner)) {
 				/* This is a three way call, the main call being a real channel,
 					and we're parking the first call. */
-				ast_masq_park_call(ast_bridged_channel(p->subs[SUB_THREEWAY].owner), chan, 0, NULL);
+				ast_masq_park_call_exten(ast_bridged_channel(p->subs[SUB_THREEWAY].owner),
+					chan, exten, chan->context, 0, NULL);
 				ast_verb(3, "Parking call to '%s'\n", chan->name);
 				break;
 			} else if (p->hidecallerid && !strcmp(exten, "*82")) {

Modified: branches/1.8/channels/chan_iax2.c
URL: http://svnview.digium.com/svn/asterisk/branches/1.8/channels/chan_iax2.c?view=diff&rev=341254&r1=341253&r2=341254
==============================================================================
--- branches/1.8/channels/chan_iax2.c (original)
+++ branches/1.8/channels/chan_iax2.c Tue Oct 18 16:03:04 2011
@@ -9255,78 +9255,125 @@
 struct iax_dual {
 	struct ast_channel *chan1;
 	struct ast_channel *chan2;
-	const char *parkexten;
+	char *park_exten;
+	char *park_context;
 };
 
 static void *iax_park_thread(void *stuff)
 {
-	struct ast_channel *chan1, *chan2;
 	struct iax_dual *d;
-	struct ast_frame *f;
+	int res;
 	int ext = 0;
 
 	d = stuff;
-	chan1 = d->chan1;
-	chan2 = d->chan2;
+
+	ast_debug(4, "IAX Park: Transferer channel %s, Transferee %s\n",
+		d->chan2->name, d->chan1->name);
+
+	res = ast_park_call_exten(d->chan1, d->chan2, d->park_exten, d->park_context, 0, &ext);
+	if (res) {
+		/* Parking failed. */
+		ast_hangup(d->chan1);
+	} else {
+		ast_log(LOG_NOTICE, "Parked on extension '%d'\n", ext);
+	}
+	ast_hangup(d->chan2);
+
+	ast_free(d->park_exten);
+	ast_free(d->park_context);
 	ast_free(d);
-	f = ast_read(chan1);
-	if (f)
-		ast_frfree(f);
-	ast_park_call(chan1, chan2, 0, d->parkexten, &ext);
-	ast_hangup(chan2);
-	ast_log(LOG_NOTICE, "Parked on extension '%d'\n", ext);
 	return NULL;
 }
 
-static int iax_park(struct ast_channel *chan1, struct ast_channel *chan2, const char *parkexten)
+/*! DO NOT hold any locks while calling iax_park */
+static int iax_park(struct ast_channel *chan1, struct ast_channel *chan2, const char *park_exten, const char *park_context)
 {
 	struct iax_dual *d;
-	struct ast_channel *chan1m, *chan2m;
+	struct ast_channel *chan1m, *chan2m;/* Chan2m: The transferer, chan1m: The transferee */
 	pthread_t th;
+
 	chan1m = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, chan2->accountcode, chan1->exten, chan1->context, chan1->linkedid, chan1->amaflags, "Parking/%s", chan1->name);
 	chan2m = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, chan2->accountcode, chan2->exten, chan2->context, chan2->linkedid, chan2->amaflags, "IAXPeer/%s", chan2->name);
-	if (chan2m && chan1m) {
-		/* Make formats okay */
-		chan1m->readformat = chan1->readformat;
-		chan1m->writeformat = chan1->writeformat;
-		ast_channel_masquerade(chan1m, chan1);
-		/* Setup the extensions and such */
-		ast_copy_string(chan1m->context, chan1->context, sizeof(chan1m->context));
-		ast_copy_string(chan1m->exten, chan1->exten, sizeof(chan1m->exten));
-		chan1m->priority = chan1->priority;
-		
-		/* We make a clone of the peer channel too, so we can play
-		   back the announcement */
-		/* Make formats okay */
-		chan2m->readformat = chan2->readformat;
-		chan2m->writeformat = chan2->writeformat;
-		ast_channel_masquerade(chan2m, chan2);
-		/* Setup the extensions and such */
-		ast_copy_string(chan2m->context, chan2->context, sizeof(chan2m->context));
-		ast_copy_string(chan2m->exten, chan2->exten, sizeof(chan2m->exten));
-		chan2m->priority = chan2->priority;
-		if (ast_do_masquerade(chan2m)) {
-			ast_log(LOG_WARNING, "Masquerade failed :(\n");
+	d = ast_calloc(1, sizeof(*d));
+	if (!chan1m || !chan2m || !d) {
+		if (chan1m) {
+			ast_hangup(chan1m);
+		}
+		if (chan2m) {
 			ast_hangup(chan2m);
-			return -1;
-		}
-	} else {
-		if (chan1m)
-			ast_hangup(chan1m);
-		if (chan2m)
-			ast_hangup(chan2m);
+		}
+		ast_free(d);
 		return -1;
 	}
-	if ((d = ast_calloc(1, sizeof(*d)))) {
-		d->chan1 = chan1m;
-		d->chan2 = chan2m;
-		d->parkexten = parkexten;
-		if (!ast_pthread_create_detached_background(&th, NULL, iax_park_thread, d)) {
-			return 0;
-		}
+	d->park_exten = ast_strdup(park_exten);
+	d->park_context = ast_strdup(park_context);
+	if (!d->park_exten || !d->park_context) {
+		ast_hangup(chan1m);
+		ast_hangup(chan2m);
+		ast_free(d->park_exten);
+		ast_free(d->park_context);
 		ast_free(d);
-	}
-	return -1;
+		return -1;
+	}
+
+	/* Make formats okay */
+	chan1m->readformat = chan1->readformat;
+	chan1m->writeformat = chan1->writeformat;
+
+	/* Prepare for taking over the channel */
+	if (ast_channel_masquerade(chan1m, chan1)) {
+		ast_hangup(chan1m);
+		ast_hangup(chan2m);
+		ast_free(d->park_exten);
+		ast_free(d->park_context);
+		ast_free(d);
+		return -1;
+	}
+
+	/* Setup the extensions and such */
+	ast_copy_string(chan1m->context, chan1->context, sizeof(chan1m->context));
+	ast_copy_string(chan1m->exten, chan1->exten, sizeof(chan1m->exten));
+	chan1m->priority = chan1->priority;
+
+	ast_do_masquerade(chan1m);
+
+	/* We make a clone of the peer channel too, so we can play
+	   back the announcement */
+
+	/* Make formats okay */
+	chan2m->readformat = chan2->readformat;
+	chan2m->writeformat = chan2->writeformat;
+	ast_string_field_set(chan2m, parkinglot, chan2->parkinglot);
+
+	/* Prepare for taking over the channel */
+	if (ast_channel_masquerade(chan2m, chan2)) {
+		ast_hangup(chan1m);
+		ast_hangup(chan2m);
+		ast_free(d->park_exten);
+		ast_free(d->park_context);
+		ast_free(d);
+		return -1;
+	}
+
+	/* Setup the extensions and such */
+	ast_copy_string(chan2m->context, chan2->context, sizeof(chan2m->context));
+	ast_copy_string(chan2m->exten, chan2->exten, sizeof(chan2m->exten));
+	chan2m->priority = chan2->priority;
+
+	ast_do_masquerade(chan2m);
+
+	d->chan1 = chan1m;	/* Transferee */
+	d->chan2 = chan2m;	/* Transferer */
+	if (ast_pthread_create_detached_background(&th, NULL, iax_park_thread, d) < 0) {
+		/* Could not start thread */
+		ast_hangup(chan1m);
+		ast_hangup(chan2m);
+		ast_free(d->park_exten);
+		ast_free(d->park_context);
+		ast_free(d);
+		return -1;
+	}
+	return 0;
 }
 
 static int check_provisioning(struct sockaddr_in *sin, int sockfd, char *si, unsigned int ver)
@@ -10695,43 +10742,45 @@
 				owner = iaxs[fr->callno]->owner;
 				bridged_chan = owner ? ast_bridged_channel(owner) : NULL;
 				if (bridged_chan && ies.called_number) {
+					const char *context;
+
+					context = ast_strdupa(iaxs[fr->callno]->context);
+
+					ast_channel_ref(owner);
+					ast_channel_ref(bridged_chan);
+					ast_channel_unlock(owner);
 					ast_mutex_unlock(&iaxsl[fr->callno]);
 
 					/* Set BLINDTRANSFER channel variables */
 					pbx_builtin_setvar_helper(owner, "BLINDTRANSFER", bridged_chan->name);
 					pbx_builtin_setvar_helper(bridged_chan, "BLINDTRANSFER", owner->name);
 
-					if (ast_parking_ext_valid(ies.called_number, owner, iaxs[fr->callno]->context)) {
+					/* DO NOT hold any locks while calling ast_parking_ext_valid() */
+					if (ast_parking_ext_valid(ies.called_number, owner, context)) {
 						ast_debug(1, "Parking call '%s'\n", bridged_chan->name);
-						if (iax_park(bridged_chan, owner, ies.called_number)) {
+						if (iax_park(bridged_chan, owner, ies.called_number, context)) {
 							ast_log(LOG_WARNING, "Failed to park call '%s'\n",
 								bridged_chan->name);
 						}
-						ast_mutex_lock(&iaxsl[fr->callno]);
 					} else {
-						ast_mutex_lock(&iaxsl[fr->callno]);
-
-						if (iaxs[fr->callno]) {
-							if (ast_async_goto(bridged_chan, iaxs[fr->callno]->context,
-								ies.called_number, 1)) {
-								ast_log(LOG_WARNING,
-									"Async goto of '%s' to '%s@%s' failed\n",
-									bridged_chan->name, ies.called_number,
-									iaxs[fr->callno]->context);
-							} else {
-								ast_debug(1, "Async goto of '%s' to '%s@%s' started\n",
-									bridged_chan->name, ies.called_number,
-									iaxs[fr->callno]->context);
-							}
+						if (ast_async_goto(bridged_chan, context, ies.called_number, 1)) {
+							ast_log(LOG_WARNING,
+								"Async goto of '%s' to '%s@%s' failed\n",
+								bridged_chan->name, ies.called_number, context);
 						} else {
-							/* Initiating call went away before we could transfer. */
+							ast_debug(1, "Async goto of '%s' to '%s@%s' started\n",
+								bridged_chan->name, ies.called_number, context);
 						}
 					}
+					ast_channel_unref(owner);
+					ast_channel_unref(bridged_chan);
+
+					ast_mutex_lock(&iaxsl[fr->callno]);
 				} else {
 					ast_debug(1, "Async goto not applicable on call %d\n", fr->callno);
-				}
-				if (owner) {
-					ast_channel_unlock(owner);
+					if (owner) {
+						ast_channel_unlock(owner);
+					}
 				}
 
 				break;

Modified: branches/1.8/channels/chan_mgcp.c
URL: http://svnview.digium.com/svn/asterisk/branches/1.8/channels/chan_mgcp.c?view=diff&rev=341254&r1=341253&r2=341254
==============================================================================
--- branches/1.8/channels/chan_mgcp.c (original)
+++ branches/1.8/channels/chan_mgcp.c Tue Oct 18 16:03:04 2011
@@ -3117,7 +3117,8 @@
 			sub->next->owner && ast_bridged_channel(sub->next->owner)) {
 			/* This is a three way call, the main call being a real channel,
 			   and we're parking the first call. */
-			ast_masq_park_call(ast_bridged_channel(sub->next->owner), chan, 0, NULL);
+			ast_masq_park_call_exten(ast_bridged_channel(sub->next->owner), chan,
+				p->dtmf_buf, chan->context, 0, NULL);
 			ast_verb(3, "Parking call to '%s'\n", chan->name);
 			break;
 		} else if (!ast_strlen_zero(p->lastcallerid) && !strcmp(p->dtmf_buf, "*60")) {

Modified: branches/1.8/channels/chan_sip.c
URL: http://svnview.digium.com/svn/asterisk/branches/1.8/channels/chan_sip.c?view=diff&rev=341254&r1=341253&r2=341254
==============================================================================
--- branches/1.8/channels/chan_sip.c (original)
+++ branches/1.8/channels/chan_sip.c Tue Oct 18 16:03:04 2011
@@ -1269,7 +1269,7 @@
 static struct sip_pvt *get_sip_pvt_byid_locked(const char *callid, const char *totag, const char *fromtag);
 static void check_pendings(struct sip_pvt *p);
 static void *sip_park_thread(void *stuff);
-static int sip_park(struct ast_channel *chan1, struct ast_channel *chan2, struct sip_request *req, int seqno, char *parkexten);
+static int sip_park(struct ast_channel *chan1, struct ast_channel *chan2, struct sip_request *req, int seqno, const char *park_exten, const char *park_context);
 
 static void *sip_pickup_thread(void *stuff);
 static int sip_pickup(struct ast_channel *chan);
@@ -20814,33 +20814,16 @@
 {
 	struct ast_channel *transferee, *transferer;	/* Chan1: The transferee, Chan2: The transferer */
 	struct sip_dual *d;
-	struct sip_request req = {0,};
 	int ext;
 	int res;
 
 	d = stuff;
 	transferee = d->chan1;
 	transferer = d->chan2;
-	copy_request(&req, &d->req);
-
-	if (!transferee || !transferer) {
-		ast_log(LOG_ERROR, "Missing channels for parking! Transferer %s Transferee %s\n", transferer ? "<available>" : "<missing>", transferee ? "<available>" : "<missing>" );
-		deinit_req(&d->req);
-		ast_free(d);
-		return NULL;
-	}
+
 	ast_debug(4, "SIP Park: Transferer channel %s, Transferee %s\n", transferer->name, transferee->name);
 
-	if (ast_do_masquerade(transferee)) {
-		ast_log(LOG_WARNING, "Masquerade failed.\n");
-		transmit_response(transferer->tech_pvt, "503 Internal error", &req);
-		deinit_req(&d->req);
-		ast_free(d);
-		return NULL;
-	}
-
-	res = ast_park_call(transferee, transferer, 0, d->parkexten, &ext);
-	
+	res = ast_park_call_exten(transferee, transferer, d->park_exten, d->park_context, 0, &ext);
 
 #ifdef WHEN_WE_KNOW_THAT_THE_CLIENT_SUPPORTS_MESSAGE
 	if (res) {
@@ -20868,31 +20851,40 @@
 		/* Do not hangup call */
 	}
 	deinit_req(&d->req);
+	ast_free(d->park_exten);
+	ast_free(d->park_context);
 	ast_free(d);
 	return NULL;
 }
 
-/*! \brief Park a call using the subsystem in res_features.c
-	This is executed in a separate thread
-*/
-static int sip_park(struct ast_channel *chan1, struct ast_channel *chan2, struct sip_request *req, int seqno, char *parkexten)
+/*! DO NOT hold any locks while calling sip_park */
+static int sip_park(struct ast_channel *chan1, struct ast_channel *chan2, struct sip_request *req, int seqno, const char *park_exten, const char *park_context)
 {
 	struct sip_dual *d;
 	struct ast_channel *transferee, *transferer;
-		/* Chan2m: The transferer, chan1m: The transferee */
 	pthread_t th;
 
 	transferee = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, chan1->accountcode, chan1->exten, chan1->context, chan1->linkedid, chan1->amaflags, "Parking/%s", chan1->name);
 	transferer = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, chan2->accountcode, chan2->exten, chan2->context, chan2->linkedid, chan2->amaflags, "SIPPeer/%s", chan2->name);
-	if ((!transferer) || (!transferee)) {
+	d = ast_calloc(1, sizeof(*d));
+	if (!transferee || !transferer || !d) {
 		if (transferee) {
-			transferee->hangupcause = AST_CAUSE_SWITCH_CONGESTION;
 			ast_hangup(transferee);
 		}
 		if (transferer) {
-			transferer->hangupcause = AST_CAUSE_SWITCH_CONGESTION;
 			ast_hangup(transferer);
 		}
+		ast_free(d);
+		return -1;
+	}
+	d->park_exten = ast_strdup(park_exten);
+	d->park_context = ast_strdup(park_context);
+	if (!d->park_exten || !d->park_context) {
+		ast_hangup(transferee);
+		ast_hangup(transferer);
+		ast_free(d->park_exten);
+		ast_free(d->park_context);
+		ast_free(d);
 		return -1;
 	}
 
@@ -20901,67 +20893,56 @@
 	transferee->writeformat = chan1->writeformat;
 
 	/* Prepare for taking over the channel */
-	ast_channel_masquerade(transferee, chan1);
+	if (ast_channel_masquerade(transferee, chan1)) {
+		ast_hangup(transferee);
+		ast_hangup(transferer);
+		ast_free(d->park_exten);
+		ast_free(d->park_context);
+		ast_free(d);
+		return -1;
+	}
 
 	/* Setup the extensions and such */
 	ast_copy_string(transferee->context, chan1->context, sizeof(transferee->context));
 	ast_copy_string(transferee->exten, chan1->exten, sizeof(transferee->exten));
 	transferee->priority = chan1->priority;
-		
+
+	ast_do_masquerade(transferee);
+
 	/* We make a clone of the peer channel too, so we can play
 	   back the announcement */
 
 	/* Make formats okay */
 	transferer->readformat = chan2->readformat;
 	transferer->writeformat = chan2->writeformat;
-	if (!ast_strlen_zero(chan2->parkinglot))
-		ast_string_field_set(transferer, parkinglot, chan2->parkinglot);
-
-	/* Prepare for taking over the channel.  Go ahead and grab this channel
-	 * lock here to avoid a deadlock with callbacks into the channel driver
-	 * that hold the channel lock and want the pvt lock.  */
-	while (ast_channel_trylock(chan2)) {
-		struct sip_pvt *pvt = chan2->tech_pvt;
-		sip_pvt_unlock(pvt);
-		usleep(1);
-		sip_pvt_lock(pvt);
-	}
-	ast_channel_masquerade(transferer, chan2);
-	ast_channel_unlock(chan2);
+	ast_string_field_set(transferer, parkinglot, chan2->parkinglot);
+
+	/* Prepare for taking over the channel */
+	if (ast_channel_masquerade(transferer, chan2)) {
+		ast_hangup(transferer);
+		ast_free(d->park_exten);
+		ast_free(d->park_context);
+		ast_free(d);
+		return -1;
+	}
 
 	/* Setup the extensions and such */
 	ast_copy_string(transferer->context, chan2->context, sizeof(transferer->context));
 	ast_copy_string(transferer->exten, chan2->exten, sizeof(transferer->exten));
 	transferer->priority = chan2->priority;
 
-	if (ast_do_masquerade(transferer)) {
-		ast_log(LOG_WARNING, "Masquerade failed :(\n");
-		transferer->hangupcause = AST_CAUSE_SWITCH_CONGESTION;
-		ast_hangup(transferer);
-		return -1;
-	}
-	if (!transferer || !transferee) {
-		if (!transferer) {
-			ast_debug(1, "No transferer channel, giving up parking\n");
-		}
-		if (!transferee) {
-			ast_debug(1, "No transferee channel, giving up parking\n");
-		}
-		return -1;
-	}
-	if (!(d = ast_calloc(1, sizeof(*d)))) {
-		return -1;
-	}
+	ast_do_masquerade(transferer);
 
 	/* Save original request for followup */
 	copy_request(&d->req, req);
 	d->chan1 = transferee;	/* Transferee */
 	d->chan2 = transferer;	/* Transferer */
 	d->seqno = seqno;
-	d->parkexten = parkexten;
 	if (ast_pthread_create_detached_background(&th, NULL, sip_park_thread, d) < 0) {
 		/* Could not start thread */
 		deinit_req(&d->req);
+		ast_free(d->park_exten);
+		ast_free(d->park_context);
 		ast_free(d);	/* We don't need it anymore. If thread is created, d will be free'd
 				   by sip_park_thread() */
 		return -1;
@@ -22987,6 +22968,7 @@
 	callid = ast_strdupa(p->callid);
 	localtransfer = p->refer->localtransfer;
 	attendedtransfer = p->refer->attendedtransfer;
+
 	if (!*nounlock) {
 		ast_channel_unlock(p->owner);
 		*nounlock = 1;
@@ -22995,9 +22977,6 @@
 
 	/* Parking a call.  DO NOT hold any locks while calling ast_parking_ext_valid() */
 	if (localtransfer && ast_parking_ext_valid(refer_to, current.chan1, current.chan1->context)) {
-
-		copy_request(&current.req, req);
-
 		sip_pvt_lock(p);
 		ast_clear_flag(&p->flags[0], SIP_GOTREFER);
 		p->refer->status = REFER_200OK;
@@ -23026,7 +23005,7 @@
 		}
 
 		/* DO NOT hold any locks while calling sip_park */
-		if (sip_park(current.chan2, current.chan1, req, seqno, refer_to)) {
+		if (sip_park(current.chan2, current.chan1, req, seqno, refer_to, current.chan1->context)) {
 			sip_pvt_lock(p);
 			transmit_notify_with_sipfrag(p, seqno, "500 Internal Server Error", TRUE);
 		} else {

Modified: branches/1.8/channels/sig_analog.c
URL: http://svnview.digium.com/svn/asterisk/branches/1.8/channels/sig_analog.c?view=diff&rev=341254&r1=341253&r2=341254
==============================================================================
--- branches/1.8/channels/sig_analog.c (original)
+++ branches/1.8/channels/sig_analog.c Tue Oct 18 16:03:04 2011
@@ -2258,7 +2258,9 @@
 						ast_bridged_channel(p->subs[ANALOG_SUB_THREEWAY].owner)) {
 				/* This is a three way call, the main call being a real channel,
 					and we're parking the first call. */
-				ast_masq_park_call(ast_bridged_channel(p->subs[ANALOG_SUB_THREEWAY].owner), chan, 0, NULL);
+				ast_masq_park_call_exten(
+					ast_bridged_channel(p->subs[ANALOG_SUB_THREEWAY].owner), chan, exten,
+					chan->context, 0, NULL);
 				ast_verb(3, "Parking call to '%s'\n", chan->name);
 				break;
 			} else if (!ast_strlen_zero(p->lastcid_num) && !strcmp(exten, "*60")) {

Modified: branches/1.8/channels/sip/include/sip.h
URL: http://svnview.digium.com/svn/asterisk/branches/1.8/channels/sip/include/sip.h?view=diff&rev=341254&r1=341253&r2=341254
==============================================================================
--- branches/1.8/channels/sip/include/sip.h (original)
+++ branches/1.8/channels/sip/include/sip.h Tue Oct 18 16:03:04 2011
@@ -774,7 +774,8 @@
 	struct ast_channel *chan2;   /*!< Second channel involved */
 	struct sip_request req;      /*!< Request that caused the transfer (REFER) */
 	int seqno;                   /*!< Sequence number */
-	const char *parkexten;
+	char *park_exten;
+	char *park_context;
 };
 
 /*! \brief Parameters to the transmit_invite function */

Modified: branches/1.8/include/asterisk/features.h
URL: http://svnview.digium.com/svn/asterisk/branches/1.8/include/asterisk/features.h?view=diff&rev=341254&r1=341253&r2=341254
==============================================================================
--- branches/1.8/include/asterisk/features.h (original)
+++ branches/1.8/include/asterisk/features.h Tue Oct 18 16:03:04 2011
@@ -78,33 +78,87 @@
 };
 
 /*!
- * \brief Park a call and read back parked location 
- * \param chan the channel to actually be parked
- * \param host the channel which will have the parked location read to.
- * \param timeout is a timeout in milliseconds
- * \param extout is a parameter to an int that will hold the parked location, or NULL if you want.
- * 
- * Park the channel chan, and read back the parked location to the host. 
- * If the call is not picked up within a specified period of time, 
- * then the call will return to the last step that it was in 
- * (in terms of exten, priority and context)
- * \retval 0 on success.
- * \retval -1 on failure.
-*/
-int ast_park_call(struct ast_channel *chan, struct ast_channel *host, int timeout, const char *parkexten, int *extout);
-
-/*! 
+ * \brief Park a call and read back parked location
+ *
+ * \param park_me Channel to be parked.
+ * \param parker Channel parking the call.
+ * \param timeout is a timeout in milliseconds
+ * \param park_exten Parking lot access extension (Not used)
+ * \param extout is a parameter to an int that will hold the parked location, or NULL if you want.
+ *
+ * \details
+ * Park the park_me channel, and read back the parked location
+ * to the parker channel.  If the call is not picked up within a
+ * specified period of time, then the call will return to the
+ * last step that it was in (in terms of exten, priority and
+ * context).
+ *
+ * \note Use ast_park_call_exten() instead.
+ *
+ * \retval 0 on success.
+ * \retval -1 on failure.
+ */
+int ast_park_call(struct ast_channel *park_me, struct ast_channel *parker, int timeout, const char *park_exten, int *extout);
+
+/*!
+ * \brief Park a call and read back parked location
+ * \since 1.8.9
+ *
+ * \param park_me Channel to be parked.
+ * \param parker Channel parking the call.
+ * \param park_exten Parking lot access extension
+ * \param park_context Parking lot context
+ * \param timeout is a timeout in milliseconds
+ * \param extout is a parameter to an int that will hold the parked location, or NULL if you want.
+ *
+ * \details
+ * Park the park_me channel, and read back the parked location
+ * to the parker channel.  If the call is not picked up within a
+ * specified period of time, then the call will return to the
+ * last step that it was in (in terms of exten, priority and
+ * context).
+ *
+ * \retval 0 on success.
+ * \retval -1 on failure.
+ */
+int ast_park_call_exten(struct ast_channel *park_me, struct ast_channel *parker, const char *park_exten, const char *park_context, int timeout, int *extout);
+
+/*!
  * \brief Park a call via a masqueraded channel
- * \param rchan the real channel to be parked
- * \param host the channel to have the parking read to.
- * \param timeout is a timeout in milliseconds
- * \param extout is a parameter to an int that will hold the parked location, or NULL if you want.
- * 
- * Masquerade the channel rchan into a new, empty channel which is then parked with ast_park_call
- * \retval 0 on success.
- * \retval -1 on failure.
-*/
-int ast_masq_park_call(struct ast_channel *rchan, struct ast_channel *host, int timeout, int *extout);
+ *
+ * \param park_me Channel to be parked.
+ * \param parker Channel parking the call.
+ * \param timeout is a timeout in milliseconds
+ * \param extout is a parameter to an int that will hold the parked location, or NULL if you want.
+ *
+ * \details
+ * Masquerade the park_me channel into a new, empty channel which is then parked.
+ *
+ * \note Use ast_masq_park_call_exten() instead.
+ *
+ * \retval 0 on success.
+ * \retval -1 on failure.
+ */
+int ast_masq_park_call(struct ast_channel *park_me, struct ast_channel *parker, int timeout, int *extout);
+
+/*!
+ * \brief Park a call via a masqueraded channel
+ * \since 1.8.9
+ *
+ * \param park_me Channel to be parked.
+ * \param parker Channel parking the call.
+ * \param park_exten Parking lot access extension
+ * \param park_context Parking lot context
+ * \param timeout is a timeout in milliseconds
+ * \param extout is a parameter to an int that will hold the parked location, or NULL if you want.
+ *
+ * \details
+ * Masquerade the park_me channel into a new, empty channel which is then parked.
+ *
+ * \retval 0 on success.
+ * \retval -1 on failure.
+ */
+int ast_masq_park_call_exten(struct ast_channel *park_me, struct ast_channel *parker, const char *park_exten, const char *park_context, int timeout, int *extout);
 
 /*! 
  * \brief Determine if parking extension exists in a given context

Modified: branches/1.8/main/features.c
URL: http://svnview.digium.com/svn/asterisk/branches/1.8/main/features.c?view=diff&rev=341254&r1=341253&r2=341254
==============================================================================
--- branches/1.8/main/features.c (original)
+++ branches/1.8/main/features.c Tue Oct 18 16:03:04 2011
@@ -480,7 +480,7 @@
 	enum ast_control_frame_type hold_method;
 	unsigned int notquiteyet:1;
 	unsigned int options_specified:1;
-	char peername[1024];
+	char peername[AST_CHANNEL_NAME];
 	unsigned char moh_trys;
 	/*! Parking lot this entry belongs to.  Holds a parking lot reference. */
 	struct ast_parkinglot *parkinglot;
@@ -1171,6 +1171,32 @@
 
 /*!
  * \internal
+ * \brief Abort parking a call that has not completed parking yet.
+ *
+ * \param pu Parked user item to clean up.
+ *
+ * \note The parking lot parkings list is locked on entry.
+ *
+ * \return Nothing
+ */
+static void park_space_abort(struct parkeduser *pu)
+{
+	struct ast_parkinglot *parkinglot;
+
+	parkinglot = pu->parkinglot;
+
+	/* Put back the parking space just allocated. */
+	--parkinglot->next_parking_space;
+
+	AST_LIST_REMOVE(&parkinglot->parkings, pu, list);
+
+	AST_LIST_UNLOCK(&parkinglot->parkings);
+	parkinglot_unref(parkinglot);
+	ast_free(pu);
+}
+
+/*!
+ * \internal
  * \brief Reserve a parking space in a parking lot for a call being parked.
  *
  * \param park_me Channel being parked.
@@ -1525,38 +1551,80 @@
 	return 0;
 }
 
-/*! \brief Park a call */
-int ast_park_call(struct ast_channel *chan, struct ast_channel *peer, int timeout, const char *parkexten, int *extout)
-{
+int ast_park_call_exten(struct ast_channel *park_me, struct ast_channel *parker, const char *park_exten, const char *park_context, int timeout, int *extout)
+{
+	int res;
+	char *parse;
+	const char *app_data;
+	struct ast_exten *exten;
+	struct park_app_args app_args;
 	struct ast_park_call_args args = {
 		.timeout = timeout,
 		.extout = extout,
 	};
 
-	return park_call_full(chan, peer, &args);
+	if (!park_exten || !park_context) {
+		return park_call_full(park_me, parker, &args);
+	}
+
+	/*
+	 * Determiine if the specified park extension has an exclusive
+	 * parking lot to use.
+	 */
+	if (parker && parker != park_me) {
+		ast_autoservice_start(park_me);
+	}
+	exten = get_parking_exten(park_exten, parker, park_context);
+	if (exten) {
+		app_data = ast_get_extension_app_data(exten);
+		if (!app_data) {
+			app_data = "";
+		}
+		parse = ast_strdupa(app_data);
+		AST_STANDARD_APP_ARGS(app_args, parse);
+	
+		if (!ast_strlen_zero(app_args.pl_name)) {
+			/* Find the specified exclusive parking lot */
+			args.parkinglot = find_parkinglot(app_args.pl_name);
+			if (!args.parkinglot && parkeddynamic) {
+				args.parkinglot = create_dynamic_parkinglot(app_args.pl_name, park_me);
+			}
+		}
+	}
+	if (parker && parker != park_me) {
+		ast_autoservice_stop(park_me);
+	}
+
+	res = park_call_full(park_me, parker, &args);
+	if (args.parkinglot) {
+		parkinglot_unref(args.parkinglot);
+	}
+	return res;
+}
+
+int ast_park_call(struct ast_channel *park_me, struct ast_channel *parker, int timeout, const char *park_exten, int *extout)
+{
+	struct ast_park_call_args args = {
+		.timeout = timeout,
+		.extout = extout,
+	};
+
+	return park_call_full(park_me, parker, &args);
 }
 
 /*!
+ * \brief Park call via masqueraded channel and announce parking spot on peer channel.
+ *
  * \param rchan the real channel to be parked
  * \param peer the channel to have the parking read to.
- * \param timeout is a timeout in milliseconds
- * \param extout is a parameter to an int that will hold the parked location, or NULL if you want.
- * \param play_announcement TRUE if to play which parking space call parked in to peer.
- * \param args Optional additional parking options when parking a call.
+ * \param args Additional parking options when parking a call.
  *
  * \retval 0 on success.
  * \retval -1 on failure.
  */
-static int masq_park_call(struct ast_channel *rchan, struct ast_channel *peer, int timeout, int *extout, int play_announcement, struct ast_park_call_args *args)
+static int masq_park_call(struct ast_channel *rchan, struct ast_channel *peer, struct ast_park_call_args *args)
 {
 	struct ast_channel *chan;
-	struct ast_park_call_args park_args = {0,};
-
-	if (!args) {
-		args = &park_args;
-		args->timeout = timeout;
-		args->extout = extout;
-	}
 
 	/* Make a new, channel that we'll use to masquerade in the real one */
 	chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, rchan->accountcode, rchan->exten,
@@ -1577,7 +1645,6 @@
 
 	args->pu = park_space_reserve(rchan, peer, args);
 	if (!args->pu) {
-		chan->hangupcause = AST_CAUSE_SWITCH_CONGESTION;
 		ast_hangup(chan);
 		if (!ast_test_flag(args, AST_PARK_OPT_SILENCE)) {
 			if (peer == rchan) {
@@ -1594,7 +1661,22 @@
 	/* Make formats okay */
 	chan->readformat = rchan->readformat;
 	chan->writeformat = rchan->writeformat;
-	ast_channel_masquerade(chan, rchan);
+
+	if (ast_channel_masquerade(chan, rchan)) {
+		park_space_abort(args->pu);
+		args->pu = NULL;
+		ast_hangup(chan);
+		if (!ast_test_flag(args, AST_PARK_OPT_SILENCE)) {
+			if (peer == rchan) {
+				/* Only have one channel to worry about. */
+				ast_stream_and_wait(peer, "pbx-parkingfailed", "");
+			} else if (peer) {
+				/* Have two different channels to worry about. */
+				play_message_on_chan(peer, rchan, "failure message", "pbx-parkingfailed");
+			}
+		}
+		return -1;
+	}
 
 	/* Setup the extensions and such */
 	set_c_e_p(chan, rchan->context, rchan->exten, rchan->priority);
@@ -1611,34 +1693,77 @@
 		peer = chan;
 	}
 
-	if (peer && (!play_announcement && args == &park_args)) {
-		args->orig_chan_name = ast_strdupa(peer->name);
-	}
-
 	/* parking space reserved, return code check unnecessary */
 	park_call_full(chan, peer, args);
 
 	return 0;
 }
 
+int ast_masq_park_call_exten(struct ast_channel *park_me, struct ast_channel *parker, const char *park_exten, const char *park_context, int timeout, int *extout)
+{
+	int res;
+	char *parse;
+	const char *app_data;
+	struct ast_exten *exten;
+	struct park_app_args app_args;
+	struct ast_park_call_args args = {
+		.timeout = timeout,
+		.extout = extout,
+	};
+
+	if (parker) {
+		args.orig_chan_name = ast_strdupa(parker->name);
+	}
+	if (!park_exten || !park_context) {
+		return masq_park_call(park_me, parker, &args);
+	}
+
+	/*
+	 * Determiine if the specified park extension has an exclusive
+	 * parking lot to use.
+	 */
+	if (parker && parker != park_me) {
+		ast_autoservice_start(park_me);
+	}
+	exten = get_parking_exten(park_exten, parker, park_context);
+	if (exten) {
+		app_data = ast_get_extension_app_data(exten);
+		if (!app_data) {
+			app_data = "";
+		}
+		parse = ast_strdupa(app_data);
+		AST_STANDARD_APP_ARGS(app_args, parse);
+	
+		if (!ast_strlen_zero(app_args.pl_name)) {
+			/* Find the specified exclusive parking lot */
+			args.parkinglot = find_parkinglot(app_args.pl_name);
+			if (!args.parkinglot && parkeddynamic) {
+				args.parkinglot = create_dynamic_parkinglot(app_args.pl_name, park_me);
+			}
+		}
+	}
+	if (parker && parker != park_me) {
+		ast_autoservice_stop(park_me);
+	}
+
+	res = masq_park_call(park_me, parker, &args);
+	if (args.parkinglot) {
+		parkinglot_unref(args.parkinglot);
+	}
+	return res;
+}
+
 int ast_masq_park_call(struct ast_channel *rchan, struct ast_channel *peer, int timeout, int *extout)
 {
-	return masq_park_call(rchan, peer, timeout, extout, 0, NULL);
-}
-
-/*!
- * \brief Park call via masqueraded channel and announce parking spot on peer channel.
- *
- * \param rchan the real channel to be parked
- * \param peer the channel to have the parking read to.
- * \param args Optional additional parking options when parking a call.
- *
- * \retval 0 on success.
- * \retval -1 on failure.
- */
-static int masq_park_call_announce(struct ast_channel *rchan, struct ast_channel *peer, struct ast_park_call_args *args)
-{
-	return masq_park_call(rchan, peer, 0, NULL, 1, args);
+	struct ast_park_call_args args = {
+		.timeout = timeout,
+		.extout = extout,
+	};
+
+	if (peer) {
+		args.orig_chan_name = ast_strdupa(peer->name);
+	}
+	return masq_park_call(rchan, peer, &args);
 }
 
 static int finishup(struct ast_channel *chan)
@@ -1702,7 +1827,7 @@
 			parkinglot_unref(args.parkinglot);
 			return -1;
 		}
-		res = masq_park_call_announce(park_me, parker, &args);
+		res = masq_park_call(park_me, parker, &args);
 		parkinglot_unref(args.parkinglot);
 	} else {
 		/* Parking failed because parking lot does not exist. */
@@ -1751,6 +1876,7 @@
 {
 	struct ast_channel *parker;
 	struct ast_channel *parkee;
+	struct ast_park_call_args args = { 0, };
 
 	/*
 	 * We used to set chan's exten and priority to "s" and 1 here,
@@ -1779,8 +1905,7 @@
 
 	/* one direction used to call park_call.... */
 	set_peers(&parker, &parkee, peer, chan, sense);
-	return masq_park_call_announce(parkee, parker, NULL)
-		? AST_FEATURE_RETURN_SUCCESS : -1;
+	return masq_park_call(parkee, parker, &args) ? AST_FEATURE_RETURN_SUCCESS : -1;
 }
 
 /*!
@@ -4811,7 +4936,7 @@
 		}
 	}
 	if (args.parkinglot) {
-		res = masq_park_call_announce(chan, chan, &args);
+		res = masq_park_call(chan, chan, &args);
 		parkinglot_unref(args.parkinglot);
 	} else {
 		/* Parking failed because the parking lot does not exist. */
@@ -6950,7 +7075,7 @@
 		args.parkinglot = find_parkinglot(parkinglotname);
 	}
 
-	res = masq_park_call(ch1, ch2, 0, NULL, 0, &args);
+	res = masq_park_call(ch1, ch2, &args);
 	if (!res) {
 		ast_softhangup(ch2, AST_SOFTHANGUP_EXPLICIT);
 		astman_send_ack(s, m, "Park successful");
@@ -7870,7 +7995,7 @@
 	pbx_builtin_setvar_helper(test_channel1, "PARKINGDYNCONTEXT", unique_context_2);
 	pbx_builtin_setvar_helper(test_channel1, "PARKINGDYNEXTEN", parkinglot_parkext);
 	pbx_builtin_setvar_helper(test_channel1, "PARKINGDYNPOS", parkinglot_range);
-	if (masq_park_call(test_channel1, NULL, 0, NULL, 0, &args)) {
+	if (masq_park_call(test_channel1, NULL, &args)) {
 		res = -1;
 		goto exit_features_test;
 	}




More information about the svn-commits mailing list