mirror of
https://github.com/asterisk/asterisk.git
synced 2025-11-20 08:40:16 +00:00
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: https://origsvn.digium.com/svn/asterisk/trunk@251679 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
178
main/features.c
178
main/features.c
@@ -56,6 +56,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
|||||||
#include "asterisk/global_datastores.h"
|
#include "asterisk/global_datastores.h"
|
||||||
#include "asterisk/astobj2.h"
|
#include "asterisk/astobj2.h"
|
||||||
#include "asterisk/cel.h"
|
#include "asterisk/cel.h"
|
||||||
|
#include "asterisk/test.h"
|
||||||
|
|
||||||
/*** DOCUMENTATION
|
/*** DOCUMENTATION
|
||||||
<application name="Bridge" language="en_US">
|
<application name="Bridge" language="en_US">
|
||||||
@@ -702,6 +703,8 @@ static struct parkeduser *park_space_reserve(struct ast_channel *chan, struct as
|
|||||||
|
|
||||||
if (peer)
|
if (peer)
|
||||||
parkinglotname = findparkinglotname(peer);
|
parkinglotname = findparkinglotname(peer);
|
||||||
|
else /* peer was NULL, check chan (ParkAndAnnounce / res_agi) */
|
||||||
|
parkinglotname = findparkinglotname(chan);
|
||||||
|
|
||||||
if (parkinglotname) {
|
if (parkinglotname) {
|
||||||
ast_debug(1, "Found chanvar Parkinglot: %s\n", parkinglotname);
|
ast_debug(1, "Found chanvar Parkinglot: %s\n", parkinglotname);
|
||||||
@@ -856,7 +859,7 @@ static int park_call_full(struct ast_channel *chan, struct ast_channel *peer, st
|
|||||||
const char *event_from;
|
const char *event_from;
|
||||||
|
|
||||||
if (pu == NULL)
|
if (pu == NULL)
|
||||||
pu = park_space_reserve(chan, peer, args);
|
args->pu = pu = park_space_reserve(chan, peer, args);
|
||||||
if (pu == NULL)
|
if (pu == NULL)
|
||||||
return 1; /* Continue execution if possible */
|
return 1; /* Continue execution if possible */
|
||||||
|
|
||||||
@@ -1067,7 +1070,7 @@ static int masq_park_call(struct ast_channel *rchan, struct ast_channel *peer, i
|
|||||||
return 0;
|
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)
|
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);
|
return masq_park_call(rchan, peer, timeout, extout, 0, NULL);
|
||||||
@@ -1083,6 +1086,174 @@ static int masq_park_call_announce(struct ast_channel *rchan, struct ast_channel
|
|||||||
return masq_park_call(rchan, peer, timeout, extout, 1, NULL);
|
return masq_park_call(rchan, peer, timeout, extout, 1, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#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
|
* \brief set caller and callee according to the direction
|
||||||
* \param caller, callee, peer, chan, sense
|
* \param caller, callee, peer, chan, sense
|
||||||
@@ -5258,6 +5429,9 @@ int ast_features_init(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
res |= ast_devstate_prov_add("Park", metermaidstate);
|
res |= ast_devstate_prov_add("Park", metermaidstate);
|
||||||
|
#ifdef TEST_FRAMEWORK
|
||||||
|
res |= AST_TEST_REGISTER(features_test);
|
||||||
|
#endif
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user