[asterisk-commits] rmudgett: branch 10 r341255 - in /branches/10: ./ channels/ channels/sip/incl...
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Tue Oct 18 16:11:47 CDT 2011
Author: rmudgett
Date: Tue Oct 18 16:11:42 2011
New Revision: 341255
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=341255
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.
........
Merged revisions 341254 from http://svn.asterisk.org/svn/asterisk/branches/1.8
Modified:
branches/10/ (props changed)
branches/10/channels/chan_dahdi.c
branches/10/channels/chan_iax2.c
branches/10/channels/chan_mgcp.c
branches/10/channels/chan_sip.c
branches/10/channels/sig_analog.c
branches/10/channels/sip/include/sip.h
branches/10/include/asterisk/features.h
branches/10/main/features.c
Propchange: branches/10/
------------------------------------------------------------------------------
Binary property 'branch-1.8-merged' - no diff available.
Modified: branches/10/channels/chan_dahdi.c
URL: http://svnview.digium.com/svn/asterisk/branches/10/channels/chan_dahdi.c?view=diff&rev=341255&r1=341254&r2=341255
==============================================================================
--- branches/10/channels/chan_dahdi.c (original)
+++ branches/10/channels/chan_dahdi.c Tue Oct 18 16:11:42 2011
@@ -10324,7 +10324,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/10/channels/chan_iax2.c
URL: http://svnview.digium.com/svn/asterisk/branches/10/channels/chan_iax2.c?view=diff&rev=341255&r1=341254&r2=341255
==============================================================================
--- branches/10/channels/chan_iax2.c (original)
+++ branches/10/channels/chan_iax2.c Tue Oct 18 16:11:42 2011
@@ -9358,78 +9358,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)
@@ -10806,43 +10853,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/10/channels/chan_mgcp.c
URL: http://svnview.digium.com/svn/asterisk/branches/10/channels/chan_mgcp.c?view=diff&rev=341255&r1=341254&r2=341255
==============================================================================
--- branches/10/channels/chan_mgcp.c (original)
+++ branches/10/channels/chan_mgcp.c Tue Oct 18 16:11:42 2011
@@ -3133,7 +3133,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/10/channels/chan_sip.c
URL: http://svnview.digium.com/svn/asterisk/branches/10/channels/chan_sip.c?view=diff&rev=341255&r1=341254&r2=341255
==============================================================================
--- branches/10/channels/chan_sip.c (original)
+++ branches/10/channels/chan_sip.c Tue Oct 18 16:11:42 2011
@@ -1286,7 +1286,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);
@@ -21389,32 +21389,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) {
@@ -21442,31 +21426,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;
}
@@ -21475,67 +21468,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;
@@ -23562,6 +23544,7 @@
callid = ast_strdupa(p->callid);
localtransfer = p->refer->localtransfer;
attendedtransfer = p->refer->attendedtransfer;
+
if (!*nounlock) {
ast_channel_unlock(p->owner);
*nounlock = 1;
@@ -23570,9 +23553,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(¤t.req, req);
-
sip_pvt_lock(p);
ast_clear_flag(&p->flags[0], SIP_GOTREFER);
p->refer->status = REFER_200OK;
@@ -23601,7 +23581,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/10/channels/sig_analog.c
URL: http://svnview.digium.com/svn/asterisk/branches/10/channels/sig_analog.c?view=diff&rev=341255&r1=341254&r2=341255
==============================================================================
--- branches/10/channels/sig_analog.c (original)
+++ branches/10/channels/sig_analog.c Tue Oct 18 16:11:42 2011
@@ -2261,7 +2261,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/10/channels/sip/include/sip.h
URL: http://svnview.digium.com/svn/asterisk/branches/10/channels/sip/include/sip.h?view=diff&rev=341255&r1=341254&r2=341255
==============================================================================
--- branches/10/channels/sip/include/sip.h (original)
+++ branches/10/channels/sip/include/sip.h Tue Oct 18 16:11:42 2011
@@ -804,7 +804,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/10/include/asterisk/features.h
URL: http://svnview.digium.com/svn/asterisk/branches/10/include/asterisk/features.h?view=diff&rev=341255&r1=341254&r2=341255
==============================================================================
--- branches/10/include/asterisk/features.h (original)
+++ branches/10/include/asterisk/features.h Tue Oct 18 16:11:42 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/10/main/features.c
URL: http://svnview.digium.com/svn/asterisk/branches/10/main/features.c?view=diff&rev=341255&r1=341254&r2=341255
==============================================================================
--- branches/10/main/features.c (original)
+++ branches/10/main/features.c Tue Oct 18 16:11:42 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;
}
/*!
@@ -4826,7 +4951,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. */
@@ -6965,7 +7090,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");
@@ -7888,7 +8013,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 asterisk-commits
mailing list