diff options
Diffstat (limited to 'main')
-rw-r--r-- | main/ccss.c | 4 | ||||
-rw-r--r-- | main/channel.c | 3 | ||||
-rw-r--r-- | main/dial.c | 15 | ||||
-rw-r--r-- | main/features.c | 28 | ||||
-rw-r--r-- | main/global_datastores.c | 56 | ||||
-rw-r--r-- | main/max_forwards.c | 165 |
6 files changed, 187 insertions, 84 deletions
diff --git a/main/ccss.c b/main/ccss.c index ff5739ab0..0605810c5 100644 --- a/main/ccss.c +++ b/main/ccss.c @@ -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 diff --git a/main/channel.c b/main/channel.c index a9fe7e358..c56f3abe0 100644 --- a/main/channel.c +++ b/main/channel.c @@ -75,6 +75,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #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); } diff --git a/main/dial.c b/main/dial.c index 827b5ef23..ca85cd367 100644 --- a/main/dial.c +++ b/main/dial.c @@ -44,6 +44,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #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)); diff --git a/main/features.c b/main/features.c index f3bf7a714..2f0438692 100644 --- a/main/features.c +++ b/main/features.c @@ -78,6 +78,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #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"> @@ -421,22 +422,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) { @@ -573,20 +558,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); diff --git a/main/global_datastores.c b/main/global_datastores.c index 92c6bb4f7..b63e1df8f 100644 --- a/main/global_datastores.c +++ b/main/global_datastores.c @@ -32,62 +32,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #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) { diff --git a/main/max_forwards.c b/main/max_forwards.c new file mode 100644 index 000000000..8f1d4eed1 --- /dev/null +++ b/main/max_forwards.c @@ -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; +} |