Fix transfer bug, fix leak and make the channel hangup if the extension is \!hangup_cause

git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@11604 d0543943-73ff-0310-b7d9-9358b9ac24b2
This commit is contained in:
Mathieu Rene 2009-02-03 02:34:37 +00:00
parent 40f18d3014
commit d0490570ad
1 changed files with 45 additions and 21 deletions

View File

@ -57,12 +57,16 @@ static struct {
#endif #endif
} globals; } globals;
struct limit_hash_item { typedef struct {
uint32_t total_usage; uint32_t total_usage;
uint32_t rate_usage; uint32_t rate_usage;
time_t last_check; time_t last_check;
}; } limit_hash_item_t;
typedef struct limit_hash_item limit_hash_item_t;
typedef struct {
uint8_t have_state_handler;
switch_hash_t *hash;
} limit_hash_private_t;
static char limit_sql[] = static char limit_sql[] =
@ -295,7 +299,7 @@ static switch_status_t hash_state_handler(switch_core_session_t *session)
{ {
switch_channel_t *channel = switch_core_session_get_channel(session); switch_channel_t *channel = switch_core_session_get_channel(session);
switch_channel_state_t state = switch_channel_get_state(channel); switch_channel_state_t state = switch_channel_get_state(channel);
switch_hash_t *channel_hash = switch_channel_get_private(channel, "limit_hash"); limit_hash_private_t *pvt = switch_channel_get_private(channel, "limit_hash");
/* The call is either hung up, or is going back into the dialplan, decrement appropriate couters */ /* The call is either hung up, or is going back into the dialplan, decrement appropriate couters */
if (state == CS_HANGUP || state == CS_ROUTING) { if (state == CS_HANGUP || state == CS_ROUTING) {
@ -303,7 +307,8 @@ static switch_status_t hash_state_handler(switch_core_session_t *session)
switch_mutex_lock(globals.limit_hash_mutex); switch_mutex_lock(globals.limit_hash_mutex);
/* Loop through the channel's hashtable which contains mapping to all the limit_hash_item_t referenced by that channel */ /* Loop through the channel's hashtable which contains mapping to all the limit_hash_item_t referenced by that channel */
for(hi = switch_hash_first(NULL, channel_hash); hi; hi = switch_hash_next(hi)) //for(hi = switch_hash_first(NULL, pvt->hash); hi; hi = switch_hash_next(hi))
while((hi = switch_hash_first(NULL, pvt->hash)))
{ {
void *val = NULL; void *val = NULL;
const void *key; const void *key;
@ -317,8 +322,20 @@ static switch_status_t hash_state_handler(switch_core_session_t *session)
/* We keep the structure even though the count is 0 so we do not allocate too often */ /* We keep the structure even though the count is 0 so we do not allocate too often */
item->total_usage--; item->total_usage--;
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Usage for %s is now %d\n", (const char*)key, item->total_usage); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Usage for %s is now %d\n", (const char*)key, item->total_usage);
if (item->total_usage == 0) {
/* Noone is using this item anymore */
switch_core_hash_delete(globals.limit_hash, (const char*)key);
free(item);
}
switch_core_hash_delete(pvt->hash, (const char*)key);
} }
/* Remove handler */
switch_core_event_hook_remove_state_change(session, hash_state_handler); switch_core_event_hook_remove_state_change(session, hash_state_handler);
pvt->have_state_handler = 0;
switch_mutex_unlock(globals.limit_hash_mutex); switch_mutex_unlock(globals.limit_hash_mutex);
} }
@ -812,9 +829,8 @@ SWITCH_STANDARD_APP(limit_hash_function)
limit_hash_item_t *item = NULL; limit_hash_item_t *item = NULL;
switch_channel_t *channel = switch_core_session_get_channel(session); switch_channel_t *channel = switch_core_session_get_channel(session);
time_t now = switch_epoch_time_now(NULL); time_t now = switch_epoch_time_now(NULL);
switch_hash_t *channel_hash = NULL; limit_hash_private_t *pvt = NULL;
uint8_t increment = 1; uint8_t increment = 1;
uint8_t new_channel = 0;
/* Parse application data */ /* Parse application data */
if (!switch_strlen_zero(data)) { if (!switch_strlen_zero(data)) {
@ -857,22 +873,25 @@ SWITCH_STANDARD_APP(limit_hash_function)
/* Check if that realm+id has ever been checked */ /* Check if that realm+id has ever been checked */
if (!(item = (limit_hash_item_t*)switch_core_hash_find(globals.limit_hash, hashkey))) { if (!(item = (limit_hash_item_t*)switch_core_hash_find(globals.limit_hash, hashkey))) {
/* No, create an empty structure and add it, then continue like as if it existed */ /* No, create an empty structure and add it, then continue like as if it existed */
item = (limit_hash_item_t*)switch_core_alloc(globals.pool, sizeof(limit_hash_item_t)); item = (limit_hash_item_t*)malloc(sizeof(limit_hash_item_t));
memset(item, 0, sizeof(limit_hash_item_t)); memset(item, 0, sizeof(limit_hash_item_t));
switch_core_hash_insert(globals.limit_hash, hashkey, item); switch_core_hash_insert(globals.limit_hash, hashkey, item);
} }
/* Did we already run on this channel before? */ /* Did we already run on this channel before? */
if ((channel_hash = switch_channel_get_private(channel, "limit_hash"))) if ((pvt = switch_channel_get_private(channel, "limit_hash")))
{ {
/* Yes, but check if we did that realm+id /* Yes, but check if we did that realm+id
If we didnt, allow incrementing the counter. If we didnt, allow incrementing the counter.
If we did, dont touch it but do the validation anyways If we did, dont touch it but do the validation anyways
*/ */
increment = !switch_core_hash_find(channel_hash, hashkey); increment = !switch_core_hash_find(pvt->hash, hashkey);
} else { } else {
/* This is the first limit check on this channel, create a hashtable, set our prviate data and add a state handler */ /* This is the first limit check on this channel, create a hashtable, set our prviate data and add a state handler */
new_channel = 1; pvt = (limit_hash_private_t*)switch_core_session_alloc(session, sizeof(limit_hash_private_t));
memset(pvt, 0, sizeof(limit_hash_private_t));
switch_core_hash_init(&pvt->hash, switch_core_session_get_pool(session));
switch_channel_set_private(channel, "limit_hash", pvt);
} }
if (interval > 0) { if (interval > 0) {
@ -885,22 +904,29 @@ SWITCH_STANDARD_APP(limit_hash_function)
if ((max >= 0) && (item->rate_usage > (uint32_t)max)) { if ((max >= 0) && (item->rate_usage > (uint32_t)max)) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Usage for %s exceeds maximum rate of %d/%ds, now at %d\n", hashkey, max, interval, item->rate_usage); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Usage for %s exceeds maximum rate of %d/%ds, now at %d\n", hashkey, max, interval, item->rate_usage);
switch_ivr_session_transfer(session, xfer_exten, argv[4], argv[5]); if (*xfer_exten == '!') {
switch_channel_hangup(channel, switch_channel_str2cause(xfer_exten+1));
} else {
switch_ivr_session_transfer(session, xfer_exten, argv[4], argv[5]);
}
goto end; goto end;
} }
} }
} else if ((max >= 0) && (item->total_usage + increment > (uint32_t)max)) { } else if ((max >= 0) && (item->total_usage + increment > (uint32_t)max)) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Usage for %s is already at max value (%d)\n", hashkey, item->total_usage); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Usage for %s is already at max value (%d)\n", hashkey, item->total_usage);
switch_ivr_session_transfer(session, xfer_exten, argv[4], argv[5]); if (*xfer_exten == '!') {
switch_channel_hangup(channel, switch_channel_str2cause(xfer_exten+1));
} else {
switch_ivr_session_transfer(session, xfer_exten, argv[4], argv[5]);
}
goto end; goto end;
} }
if (increment) { if (increment) {
item->total_usage++; item->total_usage++;
if (!new_channel) {
switch_core_hash_insert(channel_hash, hashkey, item); switch_core_hash_insert(pvt->hash, hashkey, item);
}
if (max == -1) { if (max == -1) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Usage for %s is now %d\n", hashkey, item->total_usage); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Usage for %s is now %d\n", hashkey, item->total_usage);
@ -915,11 +941,9 @@ SWITCH_STANDARD_APP(limit_hash_function)
switch_channel_set_variable(channel, "limit_usage", switch_core_session_sprintf(session, "%d", item->total_usage)); switch_channel_set_variable(channel, "limit_usage", switch_core_session_sprintf(session, "%d", item->total_usage));
switch_channel_set_variable(channel, "limit_rate", switch_core_session_sprintf(session, "%d", item->rate_usage)); switch_channel_set_variable(channel, "limit_rate", switch_core_session_sprintf(session, "%d", item->rate_usage));
if (new_channel) { if (!pvt->have_state_handler) {
switch_core_hash_init(&channel_hash, switch_core_session_get_pool(session));
switch_core_hash_insert(channel_hash, hashkey, item);
switch_channel_set_private(channel, "limit_hash", channel_hash);
switch_core_event_hook_add_state_change(session, hash_state_handler); switch_core_event_hook_add_state_change(session, hash_state_handler);
pvt->have_state_handler = 1;
} }
end: end: