freetdm: call rate limit

This commit is contained in:
Moises Silva 2010-07-28 11:35:39 -04:00
parent 889cadb8aa
commit a1fe7c8de4
1 changed files with 67 additions and 9 deletions

View File

@ -38,6 +38,7 @@
#define __FUNCTION__ __SWITCH_FUNC__
#endif
#define FREETDM_LIMIT_REALM "__freetdm"
#define FREETDM_VAR_PREFIX "freetdm_"
#define FREETDM_VAR_PREFIX_LEN 8
@ -55,6 +56,11 @@ typedef enum {
ANALOG_OPTION_CALL_SWAP = (1 << 1)
} analog_option_t;
typedef enum {
FTDM_LIMIT_RESET_ON_TIMEOUT = 0,
FTDM_LIMIT_RESET_ON_ANSWER = 1
} limit_reset_event_t;
typedef enum {
TFLAG_IO = (1 << 0),
TFLAG_DTMF = (1 << 1),
@ -119,6 +125,10 @@ struct span_config {
char hold_music[256];
char type[256];
analog_option_t analog_options;
const char *limit_backend;
int limit_calls;
int limit_seconds;
limit_reset_event_t limit_reset_event;
chan_pvt_t pvts[FTDM_MAX_CHANNELS_SPAN];
};
@ -1292,6 +1302,9 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi
switch_caller_profile_t *caller_profile;
switch_channel_t *channel = switch_core_session_get_channel(*new_session);
span_id = ftdm_channel_get_span_id(ftdmchan);
chan_id = ftdm_channel_get_id(ftdmchan);
switch_core_session_add_stream(*new_session, NULL);
if ((tech_pvt = (private_t *) switch_core_session_alloc(*new_session, sizeof(private_t))) != 0) {
tech_init(tech_pvt, *new_session, ftdmchan);
@ -1302,12 +1315,12 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi
goto fail;
}
snprintf(name, sizeof(name), "FreeTDM/%u:%u/%s", ftdm_channel_get_span_id(ftdmchan), ftdm_channel_get_id(ftdmchan), dest);
snprintf(name, sizeof(name), "FreeTDM/%u:%u/%s", span_id, chan_id, dest);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Connect outbound channel %s\n", name);
switch_channel_set_name(channel, name);
switch_channel_set_variable(channel, "freetdm_span_name", ftdm_channel_get_span_name(ftdmchan));
switch_channel_set_variable_printf(channel, "freetdm_span_number", "%d", ftdm_channel_get_span_id(ftdmchan));
switch_channel_set_variable_printf(channel, "freetdm_chan_number", "%d", ftdm_channel_get_id(ftdmchan));
switch_channel_set_variable_printf(channel, "freetdm_span_number", "%d", span_id);
switch_channel_set_variable_printf(channel, "freetdm_chan_number", "%d", chan_id);
ftdm_channel_set_caller_data(ftdmchan, &caller_data);
caller_profile = switch_caller_profile_clone(*new_session, outbound_profile);
caller_profile->destination_number = switch_core_strdup(caller_profile->pool, switch_str_nil(dest_num));
@ -1325,6 +1338,18 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi
}
if (SPAN_CONFIG[span_id].limit_calls) {
char spanresource[512];
snprintf(spanresource, sizeof(spanresource), "span_%s_%s", ftdm_channel_get_span_name(ftdmchan), caller_data.dnis.digits);
ftdm_log(FTDM_LOG_DEBUG, "Adding rate limit resource on channel %d:%d (%s/%s/%d/%d)\n", span_id, chan_id, FREETDM_LIMIT_REALM,
spanresource, SPAN_CONFIG[span_id].limit_calls, SPAN_CONFIG[span_id].limit_seconds);
if (switch_limit_incr("hash", *new_session, FREETDM_LIMIT_REALM, spanresource, SPAN_CONFIG[span_id].limit_calls, SPAN_CONFIG[span_id].limit_seconds) != SWITCH_STATUS_SUCCESS) {
switch_core_session_destroy(new_session);
cause = SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
goto fail;
}
}
if ((status = ftdm_channel_call_place(ftdmchan)) != FTDM_SUCCESS) {
if (tech_pvt->read_codec.implementation) {
switch_core_codec_destroy(&tech_pvt->read_codec);
@ -1516,6 +1541,18 @@ static FIO_SIGNAL_CB_FUNCTION(on_common_signal)
}
}
break;
case FTDM_SIGEVENT_UP:
{
/* clear any rate limit resource for this span */
char spanresource[512];
if (SPAN_CONFIG[spanid].limit_reset_event == FTDM_LIMIT_RESET_ON_ANSWER && SPAN_CONFIG[spanid].limit_calls) {
ftdm_caller_data_t *caller_data = ftdm_channel_get_caller_data(sigmsg->channel);
snprintf(spanresource, sizeof(spanresource), "span_%s_%s", ftdm_channel_get_span_name(sigmsg->channel), caller_data->dnis.digits);
ftdm_log(FTDM_LOG_DEBUG, "Clearing rate limit resource on channel %d:%d (%s/%s)\n", spanid, chanid, FREETDM_LIMIT_REALM, spanresource);
switch_limit_interval_reset("hash", FREETDM_LIMIT_REALM, spanresource);
}
return FTDM_SUCCESS;
}
default:
return FTDM_SUCCESS;
break;
@ -2344,7 +2381,7 @@ static switch_status_t load_config(void)
}
}
if ((spans = switch_xml_child(cfg, "sangoma_isdn_spans"))) {
if ((spans = switch_xml_child(cfg, "sangoma_pri_spans")) || (spans = switch_xml_child(cfg, "sangoma_bri_spans"))) {
for (myspan = switch_xml_child(spans, "span"); myspan; myspan = myspan->next) {
ftdm_status_t zstatus = FTDM_FAIL;
const char *context = "default";
@ -2362,11 +2399,6 @@ static switch_status_t load_config(void)
continue;
}
if (!configname) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "sangoma isdn span missing required attribute, skipping ...\n");
continue;
}
if (name) {
zstatus = ftdm_span_find_by_name(name, &span);
} else {
@ -2399,6 +2431,10 @@ static switch_status_t load_config(void)
}
}
/* some defaults first */
SPAN_CONFIG[span_id].limit_backend = "hash";
SPAN_CONFIG[span_id].limit_reset_event = FTDM_LIMIT_RESET_ON_TIMEOUT;
for (param = switch_xml_child(myspan, "param"); param; param = param->next) {
char *var = (char *) switch_xml_attr_soft(param, "name");
char *val = (char *) switch_xml_attr_soft(param, "value");
@ -2412,6 +2448,28 @@ static switch_status_t load_config(void)
context = val;
} else if (!strcasecmp(var, "dialplan")) {
dialplan = val;
} else if (!strcasecmp(var, "call_limit_backend")) {
SPAN_CONFIG[span_id].limit_backend = val;
ftdm_log(FTDM_LOG_DEBUG, "Using limit backend %s for span %d\n", SPAN_CONFIG[span_id].limit_backend, span_id);
} else if (!strcasecmp(var, "call_limit_rate")) {
int calls;
int seconds;
if (sscanf(val, "%d/%d", &calls, &seconds) != 2) {
ftdm_log(FTDM_LOG_ERROR, "Invalid %s parameter, format example: 3/1 for 3 calls per second\n", var);
} else {
if (calls < 1 || seconds < 1) {
ftdm_log(FTDM_LOG_ERROR, "Invalid %s parameter value, minimum call limit must be 1 per second\n", var);
} else {
SPAN_CONFIG[span_id].limit_calls = calls;
SPAN_CONFIG[span_id].limit_seconds = seconds;
}
}
} else if (!strcasecmp(var, "call_limit_reset_event")) {
if (!strcasecmp(val, "answer")) {
SPAN_CONFIG[span_id].limit_reset_event = FTDM_LIMIT_RESET_ON_ANSWER;
} else {
ftdm_log(FTDM_LOG_ERROR, "Invalid %s parameter value, only accepted event is 'answer'\n", var);
}
} else {
spanparameters[paramindex].var = var;
spanparameters[paramindex].val = val;