diff --git a/src/include/switch_limit.h b/src/include/switch_limit.h index c63ac7fb57..e798f9c8af 100644 --- a/src/include/switch_limit.h +++ b/src/include/switch_limit.h @@ -76,6 +76,14 @@ SWITCH_DECLARE(switch_status_t) switch_limit_release(const char *backend, switch */ SWITCH_DECLARE(int) switch_limit_usage(const char *backend, const char *realm, const char *resource, uint32_t *rcount); +/*! + \brief reset interval usage counter for a given resource + \param backend + \param realm + \param resource +*/ +SWITCH_DECLARE(switch_status_t) switch_limit_interval_reset(const char *backend, const char *realm, const char *resource); + /*! \brief reset all usage counters \param backend to use @@ -106,6 +114,7 @@ SWITCH_DECLARE(char *) switch_limit_status(const char *backend); #define SWITCH_LIMIT_RELEASE(name) static switch_status_t name (switch_core_session_t *session, const char *realm, const char *resource) #define SWITCH_LIMIT_USAGE(name) static int name (const char *realm, const char *resource, uint32_t *rcount) #define SWITCH_LIMIT_RESET(name) static switch_status_t name (void) +#define SWITCH_LIMIT_INTERVAL_RESET(name) static switch_status_t name (const char *realm, const char *resource) #define SWITCH_LIMIT_STATUS(name) static char * name (void) #define LIMIT_IGNORE_TRANSFER_VARIABLE "limit_ignore_transfer" diff --git a/src/include/switch_loadable_module.h b/src/include/switch_loadable_module.h index d1c578b931..158de6ce63 100644 --- a/src/include/switch_loadable_module.h +++ b/src/include/switch_loadable_module.h @@ -324,13 +324,14 @@ SWITCH_MOD_DECLARE(switch_status_t) switch_module_shutdown(void); break; \ } -#define SWITCH_ADD_LIMIT(limit_int, int_name, incrptr, releaseptr, usageptr, resetptr, statusptr) \ +#define SWITCH_ADD_LIMIT(limit_int, int_name, incrptr, releaseptr, usageptr, resetptr, statusptr, interval_resetptr) \ for (;;) { \ limit_int = (switch_limit_interface_t *)switch_loadable_module_create_interface(*module_interface, SWITCH_LIMIT_INTERFACE); \ limit_int->incr = incrptr; \ limit_int->release = releaseptr; \ limit_int->usage = usageptr; \ limit_int->reset = resetptr; \ + limit_int->interval_reset = interval_resetptr; \ limit_int->status = statusptr; \ limit_int->interface_name = int_name; \ break; \ diff --git a/src/include/switch_module_interfaces.h b/src/include/switch_module_interfaces.h index 64131378de..078b83d2fd 100644 --- a/src/include/switch_module_interfaces.h +++ b/src/include/switch_module_interfaces.h @@ -526,6 +526,8 @@ struct switch_limit_interface { switch_status_t (*reset) (void); /*! freform status */ char * (*status) (void); + /*! reset interval counter */ + switch_status_t (*interval_reset) (const char *realm, const char *resource); /* internal */ switch_thread_rwlock_t *rwlock; int refs; diff --git a/src/mod/applications/mod_commands/mod_commands.c b/src/mod/applications/mod_commands/mod_commands.c index a645105994..07da553cd2 100644 --- a/src/mod/applications/mod_commands/mod_commands.c +++ b/src/mod/applications/mod_commands/mod_commands.c @@ -4227,7 +4227,7 @@ SWITCH_STANDARD_API(sql_escape) } /* LIMIT Stuff */ -#define LIMIT_USAGE_USAGE " [rate]" +#define LIMIT_USAGE_SYNTAX " [rate]" SWITCH_STANDARD_API(limit_usage_function) { int argc = 0; @@ -4255,7 +4255,7 @@ SWITCH_STANDARD_API(limit_usage_function) } if (argc < 3) { - stream->write_function(stream, "USAGE: limit_usage %s\n", LIMIT_USAGE_USAGE); + stream->write_function(stream, "USAGE: limit_usage %s\n", LIMIT_USAGE_SYNTAX); goto end; } @@ -4279,7 +4279,7 @@ end: return SWITCH_STATUS_SUCCESS; } -#define LIMIT_HASH_USAGE_USAGE " [rate] (Using deprecated limit api, check limit_usage with backend param)" +#define LIMIT_HASH_USAGE_SYNTAX " [rate] (Using deprecated limit api, check limit_usage with backend param)" SWITCH_STANDARD_API(limit_hash_usage_function) { char *mydata = NULL; @@ -4290,12 +4290,12 @@ SWITCH_STANDARD_API(limit_hash_usage_function) switch_safe_free(mydata); return ret; } else { - stream->write_function(stream, "USAGE: limit_hash_usage %s\n", LIMIT_HASH_USAGE_USAGE); + stream->write_function(stream, "USAGE: limit_hash_usage %s\n", LIMIT_HASH_USAGE_SYNTAX); return SWITCH_STATUS_SUCCESS; } } -#define LIMIT_STATUS_USAGE "" +#define LIMIT_STATUS_SYNTAX "" SWITCH_STANDARD_API(limit_status_function) { int argc = 0; @@ -4310,7 +4310,7 @@ SWITCH_STANDARD_API(limit_status_function) } if (argc < 1) { - stream->write_function(stream, "USAGE: limit_status %s\n", LIMIT_STATUS_USAGE); + stream->write_function(stream, "USAGE: limit_status %s\n", LIMIT_STATUS_SYNTAX); goto end; } @@ -4325,7 +4325,7 @@ end: return SWITCH_STATUS_SUCCESS; } -#define LIMIT_RESET_USAGE "" +#define LIMIT_RESET_SYNTAX "" SWITCH_STANDARD_API(limit_reset_function) { int argc = 0; @@ -4340,7 +4340,7 @@ SWITCH_STANDARD_API(limit_reset_function) } if (argc < 1) { - stream->write_function(stream, "USAGE: limit_reset %s\n", LIMIT_RESET_USAGE); + stream->write_function(stream, "USAGE: limit_reset %s\n", LIMIT_RESET_SYNTAX); goto end; } @@ -4354,6 +4354,81 @@ end: return SWITCH_STATUS_SUCCESS; } +#define LIMIT_RELEASE_SYNTAX " [realm] [resource]" +SWITCH_STANDARD_API(uuid_limit_release_function) +{ + int argc = 0; + char *argv[5] = { 0 }; + char *mydata = NULL; + char *realm = NULL; + char *resource = NULL; + switch_core_session_t *sess = NULL; + + if (!zstr(cmd)) { + mydata = strdup(cmd); + switch_assert(mydata); + argc = switch_separate_string(mydata, ' ', argv, (sizeof(argv) / sizeof(argv[0]))); + } + + if (argc < 2) { + stream->write_function(stream, "USAGE: uuid_limit_release %s\n", LIMIT_RELEASE_SYNTAX); + goto end; + } + + if (argc > 2) { + realm = argv[2]; + } + + if (argc > 3) { + resource = argv[3]; + } + + sess = switch_core_session_locate(argv[0]); + if (!sess) { + stream->write_function(stream, "-ERR did not find a session with uuid %s\n", argv[0]); + goto end; + } + + switch_limit_release(argv[1], sess, realm, resource); + + switch_core_session_rwunlock(sess); + + stream->write_function(stream, "+OK"); + +end: + switch_safe_free(mydata); + + return SWITCH_STATUS_SUCCESS; +} + +#define LIMIT_INTERVAL_RESET_SYNTAX " " +SWITCH_STANDARD_API(limit_interval_reset_function) +{ + int argc = 0; + char *argv[5] = { 0 }; + char *mydata = NULL; + + if (!zstr(cmd)) { + mydata = strdup(cmd); + switch_assert(mydata); + argc = switch_separate_string(mydata, ' ', argv, (sizeof(argv) / sizeof(argv[0]))); + } + + if (argc < 3) { + stream->write_function(stream, "USAGE: limit_interval_reset %s\n", LIMIT_INTERVAL_RESET_SYNTAX); + goto end; + } + + switch_limit_interval_reset(argv[0], argv[1], argv[2]); + + stream->write_function(stream, "+OK"); + +end: + switch_safe_free(mydata); + + return SWITCH_STATUS_SUCCESS; +} + SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_commands_shutdown) { int x; @@ -4446,6 +4521,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_commands_load) SWITCH_ADD_API(commands_api_interface, "limit_hash_usage", "Deprecated: gets the usage count of a limited resource", limit_hash_usage_function, " "); SWITCH_ADD_API(commands_api_interface, "limit_status", "Gets the status of a limit backend", limit_status_function, ""); SWITCH_ADD_API(commands_api_interface, "limit_reset", "Reset the counters of a limit backend", limit_reset_function, ""); + SWITCH_ADD_API(commands_api_interface, "limit_interval_reset", "Reset the interval counter for a limited resource", limit_interval_reset_function, LIMIT_INTERVAL_RESET_SYNTAX); SWITCH_ADD_API(commands_api_interface, "load", "Load Module", load_function, LOAD_SYNTAX); SWITCH_ADD_API(commands_api_interface, "log", "Log", log_function, LOG_SYNTAX); SWITCH_ADD_API(commands_api_interface, "md5", "md5", md5_function, ""); @@ -4494,6 +4570,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_commands_load) SWITCH_ADD_API(commands_api_interface, "uuid_getvar", "uuid_getvar", uuid_getvar_function, GETVAR_SYNTAX); SWITCH_ADD_API(commands_api_interface, "uuid_hold", "hold", uuid_hold_function, HOLD_SYNTAX); SWITCH_ADD_API(commands_api_interface, "uuid_kill", "Kill Channel", kill_function, KILL_SYNTAX); + SWITCH_ADD_API(commands_api_interface, "uuid_limit_release", "Release limit resource", uuid_limit_release_function, LIMIT_RELEASE_SYNTAX); SWITCH_ADD_API(commands_api_interface, "uuid_loglevel", "set loglevel on session", uuid_loglevel, UUID_LOGLEVEL_SYNTAX); SWITCH_ADD_API(commands_api_interface, "uuid_media", "media", uuid_media_function, MEDIA_SYNTAX); SWITCH_ADD_API(commands_api_interface, "uuid_park", "Park Channel", park_function, PARK_SYNTAX); @@ -4600,6 +4677,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_commands_load) switch_console_set_complete("add uuid_getvar ::console::list_uuid"); switch_console_set_complete("add uuid_hold ::console::list_uuid"); switch_console_set_complete("add uuid_kill ::console::list_uuid"); + switch_console_set_complete("add uuid_limit_release ::console::list_uuid"); switch_console_set_complete("add uuid_loglevel ::console::list_uuid console"); switch_console_set_complete("add uuid_loglevel ::console::list_uuid alert"); switch_console_set_complete("add uuid_loglevel ::console::list_uuid crit"); diff --git a/src/mod/applications/mod_db/mod_db.c b/src/mod/applications/mod_db/mod_db.c index d22f1a8eec..088d9d0a85 100644 --- a/src/mod/applications/mod_db/mod_db.c +++ b/src/mod/applications/mod_db/mod_db.c @@ -620,7 +620,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_db_load) *module_interface = switch_loadable_module_create_module_interface(pool, modname); /* register limit interfaces */ - SWITCH_ADD_LIMIT(limit_interface, "db", limit_incr_db, limit_release_db, limit_usage_db, limit_reset_db, limit_status_db); + SWITCH_ADD_LIMIT(limit_interface, "db", limit_incr_db, limit_release_db, limit_usage_db, limit_reset_db, limit_status_db, NULL); SWITCH_ADD_APP(app_interface, "db", "Insert to the db", DB_DESC, db_function, DB_USAGE, SAF_SUPPORT_NOMEDIA); SWITCH_ADD_APP(app_interface, "group", "Manage a group", GROUP_DESC, group_function, GROUP_USAGE, SAF_SUPPORT_NOMEDIA); diff --git a/src/mod/applications/mod_hash/mod_hash.c b/src/mod/applications/mod_hash/mod_hash.c index f4eec4f3c1..a13a1874ae 100644 --- a/src/mod/applications/mod_hash/mod_hash.c +++ b/src/mod/applications/mod_hash/mod_hash.c @@ -360,6 +360,24 @@ SWITCH_LIMIT_RESET(limit_reset_hash) return SWITCH_STATUS_GENERR; } +SWITCH_LIMIT_INTERVAL_RESET(limit_interval_reset_hash) +{ + char *hash_key = NULL; + limit_hash_item_t *item = NULL; + + switch_thread_rwlock_rdlock(globals.limit_hash_rwlock); + + hash_key = switch_mprintf("%s_%s", realm, resource); + if ((item = switch_core_hash_find(globals.limit_hash, hash_key))) { + item->rate_usage = 0; + item->last_check = switch_epoch_time_now(NULL); + } + + switch_safe_free(hash_key); + switch_thread_rwlock_unlock(globals.limit_hash_rwlock); + return SWITCH_STATUS_SUCCESS; +} + SWITCH_LIMIT_STATUS(limit_status_hash) { /* @@ -892,7 +910,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_hash_load) *module_interface = switch_loadable_module_create_module_interface(pool, modname); /* register limit interfaces */ - SWITCH_ADD_LIMIT(limit_interface, "hash", limit_incr_hash, limit_release_hash, limit_usage_hash, limit_reset_hash, limit_status_hash); + SWITCH_ADD_LIMIT(limit_interface, "hash", limit_incr_hash, limit_release_hash, limit_usage_hash, limit_reset_hash, limit_status_hash, limit_interval_reset_hash); switch_scheduler_add_task(switch_epoch_time_now(NULL) + LIMIT_HASH_CLEANUP_INTERVAL, limit_hash_cleanup_callback, "limit_hash_cleanup", "mod_hash", 0, NULL, SSHF_NONE); diff --git a/src/mod/applications/mod_redis/mod_redis.c b/src/mod/applications/mod_redis/mod_redis.c index ca509520c0..75dfd6fdd7 100755 --- a/src/mod/applications/mod_redis/mod_redis.c +++ b/src/mod/applications/mod_redis/mod_redis.c @@ -300,7 +300,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_redis_load) /* If FreeSWITCH was restarted and we still have active calls, decrement them so our global count stays valid */ limit_reset_redis(); - SWITCH_ADD_LIMIT(limit_interface, "redis", limit_incr_redis, limit_release_redis, limit_usage_redis, limit_reset_redis, limit_status_redis); + SWITCH_ADD_LIMIT(limit_interface, "redis", limit_incr_redis, limit_release_redis, limit_usage_redis, limit_reset_redis, limit_status_redis, NULL); return SWITCH_STATUS_SUCCESS; } diff --git a/src/switch_limit.c b/src/switch_limit.c index f76e1de1c0..9313ecf5cf 100644 --- a/src/switch_limit.c +++ b/src/switch_limit.c @@ -196,6 +196,28 @@ end: return status; } +SWITCH_DECLARE(switch_status_t) switch_limit_interval_reset(const char *backend, const char *realm, const char *resource) { + switch_limit_interface_t *limit = NULL; + int status = SWITCH_STATUS_SUCCESS; + + /* locate impl, call appropriate func */ + if (!(limit = get_backend(backend))) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Limit subsystem %s not found!\n", backend); + switch_goto_status(SWITCH_STATUS_GENERR, end); + } + + if (!limit->interval_reset) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Limit subsystem %s does not implement interval_reset!\n", backend); + switch_goto_status(SWITCH_STATUS_GENERR, end); + } + + status = limit->interval_reset(realm, resource); + +end: + release_backend(limit); + return status; +} + SWITCH_DECLARE(char *) switch_limit_status(const char *backend) { switch_limit_interface_t *limit = NULL; char *status = NULL;