[Freeswitch-svn] [commit] r10337 - freeswitch/trunk/scripts/contrib/mrene/mod_limit_hash
FreeSWITCH SVN
mrene at freeswitch.org
Tue Nov 11 16:28:49 PST 2008
Author: mrene
Date: Tue Nov 11 19:28:48 2008
New Revision: 10337
Log:
Hashtable-based resource limitations module.
Resembles mod_limit a lot, except you can do rate-limiting.
<action application="limit_hash" data="test test 3/10 default uhoh" />
This will limit to 3 calls per 10 seconds. Omitting /interval will behave exactly like mod_limit.
Added:
freeswitch/trunk/scripts/contrib/mrene/mod_limit_hash/
freeswitch/trunk/scripts/contrib/mrene/mod_limit_hash/mod_limit_hash.c
Added: freeswitch/trunk/scripts/contrib/mrene/mod_limit_hash/mod_limit_hash.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/scripts/contrib/mrene/mod_limit_hash/mod_limit_hash.c Tue Nov 11 19:28:48 2008
@@ -0,0 +1,198 @@
+/*
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ * Copyright (C) 2005/2006, Anthony Minessale II <anthmct at yahoo.com>
+ *
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ *
+ * The Initial Developer of the Original Code is
+ * Mathieu Rene <mathieu.rene at gmail.com>
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Anyone writing code for the original mod_limit
+ *
+ * mod_limit_hash.c -- Resource Limit Module
+ *
+ */
+
+#include <switch.h>
+
+#define LIMIT_SYNTAX "<realm> <id> <max> [transfer_destination_number]"
+
+SWITCH_MODULE_LOAD_FUNCTION(mod_limit_hash_load);
+SWITCH_MODULE_DEFINITION(mod_limit_hash, mod_limit_hash_load, NULL , NULL);
+
+
+static struct {
+ switch_memory_pool_t *pool;
+ switch_mutex_t *mutex;
+ switch_hash_t *hash;
+} globals;
+
+
+struct limit_hash_item {
+ uint32_t total_usage;
+ uint32_t rate_usage;
+ time_t last_check;
+};
+
+static char *limit_def_xfer_exten = "limit_exceeded";
+
+typedef struct limit_hash_item limit_hash_item_t;
+
+static switch_status_t state_handler(switch_core_session_t *session)
+{
+ switch_channel_t *channel = switch_core_session_get_channel(session);
+ switch_channel_state_t state = switch_channel_get_state(channel);
+ char *hashkey = switch_channel_get_private(channel, "limit_hashkey");
+ limit_hash_item_t *item = NULL;
+
+ if (state == CS_HANGUP || state == CS_ROUTING) {
+ switch_mutex_lock(globals.mutex);
+ item = (limit_hash_item_t*)switch_core_hash_find(globals.hash, hashkey);
+
+ /* We keep the structure even though the count is 0 so we do not allocate too often */
+ item->total_usage--;
+
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Usage for %s is now %d\n", hashkey, item->total_usage);
+
+ switch_mutex_unlock(globals.mutex);
+ }
+
+ return SWITCH_STATUS_SUCCESS;
+}
+
+SWITCH_STANDARD_APP(limit_hash_function)
+{
+ int argc = 0;
+ char *argv[6] = { 0 };
+ char *mydata = NULL;
+ char *realm = NULL;
+ char *id = NULL;
+ char *hashkey = NULL;
+ char *xfer_exten = NULL;
+ int max = 0;
+ int interval = 0;
+ char *szinterval = NULL;
+ limit_hash_item_t *item = NULL;
+ switch_channel_t *channel = switch_core_session_get_channel(session);
+ time_t now = switch_timestamp(NULL);
+
+ if (!switch_strlen_zero(data)) {
+ mydata = switch_core_session_strdup(session, data);
+ argc = switch_separate_string(mydata, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
+ }
+
+ if (argc < 3) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "USAGE: limit_hash %s\n", LIMIT_SYNTAX);
+ return;
+ }
+
+ switch_mutex_lock(globals.mutex);
+
+ realm = argv[0];
+ id = argv[1];
+ if ((szinterval = strchr(argv[2], '/')))
+ {
+ *szinterval++ = '\0';
+ interval = atoi(szinterval);
+ }
+
+ max = atoi(argv[2]);
+
+ if (argc >= 4) {
+ xfer_exten = argv[3];
+ } else {
+ xfer_exten = limit_def_xfer_exten;
+ }
+
+ if (max < 0) {
+ max = 0;
+ }
+
+ hashkey = switch_core_session_sprintf(session, "limit_%s_%s", realm, id);
+
+ if (!(item = (limit_hash_item_t*)switch_core_hash_find(globals.hash, hashkey))) {
+ item = (limit_hash_item_t*)switch_core_alloc(globals.pool, sizeof(limit_hash_item_t));
+ memset(item, 0, sizeof(limit_hash_item_t));
+ switch_core_hash_insert(globals.hash, hashkey, item);
+ }
+
+ if (item->last_check <= (now - interval)) {
+ item->rate_usage = 1;
+ item->last_check = now;
+ } else {
+ if (interval > 0 && item->rate_usage + 1 > max) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Usage for %s exceeds maximum rate of %d/%ds\n",
+ hashkey, max, interval);
+ switch_ivr_session_transfer(session, xfer_exten, argv[4], argv[5]);
+ goto end;
+ }
+ item->rate_usage++;
+ }
+
+ if (interval == 0 && item->total_usage + 1 > max) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Usage for %s is already at max value\n", hashkey);
+ switch_ivr_session_transfer(session, xfer_exten, argv[4], argv[5]);
+ goto end;
+ }
+
+ item->total_usage++;
+
+ if (interval == 0) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Usage for %s is now %d/%d\n", hashkey, item->total_usage, max);
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Usage for %s is now %d/%d for the last %d seconds\n", hashkey, item->rate_usage, max, interval);
+ }
+
+ switch_channel_set_private(channel, "limit_hashkey", hashkey);
+ switch_core_event_hook_add_state_change(session, state_handler);
+
+end:
+ switch_mutex_unlock(globals.mutex);
+}
+
+
+SWITCH_MODULE_LOAD_FUNCTION(mod_limit_hash_load)
+{
+ switch_application_interface_t *app_interface;
+
+ memset(&globals, 0, sizeof(&globals));
+
+ globals.pool = pool;
+
+ switch_mutex_init(&globals.mutex, SWITCH_MUTEX_NESTED, globals.pool);
+
+ *module_interface = switch_loadable_module_create_module_interface(pool, modname);
+
+ switch_core_hash_init(&globals.hash, pool);
+
+ SWITCH_ADD_APP(app_interface, "limit_hash", "Limit",
+ "Limits various resources usage", limit_hash_function, LIMIT_SYNTAX, SAF_SUPPORT_NOMEDIA);
+
+ return SWITCH_STATUS_NOUNLOAD; /* Potential Kaboom(tm) if we have active calls */
+}
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
More information about the Freeswitch-svn
mailing list