summaryrefslogtreecommitdiff
path: root/main
diff options
context:
space:
mode:
Diffstat (limited to 'main')
-rw-r--r--main/ccss.c4
-rw-r--r--main/channel.c3
-rw-r--r--main/dial.c15
-rw-r--r--main/features.c28
-rw-r--r--main/global_datastores.c56
-rw-r--r--main/max_forwards.c165
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;
+}