Merge branch 'master' of ssh://git.freeswitch.org/freeswitch
This commit is contained in:
commit
cb42c09bf9
|
@ -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>
|
|
@ -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));
|
||||
esl_assert(header);
|
||||
|
||||
if ((event->flags & EF_UNIQ_HEADERS)) {
|
||||
if ((event->flags & ESL_UNIQ_HEADERS)) {
|
||||
esl_event_del_header(event, header_name);
|
||||
}
|
||||
|
||||
|
|
|
@ -172,7 +172,7 @@ struct esl_event {
|
|||
};
|
||||
|
||||
typedef enum {
|
||||
EF_UNIQ_HEADERS = (1 << 0)
|
||||
ESL_UNIQ_HEADERS = (1 << 0)
|
||||
} esl_event_flag_t;
|
||||
|
||||
|
||||
|
|
|
@ -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");
|
||||
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");
|
||||
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");
|
||||
|
@ -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");
|
||||
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");
|
||||
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");
|
||||
|
@ -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");
|
||||
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");
|
||||
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");
|
||||
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");
|
||||
if (sipvar) {
|
||||
caller_data.pres = atoi(sipvar);
|
||||
caller_data.pres = (uint8_t)atoi(sipvar);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1115,7 +1115,7 @@ static void *SWITCH_THREAD_FUNC ringall_thread_run(switch_thread_t *thread, void
|
|||
char nstr[256] = "";
|
||||
|
||||
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 {
|
||||
switch_snprintf(nstr, sizeof(nstr), "%s@%si@%sh", codec, ptime, rate);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
LOCAL_CFLAGS=-I../../../../libs/esl/src/include
|
||||
LOCAL_LDFLAGS=-L../../../../libs/esl -lesl
|
||||
BASE=../../../..
|
||||
include $(BASE)/build/modmake.rules
|
|
@ -34,6 +34,7 @@
|
|||
*/
|
||||
|
||||
#include <switch.h>
|
||||
#include "esl.h"
|
||||
|
||||
#define LIMIT_HASH_CLEANUP_INTERVAL 900
|
||||
|
||||
|
@ -48,13 +49,16 @@ static struct {
|
|||
switch_hash_t *limit_hash;
|
||||
switch_thread_rwlock_t *db_hash_rwlock;
|
||||
switch_hash_t *db_hash;
|
||||
switch_thread_rwlock_t *remote_hash_rwlock;
|
||||
switch_hash_t *remote_hash;
|
||||
} globals;
|
||||
|
||||
typedef struct {
|
||||
uint32_t total_usage;
|
||||
uint32_t rate_usage;
|
||||
time_t last_check;
|
||||
uint32_t interval;
|
||||
uint32_t total_usage; /* < Total */
|
||||
uint32_t rate_usage; /* < Current rate usage */
|
||||
time_t last_check; /* < Last rate check */
|
||||
uint32_t interval; /* < Interval used on last rate check */
|
||||
uint32_t last_update; /* < Last updated timestamp (rate or total) */
|
||||
} limit_hash_item_t;
|
||||
|
||||
struct callback {
|
||||
|
@ -70,6 +74,50 @@ typedef struct {
|
|||
switch_hash_t *hash;
|
||||
} 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
|
||||
* \param session current session
|
||||
* \param realm limit realm
|
||||
|
@ -87,6 +135,7 @@ SWITCH_LIMIT_INCR(limit_incr_hash)
|
|||
time_t now = switch_epoch_time_now(NULL);
|
||||
limit_hash_private_t *pvt = NULL;
|
||||
uint8_t increment = 1;
|
||||
limit_hash_item_t remote_usage;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
remote_usage = get_remote_usage(hashkey);
|
||||
|
||||
if (interval > 0) {
|
||||
item->interval = interval;
|
||||
if (item->last_check <= (now - interval)) {
|
||||
|
@ -134,7 +185,7 @@ SWITCH_LIMIT_INCR(limit_incr_hash)
|
|||
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);
|
||||
status = SWITCH_STATUS_GENERR;
|
||||
goto end;
|
||||
|
@ -195,6 +246,19 @@ SWITCH_HASH_DELETE_FUNC(limit_hash_cleanup_delete_callback) {
|
|||
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 */
|
||||
SWITCH_STANDARD_SCHED_FUNC(limit_hash_cleanup_callback)
|
||||
{
|
||||
|
@ -270,14 +334,19 @@ SWITCH_LIMIT_USAGE(limit_usage_hash)
|
|||
char *hash_key = NULL;
|
||||
limit_hash_item_t *item = NULL;
|
||||
int count = 0;
|
||||
limit_hash_item_t remote_usage;
|
||||
|
||||
switch_thread_rwlock_rdlock(globals.limit_hash_rwlock);
|
||||
|
||||
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))) {
|
||||
count = item->total_usage;
|
||||
*rcount = item->rate_usage;
|
||||
count += item->total_usage;
|
||||
*rcount += item->rate_usage;
|
||||
}
|
||||
|
||||
switch_safe_free(hash_key);
|
||||
|
@ -440,8 +509,361 @@ SWITCH_STANDARD_API(hash_api_function)
|
|||
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_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.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.db_hash, pool);
|
||||
switch_core_hash_init(&globals.remote_hash, globals.pool);
|
||||
|
||||
/* connect my internal structure to the blank pointer passed to me */
|
||||
*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_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 delete");
|
||||
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 */
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
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");
|
||||
|
||||
/* 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.db_hash_rwlock);
|
||||
|
||||
|
|
|
@ -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_core_event_hook_remove_state_change(session, limit_state_handler);
|
||||
/* Remove limit_realm variable so we register another hook if limit is called again */
|
||||
switch_channel_set_variable(channel, "limit_realm", NULL);
|
||||
/* Remove limit_backend variable so we register another hook if limit is called again */
|
||||
switch_channel_set_variable(channel, LIMIT_BACKEND_VARIABLE, NULL);
|
||||
|
||||
free(mydata);
|
||||
}
|
||||
|
|
|
@ -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++;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
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 &&
|
||||
|
@ -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)) {
|
||||
*flags |= SFF_UDPTL_PACKET;
|
||||
}
|
||||
|
||||
|
||||
ret = (int) bytes;
|
||||
goto end;
|
||||
}
|
||||
|
@ -2540,6 +2542,12 @@ static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_
|
|||
if (bytes) {
|
||||
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)) {
|
||||
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
|
||||
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_size_t len = bytes - rtp_header_len;
|
||||
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;
|
||||
return SWITCH_STATUS_BREAK;
|
||||
} else {
|
||||
bytes -= rtp_header_len;
|
||||
if (bytes > rtp_header_len) {
|
||||
bytes -= rtp_header_len;
|
||||
}
|
||||
}
|
||||
|
||||
*datalen = bytes;
|
||||
|
@ -3069,7 +3079,7 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_zerocopy_read_frame(switch_rtp_t *rtp
|
|||
if (bytes < 0) {
|
||||
frame->datalen = 0;
|
||||
return bytes == -2 ? SWITCH_STATUS_TIMEOUT : SWITCH_STATUS_GENERR;
|
||||
} else if (bytes == 0) {
|
||||
} else if (bytes < rtp_header_len) {
|
||||
frame->datalen = 0;
|
||||
return SWITCH_STATUS_BREAK;
|
||||
} else {
|
||||
|
@ -3098,7 +3108,9 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_zerocopy_read(switch_rtp_t *rtp_sessi
|
|||
*datalen = 0;
|
||||
return SWITCH_STATUS_GENERR;
|
||||
} else {
|
||||
bytes -= rtp_header_len;
|
||||
if (bytes > rtp_header_len) {
|
||||
bytes -= rtp_header_len;
|
||||
}
|
||||
}
|
||||
|
||||
*datalen = bytes;
|
||||
|
@ -3126,7 +3138,9 @@ static int rtp_common_write(switch_rtp_t *rtp_session,
|
|||
send_msg->header.pt = rtp_session->te;
|
||||
}
|
||||
data = send_msg->body;
|
||||
datalen -= rtp_header_len;
|
||||
if (datalen > rtp_header_len) {
|
||||
datalen -= rtp_header_len;
|
||||
}
|
||||
} else {
|
||||
uint8_t m = 0;
|
||||
|
||||
|
|
Loading…
Reference in New Issue