#define __FUNCTION__ __SWITCH_FUNC__
#endif
+#define FREETDM_LIMIT_REALM "__freetdm"
#define FREETDM_VAR_PREFIX "freetdm_"
#define FREETDM_VAR_PREFIX_LEN 8
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),
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];
};
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);
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));
}
+ 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);
}
}
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;
}
}
- 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";
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 {
}
}
+ /* 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");
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;