summaryrefslogtreecommitdiff
path: root/main/features.c
diff options
context:
space:
mode:
authorRichard Mudgett <rmudgett@digium.com>2011-10-18 21:15:45 +0000
committerRichard Mudgett <rmudgett@digium.com>2011-10-18 21:15:45 +0000
commit10de040b6e89e7c973c23353d477c5dd465a14df (patch)
tree25a7d164a2b8276213348bc5f63fe7c6ed9af4cf /main/features.c
parentd19ddf87410ce65071cf92c298bf048f3ab0f9bb (diff)
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 ........ Merged revisions 341255 from http://svn.asterisk.org/svn/asterisk/branches/10 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@341256 65c4cc65-6c06-0410-ace0-fbb531ad65f3
Diffstat (limited to 'main/features.c')
-rw-r--r--main/features.c209
1 files changed, 167 insertions, 42 deletions
diff --git a/main/features.c b/main/features.c
index 84e427cc7..73974ca56 100644
--- a/main/features.c
+++ b/main/features.c
@@ -480,7 +480,7 @@ struct parkeduser {
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 @@ static struct ast_parkinglot *create_dynamic_parkinglot(const char *name, struct
/*!
* \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 @@ static int park_call_full(struct ast_channel *chan, struct ast_channel *peer, st
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 @@ static int masq_park_call(struct ast_channel *rchan, struct ast_channel *peer, i
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 @@ static int masq_park_call(struct ast_channel *rchan, struct ast_channel *peer, i
/* 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 @@ static int masq_park_call(struct ast_channel *rchan, struct ast_channel *peer, i
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(struct ast_channel *rchan, struct ast_channel *peer, int timeout, int *extout)
+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)
{
- return masq_park_call(rchan, peer, timeout, extout, 0, NULL);
+ 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;
}
-/*!
- * \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)
+int ast_masq_park_call(struct ast_channel *rchan, struct ast_channel *peer, int timeout, int *extout)
{
- 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 @@ static int xfer_park_call_helper(struct ast_channel *park_me, struct ast_channel
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 @@ static int builtin_parkcall(struct ast_channel *chan, struct ast_channel *peer,
{
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 @@ static int builtin_parkcall(struct ast_channel *chan, struct ast_channel *peer,
/* 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;
}
/*!
@@ -4827,7 +4952,7 @@ static int park_call_exec(struct ast_channel *chan, const char *data)
}
}
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. */
@@ -6966,7 +7091,7 @@ static int manager_park(struct mansession *s, const struct message *m)
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");
@@ -7889,7 +8014,7 @@ AST_TEST_DEFINE(features_test)
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;
}