summaryrefslogtreecommitdiff
path: root/apps
diff options
context:
space:
mode:
authorMatt Jordan <mjordan@digium.com>2015-04-17 15:58:13 -0500
committerGerrit Code Review <gerrit2@gerrit.digium.api>2015-04-17 15:58:13 -0500
commit8435a0cdff848f77ff55e709a393ea96635e5b19 (patch)
tree5d785a134dd42fe013f924a30ffc1be6189840d9 /apps
parentbb347fa594e195c79cbda45cb55fde3e72f90f9c (diff)
parentaae45acbda1f6100cd9de816855166a32b991ce0 (diff)
Merge "Detect potential forwarding loops based on count."
Diffstat (limited to 'apps')
-rw-r--r--apps/app_dial.c85
-rw-r--r--apps/app_followme.c13
-rw-r--r--apps/app_queue.c96
3 files changed, 40 insertions, 154 deletions
diff --git a/apps/app_dial.c b/apps/app_dial.c
index 0390cfe7f..895d4b883 100644
--- a/apps/app_dial.c
+++ b/apps/app_dial.c
@@ -58,7 +58,6 @@ ASTERISK_REGISTER_FILE()
#include "asterisk/manager.h"
#include "asterisk/privacy.h"
#include "asterisk/stringfields.h"
-#include "asterisk/global_datastores.h"
#include "asterisk/dsp.h"
#include "asterisk/aoc.h"
#include "asterisk/ccss.h"
@@ -68,6 +67,7 @@ ASTERISK_REGISTER_FILE()
#include "asterisk/stasis_channels.h"
#include "asterisk/bridge_after.h"
#include "asterisk/features_config.h"
+#include "asterisk/max_forwards.h"
/*** DOCUMENTATION
<application name="Dial" language="en_US">
@@ -881,6 +881,7 @@ static void do_forward(struct chanlist *o, struct cause_args *num,
ast_channel_lock_both(in, o->chan);
ast_channel_inherit_variables(in, o->chan);
ast_channel_datastore_inherit(in, o->chan);
+ ast_max_forwards_decrement(o->chan);
ast_channel_unlock(in);
ast_channel_unlock(o->chan);
/* When a call is forwarded, we don't want to track new interfaces
@@ -2074,7 +2075,6 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
);
struct ast_flags64 opts = { 0, };
char *opt_args[OPT_ARG_ARRAY_SIZE];
- struct ast_datastore *datastore = NULL;
int fulldial = 0, num_dialed = 0;
int ignore_cc = 0;
char device_name[AST_CHANNEL_NAME];
@@ -2101,6 +2101,7 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
* \note This will not have any malloced strings so do not free it.
*/
struct ast_party_caller caller;
+ int max_forwards;
/* Reset all DIAL variables back to blank, to prevent confusion (in case we don't reset all of them). */
ast_channel_lock(chan);
@@ -2111,8 +2112,16 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
pbx_builtin_setvar_helper(chan, "ANSWEREDTIME", "");
pbx_builtin_setvar_helper(chan, "DIALEDTIME", "");
ast_channel_stage_snapshot_done(chan);
+ max_forwards = ast_max_forwards_get(chan);
ast_channel_unlock(chan);
+ if (max_forwards <= 0) {
+ ast_log(LOG_WARNING, "Cannot place outbound call from channel '%s'. Max forwards exceeded\n",
+ ast_channel_name(chan));
+ pbx_builtin_setvar_helper(chan, "DIALSTATUS", "BUSY");
+ return -1;
+ }
+
if (ast_strlen_zero(data)) {
ast_log(LOG_WARNING, "Dial requires an argument (technology/resource)\n");
pbx_builtin_setvar_helper(chan, "DIALSTATUS", pa.status);
@@ -2314,9 +2323,6 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
char *tech = strsep(&number, "/");
size_t tech_len;
size_t number_len;
- /* find if we already dialed this interface */
- struct ast_dialed_interface *di;
- AST_LIST_HEAD(,ast_dialed_interface) *dialed_interfaces;
num_dialed++;
if (ast_strlen_zero(number)) {
@@ -2360,7 +2366,6 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
/* Request the peer */
ast_channel_lock(chan);
- datastore = ast_channel_datastore_find(chan, &dialed_interface_info, NULL);
/*
* Seed the chanlist's connected line information with previously
* acquired connected line info from the incoming channel. The
@@ -2370,61 +2375,6 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
ast_party_connected_line_copy(&tmp->connected, ast_channel_connected(chan));
ast_channel_unlock(chan);
- if (datastore)
- dialed_interfaces = datastore->data;
- else {
- if (!(datastore = ast_datastore_alloc(&dialed_interface_info, NULL))) {
- ast_log(LOG_WARNING, "Unable to create channel datastore for dialed interfaces. Aborting!\n");
- chanlist_free(tmp);
- goto out;
- }
- datastore->inheritance = DATASTORE_INHERIT_FOREVER;
-
- if (!(dialed_interfaces = ast_calloc(1, sizeof(*dialed_interfaces)))) {
- ast_datastore_free(datastore);
- chanlist_free(tmp);
- goto out;
- }
-
- datastore->data = dialed_interfaces;
- AST_LIST_HEAD_INIT(dialed_interfaces);
-
- ast_channel_lock(chan);
- ast_channel_datastore_add(chan, datastore);
- ast_channel_unlock(chan);
- }
-
- AST_LIST_LOCK(dialed_interfaces);
- AST_LIST_TRAVERSE(dialed_interfaces, di, list) {
- if (!strcasecmp(di->interface, tmp->interface)) {
- ast_log(LOG_WARNING, "Skipping dialing interface '%s' again since it has already been dialed\n",
- di->interface);
- break;
- }
- }
- AST_LIST_UNLOCK(dialed_interfaces);
- if (di) {
- fulldial++;
- chanlist_free(tmp);
- continue;
- }
-
- /* It is always ok to dial a Local interface. We only keep track of
- * which "real" interfaces have been dialed. The Local channel will
- * inherit this list so that if it ends up dialing a real interface,
- * it won't call one that has already been called. */
- if (strcasecmp(tmp->tech, "Local")) {
- if (!(di = ast_calloc(1, sizeof(*di) + strlen(tmp->interface)))) {
- chanlist_free(tmp);
- goto out;
- }
- strcpy(di->interface, tmp->interface);
-
- AST_LIST_LOCK(dialed_interfaces);
- AST_LIST_INSERT_TAIL(dialed_interfaces, di, list);
- AST_LIST_UNLOCK(dialed_interfaces);
- }
-
tc = ast_request(tmp->tech, ast_channel_nativeformats(chan), NULL, chan, tmp->number, &cause);
if (!tc) {
/* If we can't, just go on to the next call */
@@ -2465,6 +2415,7 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
/* Inherit specially named variables from parent channel */
ast_channel_inherit_variables(chan, tc);
ast_channel_datastore_inherit(chan, tc);
+ ast_max_forwards_decrement(tc);
ast_channel_appl_set(tc, "AppDial");
ast_channel_data_set(tc, "(Outgoing Line)");
@@ -2680,18 +2631,6 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
peer = wait_for_answer(chan, &out_chans, &to, peerflags, opt_args, &pa, &num, &result,
dtmf_progress, ignore_cc, &forced_clid, &stored_clid);
- /* The ast_channel_datastore_remove() function could fail here if the
- * datastore was moved to another channel during a masquerade. If this is
- * the case, don't free the datastore here because later, when the channel
- * to which the datastore was moved hangs up, it will attempt to free this
- * datastore again, causing a crash
- */
- ast_channel_lock(chan);
- datastore = ast_channel_datastore_find(chan, &dialed_interface_info, NULL); /* make sure we weren't cleaned up already */
- if (datastore && !ast_channel_datastore_remove(chan, datastore)) {
- ast_datastore_free(datastore);
- }
- ast_channel_unlock(chan);
if (!peer) {
if (result) {
res = result;
diff --git a/apps/app_followme.c b/apps/app_followme.c
index 4a2e569df..5fd5d15ba 100644
--- a/apps/app_followme.c
+++ b/apps/app_followme.c
@@ -64,6 +64,7 @@ ASTERISK_REGISTER_FILE()
#include "asterisk/dsp.h"
#include "asterisk/app.h"
#include "asterisk/stasis_channels.h"
+#include "asterisk/max_forwards.h"
/*** DOCUMENTATION
<application name="FollowMe" language="en_US">
@@ -1069,6 +1070,7 @@ static struct ast_channel *findmeexec(struct fm_args *tpargs, struct ast_channel
ast_connected_line_copy_from_caller(ast_channel_connected(outbound), ast_channel_caller(caller));
ast_channel_inherit_variables(caller, outbound);
ast_channel_datastore_inherit(caller, outbound);
+ ast_max_forwards_decrement(outbound);
ast_channel_language_set(outbound, ast_channel_language(caller));
ast_channel_req_accountcodes(outbound, caller, AST_CHANNEL_REQUESTOR_BRIDGE_PEER);
ast_channel_musicclass_set(outbound, ast_channel_musicclass(caller));
@@ -1304,12 +1306,23 @@ static int app_exec(struct ast_channel *chan, const char *data)
AST_APP_ARG(options);
);
char *opt_args[FOLLOWMEFLAG_ARG_ARRAY_SIZE];
+ int max_forwards;
if (ast_strlen_zero(data)) {
ast_log(LOG_WARNING, "%s requires an argument (followmeid)\n", app);
return -1;
}
+ ast_channel_lock(chan);
+ max_forwards = ast_max_forwards_get(chan);
+ ast_channel_unlock(chan);
+
+ if (max_forwards <= 0) {
+ ast_log(LOG_WARNING, "Unable to execute FollowMe on channel %s. Max forwards exceeded\n",
+ ast_channel_name(chan));
+ return -1;
+ }
+
argstr = ast_strdupa((char *) data);
AST_STANDARD_APP_ARGS(args, argstr);
diff --git a/apps/app_queue.c b/apps/app_queue.c
index a82632d8e..0b8204c33 100644
--- a/apps/app_queue.c
+++ b/apps/app_queue.c
@@ -98,7 +98,6 @@ ASTERISK_REGISTER_FILE()
#include "asterisk/stringfields.h"
#include "asterisk/astobj2.h"
#include "asterisk/strings.h"
-#include "asterisk/global_datastores.h"
#include "asterisk/taskprocessor.h"
#include "asterisk/aoc.h"
#include "asterisk/callerid.h"
@@ -113,6 +112,7 @@ ASTERISK_REGISTER_FILE()
#include "asterisk/mixmonitor.h"
#include "asterisk/core_unreal.h"
#include "asterisk/bridge_basic.h"
+#include "asterisk/max_forwards.h"
/*!
* \par Please read before modifying this file.
@@ -4301,6 +4301,7 @@ static int ring_entry(struct queue_ent *qe, struct callattempt *tmp, int *busies
/* Inherit specially named variables from parent channel */
ast_channel_inherit_variables(qe->chan, tmp->chan);
ast_channel_datastore_inherit(qe->chan, tmp->chan);
+ ast_max_forwards_decrement(tmp->chan);
/* Presense of ADSI CPE on outgoing channel follows ours */
ast_channel_adsicpe_set(tmp->chan, ast_channel_adsicpe(qe->chan));
@@ -4794,6 +4795,7 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte
ast_channel_lock_both(o->chan, in);
ast_channel_inherit_variables(in, o->chan);
ast_channel_datastore_inherit(in, o->chan);
+ ast_max_forwards_decrement(o->chan);
if (o->pending_connected_update) {
/*
@@ -6275,10 +6277,7 @@ static void setup_mixmonitor(struct queue_ent *qe, const char *filename)
*
* Here is the process of this function
* 1. Process any options passed to the Queue() application. Options here mean the third argument to Queue()
- * 2. Iterate trough the members of the queue, creating a callattempt corresponding to each member. During this
- * iteration, we also check the dialed_interfaces datastore to see if we have already attempted calling this
- * member. If we have, we do not create a callattempt. This is in place to prevent call forwarding loops. Also
- * during each iteration, we call calc_metric to determine which members should be rung when.
+ * 2. Iterate trough the members of the queue, creating a callattempt corresponding to each member.
* 3. Call ring_one to place a call to the appropriate member(s)
* 4. Call wait_for_answer to wait for an answer. If no one answers, return.
* 5. Take care of any holdtime announcements, member delays, or other options which occur after a call has been answered.
@@ -6331,13 +6330,8 @@ static int try_calling(struct queue_ent *qe, struct ast_flags opts, char **opt_a
int block_connected_line = 0;
int callcompletedinsl;
struct ao2_iterator memi;
- struct ast_datastore *datastore;
struct queue_end_bridge *queue_end_bridge = NULL;
- ast_channel_lock(qe->chan);
- datastore = ast_channel_datastore_find(qe->chan, &dialed_interface_info, NULL);
- ast_channel_unlock(qe->chan);
-
memset(&bridge_config, 0, sizeof(bridge_config));
tmpid[0] = 0;
time(&now);
@@ -6424,73 +6418,12 @@ static int try_calling(struct queue_ent *qe, struct ast_flags opts, char **opt_a
memi = ao2_iterator_init(qe->parent->members, 0);
while ((cur = ao2_iterator_next(&memi))) {
struct callattempt *tmp = ast_calloc(1, sizeof(*tmp));
- struct ast_dialed_interface *di;
- AST_LIST_HEAD(,ast_dialed_interface) *dialed_interfaces;
if (!tmp) {
ao2_ref(cur, -1);
ao2_iterator_destroy(&memi);
ao2_unlock(qe->parent);
goto out;
}
- if (!datastore) {
- if (!(datastore = ast_datastore_alloc(&dialed_interface_info, NULL))) {
- callattempt_free(tmp);
- ao2_ref(cur, -1);
- ao2_iterator_destroy(&memi);
- ao2_unlock(qe->parent);
- goto out;
- }
- datastore->inheritance = DATASTORE_INHERIT_FOREVER;
- if (!(dialed_interfaces = ast_calloc(1, sizeof(*dialed_interfaces)))) {
- callattempt_free(tmp);
- ao2_ref(cur, -1);
- ao2_iterator_destroy(&memi);
- ao2_unlock(qe->parent);
- goto out;
- }
- datastore->data = dialed_interfaces;
- AST_LIST_HEAD_INIT(dialed_interfaces);
-
- ast_channel_lock(qe->chan);
- ast_channel_datastore_add(qe->chan, datastore);
- ast_channel_unlock(qe->chan);
- } else
- dialed_interfaces = datastore->data;
-
- AST_LIST_LOCK(dialed_interfaces);
- AST_LIST_TRAVERSE(dialed_interfaces, di, list) {
- if (!strcasecmp(cur->interface, di->interface)) {
- ast_debug(1, "Skipping dialing interface '%s' since it has already been dialed\n",
- di->interface);
- break;
- }
- }
- AST_LIST_UNLOCK(dialed_interfaces);
-
- if (di) {
- callattempt_free(tmp);
- ao2_ref(cur, -1);
- continue;
- }
-
- /* It is always ok to dial a Local interface. We only keep track of
- * which "real" interfaces have been dialed. The Local channel will
- * inherit this list so that if it ends up dialing a real interface,
- * it won't call one that has already been called. */
- if (strncasecmp(cur->interface, "Local/", 6)) {
- if (!(di = ast_calloc(1, sizeof(*di) + strlen(cur->interface)))) {
- callattempt_free(tmp);
- ao2_ref(cur, -1);
- ao2_iterator_destroy(&memi);
- ao2_unlock(qe->parent);
- goto out;
- }
- strcpy(di->interface, cur->interface);
-
- AST_LIST_LOCK(dialed_interfaces);
- AST_LIST_INSERT_TAIL(dialed_interfaces, di, list);
- AST_LIST_UNLOCK(dialed_interfaces);
- }
/*
* Seed the callattempt's connected line information with previously
@@ -6549,16 +6482,7 @@ static int try_calling(struct queue_ent *qe, struct ast_flags opts, char **opt_a
lpeer = wait_for_answer(qe, outgoing, &to, &digit, numbusies,
ast_test_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT),
forwardsallowed, ringing);
- /* The ast_channel_datastore_remove() function could fail here if the
- * datastore was moved to another channel during a masquerade. If this is
- * the case, don't free the datastore here because later, when the channel
- * to which the datastore was moved hangs up, it will attempt to free this
- * datastore again, causing a crash
- */
- ast_channel_lock(qe->chan);
- if (datastore && !ast_channel_datastore_remove(qe->chan, datastore)) {
- ast_datastore_free(datastore);
- }
+
ast_channel_unlock(qe->chan);
ao2_lock(qe->parent);
if (qe->parent->strategy == QUEUE_STRATEGY_RRMEMORY || qe->parent->strategy == QUEUE_STRATEGY_RRORDERED) {
@@ -7750,12 +7674,22 @@ static int queue_exec(struct ast_channel *chan, const char *data)
struct queue_ent qe = { 0 };
struct ast_flags opts = { 0, };
char *opt_args[OPT_ARG_ARRAY_SIZE];
+ int max_forwards;
if (ast_strlen_zero(data)) {
ast_log(LOG_WARNING, "Queue requires an argument: queuename[,options[,URL[,announceoverride[,timeout[,agi[,macro[,gosub[,rule[,position]]]]]]]]]\n");
return -1;
}
+ ast_channel_lock(chan);
+ max_forwards = ast_max_forwards_get(chan);
+ ast_channel_unlock(chan);
+
+ if (max_forwards <= 0) {
+ ast_log(LOG_WARNING, "Channel '%s' cannot enter queue. Max forwards exceeded\n", ast_channel_name(chan));
+ return -1;
+ }
+
parse = ast_strdupa(data);
AST_STANDARD_APP_ARGS(args, parse);