diff options
author | Matt Jordan <mjordan@digium.com> | 2015-04-17 15:58:13 -0500 |
---|---|---|
committer | Gerrit Code Review <gerrit2@gerrit.digium.api> | 2015-04-17 15:58:13 -0500 |
commit | 8435a0cdff848f77ff55e709a393ea96635e5b19 (patch) | |
tree | 5d785a134dd42fe013f924a30ffc1be6189840d9 /apps | |
parent | bb347fa594e195c79cbda45cb55fde3e72f90f9c (diff) | |
parent | aae45acbda1f6100cd9de816855166a32b991ce0 (diff) |
Merge "Detect potential forwarding loops based on count."
Diffstat (limited to 'apps')
-rw-r--r-- | apps/app_dial.c | 85 | ||||
-rw-r--r-- | apps/app_followme.c | 13 | ||||
-rw-r--r-- | apps/app_queue.c | 96 |
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); |