Merge branch 'master' of ssh://git.freeswitch.org/freeswitch

This commit is contained in:
cypromis 2010-07-19 18:10:16 +02:00
commit cb42c09bf9
9 changed files with 513 additions and 32 deletions

View File

@ -0,0 +1,6 @@
<configuration name="hash.conf" description="Hash Configuration">
<remotes>
<!-- List of hosts from where to pull usage data -->
<!-- <remote name="Test1" host="10.0.0.10" port="8021" password="ClueCon" interval="1000" /> -->
</remotes>
</configuration>

View File

@ -307,7 +307,7 @@ static esl_status_t esl_event_base_add_header(esl_event_t *event, esl_stack_t st
header = ALLOC(sizeof(*header)); header = ALLOC(sizeof(*header));
esl_assert(header); esl_assert(header);
if ((event->flags & EF_UNIQ_HEADERS)) { if ((event->flags & ESL_UNIQ_HEADERS)) {
esl_event_del_header(event, header_name); esl_event_del_header(event, header_name);
} }

View File

@ -172,7 +172,7 @@ struct esl_event {
}; };
typedef enum { typedef enum {
EF_UNIQ_HEADERS = (1 << 0) ESL_UNIQ_HEADERS = (1 << 0)
} esl_event_flag_t; } esl_event_flag_t;

View File

@ -1158,12 +1158,12 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi
sipvar = switch_channel_get_variable(channel, "sip_h_X-FreeTDM-ANI-TON"); sipvar = switch_channel_get_variable(channel, "sip_h_X-FreeTDM-ANI-TON");
if (sipvar) { if (sipvar) {
caller_data.ani.type = atoi(sipvar); caller_data.ani.type = (uint8_t)atoi(sipvar);
} }
sipvar = switch_channel_get_variable(channel, "sip_h_X-FreeTDM-ANI-Plan"); sipvar = switch_channel_get_variable(channel, "sip_h_X-FreeTDM-ANI-Plan");
if (sipvar) { if (sipvar) {
caller_data.ani.plan = atoi(sipvar); caller_data.ani.plan = (uint8_t)atoi(sipvar);
} }
sipvar = switch_channel_get_variable(channel, "sip_h_X-FreeTDM-ANI2"); sipvar = switch_channel_get_variable(channel, "sip_h_X-FreeTDM-ANI2");
@ -1178,12 +1178,12 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi
sipvar = switch_channel_get_variable(channel, "sip_h_X-FreeTDM-DNIS-TON"); sipvar = switch_channel_get_variable(channel, "sip_h_X-FreeTDM-DNIS-TON");
if (sipvar) { if (sipvar) {
caller_data.dnis.type = atoi(sipvar); caller_data.dnis.type = (uint8_t)atoi(sipvar);
} }
sipvar = switch_channel_get_variable(channel, "sip_h_X-FreeTDM-DNIS-Plan"); sipvar = switch_channel_get_variable(channel, "sip_h_X-FreeTDM-DNIS-Plan");
if (sipvar) { if (sipvar) {
caller_data.dnis.plan = atoi(sipvar); caller_data.dnis.plan = (uint8_t)atoi(sipvar);
} }
sipvar = switch_channel_get_variable(channel, "sip_h_X-FreeTDM-RDNIS"); sipvar = switch_channel_get_variable(channel, "sip_h_X-FreeTDM-RDNIS");
@ -1193,22 +1193,22 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi
sipvar = switch_channel_get_variable(channel, "sip_h_X-FreeTDM-RDNIS-TON"); sipvar = switch_channel_get_variable(channel, "sip_h_X-FreeTDM-RDNIS-TON");
if (sipvar) { if (sipvar) {
caller_data.rdnis.type = atoi(sipvar); caller_data.rdnis.type = (uint8_t)atoi(sipvar);
} }
sipvar = switch_channel_get_variable(channel, "sip_h_X-FreeTDM-RDNIS-Plan"); sipvar = switch_channel_get_variable(channel, "sip_h_X-FreeTDM-RDNIS-Plan");
if (sipvar) { if (sipvar) {
caller_data.rdnis.plan = atoi(sipvar); caller_data.rdnis.plan = (uint8_t)atoi(sipvar);
} }
sipvar = switch_channel_get_variable(channel, "sip_h_X-FreeTDM-Screen"); sipvar = switch_channel_get_variable(channel, "sip_h_X-FreeTDM-Screen");
if (sipvar) { if (sipvar) {
caller_data.screen = atoi(sipvar); caller_data.screen = (uint8_t)atoi(sipvar);
} }
sipvar = switch_channel_get_variable(channel, "sip_h_X-FreeTDM-Presentation"); sipvar = switch_channel_get_variable(channel, "sip_h_X-FreeTDM-Presentation");
if (sipvar) { if (sipvar) {
caller_data.pres = atoi(sipvar); caller_data.pres = (uint8_t)atoi(sipvar);
} }
} }

View File

@ -1115,7 +1115,7 @@ static void *SWITCH_THREAD_FUNC ringall_thread_run(switch_thread_t *thread, void
char nstr[256] = ""; char nstr[256] = "";
if (strcasecmp(codec, "PCMU") && strcasecmp(codec, "PCMA")) { if (strcasecmp(codec, "PCMU") && strcasecmp(codec, "PCMA")) {
switch_snprintf(nstr, sizeof(nstr), "%s@%si@%sh,PCMU,PCMA", codec, ptime, rate); switch_snprintf(nstr, sizeof(nstr), "%s@%si@%sh,PCMU@%di,PCMA@%di", codec, ptime, rate, ptime, ptime);
} else { } else {
switch_snprintf(nstr, sizeof(nstr), "%s@%si@%sh", codec, ptime, rate); switch_snprintf(nstr, sizeof(nstr), "%s@%si@%sh", codec, ptime, rate);
} }

View File

@ -0,0 +1,4 @@
LOCAL_CFLAGS=-I../../../../libs/esl/src/include
LOCAL_LDFLAGS=-L../../../../libs/esl -lesl
BASE=../../../..
include $(BASE)/build/modmake.rules

View File

@ -34,6 +34,7 @@
*/ */
#include <switch.h> #include <switch.h>
#include "esl.h"
#define LIMIT_HASH_CLEANUP_INTERVAL 900 #define LIMIT_HASH_CLEANUP_INTERVAL 900
@ -48,13 +49,16 @@ static struct {
switch_hash_t *limit_hash; switch_hash_t *limit_hash;
switch_thread_rwlock_t *db_hash_rwlock; switch_thread_rwlock_t *db_hash_rwlock;
switch_hash_t *db_hash; switch_hash_t *db_hash;
switch_thread_rwlock_t *remote_hash_rwlock;
switch_hash_t *remote_hash;
} globals; } globals;
typedef struct { typedef struct {
uint32_t total_usage; uint32_t total_usage; /* < Total */
uint32_t rate_usage; uint32_t rate_usage; /* < Current rate usage */
time_t last_check; time_t last_check; /* < Last rate check */
uint32_t interval; uint32_t interval; /* < Interval used on last rate check */
uint32_t last_update; /* < Last updated timestamp (rate or total) */
} limit_hash_item_t; } limit_hash_item_t;
struct callback { struct callback {
@ -70,6 +74,50 @@ typedef struct {
switch_hash_t *hash; switch_hash_t *hash;
} limit_hash_private_t; } limit_hash_private_t;
typedef enum {
REMOTE_OFF = 0, /* < Thread not running */
REMOTE_DOWN, /* <C annot connect to remote instance */
REMOTE_UP /* < All good */
} limit_remote_state_t;
static inline const char *state_str(limit_remote_state_t state) {
switch (state) {
case REMOTE_OFF:
return "Off";
case REMOTE_DOWN:
return "Down";
case REMOTE_UP:
return "Up";
}
return "";
}
typedef struct {
const char *name;
const char *host;
const char *username;
const char *password;
int port;
int interval;
esl_handle_t handle;
switch_hash_t *index;
switch_thread_rwlock_t *rwlock;
switch_memory_pool_t *pool;
switch_bool_t running;
switch_thread_t *thread;
limit_remote_state_t state;
} limit_remote_t;
static limit_hash_item_t get_remote_usage(const char *key);
void limit_remote_destroy(limit_remote_t **r);
static void do_config(switch_bool_t reload);
/* \brief Enforces limit_hash restrictions /* \brief Enforces limit_hash restrictions
* \param session current session * \param session current session
* \param realm limit realm * \param realm limit realm
@ -87,6 +135,7 @@ SWITCH_LIMIT_INCR(limit_incr_hash)
time_t now = switch_epoch_time_now(NULL); time_t now = switch_epoch_time_now(NULL);
limit_hash_private_t *pvt = NULL; limit_hash_private_t *pvt = NULL;
uint8_t increment = 1; uint8_t increment = 1;
limit_hash_item_t remote_usage;
hashkey = switch_core_session_sprintf(session, "%s_%s", realm, resource); hashkey = switch_core_session_sprintf(session, "%s_%s", realm, resource);
@ -116,6 +165,8 @@ SWITCH_LIMIT_INCR(limit_incr_hash)
switch_channel_set_private(channel, "limit_hash", pvt); switch_channel_set_private(channel, "limit_hash", pvt);
} }
remote_usage = get_remote_usage(hashkey);
if (interval > 0) { if (interval > 0) {
item->interval = interval; item->interval = interval;
if (item->last_check <= (now - interval)) { if (item->last_check <= (now - interval)) {
@ -134,7 +185,7 @@ SWITCH_LIMIT_INCR(limit_incr_hash)
goto end; goto end;
} }
} }
} else if ((max >= 0) && (item->total_usage + increment > (uint32_t) max)) { } else if ((max >= 0) && (item->total_usage + increment + remote_usage.total_usage > (uint32_t) max)) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "Usage for %s is already at max value (%d)\n", hashkey, item->total_usage); switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "Usage for %s is already at max value (%d)\n", hashkey, item->total_usage);
status = SWITCH_STATUS_GENERR; status = SWITCH_STATUS_GENERR;
goto end; goto end;
@ -195,6 +246,19 @@ SWITCH_HASH_DELETE_FUNC(limit_hash_cleanup_delete_callback) {
return SWITCH_FALSE; return SWITCH_FALSE;
} }
SWITCH_HASH_DELETE_FUNC(limit_hash_remote_cleanup_callback)
{
limit_hash_item_t *item = (limit_hash_item_t *) val;
switch_time_t now = (switch_time_t)(intptr_t)pData;
if (item->last_update != now) {
free(item);
return SWITCH_TRUE;
}
return SWITCH_FALSE;
}
/* !\brief Periodically checks for unused limit entries and frees them */ /* !\brief Periodically checks for unused limit entries and frees them */
SWITCH_STANDARD_SCHED_FUNC(limit_hash_cleanup_callback) SWITCH_STANDARD_SCHED_FUNC(limit_hash_cleanup_callback)
{ {
@ -270,14 +334,19 @@ SWITCH_LIMIT_USAGE(limit_usage_hash)
char *hash_key = NULL; char *hash_key = NULL;
limit_hash_item_t *item = NULL; limit_hash_item_t *item = NULL;
int count = 0; int count = 0;
limit_hash_item_t remote_usage;
switch_thread_rwlock_rdlock(globals.limit_hash_rwlock); switch_thread_rwlock_rdlock(globals.limit_hash_rwlock);
hash_key = switch_mprintf("%s_%s", realm, resource); hash_key = switch_mprintf("%s_%s", realm, resource);
remote_usage = get_remote_usage(hash_key);
count = remote_usage.total_usage;
*rcount = remote_usage.rate_usage;
if ((item = switch_core_hash_find(globals.limit_hash, hash_key))) { if ((item = switch_core_hash_find(globals.limit_hash, hash_key))) {
count = item->total_usage; count += item->total_usage;
*rcount = item->rate_usage; *rcount += item->rate_usage;
} }
switch_safe_free(hash_key); switch_safe_free(hash_key);
@ -440,8 +509,361 @@ SWITCH_STANDARD_API(hash_api_function)
return SWITCH_STATUS_SUCCESS; return SWITCH_STATUS_SUCCESS;
} }
/* INIT/DEINIT STUFF */ #define HASH_DUMP_SYNTAX "all|limit|db"
SWITCH_STANDARD_API(hash_dump_function)
{
int mode;
switch_hash_index_t *hi;
if (zstr(cmd)) {
stream->write_function(stream, "Usage: "HASH_DUMP_SYNTAX"\n");
return SWITCH_STATUS_SUCCESS;
}
if (!strcmp(cmd, "all")) {
mode = 3;
} else if (!strcmp(cmd, "limit")) {
mode = 1;
} else if (!strcmp(cmd, "db")) {
mode = 2;
} else {
stream->write_function(stream, "Usage: "HASH_DUMP_SYNTAX"\n");
return SWITCH_STATUS_SUCCESS;
}
if (mode & 1) {
switch_thread_rwlock_rdlock(globals.limit_hash_rwlock);
for (hi = switch_hash_first(NULL, globals.limit_hash); hi; hi = switch_hash_next(hi)) {
void *val = NULL;
const void *key;
switch_ssize_t keylen;
limit_hash_item_t *item;
switch_hash_this(hi, &key, &keylen, &val);
item = (limit_hash_item_t *)val;
stream->write_function(stream, "L/%s/%d/%d/%d/%d\n", key, item->total_usage, item->rate_usage, item->interval, item->last_check);
}
switch_thread_rwlock_unlock(globals.limit_hash_rwlock);
}
if (mode & 2) {
switch_thread_rwlock_rdlock(globals.db_hash_rwlock);
for (hi = switch_hash_first(NULL, globals.db_hash); hi; hi = switch_hash_next(hi)) {
void *val = NULL;
const void *key;
switch_ssize_t keylen;
switch_hash_this(hi, &key, &keylen, &val);
stream->write_function(stream, "D/%s/%s\n", key, (char*)val);
}
switch_thread_rwlock_unlock(globals.db_hash_rwlock);
}
return SWITCH_STATUS_SUCCESS;
}
#define HASH_REMOTE_SYNTAX "list|kill [name]|rescan"
SWITCH_STANDARD_API(hash_remote_function)
{
int argc;
char *argv[10];
char *dup = NULL;
if (zstr(cmd)) {
stream->write_function(stream, "-ERR Usage: "HASH_REMOTE_SYNTAX"\n");
return SWITCH_STATUS_SUCCESS;
}
dup = strdup(cmd);
argc = switch_split(dup, ' ', argv);
if (argv[0] && !strcmp(argv[0], "list")) {
switch_hash_index_t *hi;
stream->write_function(stream, "Remote connections:\nName\t\t\tState\n");
switch_thread_rwlock_rdlock(globals.remote_hash_rwlock);
for (hi = switch_hash_first(NULL, globals.remote_hash); hi; hi = switch_hash_next(hi)) {
void *val;
const void *key;
switch_ssize_t keylen;
limit_remote_t *item;
switch_hash_this(hi, &key, &keylen, &val);
item = (limit_remote_t *)val;
stream->write_function(stream, "%s\t\t\t%s\n", item->name, state_str(item->state));
}
switch_thread_rwlock_unlock(globals.remote_hash_rwlock);
stream->write_function(stream, "+OK\n");
} else if (argv[0] && !strcmp(argv[0], "kill")) {
const char *name = argv[1];
limit_remote_t *remote;
if (zstr(name)) {
stream->write_function(stream, "-ERR Usage: "HASH_REMOTE_SYNTAX"\n");
goto done;
}
switch_thread_rwlock_rdlock(globals.remote_hash_rwlock);
remote = switch_core_hash_find(globals.remote_hash, name);
switch_thread_rwlock_unlock(globals.remote_hash_rwlock);
limit_remote_destroy(&remote);
switch_thread_rwlock_wrlock(globals.remote_hash_rwlock);
switch_core_hash_delete(globals.remote_hash, name);
switch_thread_rwlock_unlock(globals.remote_hash_rwlock);
stream->write_function(stream, "+OK\n");
} else if (argv[0] && !strcmp(argv[0], "rescan")) {
do_config(SWITCH_TRUE);
stream->write_function(stream, "+OK\n");
} else {
stream->write_function(stream, "-ERR Usage: "HASH_REMOTE_SYNTAX"\n");
}
done:
if (dup) {
free(dup);
}
return SWITCH_STATUS_SUCCESS;
}
limit_remote_t *limit_remote_create(const char *name, const char *host, uint16_t port, const char *username, const char *password, int interval)
{
limit_remote_t *r;
switch_memory_pool_t *pool;
switch_thread_rwlock_rdlock(globals.remote_hash_rwlock);
if (switch_core_hash_find(globals.remote_hash, name)) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Already have a remote instance named %s\n", name);
switch_thread_rwlock_unlock(globals.remote_hash_rwlock);
return NULL;
}
switch_thread_rwlock_unlock(globals.remote_hash_rwlock);
if (switch_core_new_memory_pool(&pool) != SWITCH_STATUS_SUCCESS) {
return NULL;
}
r = switch_core_alloc(pool, sizeof(limit_remote_t));
r->pool = pool;
r->name = switch_core_strdup(r->pool, name);
r->host = switch_core_strdup(r->pool, host);
r->port = port;
r->username = switch_core_strdup(r->pool, username);
r->password = switch_core_strdup(r->pool, password);
r->interval = interval;
switch_thread_rwlock_create(&r->rwlock, pool);
switch_core_hash_init(&r->index, pool);
switch_thread_rwlock_rdlock(globals.remote_hash_rwlock);
switch_core_hash_insert(globals.remote_hash, name, r);
switch_thread_rwlock_unlock(globals.remote_hash_rwlock);
return r;
}
void limit_remote_destroy(limit_remote_t **r)
{
if (r && *r) {
switch_hash_index_t *hi;
(*r)->state = REMOTE_OFF;
if ((*r)->thread) {
switch_status_t retval;
switch_thread_join(&retval, (*r)->thread);
}
switch_thread_rwlock_wrlock((*r)->rwlock);
/* Free hashtable data */
for (hi = switch_hash_first(NULL, (*r)->index); hi; hi = switch_hash_next(hi)) {
void *val;
const void *key;
switch_ssize_t keylen;
switch_hash_this(hi, &key, &keylen, &val);
free(val);
}
switch_thread_rwlock_unlock((*r)->rwlock);
switch_thread_rwlock_destroy((*r)->rwlock);
switch_core_destroy_memory_pool(&((*r)->pool));
*r = NULL;
}
}
/* Compute the usage sum of a resource on remote boxes */
static limit_hash_item_t get_remote_usage(const char *key) {
limit_hash_item_t usage = { 0 };
switch_hash_index_t *hi;
switch_thread_rwlock_rdlock(globals.remote_hash_rwlock);
for (hi = switch_hash_first(NULL, globals.remote_hash); hi; hi = switch_hash_next(hi)) {
void *val;
const void *hashkey;
switch_ssize_t keylen;
limit_remote_t *remote;
limit_hash_item_t *item;
switch_hash_this(hi, &hashkey, &keylen, &val);
remote = (limit_remote_t *)val;
if (remote->state != REMOTE_UP) {
continue;
}
switch_thread_rwlock_rdlock(remote->rwlock);
if ((item = switch_core_hash_find(remote->index, key))) {
usage.total_usage += item->total_usage;
usage.rate_usage += item->rate_usage;
if (!usage.last_check) {
usage.last_check = item->last_check;
}
}
switch_thread_rwlock_unlock(remote->rwlock);
}
switch_thread_rwlock_unlock(globals.remote_hash_rwlock);
return usage;
}
static void *SWITCH_THREAD_FUNC limit_remote_thread(switch_thread_t *thread, void *obj)
{
limit_remote_t *remote = (limit_remote_t*)obj;
while (remote->state > REMOTE_OFF) {
if (remote->state != REMOTE_UP) {
if (esl_connect(&remote->handle, remote->host, remote->port, remote->username, remote->password) == ESL_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Connected to remote FreeSWITCH at %s:%d\n",
remote->host, remote->port);
remote->state = REMOTE_UP;
}
} else {
if (esl_send_recv(&remote->handle, "api hash_dump limit") != ESL_SUCCESS) {
esl_disconnect(&remote->handle);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Disconnected from remote FreeSWITCH at %s:%d\n",
remote->host, remote->port);
memset(&remote->handle, 0, sizeof(remote->handle));
remote->state = REMOTE_DOWN;
/* Delete all remote tracking entries */
switch_thread_rwlock_wrlock(remote->rwlock);
switch_core_hash_delete_multi(remote->index, limit_hash_remote_cleanup_callback, NULL);
switch_thread_rwlock_unlock(remote->rwlock);
} else {
if (!zstr(remote->handle.last_sr_event->body)) {
char *data = strdup(remote->handle.last_sr_event->body);
char *p = data, *p2;
switch_time_t now = switch_epoch_time_now(NULL);
while (p && *p) {
/* We are getting the limit data as:
L/key/usage/rate/interval/last_checked
*/
if ((p2 = strchr(p, '\n'))) {
*p2++ = '\0';
}
/* Now p points at the beginning of the current line,
p2 at the start of the next one */
if (*p == 'L') { /* Limit data */
char *argv[5];
int argc = switch_split(p+2, '/', argv);
if (argc < 5) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Protocol error: missing argument in line: %s\n", p);
} else {
limit_hash_item_t *item;
switch_thread_rwlock_wrlock(remote->rwlock);
if (!(item = switch_core_hash_find(remote->index, argv[0]))) {
item = malloc(sizeof(*item));
switch_core_hash_insert(remote->index, argv[0], item);
}
item->total_usage = atoi(argv[1]);
item->rate_usage = atoi(argv[2]);
item->interval = atoi(argv[3]);
item->last_check = atoi(argv[4]);
item->last_update = now;
switch_thread_rwlock_unlock(remote->rwlock);
/*switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Imported key %s %d %d/%d (%d - %d)\n",
argv[0], item->total_usage, item->rate_usage, item->interval, (int)item->last_check, (int)item->last_update);*/
}
}
p = p2;
}
free(data);
/* Now free up anything that wasnt in this update since it means their usage is 0 */
switch_thread_rwlock_wrlock(remote->rwlock);
switch_core_hash_delete_multi(remote->index, limit_hash_remote_cleanup_callback, (void*)(intptr_t)now);
switch_thread_rwlock_unlock(remote->rwlock);
}
}
}
switch_yield(remote->interval * 1000);
}
remote->thread = NULL;
return NULL;
}
static void do_config(switch_bool_t reload)
{
switch_xml_t xml = NULL, x_lists = NULL, x_list = NULL, cfg = NULL;
if ((xml = switch_xml_open_cfg("hash.conf", &cfg, NULL))) {
if ((x_lists = switch_xml_child(cfg, "remotes"))) {
for (x_list = switch_xml_child(x_lists, "remote"); x_list; x_list = x_list->next) {
const char *name = switch_xml_attr(x_list, "name");
const char *host = switch_xml_attr(x_list, "host");
const char *szport = switch_xml_attr(x_list, "port");
const char *username = switch_xml_attr(x_list, "username");
const char *password = switch_xml_attr(x_list, "password");
const char *szinterval = switch_xml_attr(x_list, "interval");
int port = 0, interval = 0;
limit_remote_t *remote;
switch_threadattr_t *thd_attr = NULL;
if (reload) {
switch_thread_rwlock_rdlock(globals.remote_hash_rwlock);
if (switch_core_hash_find(globals.remote_hash, name)) {
switch_thread_rwlock_unlock(globals.remote_hash_rwlock);
continue;
}
switch_thread_rwlock_unlock(globals.remote_hash_rwlock);
}
if (!zstr(szport)) {
port = atoi(szport);
}
if (!zstr(szinterval)) {
interval = atoi(szinterval);
}
remote = limit_remote_create(name, host, port, username, password, interval);
remote->state = REMOTE_DOWN;
switch_threadattr_create(&thd_attr, remote->pool);
//switch_threadattr_detach_set(thd_attr, 1);
switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE);
switch_thread_create(&remote->thread, thd_attr, limit_remote_thread, remote, remote->pool);
}
}
switch_xml_free(xml);
}
}
/* INIT/DEINIT STUFF */
SWITCH_MODULE_LOAD_FUNCTION(mod_hash_load) SWITCH_MODULE_LOAD_FUNCTION(mod_hash_load)
{ {
switch_application_interface_t *app_interface; switch_application_interface_t *app_interface;
@ -460,8 +882,10 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_hash_load)
switch_thread_rwlock_create(&globals.limit_hash_rwlock, globals.pool); switch_thread_rwlock_create(&globals.limit_hash_rwlock, globals.pool);
switch_thread_rwlock_create(&globals.db_hash_rwlock, globals.pool); switch_thread_rwlock_create(&globals.db_hash_rwlock, globals.pool);
switch_thread_rwlock_create(&globals.remote_hash_rwlock, globals.pool);
switch_core_hash_init(&globals.limit_hash, pool); switch_core_hash_init(&globals.limit_hash, pool);
switch_core_hash_init(&globals.db_hash, pool); switch_core_hash_init(&globals.db_hash, pool);
switch_core_hash_init(&globals.remote_hash, globals.pool);
/* connect my internal structure to the blank pointer passed to me */ /* connect my internal structure to the blank pointer passed to me */
*module_interface = switch_loadable_module_create_module_interface(pool, modname); *module_interface = switch_loadable_module_create_module_interface(pool, modname);
@ -474,22 +898,55 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_hash_load)
SWITCH_ADD_APP(app_interface, "hash", "Insert into the hashtable", HASH_DESC, hash_function, HASH_USAGE, SAF_SUPPORT_NOMEDIA) SWITCH_ADD_APP(app_interface, "hash", "Insert into the hashtable", HASH_DESC, hash_function, HASH_USAGE, SAF_SUPPORT_NOMEDIA)
SWITCH_ADD_API(commands_api_interface, "hash", "hash get/set", hash_api_function, "[insert|delete|select]/<realm>/<key>/<value>"); SWITCH_ADD_API(commands_api_interface, "hash", "hash get/set", hash_api_function, "[insert|delete|select]/<realm>/<key>/<value>");
SWITCH_ADD_API(commands_api_interface, "hash_dump", "dump hash/limit_hash data (used for synchronization)", hash_dump_function, HASH_DUMP_SYNTAX);
SWITCH_ADD_API(commands_api_interface, "hash_remote", "hash remote", hash_remote_function, HASH_REMOTE_SYNTAX);
switch_console_set_complete("add hash insert"); switch_console_set_complete("add hash insert");
switch_console_set_complete("add hash delete"); switch_console_set_complete("add hash delete");
switch_console_set_complete("add hash select"); switch_console_set_complete("add hash select");
switch_console_set_complete("add hash_remote list");
switch_console_set_complete("add hash_remote kill");
switch_console_set_complete("add hash_remote rescan");
do_config(SWITCH_FALSE);
/* indicate that the module should continue to be loaded */ /* indicate that the module should continue to be loaded */
return SWITCH_STATUS_SUCCESS; return SWITCH_STATUS_SUCCESS;
} }
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_hash_shutdown) SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_hash_shutdown)
{ {
switch_hash_index_t *hi = NULL; switch_hash_index_t *hi;
switch_bool_t remote_clean = SWITCH_TRUE;
switch_scheduler_del_task_group("mod_hash"); switch_scheduler_del_task_group("mod_hash");
/* Kill remote connections, destroy needs a wrlock so we unlock after finding a pointer */
while(remote_clean) {
void *val;
const void *key;
switch_ssize_t keylen;
limit_remote_t *item = NULL;
switch_thread_rwlock_rdlock(globals.remote_hash_rwlock);
if ((hi = switch_hash_first(NULL, globals.remote_hash))) {
switch_hash_this(hi, &key, &keylen, &val);
item = (limit_remote_t *)val;
}
switch_thread_rwlock_unlock(globals.remote_hash_rwlock);
if (!item) {
remote_clean = SWITCH_FALSE;
} else {
limit_remote_destroy(&item);
switch_thread_rwlock_wrlock(globals.remote_hash_rwlock);
switch_core_hash_delete(globals.remote_hash, key);
switch_thread_rwlock_unlock(globals.remote_hash_rwlock);
}
}
switch_thread_rwlock_wrlock(globals.limit_hash_rwlock); switch_thread_rwlock_wrlock(globals.limit_hash_rwlock);
switch_thread_rwlock_wrlock(globals.db_hash_rwlock); switch_thread_rwlock_wrlock(globals.db_hash_rwlock);

4
src/switch_limit.c Executable file → Normal file
View File

@ -98,8 +98,8 @@ static switch_status_t limit_state_handler(switch_core_session_t *session)
switch_limit_release(argv[x], session, NULL, NULL); switch_limit_release(argv[x], session, NULL, NULL);
} }
switch_core_event_hook_remove_state_change(session, limit_state_handler); switch_core_event_hook_remove_state_change(session, limit_state_handler);
/* Remove limit_realm variable so we register another hook if limit is called again */ /* Remove limit_backend variable so we register another hook if limit is called again */
switch_channel_set_variable(channel, "limit_realm", NULL); switch_channel_set_variable(channel, LIMIT_BACKEND_VARIABLE, NULL);
free(mydata); free(mydata);
} }

View File

@ -2077,10 +2077,12 @@ static switch_status_t read_rtp_packet(switch_rtp_t *rtp_session, switch_size_t
rtp_session->stats.inbound.packet_count++; rtp_session->stats.inbound.packet_count++;
} }
if (rtp_session->recv_te && rtp_session->recv_msg.header.pt == rtp_session->recv_te) { if ((rtp_session->recv_te && rtp_session->recv_msg.header.pt == rtp_session->recv_te) ||
*bytes < rtp_header_len ||
switch_test_flag(rtp_session, SWITCH_RTP_FLAG_PROXY_MEDIA) || switch_test_flag(rtp_session, SWITCH_RTP_FLAG_UDPTL)) {
return SWITCH_STATUS_SUCCESS; return SWITCH_STATUS_SUCCESS;
} }
if (rtp_session->jb && rtp_session->recv_msg.header.version == 2 && *bytes) { if (rtp_session->jb && rtp_session->recv_msg.header.version == 2 && *bytes) {
if (rtp_session->recv_msg.header.m && rtp_session->recv_msg.header.pt != rtp_session->recv_te && if (rtp_session->recv_msg.header.m && rtp_session->recv_msg.header.pt != rtp_session->recv_te &&
@ -2532,7 +2534,7 @@ static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_
if (switch_test_flag(rtp_session, SWITCH_RTP_FLAG_UDPTL)) { if (switch_test_flag(rtp_session, SWITCH_RTP_FLAG_UDPTL)) {
*flags |= SFF_UDPTL_PACKET; *flags |= SFF_UDPTL_PACKET;
} }
ret = (int) bytes; ret = (int) bytes;
goto end; goto end;
} }
@ -2540,6 +2542,12 @@ static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_
if (bytes) { if (bytes) {
rtp_session->missed_count = 0; rtp_session->missed_count = 0;
if (bytes < rtp_header_len) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Ignoring invalid RTP packet size of %ld bytes.\n", (long)bytes);
bytes = 0;
goto do_continue;
}
if (rtp_session->recv_msg.header.pt && (rtp_session->recv_msg.header.pt == rtp_session->cng_pt || rtp_session->recv_msg.header.pt == 13)) { if (rtp_session->recv_msg.header.pt && (rtp_session->recv_msg.header.pt == rtp_session->cng_pt || rtp_session->recv_msg.header.pt == 13)) {
return_cng_frame(); return_cng_frame();
} }
@ -2667,7 +2675,7 @@ static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_
we put up with as much as we can so we don't have to deal with being punished for we put up with as much as we can so we don't have to deal with being punished for
doing it right. Nice guys finish last! doing it right. Nice guys finish last!
*/ */
if (bytes && !switch_test_flag(rtp_session, SWITCH_RTP_FLAG_PROXY_MEDIA) && if (bytes > rtp_header_len && !switch_test_flag(rtp_session, SWITCH_RTP_FLAG_PROXY_MEDIA) &&
!switch_test_flag(rtp_session, SWITCH_RTP_FLAG_PASS_RFC2833) && rtp_session->recv_msg.header.pt == rtp_session->recv_te) { !switch_test_flag(rtp_session, SWITCH_RTP_FLAG_PASS_RFC2833) && rtp_session->recv_msg.header.pt == rtp_session->recv_te) {
switch_size_t len = bytes - rtp_header_len; switch_size_t len = bytes - rtp_header_len;
unsigned char *packet = (unsigned char *) rtp_session->recv_msg.body; unsigned char *packet = (unsigned char *) rtp_session->recv_msg.body;
@ -2959,7 +2967,9 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_read(switch_rtp_t *rtp_session, void
*datalen = 0; *datalen = 0;
return SWITCH_STATUS_BREAK; return SWITCH_STATUS_BREAK;
} else { } else {
bytes -= rtp_header_len; if (bytes > rtp_header_len) {
bytes -= rtp_header_len;
}
} }
*datalen = bytes; *datalen = bytes;
@ -3069,7 +3079,7 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_zerocopy_read_frame(switch_rtp_t *rtp
if (bytes < 0) { if (bytes < 0) {
frame->datalen = 0; frame->datalen = 0;
return bytes == -2 ? SWITCH_STATUS_TIMEOUT : SWITCH_STATUS_GENERR; return bytes == -2 ? SWITCH_STATUS_TIMEOUT : SWITCH_STATUS_GENERR;
} else if (bytes == 0) { } else if (bytes < rtp_header_len) {
frame->datalen = 0; frame->datalen = 0;
return SWITCH_STATUS_BREAK; return SWITCH_STATUS_BREAK;
} else { } else {
@ -3098,7 +3108,9 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_zerocopy_read(switch_rtp_t *rtp_sessi
*datalen = 0; *datalen = 0;
return SWITCH_STATUS_GENERR; return SWITCH_STATUS_GENERR;
} else { } else {
bytes -= rtp_header_len; if (bytes > rtp_header_len) {
bytes -= rtp_header_len;
}
} }
*datalen = bytes; *datalen = bytes;
@ -3126,7 +3138,9 @@ static int rtp_common_write(switch_rtp_t *rtp_session,
send_msg->header.pt = rtp_session->te; send_msg->header.pt = rtp_session->te;
} }
data = send_msg->body; data = send_msg->body;
datalen -= rtp_header_len; if (datalen > rtp_header_len) {
datalen -= rtp_header_len;
}
} else { } else {
uint8_t m = 0; uint8_t m = 0;