aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjpeeler <jpeeler@f38db490-d61c-443f-a65b-d21fe96a405b>2010-03-10 20:51:23 +0000
committerjpeeler <jpeeler@f38db490-d61c-443f-a65b-d21fe96a405b>2010-03-10 20:51:23 +0000
commitfc2091f8baed2822bc076cf20f8b4f497907a45f (patch)
tree3b1d4967d262c5c1996f217b818d866a0f47ba1a
parentd07d6eea8b31e3940a095d016677d6d740a08908 (diff)
Fix ParkAndAnnounce not respecting parking options.
The patch ensures that if a peer does not exist, parking settings are read from the channel. A unit test has been written to ensure proper operation for both standard parking and parking using masquerades. (closes issue #16592) Reported by: mwyres Patches: bug_16592.diff uploaded by snuffy (license 35) Review: https://reviewboard.asterisk.org/r/539/ git-svn-id: http://svn.digium.com/svn/asterisk/trunk@251679 f38db490-d61c-443f-a65b-d21fe96a405b
-rw-r--r--main/features.c188
1 files changed, 181 insertions, 7 deletions
diff --git a/main/features.c b/main/features.c
index 2d7723ea5..5a2bb0269 100644
--- a/main/features.c
+++ b/main/features.c
@@ -56,6 +56,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/global_datastores.h"
#include "asterisk/astobj2.h"
#include "asterisk/cel.h"
+#include "asterisk/test.h"
/*** DOCUMENTATION
<application name="Bridge" language="en_US">
@@ -702,6 +703,8 @@ static struct parkeduser *park_space_reserve(struct ast_channel *chan, struct as
if (peer)
parkinglotname = findparkinglotname(peer);
+ else /* peer was NULL, check chan (ParkAndAnnounce / res_agi) */
+ parkinglotname = findparkinglotname(chan);
if (parkinglotname) {
ast_debug(1, "Found chanvar Parkinglot: %s\n", parkinglotname);
@@ -856,17 +859,17 @@ static int park_call_full(struct ast_channel *chan, struct ast_channel *peer, st
const char *event_from;
if (pu == NULL)
- pu = park_space_reserve(chan, peer, args);
+ args->pu = pu = park_space_reserve(chan, peer, args);
if (pu == NULL)
return 1; /* Continue execution if possible */
snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", pu->parkingnum);
-
+
chan->appl = "Parked Call";
- chan->data = NULL;
+ chan->data = NULL;
pu->chan = chan;
-
+
/* Put the parked channel on hold if we have two different channels */
if (chan != peer) {
if (ast_test_flag(args, AST_PARK_OPT_RINGING)) {
@@ -1067,7 +1070,7 @@ static int masq_park_call(struct ast_channel *rchan, struct ast_channel *peer, i
return 0;
}
-/* Park call via masquraded channel */
+/* Park call via masqueraded channel */
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);
@@ -1083,8 +1086,176 @@ static int masq_park_call_announce(struct ast_channel *rchan, struct ast_channel
return masq_park_call(rchan, peer, timeout, extout, 1, NULL);
}
-/*!
- * \brief set caller and callee according to the direction
+#ifdef TEST_FRAMEWORK
+static int fake_fixup(struct ast_channel *clonechan, struct ast_channel *original)
+{
+ return 0;
+}
+
+static struct ast_channel *create_test_channel(const struct ast_channel_tech *fake_tech)
+{
+ struct ast_channel *test_channel1;
+ if (!(test_channel1 = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL,
+ NULL, NULL, 0, 0, "TestChannel1"))) {
+ return NULL;
+ }
+
+ /* normally this is done in the channel driver */
+ test_channel1->nativeformats = AST_FORMAT_GSM;
+ test_channel1->writeformat = AST_FORMAT_GSM;
+ test_channel1->rawwriteformat = AST_FORMAT_GSM;
+ test_channel1->readformat = AST_FORMAT_GSM;
+ test_channel1->rawreadformat = AST_FORMAT_GSM;
+ test_channel1->tech = fake_tech;
+
+ return test_channel1;
+}
+
+static int unpark_test_channel(struct ast_channel *toremove, struct ast_park_call_args *args)
+{
+ struct ast_context *con;
+ struct parkeduser *pu_toremove;
+ args->pu->notquiteyet = 1; /* go ahead and stop processing the test parking */
+ AST_LIST_LOCK(&args->pu->parkinglot->parkings);
+ AST_LIST_TRAVERSE_SAFE_BEGIN(&args->pu->parkinglot->parkings, pu_toremove, list) {
+ con = ast_context_find(args->pu->parkinglot->parking_con);
+ if (con) {
+ if (ast_context_remove_extension2(con, args->pu->parkingexten, 1, NULL, 0)) {
+ ast_log(LOG_WARNING, "Whoa, failed to remove the parking extension!\n");
+ return -1;
+ } else {
+ notify_metermaids(args->pu->parkingexten, pu_toremove->parkinglot->parking_con, AST_DEVICE_NOT_INUSE);
+ }
+ } else {
+ ast_log(LOG_WARNING, "Whoa, no parking context?\n");
+ return -1;
+ }
+ if (pu_toremove == args->pu) {
+ AST_LIST_REMOVE_CURRENT(list);
+ break;
+ }
+ }
+ AST_LIST_TRAVERSE_SAFE_END;
+ AST_LIST_UNLOCK(&args->pu->parkinglot->parkings);
+
+ /* the only way this would be unsafe is if a timeout occurred, which is set at 45 sec */
+ ast_free(args->pu);
+ args->pu = NULL;
+
+ ast_hangup(toremove);
+ return 0;
+}
+
+AST_TEST_DEFINE(features_test)
+{
+ int saved_parkeddynamic;
+ struct ast_channel *test_channel1 = NULL;
+ struct ast_channel *parked_chan = NULL;
+ struct ast_parkinglot *dynlot = NULL;
+ struct ast_park_call_args args = {
+ .timeout = DEFAULT_PARK_TIME,
+ };
+
+ int res = -1;
+
+ static const struct ast_channel_tech fake_tech = {
+ .fixup = fake_fixup, /* silence warning from masquerade */
+ };
+
+ static const char unique_parkinglot[] = "myuniquetestparkinglot3141592654";
+ static const char parkinglot_range[] = "750-760";
+
+ switch (cmd) {
+ case TEST_INIT:
+ info->name = "features_test";
+ info->category = "main/features/";
+ info->summary = "Features unit test";
+ info->description =
+ "Tests whether parking respects PARKINGLOT settings";
+ return AST_TEST_NOT_RUN;
+ case TEST_EXECUTE:
+ break;
+ }
+
+ /* changing a config option is a bad practice, but must be done in this case */
+ saved_parkeddynamic = parkeddynamic;
+ parkeddynamic = 1;
+
+ if (!(test_channel1 = create_test_channel(&fake_tech))) {
+ goto exit_features_test;
+ }
+
+ ast_test_status_update(test, "Test parking functionality with defaults\n");
+ if (park_call_full(test_channel1, NULL, &args)) {
+ goto exit_features_test;
+ }
+ if (unpark_test_channel(test_channel1, &args)) {
+ goto exit_features_test;
+ }
+
+ ast_test_status_update(test, "Check that certain parking options are respected\n");
+ if (!(test_channel1 = create_test_channel(&fake_tech))) {
+ goto exit_features_test;
+ }
+ pbx_builtin_setvar_helper(test_channel1, "PARKINGLOT", unique_parkinglot);
+ pbx_builtin_setvar_helper(test_channel1, "PARKINGDYNPOS", parkinglot_range);
+ if (park_call_full(test_channel1, NULL, &args)) {
+ goto exit_features_test;
+ }
+ /* grab newly created parking lot for destruction in the end */
+ dynlot = args.pu->parkinglot;
+ if (!args.pu->parkingnum == 750 || strcasecmp(args.pu->parkinglot->name, unique_parkinglot)) {
+ ast_test_status_update(test, "Parking settings were not respected\n");
+ goto exit_features_test;
+ } else {
+ ast_test_status_update(test, "Parking settings for non-masquerading park verified\n");
+ }
+ if (unpark_test_channel(test_channel1, &args)) {
+ goto exit_features_test;
+ }
+
+ ast_test_status_update(test, "Check #2 that certain parking options are respected\n");
+ if (!(test_channel1 = create_test_channel(&fake_tech))) {
+ goto exit_features_test;
+ }
+ pbx_builtin_setvar_helper(test_channel1, "PARKINGLOT", unique_parkinglot);
+ pbx_builtin_setvar_helper(test_channel1, "PARKINGDYNPOS", parkinglot_range);
+ if (masq_park_call(test_channel1, NULL, 0, NULL, 0, &args) == AST_FEATURE_RETURN_PARKFAILED) {
+ goto exit_features_test;
+ }
+ /* hangup zombie channel */
+ ast_hangup(test_channel1);
+ test_channel1 = NULL;
+ if (!args.pu->parkingnum == 750 || strcasecmp(args.pu->parkinglot->name, unique_parkinglot)) {
+ ast_test_status_update(test, "Parking settings were not respected\n");
+ goto exit_features_test;
+ } else {
+ ast_test_status_update(test, "Parking settings for masquerading park verified\n");
+ }
+ /* find the real channel */
+ parked_chan = ast_channel_get_by_name("TestChannel1");
+ if (unpark_test_channel(parked_chan, &args)) {
+ goto exit_features_test;
+ }
+
+ res = 0;
+
+exit_features_test:
+
+ if (test_channel1) {
+ ast_hangup(test_channel1);
+ }
+
+ /* careful, if PARKINGDYNCONTEXT is tested, need to delete context */
+ ao2_unlink(parkinglots, dynlot);
+ parkeddynamic = saved_parkeddynamic;
+ return res ? AST_TEST_FAIL : AST_TEST_PASS;
+}
+#endif
+
+
+/*!
+ * \brief set caller and callee according to the direction
* \param caller, callee, peer, chan, sense
*
* Detect who triggered feature and set callee/caller variables accordingly
@@ -5258,6 +5429,9 @@ int ast_features_init(void)
}
res |= ast_devstate_prov_add("Park", metermaidstate);
+#ifdef TEST_FRAMEWORK
+ res |= AST_TEST_REGISTER(features_test);
+#endif
return res;
}