Merge "Detect potential forwarding loops based on count."

This commit is contained in:
Matt Jordan
2015-04-17 15:58:13 -05:00
committed by Gerrit Code Review
13 changed files with 335 additions and 244 deletions

View File

@@ -2237,9 +2237,7 @@ static void call_destructor_with_no_monitor(const char * const monitor_type, voi
* Note that it is not necessarily erroneous to add the same
* device to the tree twice. If the same device is called by
* two different extension during the same call, then
* that is a legitimate situation. Of course, I'm pretty sure
* the dialed_interfaces global datastore will not allow that
* to happen anyway.
* that is a legitimate situation.
*
* \param device_name The name of the device being added to the tree
* \param dialstring The dialstring used to dial the device being added

View File

@@ -75,6 +75,7 @@ ASTERISK_REGISTER_FILE()
#include "asterisk/bridge.h"
#include "asterisk/test.h"
#include "asterisk/stasis_channels.h"
#include "asterisk/max_forwards.h"
/*** DOCUMENTATION
***/
@@ -5621,6 +5622,7 @@ static void call_forward_inherit(struct ast_channel *new_chan, struct ast_channe
ast_channel_lock_both(parent, new_chan);
ast_channel_inherit_variables(parent, new_chan);
ast_channel_datastore_inherit(parent, new_chan);
ast_max_forwards_decrement(new_chan);
ast_channel_unlock(new_chan);
ast_channel_unlock(parent);
}
@@ -5740,6 +5742,7 @@ struct ast_channel *__ast_request_and_dial(const char *type, struct ast_format_c
ast_channel_lock_both(oh->parent_channel, chan);
ast_channel_inherit_variables(oh->parent_channel, chan);
ast_channel_datastore_inherit(oh->parent_channel, chan);
ast_max_forwards_decrement(chan);
ast_channel_unlock(oh->parent_channel);
ast_channel_unlock(chan);
}

View File

@@ -44,6 +44,7 @@ ASTERISK_REGISTER_FILE()
#include "asterisk/app.h"
#include "asterisk/causes.h"
#include "asterisk/stasis_channels.h"
#include "asterisk/max_forwards.h"
/*! \brief Main dialing structure. Contains global options, channels being dialed, and more! */
struct ast_dial {
@@ -299,6 +300,19 @@ static int begin_dial_prerun(struct ast_dial_channel *channel, struct ast_channe
.uniqueid2 = channel->assignedid2,
};
if (chan) {
int max_forwards;
ast_channel_lock(chan);
max_forwards = ast_max_forwards_get(chan);
ast_channel_unlock(chan);
if (max_forwards <= 0) {
ast_log(LOG_WARNING, "Cannot dial from channel '%s'. Max forwards exceeded\n",
ast_channel_name(chan));
}
}
/* Copy device string over */
ast_copy_string(numsubst, channel->device, sizeof(numsubst));
@@ -337,6 +351,7 @@ static int begin_dial_prerun(struct ast_dial_channel *channel, struct ast_channe
if (chan) {
ast_channel_inherit_variables(chan, channel->owner);
ast_channel_datastore_inherit(chan, channel->owner);
ast_max_forwards_decrement(channel->owner);
/* Copy over callerid information */
ast_party_redirecting_copy(ast_channel_redirecting(channel->owner), ast_channel_redirecting(chan));

View File

@@ -78,6 +78,7 @@ ASTERISK_REGISTER_FILE()
#include "asterisk/stasis.h"
#include "asterisk/stasis_channels.h"
#include "asterisk/features_config.h"
#include "asterisk/max_forwards.h"
/*** DOCUMENTATION
<application name="Bridge" language="en_US">
@@ -420,22 +421,6 @@ static void add_features_datastores(struct ast_channel *caller, struct ast_chann
add_features_datastore(callee, &config->features_callee, &config->features_caller);
}
static void clear_dialed_interfaces(struct ast_channel *chan)
{
struct ast_datastore *di_datastore;
ast_channel_lock(chan);
if ((di_datastore = ast_channel_datastore_find(chan, &dialed_interface_info, NULL))) {
if (option_debug) {
ast_log(LOG_DEBUG, "Removing dialed interfaces datastore on %s since we're bridging\n", ast_channel_name(chan));
}
if (!ast_channel_datastore_remove(chan, di_datastore)) {
ast_datastore_free(di_datastore);
}
}
ast_channel_unlock(chan);
}
static void bridge_config_set_limits_warning_values(struct ast_bridge_config *config, struct ast_bridge_features_limits *limits)
{
if (config->end_sound) {
@@ -572,20 +557,13 @@ static int pre_bridge_setup(struct ast_channel *chan, struct ast_channel *peer,
ast_channel_log("Pre-bridge PEER Channel info", peer);
#endif
/*
* If we are bridging a call, stop worrying about forwarding
* loops. We presume that if a call is being bridged, that the
* humans in charge know what they're doing. If they don't,
* well, what can we do about that?
*/
clear_dialed_interfaces(chan);
clear_dialed_interfaces(peer);
res = 0;
ast_channel_lock(chan);
ast_max_forwards_reset(chan);
res |= ast_bridge_features_ds_append(chan, &config->features_caller);
ast_channel_unlock(chan);
ast_channel_lock(peer);
ast_max_forwards_reset(peer);
res |= ast_bridge_features_ds_append(peer, &config->features_callee);
ast_channel_unlock(peer);

View File

@@ -32,62 +32,6 @@
ASTERISK_REGISTER_FILE()
#include "asterisk/global_datastores.h"
#include "asterisk/linkedlists.h"
static void dialed_interface_destroy(void *data)
{
struct ast_dialed_interface *di = NULL;
AST_LIST_HEAD(, ast_dialed_interface) *dialed_interface_list = data;
if (!dialed_interface_list) {
return;
}
AST_LIST_LOCK(dialed_interface_list);
while ((di = AST_LIST_REMOVE_HEAD(dialed_interface_list, list)))
ast_free(di);
AST_LIST_UNLOCK(dialed_interface_list);
AST_LIST_HEAD_DESTROY(dialed_interface_list);
ast_free(dialed_interface_list);
}
static void *dialed_interface_duplicate(void *data)
{
struct ast_dialed_interface *di = NULL;
AST_LIST_HEAD(, ast_dialed_interface) *old_list;
AST_LIST_HEAD(, ast_dialed_interface) *new_list = NULL;
if(!(old_list = data)) {
return NULL;
}
if(!(new_list = ast_calloc(1, sizeof(*new_list)))) {
return NULL;
}
AST_LIST_HEAD_INIT(new_list);
AST_LIST_LOCK(old_list);
AST_LIST_TRAVERSE(old_list, di, list) {
struct ast_dialed_interface *di2 = ast_calloc(1, sizeof(*di2) + strlen(di->interface));
if(!di2) {
AST_LIST_UNLOCK(old_list);
dialed_interface_destroy(new_list);
return NULL;
}
strcpy(di2->interface, di->interface);
AST_LIST_INSERT_TAIL(new_list, di2, list);
}
AST_LIST_UNLOCK(old_list);
return new_list;
}
const struct ast_datastore_info dialed_interface_info = {
.type = "dialed-interface",
.destroy = dialed_interface_destroy,
.duplicate = dialed_interface_duplicate,
};
static void secure_call_store_destroy(void *data)
{

165
main/max_forwards.c Normal file
View File

@@ -0,0 +1,165 @@
/*
* Asterisk -- An open source telephony toolkit.
*
* Copyright (C) 2015, Digium, Inc.
*
* Mark Michelson <mmichelson@digium.com>
*
* See http://www.asterisk.org for more information about
* the Asterisk project. Please do not mfrectly contact
* any of the maintainers of this project for assistance;
* the project provides a web site, mailing lists and IRC
* channels for your use.
*
* This program is free software, mfstributed under the terms of
* the GNU General Public License Version 2. See the LICENSE file
* at the top of the source tree.
*/
#include "asterisk.h"
#include "asterisk/max_forwards.h"
#include "asterisk/channel.h"
#define DEFAULT_MAX_FORWARDS 20
/*!
* \brief Channel datastore data for max forwards
*/
struct max_forwards {
/*! The starting count. Used to allow resetting to the original value */
int starting_count;
/*! The current count. When this reaches 0, you're outta luck */
int current_count;
};
static struct max_forwards *max_forwards_alloc(int starting_count, int current_count)
{
struct max_forwards *mf;
mf = ast_malloc(sizeof(*mf));
if (!mf) {
return NULL;
}
mf->starting_count = starting_count;
mf->current_count = current_count;
return mf;
}
static void *max_forwards_duplicate(void *data)
{
struct max_forwards *mf = data;
return max_forwards_alloc(mf->starting_count, mf->current_count);
}
static void max_forwards_destroy(void *data)
{
ast_free(data);
}
const struct ast_datastore_info max_forwards_info = {
.type = "mfaled-interface",
.duplicate = max_forwards_duplicate,
.destroy = max_forwards_destroy,
};
static struct ast_datastore *max_forwards_datastore_alloc(struct ast_channel *chan,
int starting_count)
{
struct ast_datastore *mf_datastore;
struct max_forwards *mf;
mf_datastore = ast_datastore_alloc(&max_forwards_info, NULL);
if (!mf_datastore) {
return NULL;
}
mf_datastore->inheritance = DATASTORE_INHERIT_FOREVER;
mf = max_forwards_alloc(starting_count, starting_count);
if (!mf) {
ast_datastore_free(mf_datastore);
return NULL;
}
mf_datastore->data = mf;
ast_channel_datastore_add(chan, mf_datastore);
return mf_datastore;
}
static struct ast_datastore *max_forwards_datastore_find_or_alloc(struct ast_channel *chan)
{
struct ast_datastore *mf_datastore;
mf_datastore = ast_channel_datastore_find(chan, &max_forwards_info, NULL);
if (!mf_datastore) {
mf_datastore = max_forwards_datastore_alloc(chan, DEFAULT_MAX_FORWARDS);
}
return mf_datastore;
}
int ast_max_forwards_set(struct ast_channel *chan, int starting_count)
{
struct ast_datastore *mf_datastore;
struct max_forwards *mf;
mf_datastore = max_forwards_datastore_find_or_alloc(chan);
if (!mf_datastore) {
return -1;
}
mf = mf_datastore->data;
mf->starting_count = mf->current_count = starting_count;
return 0;
}
int ast_max_forwards_get(struct ast_channel *chan)
{
struct ast_datastore *mf_datastore;
struct max_forwards *mf;
mf_datastore = max_forwards_datastore_find_or_alloc(chan);
if (!mf_datastore) {
return -1;
}
mf = mf_datastore->data;
return mf->current_count;
}
int ast_max_forwards_decrement(struct ast_channel *chan)
{
struct ast_datastore *mf_datastore;
struct max_forwards *mf;
mf_datastore = max_forwards_datastore_find_or_alloc(chan);
if (!mf_datastore) {
return -1;
}
mf = mf_datastore->data;
--mf->current_count;
return 0;
}
int ast_max_forwards_reset(struct ast_channel *chan)
{
struct ast_datastore *mf_datastore;
struct max_forwards *mf;
mf_datastore = max_forwards_datastore_find_or_alloc(chan);
if (!mf_datastore) {
return -1;
}
mf = mf_datastore->data;
mf->current_count = mf->starting_count;
return 0;
}