diff --git a/src/mod/applications/mod_hiredis/mod_hiredis.c b/src/mod/applications/mod_hiredis/mod_hiredis.c index 8a6077390c..2b1b85459f 100644 --- a/src/mod/applications/mod_hiredis/mod_hiredis.c +++ b/src/mod/applications/mod_hiredis/mod_hiredis.c @@ -41,7 +41,7 @@ SWITCH_STANDARD_APP(raw_app) switch_channel_t *channel = switch_core_session_get_channel(session); char *response = NULL, *profile_name = NULL, *cmd = NULL; hiredis_profile_t *profile = NULL; - + if ( !zstr(data) ) { profile_name = strdup(data); } else { @@ -63,7 +63,7 @@ SWITCH_STANDARD_APP(raw_app) switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "hiredis: Unable to locate profile[%s]\n", profile_name); return; } - + if ( hiredis_profile_execute_sync(profile, cmd, &response) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "hiredis: profile[%s] error executing [%s] because [%s]\n", profile_name, cmd, response); } @@ -81,13 +81,13 @@ SWITCH_STANDARD_API(raw_api) hiredis_profile_t *profile = NULL; char *data = NULL, *input = NULL, *response = NULL; switch_status_t status = SWITCH_STATUS_SUCCESS; - + if ( !zstr(cmd) ) { input = strdup(cmd); } else { switch_goto_status(SWITCH_STATUS_GENERR, done); } - + if ( (data = strchr(input, ' '))) { *data = '\0'; data++; @@ -101,7 +101,7 @@ SWITCH_STANDARD_API(raw_api) switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "hiredis: Unable to locate profile[%s]\n", input); switch_goto_status(SWITCH_STATUS_GENERR, done); } - + if ( hiredis_profile_execute_sync(profile, data, &response) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "hiredis: profile[%s] error executing [%s] reason:[%s]\n", input, data, response); switch_goto_status(SWITCH_STATUS_GENERR, done); @@ -114,24 +114,26 @@ SWITCH_STANDARD_API(raw_api) return status; } -/* -SWITCH_LIMIT_INCR(name) static switch_status_t name (switch_core_session_t *session, const char *realm, const char *resource, +/* +SWITCH_LIMIT_INCR(name) static switch_status_t name (switch_core_session_t *session, const char *realm, const char *resource, const int max, const int interval) */ SWITCH_LIMIT_INCR(hiredis_limit_incr) { switch_channel_t *channel = switch_core_session_get_channel(session); hiredis_profile_t *profile = NULL; - char *hashkey = NULL, *response = NULL; + char *hashkey = NULL, *response = NULL, *limit_key = NULL; int64_t count = 0; /* Redis defines the incr action as to be performed on a 64 bit signed integer */ time_t now = switch_epoch_time_now(NULL); switch_status_t status = SWITCH_STATUS_SUCCESS; + hiredis_limit_pvt_t *limit_pvt = NULL; + switch_memory_pool_t *session_pool = switch_core_session_get_pool(session); if ( zstr(realm) ) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "hiredis: realm must be defined\n"); switch_goto_status(SWITCH_STATUS_GENERR, done); } - + profile = switch_core_hash_find(mod_hiredis_globals.profiles, realm); if ( !profile ) { @@ -140,11 +142,13 @@ SWITCH_LIMIT_INCR(hiredis_limit_incr) } if ( interval ) { - hashkey = switch_mprintf("incr %s_%d", resource, now % interval); + limit_key = switch_mprintf("%s_%d", resource, now % interval); } else { - hashkey = switch_mprintf("incr %s", resource); + limit_key = switch_mprintf("%s", resource); } + hashkey = switch_mprintf("incr %s", limit_key); + if ( hiredis_profile_execute_sync(profile, hashkey, &response) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "hiredis: profile[%s] error executing [%s] because [%s]\n", realm, hashkey, response); switch_channel_set_variable(channel, "hiredis_raw_response", response); @@ -153,6 +157,14 @@ SWITCH_LIMIT_INCR(hiredis_limit_incr) switch_channel_set_variable(channel, "hiredis_raw_response", response); + limit_pvt = switch_core_alloc(session_pool, sizeof(hiredis_limit_pvt_t)); + limit_pvt->next = switch_channel_get_private(channel, "hiredis_limit_pvt"); + limit_pvt->realm = switch_core_strdup(session_pool, realm); + limit_pvt->resource = switch_core_strdup(session_pool, resource); + limit_pvt->limit_key = switch_core_strdup(session_pool, limit_key); + limit_pvt->inc = 1; + switch_channel_set_private(channel, "hiredis_limit_pvt", limit_pvt); + count = atoll(response); if ( !count || count > max ) { @@ -160,6 +172,7 @@ SWITCH_LIMIT_INCR(hiredis_limit_incr) } done: + switch_safe_free(limit_key); switch_safe_free(response); switch_safe_free(hashkey); return status; @@ -174,32 +187,48 @@ SWITCH_LIMIT_RELEASE(hiredis_limit_release) hiredis_profile_t *profile = switch_core_hash_find(mod_hiredis_globals.profiles, realm); char *hashkey = NULL, *response = NULL; switch_status_t status = SWITCH_STATUS_SUCCESS; + hiredis_limit_pvt_t *limit_pvt = switch_channel_get_private(channel, "hiredis_limit_pvt"); if ( !zstr(realm) ) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "hiredis: realm must be defined\n"); switch_goto_status(SWITCH_STATUS_GENERR, done); } - + if ( !profile ) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "hiredis: Unable to locate profile[%s]\n", realm); switch_goto_status(SWITCH_STATUS_GENERR, done); } + /* If realm and resource are NULL, then clear all of the limits */ if ( !realm && !resource ) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "hiredis does not yet support release on NULL realm[%s] and resource[%s]\n", realm, resource); - switch_goto_status(SWITCH_STATUS_GENERR, done); - } + hiredis_limit_pvt_t *tmp = limit_pvt; - hashkey = switch_mprintf("decr %s", resource); + while (tmp) { + hashkey = switch_mprintf("decr %s", tmp->limit_key); + limit_pvt = tmp->next; + + if ( hiredis_profile_execute_sync(profile, hashkey, &response) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "hiredis: profile[%s] error executing [%s] because [%s]\n", + tmp->realm, hashkey, response); + } + + tmp = limit_pvt; + switch_safe_free(response); + switch_safe_free(hashkey); + } + } else { + + hashkey = switch_mprintf("decr %s", limit_pvt->limit_key); + + if ( hiredis_profile_execute_sync(profile, hashkey, &response) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "hiredis: profile[%s] error executing [%s] because [%s]\n", realm, hashkey, response); + switch_channel_set_variable(channel, "hiredis_raw_response", response); + switch_goto_status(SWITCH_STATUS_GENERR, done); + } - if ( hiredis_profile_execute_sync(profile, hashkey, &response) != SWITCH_STATUS_SUCCESS) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "hiredis: profile[%s] error executing [%s] because [%s]\n", realm, hashkey, response); switch_channel_set_variable(channel, "hiredis_raw_response", response); - switch_goto_status(SWITCH_STATUS_GENERR, done); } - switch_channel_set_variable(channel, "hiredis_raw_response", response); - done: switch_safe_free(response); switch_safe_free(hashkey); @@ -212,14 +241,14 @@ SWITCH_LIMIT_USAGE(name) static int name (const char *realm, const char *resourc SWITCH_LIMIT_USAGE(hiredis_limit_usage) { hiredis_profile_t *profile = switch_core_hash_find(mod_hiredis_globals.profiles, realm); - int64_t count = 0; /* Redis defines the incr action as to be performed on a 64 bit signed integer */ + int64_t count = 0; /* Redis defines the incr action as to be performed on a 64 bit signed integer */ char *hashkey = NULL, *response = NULL; - + if ( !zstr(realm) ) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "hiredis: realm must be defined\n"); goto err; } - + if ( !profile ) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "hiredis: Unable to locate profile[%s]\n", realm); goto err; @@ -237,7 +266,7 @@ SWITCH_LIMIT_USAGE(hiredis_limit_usage) switch_safe_free(response); switch_safe_free(hashkey); return count; - + err: switch_safe_free(response); switch_safe_free(hashkey); @@ -251,7 +280,7 @@ SWITCH_LIMIT_RESET(hiredis_limit_reset) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "hiredis: unable to globally reset hiredis limit resources. Use 'hiredis_raw set resource_name 0'\n"); - + return SWITCH_STATUS_GENERR; } @@ -263,12 +292,12 @@ SWITCH_LIMIT_INTERVAL_RESET(hiredis_limit_interval_reset) hiredis_profile_t *profile = switch_core_hash_find(mod_hiredis_globals.profiles, realm); switch_status_t status = SWITCH_STATUS_SUCCESS; char *hashkey = NULL, *response = NULL; - + if ( !zstr(realm) ) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "hiredis: realm must be defined\n"); switch_goto_status(SWITCH_STATUS_GENERR, done); } - + if ( !profile ) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "hiredis: Unable to locate profile[%s]\n", realm); switch_goto_status(SWITCH_STATUS_GENERR, done); @@ -306,7 +335,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_hiredis_load) mod_hiredis_globals.pool = pool; switch_core_hash_init(&(mod_hiredis_globals.profiles)); - + if ( mod_hiredis_do_config() != SWITCH_STATUS_SUCCESS ) { return SWITCH_STATUS_GENERR; } diff --git a/src/mod/applications/mod_hiredis/mod_hiredis.h b/src/mod/applications/mod_hiredis/mod_hiredis.h index becb565dcc..5655fc7501 100644 --- a/src/mod/applications/mod_hiredis/mod_hiredis.h +++ b/src/mod/applications/mod_hiredis/mod_hiredis.h @@ -29,9 +29,17 @@ typedef struct hiredis_profile_s { int debug; hiredis_connection_t *conn; - hiredis_connection_t *conn_head; + hiredis_connection_t *conn_head; } hiredis_profile_t; +typedef struct hiredis_limit_pvt_s { + char *realm; + char *resource; + char *limit_key; + int inc; + struct hiredis_limit_pvt_s *next; +} hiredis_limit_pvt_t; + switch_status_t mod_hiredis_do_config(); switch_status_t hiredis_profile_create(hiredis_profile_t **new_profile, char *name, uint8_t port); switch_status_t hiredis_profile_destroy(hiredis_profile_t **old_profile);