diff options
author | Richard Mudgett <rmudgett@digium.com> | 2011-10-18 21:15:45 +0000 |
---|---|---|
committer | Richard Mudgett <rmudgett@digium.com> | 2011-10-18 21:15:45 +0000 |
commit | 10de040b6e89e7c973c23353d477c5dd465a14df (patch) | |
tree | 25a7d164a2b8276213348bc5f63fe7c6ed9af4cf /main/features.c | |
parent | d19ddf87410ce65071cf92c298bf048f3ab0f9bb (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.c | 209 |
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; } |