diff --git a/Freeswitch.2010.sln b/Freeswitch.2010.sln
index 4f48314f5b..186969891a 100644
--- a/Freeswitch.2010.sln
+++ b/Freeswitch.2010.sln
@@ -964,9 +964,7 @@ Global
{692F6330-4D87-4C82-81DF-40DB5892636E}.Release|Win32.ActiveCfg = Release|Win32
{692F6330-4D87-4C82-81DF-40DB5892636E}.Release|x64.ActiveCfg = Release|x64
{692F6330-4D87-4C82-81DF-40DB5892636E}.Release|x64 Setup.ActiveCfg = Release|x64
- {692F6330-4D87-4C82-81DF-40DB5892636E}.Release|x64 Setup.Build.0 = Release|x64
{692F6330-4D87-4C82-81DF-40DB5892636E}.Release|x86 Setup.ActiveCfg = Release|Win32
- {692F6330-4D87-4C82-81DF-40DB5892636E}.Release|x86 Setup.Build.0 = Release|Win32
{D3EC0AFF-76FC-4210-A825-9A17410660A3}.All|Win32.ActiveCfg = Release|x64
{D3EC0AFF-76FC-4210-A825-9A17410660A3}.All|x64.ActiveCfg = Release|x64
{D3EC0AFF-76FC-4210-A825-9A17410660A3}.All|x64.Build.0 = Release|x64
diff --git a/build/Makefile.am b/build/Makefile.am
index 4b426ef6e3..1d57dad528 100644
--- a/build/Makefile.am
+++ b/build/Makefile.am
@@ -6,8 +6,13 @@ all:
@echo " + Install by running: +"
@echo " + +"
@echo " + $(MK) install +"
+ @echo " + +"
+ @echo " + While you're waiting, register for ClueCon! +"
+ @echo " + http://www.cluecon.com +"
+ @echo " + +"
@echo " +-----------------------------------------------+"
+
install:
@echo " +---------- FreeSWITCH install Complete ----------+"
@echo " + FreeSWITCH has been successfully installed. +"
diff --git a/build/modules.conf.in b/build/modules.conf.in
index 37244a188a..13e655672c 100644
--- a/build/modules.conf.in
+++ b/build/modules.conf.in
@@ -62,6 +62,7 @@ endpoints/mod_loopback
#endpoints/mod_skinny
#endpoints/mod_skypopen
#endpoints/mod_h323
+#endpoints/mod_khomp
#../../libs/openzap/mod_openzap
#../../libs/freetdm/mod_freetdm
#asr_tts/mod_unimrcp
@@ -105,5 +106,4 @@ say/mod_say_ru
#say/mod_say_th
## Experimental Modules (don't cry if they're broken)
-#endpoints/mod_khomp
#../../contrib/mod/xml_int/mod_xml_odbc
diff --git a/conf/autoload_configs/modules.conf.xml b/conf/autoload_configs/modules.conf.xml
index f5627fe965..118d7c4d81 100644
--- a/conf/autoload_configs/modules.conf.xml
+++ b/conf/autoload_configs/modules.conf.xml
@@ -38,6 +38,7 @@
+
diff --git a/libs/esl/fs_cli.c b/libs/esl/fs_cli.c
index 91836b7aec..569e2cd169 100644
--- a/libs/esl/fs_cli.c
+++ b/libs/esl/fs_cli.c
@@ -1005,7 +1005,7 @@ int main(int argc, char *argv[])
int temp_log = -1;
int argv_error = 0;
int argv_exec = 0;
- char argv_command[256] = "";
+ char argv_command[1024] = "";
char argv_loglevel[128] = "";
int argv_quiet = 0;
int loops = 2, reconnect = 0;
diff --git a/libs/freetdm/Makefile.am b/libs/freetdm/Makefile.am
index bc92e1db58..af26f7f2af 100644
--- a/libs/freetdm/Makefile.am
+++ b/libs/freetdm/Makefile.am
@@ -55,10 +55,6 @@ COMPILE = $(CC) $(FTDM_CFLAGS)
LTCOMPILE = $(LIBTOOL) --mode=compile --tag=CC $(COMPILE)
LINK = $(LIBTOOL) --mode=link --tag=CC $(CC) $(FTDM_CFLAGS) $(LDFLAGS) -o $@
-if WANT_DEBUGDTMF
-FTDM_CFLAGS += -DFTDM_DEBUG_DTMF
-endif
-
#
# GNU pkgconfig file
diff --git a/libs/freetdm/conf/freetdm.conf b/libs/freetdm/conf/freetdm.conf
index bbaf1e3687..2f9643dedd 100644
--- a/libs/freetdm/conf/freetdm.conf
+++ b/libs/freetdm/conf/freetdm.conf
@@ -45,3 +45,29 @@ fxs-channel => 1
number => 2
fxo-channel => 3
+; MFC-R2 typical span configuration
+
+; MFC-R2 with wanpipe (Sangoma)
+[span wanpipe myWanpipeSpan]
+trunk_type => E1
+cas-channel => 1-15:1101
+cas-channel => 17-31:1101
+
+; MFC-R2 with Zaptel/DAHDI
+[span zt myWanpipeSpan]
+trunk_type => E1
+cas-channel => 1-15:1101
+cas-channel => 17-31:1101
+
+; generic channel parameters
+; this parameters are accepted by any type of span/channel
+; remember that for generic channel parameters only channels
+; below the parameter within the span will be affected
+
+; Channel audio gain
+; rxgain => 0.0
+; txgain => 0.0
+
+; Whether to perform media dumps for DTMF debugging
+; debugdtmf => yes
+
diff --git a/libs/freetdm/conf/freetdm.conf.xml b/libs/freetdm/conf/freetdm.conf.xml
index 986074dffb..63a3ea62cd 100644
--- a/libs/freetdm/conf/freetdm.conf.xml
+++ b/libs/freetdm/conf/freetdm.conf.xml
@@ -1,52 +1,220 @@
+
-
-
-
-
-
-
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/libs/freetdm/configure.ac b/libs/freetdm/configure.ac
index 6b9287d791..592dfd82a3 100644
--- a/libs/freetdm/configure.ac
+++ b/libs/freetdm/configure.ac
@@ -167,17 +167,6 @@ AC_ARG_WITH([pritap],
HAVE_PRITAP="${enable_pritap}"
AM_CONDITIONAL([HAVE_PRITAP],[test "${enable_pritap}" = "yes"])
-# debug dtmf?
-AC_ARG_WITH([debugdtmf],
- [AS_HELP_STRING([--with-debugdtmf], [Debug DTMF])],
- [case "${withval}" in
- no) enable_debugdtmf="no" ;;
- *) enable_debugdtmf="yes" ;;
- esac],
- [enable_debugdtmf="no"]
-)
-AM_CONDITIONAL([WANT_DEBUGDTMF], [test "${enable_debugdtmf}" = "yes"])
-
##
# OpenR2 stack
#
diff --git a/libs/freetdm/freetdm.2008.sln b/libs/freetdm/freetdm.2008.sln
index f059d941d3..0e374545eb 100644
--- a/libs/freetdm/freetdm.2008.sln
+++ b/libs/freetdm/freetdm.2008.sln
@@ -64,6 +64,9 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ftmod_sangoma_isdn", "src\f
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ftmod_r2", "src\ftmod\ftmod_r2\ftmod_r2.2008.vcproj", "{08C3EA27-A51D-47F8-B47D-B189C649CF30}"
+ ProjectSection(ProjectDependencies) = postProject
+ {93B8812C-3EC4-4F78-8970-FFBFC99E167D} = {93B8812C-3EC4-4F78-8970-FFBFC99E167D}
+ EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -131,7 +134,6 @@ Global
{1A145EE9-BBD8-45E5-98CD-EB4BE99E1DCD}.Release|Win32.ActiveCfg = Release|Win32
{1A145EE9-BBD8-45E5-98CD-EB4BE99E1DCD}.Release|x64.ActiveCfg = Release|x64
{D021EF2A-460D-4827-A0F7-41FDECF46F1B}.Debug|Win32.ActiveCfg = Debug|Win32
- {D021EF2A-460D-4827-A0F7-41FDECF46F1B}.Debug|Win32.Build.0 = Debug|Win32
{D021EF2A-460D-4827-A0F7-41FDECF46F1B}.Debug|x64.ActiveCfg = Debug|x64
{D021EF2A-460D-4827-A0F7-41FDECF46F1B}.Debug|x64.Build.0 = Debug|x64
{D021EF2A-460D-4827-A0F7-41FDECF46F1B}.Release|Win32.ActiveCfg = Release|Win32
@@ -139,7 +141,6 @@ Global
{D021EF2A-460D-4827-A0F7-41FDECF46F1B}.Release|x64.ActiveCfg = Release|x64
{D021EF2A-460D-4827-A0F7-41FDECF46F1B}.Release|x64.Build.0 = Release|x64
{2B1BAF36-0241-43E7-B865-A8338AD48E2E}.Debug|Win32.ActiveCfg = Debug|Win32
- {2B1BAF36-0241-43E7-B865-A8338AD48E2E}.Debug|Win32.Build.0 = Debug|Win32
{2B1BAF36-0241-43E7-B865-A8338AD48E2E}.Debug|x64.ActiveCfg = Debug|x64
{2B1BAF36-0241-43E7-B865-A8338AD48E2E}.Debug|x64.Build.0 = Debug|x64
{2B1BAF36-0241-43E7-B865-A8338AD48E2E}.Release|Win32.ActiveCfg = Release|Win32
@@ -147,7 +148,6 @@ Global
{2B1BAF36-0241-43E7-B865-A8338AD48E2E}.Release|x64.ActiveCfg = Release|x64
{2B1BAF36-0241-43E7-B865-A8338AD48E2E}.Release|x64.Build.0 = Release|x64
{0DA69C18-4FA1-4E8C-89CE-12498637C5BE}.Debug|Win32.ActiveCfg = Debug|Win32
- {0DA69C18-4FA1-4E8C-89CE-12498637C5BE}.Debug|Win32.Build.0 = Debug|Win32
{0DA69C18-4FA1-4E8C-89CE-12498637C5BE}.Debug|x64.ActiveCfg = Debug|x64
{0DA69C18-4FA1-4E8C-89CE-12498637C5BE}.Debug|x64.Build.0 = Debug|x64
{0DA69C18-4FA1-4E8C-89CE-12498637C5BE}.Release|Win32.ActiveCfg = Release|Win32
@@ -155,16 +155,13 @@ Global
{0DA69C18-4FA1-4E8C-89CE-12498637C5BE}.Release|x64.ActiveCfg = Release|x64
{0DA69C18-4FA1-4E8C-89CE-12498637C5BE}.Release|x64.Build.0 = Release|x64
{B2AF4EA6-0CD7-4529-9EB5-5AF43DB90395}.Debug|Win32.ActiveCfg = Debug|Win32
- {B2AF4EA6-0CD7-4529-9EB5-5AF43DB90395}.Debug|Win32.Build.0 = Debug|Win32
{B2AF4EA6-0CD7-4529-9EB5-5AF43DB90395}.Debug|x64.ActiveCfg = Debug|Win32
{B2AF4EA6-0CD7-4529-9EB5-5AF43DB90395}.Release|Win32.ActiveCfg = Release|Win32
{B2AF4EA6-0CD7-4529-9EB5-5AF43DB90395}.Release|Win32.Build.0 = Release|Win32
{B2AF4EA6-0CD7-4529-9EB5-5AF43DB90395}.Release|x64.ActiveCfg = Release|Win32
{08C3EA27-A51D-47F8-B47D-B189C649CF30}.Debug|Win32.ActiveCfg = Debug|Win32
- {08C3EA27-A51D-47F8-B47D-B189C649CF30}.Debug|Win32.Build.0 = Debug|Win32
{08C3EA27-A51D-47F8-B47D-B189C649CF30}.Debug|x64.ActiveCfg = Debug|Win32
{08C3EA27-A51D-47F8-B47D-B189C649CF30}.Release|Win32.ActiveCfg = Release|Win32
- {08C3EA27-A51D-47F8-B47D-B189C649CF30}.Release|Win32.Build.0 = Release|Win32
{08C3EA27-A51D-47F8-B47D-B189C649CF30}.Release|x64.ActiveCfg = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
diff --git a/libs/freetdm/freetdm.2010.sln b/libs/freetdm/freetdm.2010.sln
index 1806e9ea23..f4bd907a6d 100644
--- a/libs/freetdm/freetdm.2010.sln
+++ b/libs/freetdm/freetdm.2010.sln
@@ -120,16 +120,14 @@ Global
{0DA69C18-4FA1-4E8C-89CE-12498637C5BE}.Release|x64.Build.0 = Release|x64
{B2AF4EA6-0CD7-4529-9EB5-5AF43DB90395}.Debug|Win32.ActiveCfg = Debug|Win32
{B2AF4EA6-0CD7-4529-9EB5-5AF43DB90395}.Debug|Win32.Build.0 = Debug|Win32
- {B2AF4EA6-0CD7-4529-9EB5-5AF43DB90395}.Debug|x64.ActiveCfg = Debug|Win32
+ {B2AF4EA6-0CD7-4529-9EB5-5AF43DB90395}.Debug|x64.ActiveCfg = Debug|x64
{B2AF4EA6-0CD7-4529-9EB5-5AF43DB90395}.Release|Win32.ActiveCfg = Release|Win32
{B2AF4EA6-0CD7-4529-9EB5-5AF43DB90395}.Release|Win32.Build.0 = Release|Win32
- {B2AF4EA6-0CD7-4529-9EB5-5AF43DB90395}.Release|x64.ActiveCfg = Release|Win32
+ {B2AF4EA6-0CD7-4529-9EB5-5AF43DB90395}.Release|x64.ActiveCfg = Release|x64
{08C3EA27-A51D-47F8-B47D-B189C649CF30}.Debug|Win32.ActiveCfg = Debug|Win32
- {08C3EA27-A51D-47F8-B47D-B189C649CF30}.Debug|Win32.Build.0 = Debug|Win32
- {08C3EA27-A51D-47F8-B47D-B189C649CF30}.Debug|x64.ActiveCfg = Debug|Win32
+ {08C3EA27-A51D-47F8-B47D-B189C649CF30}.Debug|x64.ActiveCfg = Debug|x64
{08C3EA27-A51D-47F8-B47D-B189C649CF30}.Release|Win32.ActiveCfg = Release|Win32
- {08C3EA27-A51D-47F8-B47D-B189C649CF30}.Release|Win32.Build.0 = Release|Win32
- {08C3EA27-A51D-47F8-B47D-B189C649CF30}.Release|x64.ActiveCfg = Release|Win32
+ {08C3EA27-A51D-47F8-B47D-B189C649CF30}.Release|x64.ActiveCfg = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/libs/freetdm/mod_freetdm/mod_freetdm.c b/libs/freetdm/mod_freetdm/mod_freetdm.c
index b5c8b84c0c..ca16e8bc71 100755
--- a/libs/freetdm/mod_freetdm/mod_freetdm.c
+++ b/libs/freetdm/mod_freetdm/mod_freetdm.c
@@ -1417,6 +1417,24 @@ fail:
}
+static void ftdm_enable_channel_dtmf(ftdm_channel_t *fchan, switch_channel_t *channel)
+{
+ if (channel) {
+ const char *var;
+ if ((var = switch_channel_get_variable(channel, "freetdm_disable_dtmf"))) {
+ if (switch_true(var)) {
+ ftdm_channel_command(fchan, FTDM_COMMAND_DISABLE_DTMF_DETECT, NULL);
+ ftdm_log(FTDM_LOG_INFO, "DTMF detection disabled in channel %d:%d\n", ftdm_channel_get_span_id(fchan), ftdm_channel_get_id(fchan));
+ return;
+ }
+ }
+ /* the variable is not present or has a negative value then proceed to enable DTMF ... */
+ }
+ if (ftdm_channel_command(fchan, FTDM_COMMAND_ENABLE_DTMF_DETECT, NULL) != FTDM_SUCCESS) {
+ ftdm_log(FTDM_LOG_ERROR, "Failed to enable DTMF detection in channel %d:%d\n", ftdm_channel_get_span_id(fchan), ftdm_channel_get_id(fchan));
+ }
+}
+
ftdm_status_t ftdm_channel_from_event(ftdm_sigmsg_t *sigmsg, switch_core_session_t **sp)
{
switch_core_session_t *session = NULL;
@@ -1440,6 +1458,9 @@ ftdm_status_t ftdm_channel_from_event(ftdm_sigmsg_t *sigmsg, switch_core_session
return FTDM_FAIL;
}
+ /* I guess we always want DTMF detection */
+ ftdm_enable_channel_dtmf(sigmsg->channel, NULL);
+
switch_core_session_add_stream(session, NULL);
tech_pvt = (private_t *) switch_core_session_alloc(session, sizeof(private_t));
@@ -1633,24 +1654,6 @@ static FIO_SIGNAL_CB_FUNCTION(on_common_signal)
return FTDM_BREAK;
}
-static void ftdm_enable_channel_dtmf(ftdm_channel_t *fchan, switch_channel_t *channel)
-{
- if (channel) {
- const char *var;
- if ((var = switch_channel_get_variable(channel, "freetdm_disable_dtmf"))) {
- if (switch_true(var)) {
- ftdm_channel_command(fchan, FTDM_COMMAND_DISABLE_DTMF_DETECT, NULL);
- ftdm_log(FTDM_LOG_INFO, "DTMF detection disabled in channel %d:%d\n", ftdm_channel_get_span_id(fchan), ftdm_channel_get_id(fchan));
- return;
- }
- }
- /* the variable is not present or has a negative value then proceed to enable DTMF ... */
- }
- if (ftdm_channel_command(fchan, FTDM_COMMAND_ENABLE_DTMF_DETECT, NULL) != FTDM_SUCCESS) {
- ftdm_log(FTDM_LOG_ERROR, "Failed to enable DTMF detection in channel %d:%d\n", ftdm_channel_get_span_id(fchan), ftdm_channel_get_id(fchan));
- }
-}
-
static FIO_SIGNAL_CB_FUNCTION(on_fxo_signal)
{
switch_core_session_t *session = NULL;
@@ -2059,6 +2062,8 @@ static FIO_SIGNAL_CB_FUNCTION(on_r2_signal)
}
break;
+ case FTDM_SIGEVENT_PROCEED:{} break;
+
default:
{
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Unhandled event %d from R2 for channel %d:%d\n",
@@ -2092,8 +2097,6 @@ static FIO_SIGNAL_CB_FUNCTION(on_clear_channel_signal)
{
ftdm_channel_add_var(sigmsg->channel, "screening_ind", ftdm_screening2str(caller_data->screen));
ftdm_channel_add_var(sigmsg->channel, "presentation_ind", ftdm_presentation2str(caller_data->pres));
-
- ftdm_enable_channel_dtmf(sigmsg->channel, NULL);
return ftdm_channel_from_event(sigmsg, &session);
}
break;
@@ -3234,33 +3237,10 @@ static switch_status_t load_config(void)
if ((spans = switch_xml_child(cfg, "r2_spans"))) {
for (myspan = switch_xml_child(spans, "span"); myspan; myspan = myspan->next) {
- char *id = (char *) switch_xml_attr(myspan, "id");
char *name = (char *) switch_xml_attr(myspan, "name");
+ char *configname = (char *) switch_xml_attr(myspan, "cfgprofile");
ftdm_status_t zstatus = FTDM_FAIL;
- /* strings */
- const char *variant = "itu";
- const char *category = "national_subscriber";
- const char *logdir = "/usr/local/freeswitch/log/"; /* FIXME: get PREFIX variable */
- const char *logging = "notice,warning,error";
- const char *advanced_protocol_file = "";
-
- /* booleans */
- int call_files = 0;
- int get_ani_first = -1;
- int immediate_accept = -1;
- int double_answer = -1;
- int skip_category = -1;
- int forced_release = -1;
- int charge_calls = -1;
-
- /* integers */
- int mfback_timeout = -1;
- int metering_pulse_timeout = -1;
- int allow_collect_calls = -1;
- int max_ani = 10;
- int max_dnis = 4;
-
/* common non r2 stuff */
const char *context = "default";
const char *dialplan = "XML";
@@ -3269,53 +3249,29 @@ static switch_status_t load_config(void)
uint32_t span_id = 0;
ftdm_span_t *span = NULL;
+ ftdm_conf_parameter_t spanparameters[30];
+ unsigned paramindex = 0;
+
+ if (!name) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "'name' attribute required for R2 spans!\n");
+ continue;
+ }
+
+ memset(spanparameters, 0, sizeof(spanparameters));
+
+ if (configname) {
+ paramindex = add_profile_parameters(cfg, configname, spanparameters, ftdm_array_len(spanparameters));
+ if (paramindex) {
+ ftdm_log(FTDM_LOG_DEBUG, "Added %d parameters from profile %s for span %d\n", paramindex, configname, span_id);
+ }
+ }
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");
/* string parameters */
- if (!strcasecmp(var, "variant")) {
- variant = val;
- } else if (!strcasecmp(var, "category")) {
- category = val;
- } else if (!strcasecmp(var, "logdir")) {
- logdir = val;
- } else if (!strcasecmp(var, "logging")) {
- logging = val;
- } else if (!strcasecmp(var, "advanced_protocol_file")) {
- advanced_protocol_file = val;
-
- /* booleans */
- } else if (!strcasecmp(var, "allow_collect_calls")) {
- allow_collect_calls = switch_true(val);
- } else if (!strcasecmp(var, "immediate_accept")) {
- immediate_accept = switch_true(val);
- } else if (!strcasecmp(var, "double_answer")) {
- double_answer = switch_true(val);
- } else if (!strcasecmp(var, "skip_category")) {
- skip_category = switch_true(var);
- } else if (!strcasecmp(var, "forced_release")) {
- forced_release = switch_true(val);
- } else if (!strcasecmp(var, "charge_calls")) {
- charge_calls = switch_true(val);
- } else if (!strcasecmp(var, "get_ani_first")) {
- get_ani_first = switch_true(val);
- } else if (!strcasecmp(var, "call_files")) {
- call_files = switch_true(val);
-
- /* integers */
- } else if (!strcasecmp(var, "mfback_timeout")) {
- mfback_timeout = atoi(val);
- } else if (!strcasecmp(var, "metering_pulse_timeout")) {
- metering_pulse_timeout = atoi(val);
- } else if (!strcasecmp(var, "max_ani")) {
- max_ani = atoi(val);
- } else if (!strcasecmp(var, "max_dnis")) {
- max_dnis = atoi(val);
-
- /* common non r2 stuff */
- } else if (!strcasecmp(var, "context")) {
+ if (!strcasecmp(var, "context")) {
context = val;
} else if (!strcasecmp(var, "dialplan")) {
dialplan = val;
@@ -3323,57 +3279,23 @@ static switch_status_t load_config(void)
dial_regex = val;
} else if (!strcasecmp(var, "fail-dial-regex")) {
fail_dial_regex = val;
+ } else {
+ spanparameters[paramindex].var = var;
+ spanparameters[paramindex].val = val;
+ paramindex++;
}
}
- if (!id && !name) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "span missing required param 'id'\n");
- continue;
- }
-
- if (name) {
- zstatus = ftdm_span_find_by_name(name, &span);
- } else {
- if (switch_is_number(id)) {
- span_id = atoi(id);
- zstatus = ftdm_span_find(span_id, &span);
- }
-
- if (zstatus != FTDM_SUCCESS) {
- zstatus = ftdm_span_find_by_name(id, &span);
- }
- }
-
+ zstatus = ftdm_span_find_by_name(name, &span);
if (zstatus != FTDM_SUCCESS) {
- ftdm_log(FTDM_LOG_ERROR, "Error finding FreeTDM span id:%s name:%s\n", switch_str_nil(id), switch_str_nil(name));
+ ftdm_log(FTDM_LOG_ERROR, "Error finding FreeTDM R2 Span '%s'\n", name);
continue;
}
+ span_id = ftdm_span_get_id(span);
- if (!span_id) {
- span_id = ftdm_span_get_id(span);
- }
-
- if (ftdm_configure_span(span, "r2", on_r2_signal,
- "variant", variant,
- "max_ani", max_ani,
- "max_dnis", max_dnis,
- "category", category,
- "logdir", logdir,
- "logging", logging,
- "advanced_protocol_file", advanced_protocol_file,
- "allow_collect_calls", allow_collect_calls,
- "immediate_accept", immediate_accept,
- "double_answer", double_answer,
- "skip_category", skip_category,
- "forced_release", forced_release,
- "charge_calls", charge_calls,
- "get_ani_first", get_ani_first,
- "call_files", call_files,
- "mfback_timeout", mfback_timeout,
- "metering_pulse_timeout", metering_pulse_timeout,
- FTDM_TAG_END) != FTDM_SUCCESS) {
- ftdm_log(FTDM_LOG_ERROR, "Error configuring R2 FreeTDM span %d, error: %s\n",
- span_id, ftdm_span_get_last_error(span));
+ if (ftdm_configure_span_signaling(span, "r2", on_r2_signal, spanparameters) != FTDM_SUCCESS) {
+ ftdm_log(FTDM_LOG_ERROR, "Error configuring FreeTDM R2 span %s, error: %s\n",
+ name, ftdm_span_get_last_error(span));
continue;
}
@@ -3388,10 +3310,10 @@ static switch_status_t load_config(void)
SPAN_CONFIG[span_id].span = span;
switch_copy_string(SPAN_CONFIG[span_id].context, context, sizeof(SPAN_CONFIG[span_id].context));
switch_copy_string(SPAN_CONFIG[span_id].dialplan, dialplan, sizeof(SPAN_CONFIG[span_id].dialplan));
- switch_copy_string(SPAN_CONFIG[span_id].type, "r2", sizeof(SPAN_CONFIG[span_id].type));
+ switch_copy_string(SPAN_CONFIG[span_id].type, "R2", sizeof(SPAN_CONFIG[span_id].type));
if (ftdm_span_start(span) == FTDM_FAIL) {
- ftdm_log(FTDM_LOG_ERROR, "Error starting R2 FreeTDM span %d, error: %s\n", span_id, ftdm_span_get_last_error(span));
+ ftdm_log(FTDM_LOG_ERROR, "Error starting FreeTDM R2 span %s, error: %s\n", name, ftdm_span_get_last_error(span));
continue;
}
}
diff --git a/libs/freetdm/msvc/testboost/testboost.2008.vcproj b/libs/freetdm/msvc/testboost/testboost.2008.vcproj
index afb44b6469..5707033f33 100644
--- a/libs/freetdm/msvc/testboost/testboost.2008.vcproj
+++ b/libs/freetdm/msvc/testboost/testboost.2008.vcproj
@@ -22,7 +22,7 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/libs/freetdm/msvc/testboost/testsangomaboost.2010.vcxproj b/libs/freetdm/msvc/testboost/testsangomaboost.2010.vcxproj
index b6c0518883..5994da6f1a 100644
--- a/libs/freetdm/msvc/testboost/testsangomaboost.2010.vcxproj
+++ b/libs/freetdm/msvc/testboost/testsangomaboost.2010.vcxproj
@@ -186,7 +186,7 @@
Level4
- true
+ false
ProgramDatabase
4100;%(DisableSpecificWarnings)
diff --git a/libs/freetdm/src/ftdm_io.c b/libs/freetdm/src/ftdm_io.c
index 3dd1aa9ece..cde3c245cf 100644
--- a/libs/freetdm/src/ftdm_io.c
+++ b/libs/freetdm/src/ftdm_io.c
@@ -48,6 +48,10 @@
#endif
#include "ftdm_cpu_monitor.h"
+#ifndef localtime_r
+struct tm *localtime_r(const time_t *clock, struct tm *result);
+#endif
+
#define FORCE_HANGUP_TIMER 3000
#define SPAN_PENDING_CHANS_QUEUE_SIZE 1000
#define SPAN_PENDING_SIGNALS_QUEUE_SIZE 1000
@@ -86,6 +90,114 @@ FT_DECLARE(ftdm_time_t) ftdm_current_time_in_ms(void)
#endif
}
+static void write_chan_io_dump(ftdm_io_dump_t *dump, char *dataptr, int dlen)
+{
+ int windex = dump->windex;
+ int avail = (int)dump->size - windex;
+
+ if (!dump->buffer) {
+ return;
+ }
+
+ if (dlen > avail) {
+ int diff = dlen - avail;
+
+ ftdm_assert(diff < dump->size, "Very small buffer or very big IO chunk!\n");
+
+ /* write only what we can and the rest at the beginning of the buffer */
+ memcpy(&dump->buffer[windex], dataptr, avail);
+ memcpy(&dump->buffer[0], &dataptr[avail], diff);
+ windex = diff;
+
+ /*ftdm_log_chan(fchan, FTDM_LOG_DEBUG, "wrapping around dump buffer %p up to index %d\n\n", dump, windex);*/
+ dump->wrapped = 1;
+ } else {
+ memcpy(&dump->buffer[windex], dataptr, dlen);
+ windex += dlen;
+ }
+
+ if (windex == dump->size) {
+ /*ftdm_log_chan(fchan, FTDM_LOG_DEBUG, "wrapping around dump buffer %p\n", dump);*/
+ windex = 0;
+ dump->wrapped = 1;
+ }
+
+ dump->windex = windex;
+}
+
+static void dump_chan_io_to_file(ftdm_channel_t *fchan, ftdm_io_dump_t *dump, FILE *file)
+{
+ /* write the saved audio buffer */
+ size_t rc = 0;
+ size_t towrite = dump->size - dump->windex;
+ if (dump->wrapped) {
+ rc = fwrite(&dump->buffer[dump->windex], 1, towrite, file);
+ if (rc != towrite) {
+ ftdm_log_chan(fchan, FTDM_LOG_ERROR, "only wrote %d out of %d bytes in DTMF debug buffer\n", rc, towrite);
+ }
+ }
+ if (dump->windex) {
+ towrite = dump->windex;
+ rc = fwrite(&dump->buffer[0], 1, towrite, file);
+ if (rc != towrite) {
+ ftdm_log_chan(fchan, FTDM_LOG_ERROR, "only wrote %d out of %d bytes in DTMF debug buffer\n", rc, towrite);
+ }
+ }
+ dump->windex = 0;
+ dump->wrapped = 0;
+}
+
+static void stop_chan_io_dump(ftdm_io_dump_t *dump)
+{
+ if (!dump->buffer) {
+ return;
+ }
+ ftdm_safe_free(dump->buffer);
+ memset(dump, 0, sizeof(dump));
+}
+
+static ftdm_status_t start_chan_io_dump(ftdm_channel_t *chan, ftdm_io_dump_t *dump, ftdm_size_t size)
+{
+ if (dump->buffer) {
+ ftdm_log_chan_msg(chan, FTDM_LOG_ERROR, "IO dump is already started\n");
+ return FTDM_FAIL;
+ }
+ memset(dump, 0, sizeof(*dump));
+ dump->buffer = ftdm_malloc((uint32_t)size);
+ if (!dump->buffer) {
+ return FTDM_FAIL;
+ }
+ dump->size = size;
+ return FTDM_SUCCESS;
+}
+
+
+static void close_dtmf_debug_file(ftdm_channel_t *ftdmchan)
+{
+ if (ftdmchan->dtmfdbg.file) {
+ ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "closing debug dtmf file\n");
+ fclose(ftdmchan->dtmfdbg.file);
+ ftdmchan->dtmfdbg.file = NULL;
+ }
+}
+
+static ftdm_status_t disable_dtmf_debug(ftdm_channel_t *ftdmchan)
+{
+ if (!ftdmchan->dtmfdbg.enabled) {
+ return FTDM_SUCCESS;
+ }
+
+ if (!ftdmchan->rxdump.buffer) {
+ ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "DTMF debug enabled but no rx dump?\n");
+ return FTDM_FAIL;
+ }
+
+ close_dtmf_debug_file(ftdmchan);
+ stop_chan_io_dump(&ftdmchan->rxdump);
+ ftdmchan->dtmfdbg.enabled = 0;
+ return FTDM_SUCCESS;
+}
+
typedef struct {
uint8_t enabled;
uint8_t running;
@@ -314,43 +426,43 @@ static ftdm_status_t ftdm_set_caller_data(ftdm_span_t *span, ftdm_caller_data_t
return FTDM_FAIL;
}
- if (caller_data->dnis.plan == FTDM_NPI_INVALID) {
+ if (caller_data->dnis.plan >= FTDM_NPI_INVALID) {
caller_data->dnis.plan = span->default_caller_data.dnis.plan;
}
- if (caller_data->dnis.type == FTDM_TON_INVALID) {
+ if (caller_data->dnis.type >= FTDM_TON_INVALID) {
caller_data->dnis.type = span->default_caller_data.dnis.type;
}
- if (caller_data->cid_num.plan == FTDM_NPI_INVALID) {
+ if (caller_data->cid_num.plan >= FTDM_NPI_INVALID) {
caller_data->cid_num.plan = span->default_caller_data.cid_num.plan;
}
- if (caller_data->cid_num.type == FTDM_TON_INVALID) {
+ if (caller_data->cid_num.type >= FTDM_TON_INVALID) {
caller_data->cid_num.type = span->default_caller_data.cid_num.type;
}
- if (caller_data->ani.plan == FTDM_NPI_INVALID) {
+ if (caller_data->ani.plan >= FTDM_NPI_INVALID) {
caller_data->ani.plan = span->default_caller_data.ani.plan;
}
- if (caller_data->ani.type == FTDM_TON_INVALID) {
+ if (caller_data->ani.type >= FTDM_TON_INVALID) {
caller_data->ani.type = span->default_caller_data.ani.type;
}
- if (caller_data->rdnis.plan == FTDM_NPI_INVALID) {
+ if (caller_data->rdnis.plan >= FTDM_NPI_INVALID) {
caller_data->rdnis.plan = span->default_caller_data.rdnis.plan;
}
- if (caller_data->rdnis.type == FTDM_NPI_INVALID) {
+ if (caller_data->rdnis.type >= FTDM_NPI_INVALID) {
caller_data->rdnis.type = span->default_caller_data.rdnis.type;
}
- if (caller_data->bearer_capability == FTDM_INVALID_INT_PARM) {
+ if (caller_data->bearer_capability >= FTDM_INVALID_INT_PARM) {
caller_data->bearer_capability = span->default_caller_data.bearer_capability;
}
- if (caller_data->bearer_layer1 == FTDM_INVALID_INT_PARM) {
+ if (caller_data->bearer_layer1 >= FTDM_INVALID_INT_PARM) {
caller_data->bearer_layer1 = span->default_caller_data.bearer_layer1;
}
@@ -448,10 +560,6 @@ static ftdm_status_t ftdm_channel_destroy(ftdm_channel_t *ftdmchan)
ftdm_sleep(500);
}
-#ifdef FTDM_DEBUG_DTMF
- ftdm_mutex_destroy(&ftdmchan->dtmfdbg.mutex);
-#endif
-
ftdm_mutex_lock(ftdmchan->pre_buffer_mutex);
ftdm_buffer_destroy(&ftdmchan->pre_buffer);
ftdm_mutex_unlock(ftdmchan->pre_buffer_mutex);
@@ -870,9 +978,6 @@ FT_DECLARE(ftdm_status_t) ftdm_span_add_channel(ftdm_span_t *span, ftdm_socket_t
ftdm_mutex_create(&new_chan->mutex);
ftdm_mutex_create(&new_chan->pre_buffer_mutex);
-#ifdef FTDM_DEBUG_DTMF
- ftdm_mutex_create(&new_chan->dtmfdbg.mutex);
-#endif
ftdm_buffer_create(&new_chan->digit_buffer, 128, 128, 0);
ftdm_buffer_create(&new_chan->gen_dtmf_buffer, 128, 128, 0);
@@ -1004,6 +1109,51 @@ FT_DECLARE(ftdm_status_t) ftdm_span_next_event(ftdm_span_t *span, ftdm_event_t *
return status;
}
+FT_DECLARE(ftdm_status_t) ftdm_channel_read_event(ftdm_channel_t *ftdmchan, ftdm_event_t **event)
+{
+ ftdm_status_t status = FTDM_FAIL;
+ ftdm_sigmsg_t sigmsg;
+ ftdm_span_t *span = ftdmchan->span;
+ ftdm_assert_return(span->fio != NULL, FTDM_FAIL, "No I/O module attached to this span!\n");
+
+ if (!span->fio->channel_next_event) {
+ ftdm_log(FTDM_LOG_ERROR, "channel_next_event method not implemented in module %s!", span->fio->name);
+ return FTDM_NOTIMPL;
+ }
+
+ status = span->fio->channel_next_event(ftdmchan, event);
+ if (status != FTDM_SUCCESS) {
+ return status;
+ }
+
+ /* before returning the event to the user we do some core operations with certain OOB events */
+ memset(&sigmsg, 0, sizeof(sigmsg));
+ sigmsg.span_id = span->span_id;
+ sigmsg.chan_id = (*event)->channel->chan_id;
+ sigmsg.channel = (*event)->channel;
+ switch ((*event)->enum_id) {
+ case FTDM_OOB_ALARM_CLEAR:
+ {
+ sigmsg.event_id = FTDM_SIGEVENT_ALARM_CLEAR;
+ ftdm_clear_flag_locked((*event)->channel, FTDM_CHANNEL_IN_ALARM);
+ ftdm_span_send_signal(span, &sigmsg);
+ }
+ break;
+ case FTDM_OOB_ALARM_TRAP:
+ {
+ sigmsg.event_id = FTDM_SIGEVENT_ALARM_TRAP;
+ ftdm_set_flag_locked((*event)->channel, FTDM_CHANNEL_IN_ALARM);
+ ftdm_span_send_signal(span, &sigmsg);
+ }
+ break;
+ default:
+ /* NOOP */
+ break;
+ }
+
+ return status;
+}
+
static ftdm_status_t ftdmchan_fsk_write_sample(int16_t *buf, ftdm_size_t buflen, void *user_data)
{
ftdm_channel_t *ftdmchan = (ftdm_channel_t *) user_data;
@@ -2355,23 +2505,6 @@ FT_DECLARE(ftdm_status_t) ftdm_span_get_sig_status(ftdm_span_t *span, ftdm_signa
}
}
-#ifdef FTDM_DEBUG_DTMF
-static void close_dtmf_debug(ftdm_channel_t *ftdmchan)
-{
- ftdm_mutex_lock(ftdmchan->dtmfdbg.mutex);
-
- if (ftdmchan->dtmfdbg.file) {
- ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "closing debug dtmf file\n");
- fclose(ftdmchan->dtmfdbg.file);
- ftdmchan->dtmfdbg.file = NULL;
- }
- ftdmchan->dtmfdbg.windex = 0;
- ftdmchan->dtmfdbg.wrapped = 0;
-
- ftdm_mutex_unlock(ftdmchan->dtmfdbg.mutex);
-}
-#endif
-
static ftdm_status_t ftdm_channel_clear_vars(ftdm_channel_t *ftdmchan);
FT_DECLARE(ftdm_status_t) ftdm_channel_done(ftdm_channel_t *ftdmchan)
{
@@ -2400,9 +2533,6 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_done(ftdm_channel_t *ftdmchan)
ftdm_buffer_destroy(&ftdmchan->pre_buffer);
ftdmchan->pre_buffer_size = 0;
ftdm_mutex_unlock(ftdmchan->pre_buffer_mutex);
-#ifdef FTDM_DEBUG_DTMF
- close_dtmf_debug(ftdmchan);
-#endif
ftdm_channel_clear_vars(ftdmchan);
if (ftdmchan->hangup_timer) {
ftdm_sched_cancel_timer(globals.timingsched, ftdmchan->hangup_timer);
@@ -2411,7 +2541,9 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_done(ftdm_channel_t *ftdmchan)
ftdmchan->init_state = FTDM_CHANNEL_STATE_DOWN;
ftdmchan->state = FTDM_CHANNEL_STATE_DOWN;
- ftdm_log(FTDM_LOG_DEBUG, "channel done %u:%u\n", ftdmchan->span_id, ftdmchan->chan_id);
+ ftdm_channel_command(ftdmchan, FTDM_COMMAND_DISABLE_DEBUG_DTMF, NULL);
+ ftdm_channel_command(ftdmchan, FTDM_COMMAND_DISABLE_INPUT_DUMP, NULL);
+ ftdm_channel_command(ftdmchan, FTDM_COMMAND_DISABLE_OUTPUT_DUMP, NULL);
if (FTDM_IS_VOICE_CHANNEL(ftdmchan)) {
ftdm_sigmsg_t sigmsg;
@@ -2423,6 +2555,8 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_done(ftdm_channel_t *ftdmchan)
ftdm_span_send_signal(ftdmchan->span, &sigmsg);
}
+ ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "channel done\n");
+
ftdm_mutex_unlock(ftdmchan->mutex);
return FTDM_SUCCESS;
@@ -2431,7 +2565,7 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_done(ftdm_channel_t *ftdmchan)
FT_DECLARE(ftdm_status_t) ftdm_channel_use(ftdm_channel_t *ftdmchan)
{
- assert(ftdmchan != NULL);
+ ftdm_assert(ftdmchan != NULL, "Null channel\n");
ftdm_set_flag_locked(ftdmchan, FTDM_CHANNEL_INUSE);
@@ -2505,8 +2639,8 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_command(ftdm_channel_t *ftdmchan, ftdm_co
{
ftdm_status_t status = FTDM_FAIL;
- assert(ftdmchan != NULL);
- assert(ftdmchan->fio != NULL);
+ ftdm_assert_return(ftdmchan != NULL, FTDM_FAIL, "No channel\n");
+ ftdm_assert_return(ftdmchan->fio != NULL, FTDM_FAIL, "No IO attached to channel\n");
ftdm_mutex_lock(ftdmchan->mutex);
@@ -2533,7 +2667,7 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_command(ftdm_channel_t *ftdmchan, ftdm_co
break;
case FTDM_COMMAND_TRACE_INPUT:
{
- char *path = (char *) obj;
+ char *path = FTDM_COMMAND_OBJ_CHAR_P;
if (ftdmchan->fds[FTDM_READ_TRACE_INDEX] > 0) {
close(ftdmchan->fds[FTDM_READ_TRACE_INDEX]);
ftdmchan->fds[FTDM_READ_TRACE_INDEX] = -1;
@@ -2576,6 +2710,127 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_command(ftdm_channel_t *ftdmchan, ftdm_co
GOTO_STATUS(done, FTDM_SUCCESS);
}
break;
+
+ /*!< Enable DTMF debugging */
+ case FTDM_COMMAND_ENABLE_DEBUG_DTMF:
+ {
+ if (ftdmchan->dtmfdbg.enabled) {
+ ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "Cannot enable debug DTMF again\n");
+ GOTO_STATUS(done, FTDM_FAIL);
+ }
+ if (ftdmchan->rxdump.buffer) {
+ ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "Cannot debug DTMF if Rx dumping is already enabled\n");
+ GOTO_STATUS(done, FTDM_FAIL);
+ }
+ if (start_chan_io_dump(ftdmchan, &ftdmchan->rxdump, FTDM_IO_DUMP_DEFAULT_BUFF_SIZE) != FTDM_SUCCESS) {
+ ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "Failed to enable rx dump for DTMF debugging\n");
+ GOTO_STATUS(done, FTDM_FAIL);
+ }
+ ftdmchan->dtmfdbg.enabled = 1;
+ ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Enabled DTMF debugging\n");
+ GOTO_STATUS(done, FTDM_SUCCESS);
+ }
+ break;
+
+ /*!< Disable DTMF debugging (if not disabled explicitly, it is disabled automatically when calls hangup) */
+ case FTDM_COMMAND_DISABLE_DEBUG_DTMF:
+ {
+ if (!ftdmchan->dtmfdbg.enabled) {
+ ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "DTMF debug is already disabled\n");
+ GOTO_STATUS(done, FTDM_SUCCESS);
+ }
+ if (disable_dtmf_debug(ftdmchan) != FTDM_SUCCESS) {
+ ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "Failed to disable DTMF debug\n");
+ GOTO_STATUS(done, FTDM_FAIL);
+ }
+ GOTO_STATUS(done, FTDM_SUCCESS);
+ }
+ break;
+
+ /*!< Start dumping all input to a circular buffer. The size of the circular buffer can be specified, default used otherwise */
+ case FTDM_COMMAND_ENABLE_INPUT_DUMP:
+ {
+ ftdm_size_t size = obj ? FTDM_COMMAND_OBJ_SIZE : FTDM_IO_DUMP_DEFAULT_BUFF_SIZE;
+ if (ftdmchan->rxdump.buffer) {
+ ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "Input dump is already enabled\n");
+ GOTO_STATUS(done, FTDM_FAIL);
+ }
+ if (start_chan_io_dump(ftdmchan, &ftdmchan->rxdump, size) != FTDM_SUCCESS) {
+ ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "Failed to enable input dump\n");
+ GOTO_STATUS(done, FTDM_FAIL);
+ }
+ ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Enabled input dump with size %zd\n", size);
+ GOTO_STATUS(done, FTDM_SUCCESS);
+ }
+ break;
+
+ /*!< Stop dumping all input to a circular buffer. */
+ case FTDM_COMMAND_DISABLE_INPUT_DUMP:
+ {
+ if (!ftdmchan->rxdump.buffer) {
+ ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "No need to disable input dump\n");
+ GOTO_STATUS(done, FTDM_SUCCESS);
+ }
+ ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Disabled input dump of size %zd\n", ftdmchan->rxdump.size);
+ stop_chan_io_dump(&ftdmchan->rxdump);
+ GOTO_STATUS(done, FTDM_SUCCESS);
+ }
+ break;
+
+ /*!< Start dumping all output to a circular buffer. The size of the circular buffer can be specified, default used otherwise */
+ case FTDM_COMMAND_ENABLE_OUTPUT_DUMP:
+ {
+ ftdm_size_t size = obj ? FTDM_COMMAND_OBJ_SIZE : FTDM_IO_DUMP_DEFAULT_BUFF_SIZE;
+ if (ftdmchan->txdump.buffer) {
+ ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "Output dump is already enabled\n");
+ GOTO_STATUS(done, FTDM_FAIL);
+ }
+ if (start_chan_io_dump(ftdmchan, &ftdmchan->txdump, size) != FTDM_SUCCESS) {
+ ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "Failed to enable output dump\n");
+ GOTO_STATUS(done, FTDM_FAIL);
+ }
+ ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Enabled output dump with size %zd\n", size);
+ GOTO_STATUS(done, FTDM_SUCCESS);
+ }
+ break;
+
+ /*!< Stop dumping all output to a circular buffer. */
+ case FTDM_COMMAND_DISABLE_OUTPUT_DUMP:
+ {
+ if (!ftdmchan->txdump.buffer) {
+ ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "No need to disable output dump\n");
+ GOTO_STATUS(done, FTDM_SUCCESS);
+ }
+ ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Disabled output dump of size %zd\n", ftdmchan->rxdump.size);
+ stop_chan_io_dump(&ftdmchan->txdump);
+ GOTO_STATUS(done, FTDM_SUCCESS);
+ }
+ break;
+
+ /*!< Dump the current input circular buffer to the specified FILE* structure */
+ case FTDM_COMMAND_DUMP_INPUT:
+ {
+ if (!obj) {
+ GOTO_STATUS(done, FTDM_FAIL);
+ }
+ dump_chan_io_to_file(ftdmchan, &ftdmchan->rxdump, obj);
+ ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Dumped input of size %d to file %p\n", ftdmchan->rxdump.size, obj);
+ GOTO_STATUS(done, FTDM_SUCCESS);
+ }
+ break;
+
+ /*!< Dump the current output circular buffer to the specified FILE* structure */
+ case FTDM_COMMAND_DUMP_OUTPUT:
+ {
+ if (!obj) {
+ GOTO_STATUS(done, FTDM_FAIL);
+ }
+ dump_chan_io_to_file(ftdmchan, &ftdmchan->txdump, obj);
+ ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Dumped input of size %zd to file %p\n", ftdmchan->txdump.size, obj);
+ GOTO_STATUS(done, FTDM_SUCCESS);
+ }
+ break;
+
case FTDM_COMMAND_SET_INTERVAL:
{
if (!ftdm_channel_test_feature(ftdmchan, FTDM_CHANNEL_FEATURE_INTERVAL)) {
@@ -3044,55 +3299,45 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_queue_dtmf(ftdm_channel_t *ftdmchan, cons
ftdm_size_t wr = 0;
const char *p;
- assert(ftdmchan != NULL);
+ ftdm_assert_return(ftdmchan != NULL, FTDM_FAIL, "No channel\n");
- ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Queuing DTMF %s\n", dtmf);
+ ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Queuing DTMF %s (debug = %d)\n", dtmf, ftdmchan->dtmfdbg.enabled);
+
+ if (!ftdmchan->dtmfdbg.enabled) {
+ goto skipdebug;
+ }
-#ifdef FTDM_DEBUG_DTMF
- ftdm_mutex_lock(ftdmchan->dtmfdbg.mutex);
if (!ftdmchan->dtmfdbg.file) {
struct tm currtime;
time_t currsec;
char dfile[512];
currsec = time(NULL);
+
+#ifdef WIN32
+ _tzset();
+ _localtime64_s(&currtime, &currsec);
+#else
localtime_r(&currsec, &currtime);
+#endif
snprintf(dfile, sizeof(dfile), "dtmf-s%dc%d-20%d-%d-%d-%d:%d:%d.%s",
ftdmchan->span_id, ftdmchan->chan_id,
currtime.tm_year-100, currtime.tm_mon+1, currtime.tm_mday,
currtime.tm_hour, currtime.tm_min, currtime.tm_sec, ftdmchan->native_codec == FTDM_CODEC_ULAW ? "ulaw" : ftdmchan->native_codec == FTDM_CODEC_ALAW ? "alaw" : "sln");
- ftdmchan->dtmfdbg.file = fopen(dfile, "w");
+ ftdmchan->dtmfdbg.file = fopen(dfile, "w");
if (!ftdmchan->dtmfdbg.file) {
ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "failed to open debug dtmf file %s\n", dfile);
} else {
- /* write the saved audio buffer */
- int rc = 0;
- int towrite = sizeof(ftdmchan->dtmfdbg.buffer) - ftdmchan->dtmfdbg.windex;
-
- ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "created debug DTMF file %s\n", dfile);
ftdmchan->dtmfdbg.closetimeout = DTMF_DEBUG_TIMEOUT;
- if (ftdmchan->dtmfdbg.wrapped) {
- rc = fwrite(&ftdmchan->dtmfdbg.buffer[ftdmchan->dtmfdbg.windex], 1, towrite, ftdmchan->dtmfdbg.file);
- if (rc != towrite) {
- ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "only wrote %d out of %d bytes in DTMF debug buffer\n", rc, towrite);
- }
- }
- if (ftdmchan->dtmfdbg.windex) {
- towrite = ftdmchan->dtmfdbg.windex;
- rc = fwrite(&ftdmchan->dtmfdbg.buffer[0], 1, towrite, ftdmchan->dtmfdbg.file);
- if (rc != towrite) {
- ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "only wrote %d out of %d bytes in DTMF debug buffer\n", rc, towrite);
- }
- }
- ftdmchan->dtmfdbg.windex = 0;
- ftdmchan->dtmfdbg.wrapped = 0;
+ ftdm_channel_command(ftdmchan, FTDM_COMMAND_DUMP_INPUT, ftdmchan->dtmfdbg.file);
+ ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Dumped initial DTMF output to %s\n", dfile);
}
} else {
- ftdmchan->dtmfdbg.closetimeout = DTMF_DEBUG_TIMEOUT;
+ ftdmchan->dtmfdbg.closetimeout = DTMF_DEBUG_TIMEOUT;
}
- ftdm_mutex_unlock(ftdmchan->dtmfdbg.mutex);
-#endif
+
+skipdebug:
if (ftdmchan->pre_buffer) {
ftdm_buffer_zero(ftdmchan->pre_buffer);
@@ -3137,16 +3382,16 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_queue_dtmf(ftdm_channel_t *ftdmchan, cons
static FIO_WRITE_FUNCTION(ftdm_raw_write)
{
+ int dlen = (int) *datalen;
if (ftdmchan->fds[FTDM_WRITE_TRACE_INDEX] > -1) {
- int dlen = (int) *datalen;
if ((write(ftdmchan->fds[FTDM_WRITE_TRACE_INDEX], data, dlen)) != dlen) {
ftdm_log(FTDM_LOG_WARNING, "Raw output trace failed to write all of the %zd bytes\n", dlen);
}
}
+ write_chan_io_dump(&ftdmchan->txdump, data, dlen);
return ftdmchan->fio->write(ftdmchan, data, datalen);
}
-
static FIO_READ_FUNCTION(ftdm_raw_read)
{
ftdm_status_t status = ftdmchan->fio->read(ftdmchan, data, datalen);
@@ -3161,48 +3406,24 @@ static FIO_READ_FUNCTION(ftdm_raw_read)
ftdmchan->span->sig_read(ftdmchan, data, *datalen);
}
-#ifdef FTDM_DEBUG_DTMF
if (status == FTDM_SUCCESS) {
int dlen = (int) *datalen;
- int rc = 0;
- ftdm_mutex_lock(ftdmchan->dtmfdbg.mutex);
- if (!ftdmchan->dtmfdbg.file) {
- /* no file yet, write to our circular buffer */
- int windex = ftdmchan->dtmfdbg.windex;
- int avail = sizeof(ftdmchan->dtmfdbg.buffer) - windex;
- char *dataptr = data;
+ size_t rc = 0;
- if (dlen > avail) {
- int diff = dlen - avail;
- /* write only what we can and the rest at the beginning of the buffer */
- memcpy(&ftdmchan->dtmfdbg.buffer[windex], dataptr, avail);
- memcpy(&ftdmchan->dtmfdbg.buffer[0], &dataptr[avail], diff);
- windex = diff;
- /*ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "wrapping around dtmf read buffer up to index %d\n\n", windex);*/
- ftdmchan->dtmfdbg.wrapped = 1;
- } else {
- memcpy(&ftdmchan->dtmfdbg.buffer[windex], dataptr, dlen);
- windex += dlen;
- }
- if (windex == sizeof(ftdmchan->dtmfdbg.buffer)) {
- /*ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "wrapping around dtmf read buffer\n");*/
- windex = 0;
- ftdmchan->dtmfdbg.wrapped = 1;
- }
- ftdmchan->dtmfdbg.windex = windex;
- } else {
+ write_chan_io_dump(&ftdmchan->rxdump, data, dlen);
+
+ /* if dtmf debug is enabled and initialized, write there too */
+ if (ftdmchan->dtmfdbg.file) {
rc = fwrite(data, 1, dlen, ftdmchan->dtmfdbg.file);
if (rc != dlen) {
ftdm_log(FTDM_LOG_WARNING, "DTMF debugger wrote only %d out of %d bytes: %s\n", rc, datalen, strerror(errno));
}
ftdmchan->dtmfdbg.closetimeout--;
if (!ftdmchan->dtmfdbg.closetimeout) {
- close_dtmf_debug(ftdmchan);
+ close_dtmf_debug_file(ftdmchan);
}
}
- ftdm_mutex_unlock(ftdmchan->dtmfdbg.mutex);
}
-#endif
return status;
}
@@ -3998,6 +4219,7 @@ static ftdm_status_t ftdm_set_channels_alarms(ftdm_span_t *span, int currindex)
FT_DECLARE(ftdm_status_t) ftdm_configure_span_channels(ftdm_span_t *span, const char* str, ftdm_channel_config_t *chan_config, unsigned *configured)
{
int currindex;
+ unsigned chan_index = 0;
ftdm_assert_return(span != NULL, FTDM_EINVAL, "span is null\n");
ftdm_assert_return(chan_config != NULL, FTDM_EINVAL, "config is null\n");
@@ -4031,6 +4253,14 @@ FT_DECLARE(ftdm_status_t) ftdm_configure_span_channels(ftdm_span_t *span, const
return FTDM_FAIL;
}
+ if (chan_config->debugdtmf) {
+ for (chan_index = currindex+1; chan_index <= span->chan_count; chan_index++) {
+ if (!FTDM_IS_VOICE_CHANNEL(span->channels[chan_index])) {
+ continue;
+ }
+ span->channels[chan_index]->dtmfdbg.requested = 1;
+ }
+ }
return FTDM_SUCCESS;
}
@@ -4049,7 +4279,7 @@ static ftdm_status_t load_config(void)
ftdm_channel_config_t chan_config;
memset(&chan_config, 0, sizeof(chan_config));
- sprintf(chan_config.group_name,"default");
+ sprintf(chan_config.group_name, "__default");
if (!ftdm_config_open_file(&cfg, cfg_name)) {
return FTDM_FAIL;
@@ -4086,6 +4316,9 @@ static ftdm_status_t load_config(void)
if (ftdm_span_create(type, name, &span) == FTDM_SUCCESS) {
ftdm_log(FTDM_LOG_DEBUG, "created span %d (%s) of type %s\n", span->span_id, span->name, type);
d = 0;
+ /* it is confusing that parameters from one span affect others, so let's clear them */
+ memset(&chan_config, 0, sizeof(chan_config));
+ sprintf(chan_config.group_name, "__default");
} else {
ftdm_log(FTDM_LOG_CRIT, "failure creating span of type %s\n", type);
span = NULL;
@@ -4209,6 +4442,9 @@ static ftdm_status_t load_config(void)
if (sscanf(val, "%f", &(chan_config.rxgain)) != 1) {
ftdm_log(FTDM_LOG_ERROR, "invalid rxgain: '%s'\n", val);
}
+ } else if (!strcasecmp(var, "debugdtmf")) {
+ chan_config.debugdtmf = ftdm_true(val);
+ ftdm_log(FTDM_LOG_DEBUG, "Setting debugdtmf to '%s'\n", chan_config.debugdtmf ? "yes" : "no");
} else if (!strcasecmp(var, "group")) {
len = strlen(val);
if (len >= FTDM_MAX_NAME_STR_SZ) {
@@ -4860,6 +5096,9 @@ FT_DECLARE(ftdm_status_t) ftdm_span_send_signal(ftdm_span_t *span, ftdm_sigmsg_t
case FTDM_SIGEVENT_START:
{
ftdm_set_echocancel_call_begin(sigmsg->channel);
+ if (sigmsg->channel->dtmfdbg.requested) {
+ ftdm_channel_command(sigmsg->channel, FTDM_COMMAND_ENABLE_DEBUG_DTMF, NULL);
+ }
/* when cleaning up the public API I added this because mod_freetdm.c on_fxs_signal was
* doing it during SIGEVENT_START, but now that flags are private they can't, wonder if
diff --git a/libs/freetdm/src/ftmod/ftmod_analog/ftmod_analog.2008.vcproj b/libs/freetdm/src/ftmod/ftmod_analog/ftmod_analog.2008.vcproj
index 448f03a545..09349fc05f 100644
--- a/libs/freetdm/src/ftmod/ftmod_analog/ftmod_analog.2008.vcproj
+++ b/libs/freetdm/src/ftmod/ftmod_analog/ftmod_analog.2008.vcproj
@@ -1,353 +1,353 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/libs/freetdm/src/ftmod/ftmod_analog/ftmod_analog.2010.vcxproj b/libs/freetdm/src/ftmod/ftmod_analog/ftmod_analog.2010.vcxproj
index 81cb93fa44..301d821af6 100644
--- a/libs/freetdm/src/ftmod/ftmod_analog/ftmod_analog.2010.vcxproj
+++ b/libs/freetdm/src/ftmod/ftmod_analog/ftmod_analog.2010.vcxproj
@@ -168,7 +168,7 @@
Level4
- true
+ false
ProgramDatabase
4100;%(DisableSpecificWarnings)
diff --git a/libs/freetdm/src/ftmod/ftmod_analog/ftmod_analog.c b/libs/freetdm/src/ftmod/ftmod_analog/ftmod_analog.c
index 99d256655a..95002e3e70 100644
--- a/libs/freetdm/src/ftmod/ftmod_analog/ftmod_analog.c
+++ b/libs/freetdm/src/ftmod/ftmod_analog/ftmod_analog.c
@@ -341,8 +341,8 @@ static void send_caller_id(ftdm_channel_t *ftdmchan)
static void analog_dial(ftdm_channel_t *ftdmchan, uint32_t *state_counter, uint32_t *dial_timeout)
{
if (ftdm_strlen_zero(ftdmchan->caller_data.dnis.digits)) {
- ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "No Digits to send!\n");
- ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_BUSY);
+ ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "No digits to send, moving to UP!\n");
+ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_UP);
} else {
if (ftdm_channel_command(ftdmchan, FTDM_COMMAND_SEND_DTMF, ftdmchan->caller_data.dnis.digits) != FTDM_SUCCESS) {
ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Send Digits Failed [%s]\n", ftdmchan->last_error);
diff --git a/libs/freetdm/src/ftmod/ftmod_analog_em/ftmod_analog_em.2008.vcproj b/libs/freetdm/src/ftmod/ftmod_analog_em/ftmod_analog_em.2008.vcproj
index 8ad183797a..837ba7de0f 100644
--- a/libs/freetdm/src/ftmod/ftmod_analog_em/ftmod_analog_em.2008.vcproj
+++ b/libs/freetdm/src/ftmod/ftmod_analog_em/ftmod_analog_em.2008.vcproj
@@ -1,353 +1,353 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/libs/freetdm/src/ftmod/ftmod_analog_em/ftmod_analog_em.2010.vcxproj b/libs/freetdm/src/ftmod/ftmod_analog_em/ftmod_analog_em.2010.vcxproj
index 44792df89f..3643e271ef 100644
--- a/libs/freetdm/src/ftmod/ftmod_analog_em/ftmod_analog_em.2010.vcxproj
+++ b/libs/freetdm/src/ftmod/ftmod_analog_em/ftmod_analog_em.2010.vcxproj
@@ -168,7 +168,7 @@
Level4
- true
+ false
ProgramDatabase
4100;%(DisableSpecificWarnings)
diff --git a/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.2010.vcxproj b/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.2010.vcxproj
index f66f5afc0d..9b893b3527 100644
--- a/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.2010.vcxproj
+++ b/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.2010.vcxproj
@@ -5,10 +5,18 @@
Debug
Win32
+
+ Debug
+ x64
+
Release
Win32
+
+ Release
+ x64
+
ftmod_r2
@@ -19,33 +27,53 @@
DynamicLibrary
+
+ DynamicLibrary
+
DynamicLibrary
+
+ DynamicLibrary
+
+
+
+
+
+
+
<_ProjectFileVersion>10.0.30319.1
- $(SolutionDir)$(Configuration)\
- $(Configuration)\
true
- $(SolutionDir)$(Configuration)\
- $(Configuration)\
+ true
true
+ true
AllRules.ruleset
+ AllRules.ruleset
+
+
AllRules.ruleset
+ AllRules.ruleset
+
+
+ $(SolutionDir)$(Platform)\$(Configuration)\
+ $(Platform)\$(Configuration)\
+ $(Platform)\$(Configuration)\
+ $(SolutionDir)$(Platform)\$(Configuration)\
@@ -68,6 +96,25 @@
MachineX86
+
+
+ Disabled
+ ..\..\include;c:\Program Files\openr2\include\openr2;C:\Program Files\openr2\include;%(AdditionalIncludeDirectories)
+ WIN32;_DEBUG;_WINDOWS;_USRDLL;FTMOD_R2_EXPORTS;%(PreprocessorDefinitions)
+ EnableFastChecks
+ MultiThreadedDebugDLL
+
+
+ Level3
+ ProgramDatabase
+
+
+ freetdm.lib;openr2.lib;%(AdditionalDependencies)
+ C:\Program Files\openr2\lib;$(OutDir);%(AdditionalLibraryDirectories)
+ true
+ Windows
+
+
..\..\include;C:\Program Files\openr2\include;%(AdditionalIncludeDirectories)
@@ -86,6 +133,23 @@
MachineX86
+
+
+ ..\..\include;C:\Program Files\openr2\include;%(AdditionalIncludeDirectories)
+ WIN32;NDEBUG;_WINDOWS;_USRDLL;FTMOD_R2_EXPORTS;%(PreprocessorDefinitions)
+ MultiThreadedDLL
+
+
+ Level3
+ ProgramDatabase
+
+
+ true
+ Windows
+ true
+ true
+
+
diff --git a/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c b/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c
index 30de78857a..0348c8b57e 100644
--- a/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c
+++ b/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c
@@ -56,24 +56,19 @@ typedef enum {
FTDM_R2_RUNNING = (1 << 0),
} ftdm_r2_flag_t;
-typedef enum {
- FTDM_R2_PROCESSING = (1 << 0),
- FTDM_R2_WAITING_ACK = (1 << 1),
-} ftdm_r2_call_flag_t;
-
/* private call information stored in ftdmchan->call_data void* ptr */
#define R2CALL(ftdmchan) ((ftdm_r2_call_t*)((ftdmchan)->call_data))
typedef struct ftdm_r2_call_t {
openr2_chan_t *r2chan;
- ftdm_r2_call_flag_t flags;
int accepted:1;
int answer_pending:1;
- int state_ack_pending:1;
int disconnect_rcvd:1;
- int ftdm_started:1;
+ int ftdm_call_started:1;
+ int protocol_error:1;
ftdm_channel_state_t chanstate;
ftdm_size_t dnis_index;
ftdm_size_t ani_index;
+ char logname[255];
char name[10];
unsigned long txdrops;
} ftdm_r2_call_t;
@@ -94,13 +89,13 @@ typedef struct ft_r2_conf_s {
int32_t max_dnis;
int32_t mfback_timeout;
int32_t metering_pulse_timeout;
+ int32_t mf_dump_size;
/* booleans */
int immediate_accept;
int skip_category;
int get_ani_first;
int call_files;
- int mf_files;
int double_answer;
int charge_calls;
int forced_release;
@@ -123,12 +118,18 @@ typedef struct ftdm_r2_data_s {
int forced_release:1;
/* whether accept the call when offered, or wait until the user decides to accept */
int accept_on_offer:1;
+ /* Size of multi-frequency (or any media) dumps used during protocol errors */
+ int32_t mf_dump_size;
/* max time spent in ms doing real work in a single loop */
- int jobmax;
- /* total working loops */
- unsigned long loops;
+ int32_t jobmax;
+ /* Total number of loops performed so far */
+ uint64_t total_loops;
+ /* number of loops per 10ms increment from 0-9ms, 10-19ms .. 100ms and above */
+ uint64_t loops[11];
/* LWP */
- unsigned long monitor_thread_id;
+ uint32_t monitor_thread_id;
+ /* Logging directory */
+ char logdir[512];
} ftdm_r2_data_t;
/* one element per span will be stored in g_mod_data_hash global var to keep track of them
@@ -151,7 +152,14 @@ static ftdm_hash_t *g_mod_data_hash;
static ftdm_io_interface_t g_ftdm_r2_interface;
static int ftdm_r2_state_advance(ftdm_channel_t *ftdmchan);
+static void ftdm_r2_state_advance_all(ftdm_channel_t *ftdmchan);
+/* whether R2 call accept process is pending */
+#define IS_ACCEPTING_PENDING(ftdmchan) \
+ ( (!ftdm_test_flag((ftdmchan), FTDM_CHANNEL_OUTBOUND)) && !R2CALL((ftdmchan))->accepted && \
+ ((ftdmchan)->state == FTDM_CHANNEL_STATE_PROGRESS || \
+ (ftdmchan)->state == FTDM_CHANNEL_STATE_PROGRESS_MEDIA || \
+ (ftdmchan)->state == FTDM_CHANNEL_STATE_UP) )
/* functions not available on windows */
#ifdef WIN32
@@ -313,9 +321,9 @@ static openr2_call_disconnect_cause_t ftdm_r2_ftdm_cause_to_openr2_cause(ftdm_ch
static void ft_r2_clean_call(ftdm_r2_call_t *call)
{
- openr2_chan_t *r2chan = call->r2chan;
- memset(call, 0, sizeof(*call));
- call->r2chan = r2chan;
+ openr2_chan_t *r2chan = call->r2chan;
+ memset(call, 0, sizeof(*call));
+ call->r2chan = r2chan;
}
static void ft_r2_accept_call(ftdm_channel_t *ftdmchan)
@@ -355,30 +363,26 @@ static FIO_CHANNEL_OUTGOING_CALL_FUNCTION(r2_outgoing_call)
}
ft_r2_clean_call(ftdmchan->call_data);
- R2CALL(ftdmchan)->ftdm_started = 1;
+ R2CALL(ftdmchan)->ftdm_call_started = 1;
R2CALL(ftdmchan)->chanstate = FTDM_CHANNEL_STATE_DOWN;
- ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DIALING);
+ ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DIALING);
callstatus = openr2_chan_make_call(R2CALL(ftdmchan)->r2chan,
ftdmchan->caller_data.cid_num.digits,
ftdmchan->caller_data.dnis.digits,
OR2_CALLING_PARTY_CATEGORY_NATIONAL_SUBSCRIBER);
- if (callstatus) {
- ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT, "Failed to make call in R2 channel, openr2_chan_make_call failed\n");
- return FTDM_FAIL;
- }
+ if (callstatus) {
+ ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT, "Failed to make call in R2 channel, openr2_chan_make_call failed\n");
+ return FTDM_FAIL;
+ }
if (ftdmchan->state != FTDM_CHANNEL_STATE_DIALING) {
ftdm_log_chan(ftdmchan, FTDM_LOG_WARNING, "Collision after call attempt, try another channel, new state = %s\n",
ftdm_channel_state2str(ftdmchan->state));
- ftdm_clear_flag(R2CALL(ftdmchan), FTDM_R2_WAITING_ACK);
return FTDM_BREAK;
}
-
- /* non-threaded implementation, we're done here */
- ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "R2 call placed in non-threaded mode\n");
- return FTDM_SUCCESS;
+ return FTDM_SUCCESS;
}
static ftdm_status_t ftdm_r2_start(ftdm_span_t *span)
@@ -398,44 +402,38 @@ static ftdm_status_t ftdm_r2_stop(ftdm_span_t *span)
return FTDM_SUCCESS;
}
-static ftdm_status_t ftdm_r2_sig_read(ftdm_channel_t *ftdmchan, void *data, ftdm_size_t size)
+static FIO_CHANNEL_GET_SIG_STATUS_FUNCTION(ftdm_r2_get_channel_sig_status)
{
- openr2_chan_t *r2chan = R2CALL(ftdmchan)->r2chan;
- if (!openr2_chan_get_read_enabled(r2chan)) {
- ftdm_mutex_lock(ftdmchan->mutex);
- //openr2_chan_process_input(r2chan, data, size);
- ftdm_mutex_unlock(ftdmchan->mutex);
+ if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_SIG_UP)) {
+ *status = FTDM_SIG_STATE_UP;
+ } else {
+ *status = FTDM_SIG_STATE_DOWN;
}
+
return FTDM_SUCCESS;
}
/* always called from the monitor thread */
-static void ftdm_r2_on_call_init(openr2_chan_t *r2chan)
+static void ftdm_r2_on_call_init(openr2_chan_t *r2chan, const char *logname)
{
- //ftdm_status_t status;
ftdm_r2_call_t *r2call;
ftdm_channel_t *ftdmchan = openr2_chan_get_client_data(r2chan);
- //ftdm_r2_data_t *r2data = ftdmchan->span->signal_data;
+ ftdm_r2_data_t *r2data = ftdmchan->span->signal_data;
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_NOTICE, "Received request to start call\n");
- ftdm_mutex_lock(ftdmchan->mutex);
-
if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_INUSE)) {
ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "Cannot start call when channel is in use (state = %s)\n", ftdm_channel_state2str(ftdmchan->state));
- ftdm_mutex_unlock(ftdmchan->mutex);
return;
}
if (ftdmchan->state != FTDM_CHANNEL_STATE_DOWN) {
ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Cannot handle request to start call in state %s\n", ftdm_channel_state2str(ftdmchan->state));
- ftdm_mutex_unlock(ftdmchan->mutex);
return;
}
if (ftdm_channel_open_chan(ftdmchan) != FTDM_SUCCESS) {
ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Failed to open channel during incoming call! [%s]\n", ftdmchan->last_error);
- ftdm_mutex_unlock(ftdmchan->mutex);
return;
}
@@ -448,43 +446,107 @@ static void ftdm_r2_on_call_init(openr2_chan_t *r2chan)
/* clean the call data structure but keep the R2 processing flag on! */
ft_r2_clean_call(ftdmchan->call_data);
r2call = R2CALL(ftdmchan);
- ftdm_set_flag(r2call, FTDM_R2_PROCESSING);
- if (ftdmchan->state == FTDM_CHANNEL_STATE_DOWN) {
- R2CALL(ftdmchan)->chanstate = FTDM_CHANNEL_STATE_DOWN;
- } else {
- R2CALL(ftdmchan)->chanstate = FTDM_CHANNEL_STATE_DIALING;
+ snprintf(r2call->logname, sizeof(r2call->logname), "%s", logname);
+
+ /* start io dump */
+ if (r2data->mf_dump_size) {
+ ftdm_channel_command(ftdmchan, FTDM_COMMAND_ENABLE_INPUT_DUMP, &r2data->mf_dump_size);
+ ftdm_channel_command(ftdmchan, FTDM_COMMAND_ENABLE_OUTPUT_DUMP, &r2data->mf_dump_size);
}
+ R2CALL(ftdmchan)->chanstate = FTDM_CHANNEL_STATE_DOWN;
ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_COLLECT);
- ftdm_mutex_unlock(ftdmchan->mutex);
}
/* only called for incoming calls when the ANI, DNIS etc is complete and the user has to decide either to accept or reject the call */
static void ftdm_r2_on_call_offered(openr2_chan_t *r2chan, const char *ani, const char *dnis, openr2_calling_party_category_t category)
{
ftdm_channel_t *ftdmchan = openr2_chan_get_client_data(r2chan);
+ ftdm_r2_data_t *r2data = ftdmchan->span->signal_data;
- ftdm_log_chan(ftdmchan, FTDM_LOG_NOTICE, "Call offered with ANI = %s, DNIS = %s, Priority = (%d)\n", ani, dnis, category);
- ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_RING);
+ ftdm_log_chan(ftdmchan, FTDM_LOG_NOTICE, "Call offered with ANI = %s, DNIS = %s, Category = (%d)\n", ani, dnis, category);
+ ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_RING);
+
+ /* nothing went wrong during call setup, MF has ended, we can and must disable the MF dump */
+ if (r2data->mf_dump_size) {
+ ftdm_channel_command(ftdmchan, FTDM_COMMAND_DISABLE_INPUT_DUMP, NULL);
+ ftdm_channel_command(ftdmchan, FTDM_COMMAND_DISABLE_OUTPUT_DUMP, NULL);
+ }
+}
+
+/*
+ * Accepting a call in R2 is a lengthy process due to MF tones,
+ * when the user sends PROGRESS indication (implicitly moving the
+ * ftdm channel to PROGRESS state) the R2 processing loop
+ * does not clear FTDM_CHANNEL_STATE_CHANGE immediately as it does
+ * for all the other states, instead has to wait for on_call_accepted
+ * callback from openr2, which means the MF has ended and the progress
+ * indication is done, in order to clear the flag. However, if
+ * a protocol error or call disconnection (which is indicated using CAS bits)
+ * occurrs while accepting, we must clear the pending flag, this function
+ * takes care of that
+ * */
+static void clear_accept_pending(ftdm_channel_t *fchan)
+{
+ if (IS_ACCEPTING_PENDING(fchan)) {
+ ftdm_clear_flag(fchan, FTDM_CHANNEL_STATE_CHANGE);
+ ftdm_channel_complete_state(fchan);
+ } else if (ftdm_test_flag(fchan, FTDM_CHANNEL_STATE_CHANGE)) {
+ ftdm_log_chan(fchan, FTDM_LOG_CRIT, "State change flag set in state %s, last state = %s\n",
+ ftdm_channel_state2str(fchan->state), ftdm_channel_state2str(fchan->last_state));
+ ftdm_clear_flag(fchan, FTDM_CHANNEL_STATE_CHANGE);
+ ftdm_channel_complete_state(fchan);
+ }
+}
+
+static void dump_mf(openr2_chan_t *r2chan)
+{
+ char dfile[512];
+ FILE *f = NULL;
+ ftdm_channel_t *ftdmchan = openr2_chan_get_client_data(r2chan);
+ ftdm_r2_data_t *r2data = ftdmchan->span->signal_data;
+ if (r2data->mf_dump_size) {
+ char *logname = R2CALL(ftdmchan)->logname;
+
+ ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Dumping IO output in prefix %s\n", logname);
+ snprintf(dfile, sizeof(dfile), logname ? "%s.s%dc%d.input.alaw" : "%s/s%dc%d.input.alaw",
+ logname ? logname : r2data->logdir, ftdmchan->span_id, ftdmchan->chan_id);
+ f = fopen(dfile, "w");
+ ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Dumping IO input in file %s\n", dfile);
+ ftdm_channel_command(ftdmchan, FTDM_COMMAND_DUMP_INPUT, f);
+ fclose(f);
+
+ snprintf(dfile, sizeof(dfile), logname ? "%s.s%dc%d.output.alaw" : "%s/s%dc%d.output.alaw",
+ logname ? logname : r2data->logdir, ftdmchan->span_id, ftdmchan->chan_id);
+ f = fopen(dfile, "w");
+ ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Dumping IO output in file %s\n", dfile);
+ ftdm_channel_command(ftdmchan, FTDM_COMMAND_DUMP_OUTPUT, f);
+ fclose(f);
+ }
}
static void ftdm_r2_on_call_accepted(openr2_chan_t *r2chan, openr2_call_mode_t mode)
{
ftdm_channel_t *ftdmchan = openr2_chan_get_client_data(r2chan);
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_NOTICE, "Call accepted\n");
+
+ clear_accept_pending(ftdmchan);
+
/* at this point the MF signaling has ended and there is no point on keep reading */
openr2_chan_disable_read(r2chan);
+
R2CALL(ftdmchan)->accepted = 1;
+
if (OR2_DIR_BACKWARD == openr2_chan_get_direction(r2chan)) {
- R2CALL(ftdmchan)->state_ack_pending = 1;
if (R2CALL(ftdmchan)->answer_pending) {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Answer was pending, answering now.\n");
ft_r2_answer_call(ftdmchan);
+ R2CALL(ftdmchan)->answer_pending = 0;
return;
}
} else {
- ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_PROGRESS_MEDIA);
+ ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_PROGRESS_MEDIA);
}
}
@@ -494,47 +556,30 @@ static void ftdm_r2_on_call_answered(openr2_chan_t *r2chan)
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_NOTICE, "Call answered\n");
/* notify the upper layer of progress in the outbound call */
if (OR2_DIR_FORWARD == openr2_chan_get_direction(r2chan)) {
- ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_UP);
+ ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_UP);
}
}
/* may be called in the signaling or media thread depending on whether the hangup is product of MF or CAS signaling */
static void ftdm_r2_on_call_disconnect(openr2_chan_t *r2chan, openr2_call_disconnect_cause_t cause)
{
- ftdm_sigmsg_t sigev;
- ftdm_r2_data_t *r2data;
ftdm_channel_t *ftdmchan = openr2_chan_get_client_data(r2chan);
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_NOTICE, "Call disconnected\n");
- ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Got openr2 disconnection, clearing call\n");
+ clear_accept_pending(ftdmchan);
R2CALL(ftdmchan)->disconnect_rcvd = 1;
if (ftdmchan->state == FTDM_CHANNEL_STATE_HANGUP) {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Call had been disconnected already by the user\n");
- /* just ack the hangup to go down */
+ /* just ack the hangup to trigger the on_call_end callback and go down */
openr2_chan_disconnect_call(r2chan, OR2_CAUSE_NORMAL_CLEARING);
return;
}
- /* if the call has not been started yet we must go to HANGUP right here */
- if (!R2CALL(ftdmchan)->ftdm_started) {
- ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
- return;
- }
-
ftdmchan->caller_data.hangup_cause = ftdm_r2_cause_to_ftdm_cause(ftdmchan, cause);
-
- /* notify the user of the call terminating */
- memset(&sigev, 0, sizeof(sigev));
- sigev.chan_id = ftdmchan->chan_id;
- sigev.span_id = ftdmchan->span_id;
- sigev.channel = ftdmchan;
- sigev.event_id = FTDM_SIGEVENT_STOP;
- r2data = ftdmchan->span->signal_data;
-
- ftdm_span_send_signal(ftdmchan->span, &sigev);
+ ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING);
}
static void ftdm_r2_on_call_end(openr2_chan_t *r2chan)
@@ -543,10 +588,10 @@ static void ftdm_r2_on_call_end(openr2_chan_t *r2chan)
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_NOTICE, "Call finished\n");
/* the call is done as far as the stack is concerned, lets move to down here */
- ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
+ ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
/* in some circumstances openr2 can call on_call_init right after this, so let's advance the state right here */
- ftdm_r2_state_advance(ftdmchan);
+ ftdm_r2_state_advance_all(ftdmchan);
}
static void ftdm_r2_on_call_read(openr2_chan_t *r2chan, const unsigned char *buf, int buflen)
@@ -570,40 +615,28 @@ static void ftdm_r2_on_os_error(openr2_chan_t *r2chan, int errorcode)
static void ftdm_r2_on_protocol_error(openr2_chan_t *r2chan, openr2_protocol_error_t reason)
{
- ftdm_sigmsg_t sigev;
- ftdm_r2_data_t *r2data;
ftdm_channel_t *ftdmchan = openr2_chan_get_client_data(r2chan);
- ftdm_mutex_lock(ftdmchan->mutex);
-
if (ftdmchan->state == FTDM_CHANNEL_STATE_DOWN) {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "Got protocol error when we're already down!\n");
- ftdm_mutex_unlock(ftdmchan->mutex);
+ return;
}
- ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "Protocol error\n");
+ dump_mf(r2chan);
+
+ clear_accept_pending(ftdmchan);
R2CALL(ftdmchan)->disconnect_rcvd = 1;
+ R2CALL(ftdmchan)->protocol_error = 1;
- if (!R2CALL(ftdmchan)->ftdm_started) {
- ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
- ftdm_mutex_unlock(ftdmchan->mutex);
+ if (ftdmchan->state == FTDM_CHANNEL_STATE_HANGUP) {
+ ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "The user already hung up, finishing call in protocol error\n");
+ ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
return;
}
ftdmchan->caller_data.hangup_cause = FTDM_CAUSE_PROTOCOL_ERROR;
-
- /* FIXME: go to terminating and notify the user from the terminating handler instead of notifying here */
- memset(&sigev, 0, sizeof(sigev));
- sigev.chan_id = ftdmchan->chan_id;
- sigev.span_id = ftdmchan->span_id;
- sigev.channel = ftdmchan;
- sigev.event_id = FTDM_SIGEVENT_STOP;
- r2data = ftdmchan->span->signal_data;
-
- ftdm_span_send_signal(ftdmchan->span, &sigev);
-
- ftdm_mutex_unlock(ftdmchan->mutex);
+ ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING);
}
static void ftdm_r2_on_line_blocked(openr2_chan_t *r2chan)
@@ -662,14 +695,13 @@ static void ftdm_r2_on_chan_log(openr2_chan_t *r2chan, const char *file, const c
openr2_log_level_t level, const char *fmt, va_list ap)
{
ftdm_channel_t *ftdmchan = openr2_chan_get_client_data(r2chan);
-#define CHAN_TAG "Chan "
- char logmsg[512];
- char completemsg[sizeof(logmsg) + sizeof(CHAN_TAG) - 1];
+ char logmsg[1024];
+ char completemsg[sizeof(logmsg)];
vsnprintf(logmsg, sizeof(logmsg), fmt, ap);
- snprintf(completemsg, sizeof(completemsg), CHAN_TAG "%d:%d [%s] %s",
- ftdmchan->span_id, ftdmchan->chan_id, ftdm_channel_state2str(ftdmchan->state), logmsg);
+ snprintf(completemsg, sizeof(completemsg), "[s%dc%d] [%d:%d] [%s] %s",
+ ftdmchan->span_id, ftdmchan->chan_id, ftdmchan->physical_span_id, ftdmchan->physical_chan_id,
+ ftdm_channel_state2str(ftdmchan->state), logmsg);
ftdm_r2_write_log(level, file, function, line, completemsg);
-#undef CHAN_TAG
}
static int ftdm_r2_on_dnis_digit_received(openr2_chan_t *r2chan, char digit)
@@ -808,7 +840,7 @@ static int ftdm_r2_io_wait(openr2_chan_t *r2chan, int *flags, int block)
int32_t timeout;
ftdm_wait_flag_t ftdmflags = 0;
- ftdm_channel_t *ftdm_chan = openr2_chan_get_fd(r2chan);
+ ftdm_channel_t *fchan = openr2_chan_get_fd(r2chan);
timeout = block ? -1 : 0;
if (*flags & OR2_IO_READ) {
@@ -821,9 +853,10 @@ static int ftdm_r2_io_wait(openr2_chan_t *r2chan, int *flags, int block)
ftdmflags |= FTDM_EVENTS;
}
- status = ftdm_channel_wait(ftdm_chan, &ftdmflags, timeout);
+ status = ftdm_channel_wait(fchan, &ftdmflags, timeout);
if (FTDM_SUCCESS != status && FTDM_TIMEOUT != status) {
+ ftdm_log_chan_msg(fchan, FTDM_LOG_ERROR, "Failed to wait for events on channel\n");
return -1;
}
@@ -867,9 +900,36 @@ static int ftdm_r2_io_setup(openr2_chan_t *r2chan)
static int ftdm_r2_io_get_oob_event(openr2_chan_t *r2chan, openr2_oob_event_t *event)
{
- *event = 0;
- ftdm_log(FTDM_LOG_ERROR, "I should not be called (I/O get oob event)!!\n");
- return 0;
+ ftdm_status_t status;
+ ftdm_event_t *fevent = NULL;
+ ftdm_channel_t *ftdmchan = openr2_chan_get_fd(r2chan);
+
+ *event = OR2_OOB_EVENT_NONE;
+ status = ftdm_channel_read_event(ftdmchan, &fevent);
+ if (status != FTDM_SUCCESS) {
+ ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "failed to retrieve freetdm event!\n");
+ return -1;
+ }
+ if (fevent->e_type != FTDM_EVENT_OOB)
+ return 0;
+ switch (fevent->enum_id) {
+ case FTDM_OOB_CAS_BITS_CHANGE:
+ {
+ *event = OR2_OOB_EVENT_CAS_CHANGE;
+ }
+ break;
+ case FTDM_OOB_ALARM_TRAP:
+ {
+ *event = OR2_OOB_EVENT_ALARM_ON;
+ }
+ break;
+ case FTDM_OOB_ALARM_CLEAR:
+ {
+ *event = OR2_OOB_EVENT_ALARM_OFF;
+ }
+ break;
+ }
+ return 0;
}
static openr2_io_interface_t ftdm_r2_io_iface = {
@@ -885,54 +945,180 @@ static openr2_io_interface_t ftdm_r2_io_iface = {
/* .get_oob_event */ ftdm_r2_io_get_oob_event /* never called */
};
-static FIO_SIG_CONFIGURE_FUNCTION(ftdm_r2_configure_span)
- //ftdm_status_t (ftdm_span_t *span, fio_signal_cb_t sig_cb, va_list ap)
+/* resolve a loglevel string, such as "debug,notice,warning", to an openr2 log level integer */
+static openr2_log_level_t ftdm_r2_loglevel_from_string(const char *level)
{
- int i = 0;
+ openr2_log_level_t tmplevel;
+ openr2_log_level_t newlevel = 0;
+ char *clevel = NULL;
+ char *logval = NULL;
+
+ logval = ftdm_malloc(strlen(level)+1); /* alloca man page scared me, so better to use good ol' malloc */
+ if (!logval) {
+ ftdm_log(FTDM_LOG_WARNING, "Ignoring R2 logging parameter: '%s', failed to alloc memory\n", level);
+ return newlevel;
+ }
+ strcpy(logval, level);
+ while (logval) {
+ clevel = strsep(&logval, ",");
+ if (-1 == (tmplevel = openr2_log_get_level(clevel))) {
+ ftdm_log(FTDM_LOG_WARNING, "Ignoring invalid R2 logging level: '%s'\n", clevel);
+ continue;
+ }
+ newlevel |= tmplevel;
+ }
+ ftdm_safe_free(logval);
+ return newlevel;
+}
+
+static ftdm_state_map_t r2_state_map = {
+ {
+ {
+ ZSD_INBOUND,
+ ZSM_UNACCEPTABLE,
+ {FTDM_CHANNEL_STATE_DOWN, FTDM_END},
+ {FTDM_CHANNEL_STATE_COLLECT, FTDM_END}
+ },
+ {
+ ZSD_INBOUND,
+ ZSM_UNACCEPTABLE,
+ {FTDM_CHANNEL_STATE_COLLECT, FTDM_END},
+ {FTDM_CHANNEL_STATE_RING, FTDM_CHANNEL_STATE_TERMINATING, FTDM_END}
+ },
+ {
+ ZSD_INBOUND,
+ ZSM_UNACCEPTABLE,
+ {FTDM_CHANNEL_STATE_RING, FTDM_END},
+ {FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_PROGRESS, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_CHANNEL_STATE_UP, FTDM_END}
+ },
+ {
+ ZSD_INBOUND,
+ ZSM_UNACCEPTABLE,
+ {FTDM_CHANNEL_STATE_HANGUP, FTDM_END},
+ {FTDM_CHANNEL_STATE_DOWN, FTDM_END},
+ },
+ {
+ ZSD_INBOUND,
+ ZSM_UNACCEPTABLE,
+ {FTDM_CHANNEL_STATE_TERMINATING, FTDM_END},
+ {FTDM_CHANNEL_STATE_HANGUP, FTDM_END},
+ },
+ {
+ ZSD_INBOUND,
+ ZSM_UNACCEPTABLE,
+ {FTDM_CHANNEL_STATE_PROGRESS, FTDM_END},
+ {FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_CHANNEL_STATE_UP, FTDM_END},
+ },
+ {
+ ZSD_INBOUND,
+ ZSM_UNACCEPTABLE,
+ {FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_END},
+ {FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_UP, FTDM_END},
+ },
+ {
+ ZSD_INBOUND,
+ ZSM_UNACCEPTABLE,
+ {FTDM_CHANNEL_STATE_UP, FTDM_END},
+ {FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_END},
+ },
+
+ /* Outbound states */
+
+ {
+ ZSD_OUTBOUND,
+ ZSM_UNACCEPTABLE,
+ {FTDM_CHANNEL_STATE_DOWN, FTDM_END},
+ {FTDM_CHANNEL_STATE_DIALING, FTDM_END}
+ },
+
+ {
+ ZSD_OUTBOUND,
+ ZSM_UNACCEPTABLE,
+ {FTDM_CHANNEL_STATE_DIALING, FTDM_END},
+ {FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_END}
+ },
+
+ {
+ ZSD_OUTBOUND,
+ ZSM_UNACCEPTABLE,
+ {FTDM_CHANNEL_STATE_HANGUP, FTDM_END},
+ {FTDM_CHANNEL_STATE_DOWN, FTDM_END}
+ },
+
+ {
+ ZSD_OUTBOUND,
+ ZSM_UNACCEPTABLE,
+ {FTDM_CHANNEL_STATE_TERMINATING, FTDM_END},
+ {FTDM_CHANNEL_STATE_HANGUP, FTDM_END}
+ },
+
+ {
+ ZSD_OUTBOUND,
+ ZSM_UNACCEPTABLE,
+ {FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_END},
+ {FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_UP, FTDM_END}
+ },
+
+ {
+ ZSD_OUTBOUND,
+ ZSM_UNACCEPTABLE,
+ {FTDM_CHANNEL_STATE_UP, FTDM_END},
+ {FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_END}
+ },
+ }
+};
+
+static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_r2_configure_span_signaling)
+{
+ unsigned int i = 0;
int conf_failure = 0;
- char *var = NULL;
- char *val = NULL;
+ const char *var = NULL, *val = NULL;
+ const char *log_level = "notice,warning,error"; /* default loglevel, if none is read from conf */
ftdm_r2_data_t *r2data = NULL;
ftdm_r2_span_pvt_t *spanpvt = NULL;
ftdm_r2_call_t *r2call = NULL;
openr2_chan_t *r2chan = NULL;
- openr2_log_level_t tmplevel;
- char *clevel = NULL;
- char *logval = NULL;
+ unsigned paramindex = 0;
ft_r2_conf_t r2conf =
{
/* .variant */ OR2_VAR_ITU,
/* .category */ OR2_CALLING_PARTY_CATEGORY_NATIONAL_SUBSCRIBER,
/* .loglevel */ OR2_LOG_ERROR | OR2_LOG_WARNING,
- /* .logdir */ NULL,
+#ifdef WIN32
+ /* .logdir */ (char *)"c:\\",
+#else
+ /* .logdir */ (char *)"/tmp",
+#endif
/* .advanced_protocol_file */ NULL,
/* .max_ani */ 10,
/* .max_dnis */ 4,
/* .mfback_timeout */ -1,
/* .metering_pulse_timeout */ -1,
+ /* .mf_dump_size */ 0,
/* .immediate_accept */ -1,
/* .skip_category */ -1,
/* .get_ani_first */ -1,
/* .call_files */ 0,
- /* .mf_files */ 0,
- /* .double_answer */ 0,
+ /* .double_answer */ -1,
/* .charge_calls */ -1,
/* .forced_release */ -1,
/* .allow_collect_calls */ -1
};
- assert(sig_cb != NULL);
+ ftdm_assert_return(sig_cb != NULL, FTDM_FAIL, "No signaling cb provided\n");
if (span->signal_type) {
snprintf(span->last_error, sizeof(span->last_error), "Span is already configured for signalling.");
return FTDM_FAIL;
}
- while ((var = va_arg(ap, char *))) {
+ for (; ftdm_parameters[paramindex].var; paramindex++) {
+ var = ftdm_parameters[paramindex].var;
+ val = ftdm_parameters[paramindex].val;
ftdm_log(FTDM_LOG_DEBUG, "Reading R2 parameter %s for span %d\n", var, span->span_id);
if (!strcasecmp(var, "variant")) {
- if (!(val = va_arg(ap, char *))) {
+ if (!val) {
break;
}
if (ftdm_strlen_zero_buf(val)) {
@@ -947,7 +1133,7 @@ static FIO_SIG_CONFIGURE_FUNCTION(ftdm_r2_configure_span)
}
ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d for variant %s\n", span->span_id, val);
} else if (!strcasecmp(var, "category")) {
- if (!(val = va_arg(ap, char *))) {
+ if (!val) {
break;
}
if (ftdm_strlen_zero_buf(val)) {
@@ -962,88 +1148,79 @@ static FIO_SIG_CONFIGURE_FUNCTION(ftdm_r2_configure_span)
}
ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d with default category %s\n", span->span_id, val);
} else if (!strcasecmp(var, "logdir")) {
- if (!(val = va_arg(ap, char *))) {
+ if (!val) {
break;
}
if (ftdm_strlen_zero_buf(val)) {
ftdm_log(FTDM_LOG_NOTICE, "Ignoring empty R2 logdir parameter\n");
continue;
}
- r2conf.logdir = val;
+ r2conf.logdir = (char *)val;
ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d with logdir %s\n", span->span_id, val);
} else if (!strcasecmp(var, "logging")) {
- if (!(val = va_arg(ap, char *))) {
+ if (!val) {
break;
}
if (ftdm_strlen_zero_buf(val)) {
ftdm_log(FTDM_LOG_NOTICE, "Ignoring empty R2 logging parameter\n");
continue;
}
- logval = ftdm_malloc(strlen(val)+1); /* alloca man page scared me, so better to use good ol' malloc */
- if (!logval) {
- ftdm_log(FTDM_LOG_WARNING, "Ignoring R2 logging parameter: '%s', failed to alloc memory\n", val);
- continue;
- }
- strcpy(logval, val);
- while (logval) {
- clevel = strsep(&logval, ",");
- if (-1 == (tmplevel = openr2_log_get_level(clevel))) {
- ftdm_log(FTDM_LOG_WARNING, "Ignoring invalid R2 logging level: '%s'\n", clevel);
- continue;
- }
- r2conf.loglevel |= tmplevel;
- ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d with loglevel %s\n", span->span_id, clevel);
- }
- ftdm_safe_free(logval);
+ log_level = val;
+ ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %s with loglevel %s\n", span->name, val);
} else if (!strcasecmp(var, "advanced_protocol_file")) {
- if (!(val = va_arg(ap, char *))) {
+ if (!val) {
break;
}
if (ftdm_strlen_zero_buf(val)) {
ftdm_log(FTDM_LOG_NOTICE, "Ignoring empty R2 advanced_protocol_file parameter\n");
continue;
}
- r2conf.advanced_protocol_file = val;
- ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d with advanced protocol file %s\n", span->span_id, val);
+ r2conf.advanced_protocol_file = (char *)val;
+ ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %s with advanced protocol file %s\n", span->name, val);
+ } else if (!strcasecmp(var, "mf_dump_size")) {
+ r2conf.mf_dump_size = atoi(val);
+ if (r2conf.mf_dump_size < 0) {
+ r2conf.mf_dump_size = FTDM_IO_DUMP_DEFAULT_BUFF_SIZE;
+ ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %s with default mf_dump_size = %d bytes\n", span->name, r2conf.mf_dump_size);
+ } else {
+ ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %s with mf_dump_size = %d bytes\n", span->name, r2conf.mf_dump_size);
+ }
} else if (!strcasecmp(var, "allow_collect_calls")) {
- r2conf.allow_collect_calls = va_arg(ap, int);
- ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d with allow collect calls max ani = %d\n", span->span_id, r2conf.allow_collect_calls);
+ r2conf.allow_collect_calls = ftdm_true(val);
+ ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %s with allow collect calls max ani = %d\n", span->name, r2conf.allow_collect_calls);
} else if (!strcasecmp(var, "double_answer")) {
- r2conf.double_answer = va_arg(ap, int);
- ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d with double answer = %d\n", span->span_id, r2conf.double_answer);
+ r2conf.double_answer = ftdm_true(val);
+ ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %s with double answer = %d\n", span->name, r2conf.double_answer);
} else if (!strcasecmp(var, "immediate_accept")) {
- r2conf.immediate_accept = va_arg(ap, int);
- ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d with immediate accept = %d\n", span->span_id, r2conf.immediate_accept);
+ r2conf.immediate_accept = ftdm_true(val);
+ ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %s with immediate accept = %d\n", span->name, r2conf.immediate_accept);
} else if (!strcasecmp(var, "skip_category")) {
- r2conf.skip_category = va_arg(ap, int);
- ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d with skip category = %d\n", span->span_id, r2conf.skip_category);
+ r2conf.skip_category = ftdm_true(val);
+ ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %s with skip category = %d\n", span->name, r2conf.skip_category);
} else if (!strcasecmp(var, "forced_release")) {
- r2conf.forced_release = va_arg(ap, int);
- ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d with forced release = %d\n", span->span_id, r2conf.forced_release);
+ r2conf.forced_release = ftdm_true(val);
+ ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %s with forced release = %d\n", span->name, r2conf.forced_release);
} else if (!strcasecmp(var, "charge_calls")) {
- r2conf.charge_calls = va_arg(ap, int);
- ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d with charge calls = %d\n", span->span_id, r2conf.charge_calls);
+ r2conf.charge_calls = ftdm_true(val);
+ ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %s with charge calls = %d\n", span->name, r2conf.charge_calls);
} else if (!strcasecmp(var, "get_ani_first")) {
- r2conf.get_ani_first = va_arg(ap, int);
- ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d with get ani first = %d\n", span->span_id, r2conf.get_ani_first);
+ r2conf.get_ani_first = ftdm_true(val);
+ ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %s with get ani first = %d\n", span->name, r2conf.get_ani_first);
} else if (!strcasecmp(var, "call_files")) {
- r2conf.call_files = va_arg(ap, int);
- ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d with call files = %d\n", span->span_id, r2conf.call_files);
- } else if (!strcasecmp(var, "mf_files")) {
- r2conf.mf_files = va_arg(ap, int);
- ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d with mf files = %d\n", span->span_id, r2conf.mf_files);
+ r2conf.call_files = ftdm_true(val);
+ ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %s with call files = %d\n", span->name, r2conf.call_files);
} else if (!strcasecmp(var, "mfback_timeout")) {
- r2conf.mfback_timeout = va_arg(ap, int);
- ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d with MF backward timeout = %dms\n", span->span_id, r2conf.mfback_timeout);
+ r2conf.mfback_timeout = atoi(val);
+ ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %s with MF backward timeout = %dms\n", span->name, r2conf.mfback_timeout);
} else if (!strcasecmp(var, "metering_pulse_timeout")) {
- r2conf.metering_pulse_timeout = va_arg(ap, int);
- ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d with metering pulse timeout = %dms\n", span->span_id, r2conf.metering_pulse_timeout);
+ r2conf.metering_pulse_timeout = atoi(val);
+ ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %s with metering pulse timeout = %dms\n", span->name, r2conf.metering_pulse_timeout);
} else if (!strcasecmp(var, "max_ani")) {
- r2conf.max_ani = va_arg(ap, int);
- ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d with max ani = %d\n", span->span_id, r2conf.max_ani);
+ r2conf.max_ani = atoi(val);
+ ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %s with max ani = %d\n", span->name, r2conf.max_ani);
} else if (!strcasecmp(var, "max_dnis")) {
- r2conf.max_dnis = va_arg(ap, int);
- ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d with max dnis = %d\n", span->span_id, r2conf.max_dnis);
+ r2conf.max_dnis = atoi(val);
+ ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %s with max dnis = %d\n", span->name, r2conf.max_dnis);
} else {
snprintf(span->last_error, sizeof(span->last_error), "Unknown R2 parameter [%s]", var);
return FTDM_FAIL;
@@ -1055,6 +1232,10 @@ static FIO_SIG_CONFIGURE_FUNCTION(ftdm_r2_configure_span)
return FTDM_FAIL;
}
+ /* set span log level */
+ r2conf.loglevel = ftdm_r2_loglevel_from_string(log_level);
+ ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d with loglevel %s\n", span->span_id, log_level);
+
r2data = ftdm_malloc(sizeof(*r2data));
if (!r2data) {
snprintf(span->last_error, sizeof(span->last_error), "Failed to allocate R2 data.");
@@ -1083,10 +1264,10 @@ static FIO_SIG_CONFIGURE_FUNCTION(ftdm_r2_configure_span)
openr2_context_set_double_answer(r2data->r2context, r2conf.double_answer);
openr2_context_set_immediate_accept(r2data->r2context, r2conf.immediate_accept);
- if (r2conf.logdir && r2conf.logdir[0]) {
- ftdm_log(FTDM_LOG_DEBUG, "Setting openr2 for span %s logdir to %s\n", span->name, r2conf.logdir);
- openr2_context_set_log_directory(r2data->r2context, r2conf.logdir);
- }
+ ftdm_log(FTDM_LOG_DEBUG, "Setting span %s logdir to %s\n", span->name, r2conf.logdir);
+ openr2_context_set_log_directory(r2data->r2context, r2conf.logdir);
+ snprintf(r2data->logdir, sizeof(r2data->logdir), "%s", r2conf.logdir);
+
if (r2conf.advanced_protocol_file) {
openr2_context_configure_from_advanced_file(r2data->r2context, r2conf.advanced_protocol_file);
}
@@ -1106,11 +1287,6 @@ static FIO_SIG_CONFIGURE_FUNCTION(ftdm_r2_configure_span)
openr2_chan_set_log_level(r2chan, r2conf.loglevel);
if (r2conf.call_files) {
openr2_chan_enable_call_files(r2chan);
-#if 0
- if (r2conf.mf_files) {
- openr2_chan_enable_mf_files(r2chan);
- }
-#endif
}
r2call = ftdm_malloc(sizeof(*r2call));
@@ -1129,6 +1305,7 @@ static FIO_SIG_CONFIGURE_FUNCTION(ftdm_r2_configure_span)
hashtable_insert(spanpvt->r2calls, (void *)r2call->name, r2call, HASHTABLE_FLAG_FREE_VALUE);
}
+ r2data->mf_dump_size = r2conf.mf_dump_size;
r2data->flags = 0;
spanpvt->r2context = r2data->r2context;
@@ -1137,13 +1314,18 @@ static FIO_SIG_CONFIGURE_FUNCTION(ftdm_r2_configure_span)
span->start = ftdm_r2_start;
span->stop = ftdm_r2_stop;
- span->sig_read = ftdm_r2_sig_read;
+ span->sig_read = NULL;
+
+ /* let the core set the states, we just read them */
+ span->get_channel_sig_status = ftdm_r2_get_channel_sig_status;
span->signal_cb = sig_cb;
span->signal_type = FTDM_SIGTYPE_R2;
span->signal_data = r2data;
span->outgoing_call = r2_outgoing_call;
+ span->state_map = &r2_state_map;
+
/* use signals queue */
ftdm_set_flag(span, FTDM_SPAN_USE_SIGNALS_QUEUE);
@@ -1177,25 +1359,27 @@ static int ftdm_r2_state_advance(ftdm_channel_t *ftdmchan)
ret = 0;
- if (R2CALL(ftdmchan)->state_ack_pending) {
- ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE);
- ftdm_channel_complete_state(ftdmchan);
- R2CALL(ftdmchan)->state_ack_pending = 0;
- }
-
- if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE) && (R2CALL(ftdmchan)->chanstate != ftdmchan->state)) {
+ /* because we do not always acknowledge the state change (clearing the FTDM_CHANNEL_STATE_CHANGE flag) due to the accept
+ * procedure described below, we need the chanstate member to NOT process some states twice, so is valid entering this
+ * function with the FTDM_CHANNEL_STATE_CHANGE flag set but with a state that was already processed and is just waiting
+ * to complete (the processing is media-bound)
+ * */
+ if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE)
+ && (R2CALL(ftdmchan)->chanstate != ftdmchan->state)) {
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Executing state handler for %s\n", ftdm_channel_state2str(ftdmchan->state));
R2CALL(ftdmchan)->chanstate = ftdmchan->state;
- if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND) && !R2CALL(ftdmchan)->accepted &&
- (ftdmchan->state == FTDM_CHANNEL_STATE_PROGRESS ||
- ftdmchan->state == FTDM_CHANNEL_STATE_PROGRESS_MEDIA ||
- ftdmchan->state == FTDM_CHANNEL_STATE_UP) ) {
- /* if an accept ack will be required we should not acknowledge the state change just yet,
- it will be done below after processing the MF signals, otherwise we have a race condition between freetdm calling
- openr2_chan_answer_call and openr2 accepting the call first, if freetdm calls openr2_chan_answer_call before the accept cycle
- completes, openr2 will fail to answer the call */
+ if (IS_ACCEPTING_PENDING(ftdmchan)) {
+ /*
+ Moving to PROGRESS, PROGRESS_MEDIA or UP means that we must accept the call first, and accepting
+ the call in R2 means sending a tone, then waiting for the acknowledge from the other end,
+ since all of that requires sending and detecting tones, it takes a few milliseconds (I'd say around 100)
+ which means during that time the user should not try to perform any operations like answer, hangup or anything
+ else, therefore we DO NOT clear the FTDM_CHANNEL_STATE_CHANGE flag here, we rely on ftdm_io.c to block
+ the user thread until we're done with the accept (see on_call_accepted callback) and then we clear the state change flag,
+ otherwise we have a race condition between freetdm calling openr2_chan_answer_call and openr2 accepting the call first,
+ if freetdm calls openr2_chan_answer_call before the accept cycle completes, openr2 will fail to answer the call */
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "State ack for state %s will have to wait a bit\n", ftdm_channel_state2str(ftdmchan->state));
} else if (ftdmchan->state != FTDM_CHANNEL_STATE_DOWN){
ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE);
@@ -1211,6 +1395,7 @@ static int ftdm_r2_state_advance(ftdm_channel_t *ftdmchan)
ftdm_channel_command(ftdmchan, FTDM_COMMAND_GET_INTERVAL, &interval);
ftdm_assert(interval != 0, "Invalid interval!");
ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Starting processing of incoming call with interval %d\n", interval);
+ openr2_chan_enable_read(r2chan);
}
break;
@@ -1222,6 +1407,7 @@ static int ftdm_r2_state_advance(ftdm_channel_t *ftdmchan)
ftdm_assert(interval != 0, "Invalid interval!");
ftdm_log_chan(ftdmchan,
FTDM_LOG_DEBUG, "Starting processing of outgoing call in channel with interval %d\n", interval);
+ openr2_chan_enable_read(r2chan);
}
break;
@@ -1237,7 +1423,7 @@ static int ftdm_r2_state_advance(ftdm_channel_t *ftdmchan)
ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_CANCEL);
break;
}
- R2CALL(ftdmchan)->ftdm_started = 1;
+ R2CALL(ftdmchan)->ftdm_call_started = 1;
break;
@@ -1252,10 +1438,11 @@ static int ftdm_r2_state_advance(ftdm_channel_t *ftdmchan)
}
} else {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Notifying progress\n");
+ sigev.event_id = FTDM_SIGEVENT_PROCEED;
+ ftdm_span_send_signal(ftdmchan->span, &sigev);
+
sigev.event_id = FTDM_SIGEVENT_PROGRESS_MEDIA;
- if (ftdm_span_send_signal(ftdmchan->span, &sigev) != FTDM_SUCCESS) {
- ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
- }
+ ftdm_span_send_signal(ftdmchan->span, &sigev);
}
}
break;
@@ -1276,25 +1463,40 @@ static int ftdm_r2_state_advance(ftdm_channel_t *ftdmchan)
} else {
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Notifying of call answered\n");
sigev.event_id = FTDM_SIGEVENT_UP;
- if (ftdm_span_send_signal(ftdmchan->span, &sigev) != FTDM_SUCCESS) {
- ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
- }
+ ftdm_span_send_signal(ftdmchan->span, &sigev);
}
}
break;
/* just got hangup */
- case FTDM_CHANNEL_STATE_HANGUP:
+ case FTDM_CHANNEL_STATE_HANGUP:
{
- openr2_call_disconnect_cause_t disconnect_cause = ftdm_r2_ftdm_cause_to_openr2_cause(ftdmchan);
- ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Clearing call, cause = %s\n", openr2_proto_get_disconnect_string(disconnect_cause));
- openr2_chan_enable_read(r2chan);
if (!R2CALL(ftdmchan)->disconnect_rcvd) {
+ openr2_call_disconnect_cause_t disconnect_cause = ftdm_r2_ftdm_cause_to_openr2_cause(ftdmchan);
+ ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Clearing call, cause = %s\n", openr2_proto_get_disconnect_string(disconnect_cause));
/* this will disconnect the call, but need to wait for the call end before moving to DOWN */
openr2_chan_disconnect_call(r2chan, disconnect_cause);
- } else {
+ } else if (!R2CALL(ftdmchan)->protocol_error) {
/* just ack the hangup, on_call_end will be called by openr2 right after */
- openr2_chan_disconnect_call(r2chan, disconnect_cause);
+ openr2_chan_disconnect_call(r2chan, OR2_CAUSE_NORMAL_CLEARING);
+ } else {
+ ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "Clearing call due to protocol error\n");
+ ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
+ }
+ }
+ break;
+
+ case FTDM_CHANNEL_STATE_TERMINATING:
+ {
+ /* if the call has not been started yet we must go to HANGUP right here */
+ if (!R2CALL(ftdmchan)->ftdm_call_started) {
+ ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_HANGUP);
+ } else {
+ openr2_call_disconnect_cause_t disconnect_cause = ftdm_r2_ftdm_cause_to_openr2_cause(ftdmchan);
+ ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Clearing call, cause = %s\n", openr2_proto_get_disconnect_string(disconnect_cause));
+ /* notify the user of the call terminating and we wait for the user to move us to hangup */
+ sigev.event_id = FTDM_SIGEVENT_STOP;
+ ftdm_span_send_signal(ftdmchan->span, &sigev);
}
}
break;
@@ -1303,7 +1505,6 @@ static int ftdm_r2_state_advance(ftdm_channel_t *ftdmchan)
case FTDM_CHANNEL_STATE_CANCEL:
{
ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Unable to receive call\n");
- openr2_chan_enable_read(r2chan);
openr2_chan_disconnect_call(r2chan, OR2_CAUSE_OUT_OF_ORDER);
}
break;
@@ -1315,6 +1516,7 @@ static int ftdm_r2_state_advance(ftdm_channel_t *ftdmchan)
if (R2CALL(ftdmchan)->txdrops) {
ftdm_log_chan(ftdmchan, FTDM_LOG_WARNING, "dropped %d tx packets\n", R2CALL(ftdmchan)->txdrops);
}
+ openr2_chan_disable_read(r2chan);
ret = 1;
}
break;
@@ -1337,19 +1539,34 @@ static int ftdm_r2_state_advance(ftdm_channel_t *ftdmchan)
return ret;
}
+/* the channel must be locked when calling this function */
+static void ftdm_r2_state_advance_all(ftdm_channel_t *ftdmchan)
+{
+ /* because we do not always acknowledge the state change (clearing the FTDM_CHANNEL_STATE_CHANGE flag) due to the accept
+ * procedure described below, we need the chanstate member to NOT process some states twice, so is valid entering this
+ * function with the FTDM_CHANNEL_STATE_CHANGE flag set but with a state that was already processed and is just waiting
+ * to complete (the processing is media-bound)
+ * */
+ while (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE)
+ && (R2CALL(ftdmchan)->chanstate != ftdmchan->state)) {
+ ftdm_r2_state_advance(ftdmchan);
+ }
+}
+
static void *ftdm_r2_run(ftdm_thread_t *me, void *obj)
{
openr2_chan_t *r2chan;
- ftdm_r2_call_t *r2call = NULL;
ftdm_channel_t *ftdmchan = NULL;
ftdm_status_t status;
ftdm_span_t *span = (ftdm_span_t *) obj;
ftdm_r2_data_t *r2data = span->signal_data;
int waitms = 20;
- int i, res;
- int ms;
+ unsigned int i;
+ int res, ms;
+ int index = 0;
struct timeval start, end;
- short *poll_events = ftdm_malloc(sizeof(short)*span->chan_count);
+ ftdm_iterator_t *chaniter = NULL;
+ short *poll_events = ftdm_malloc(sizeof(short) * span->chan_count);
#ifdef __linux__
r2data->monitor_thread_id = syscall(SYS_gettid);
@@ -1359,31 +1576,43 @@ static void *ftdm_r2_run(ftdm_thread_t *me, void *obj)
r2chan = NULL;
for (i = 1; i <= span->chan_count; i++) {
r2chan = R2CALL(span->channels[i])->r2chan;
+ openr2_chan_set_span_id(r2chan, span->span_id);
openr2_chan_set_idle(r2chan);
openr2_chan_process_cas_signaling(r2chan);
}
memset(&start, 0, sizeof(start));
memset(&end, 0, sizeof(end));
+ chaniter = ftdm_span_get_chan_iterator(span, NULL);
while (ftdm_running() && ftdm_test_flag(r2data, FTDM_R2_RUNNING)) {
- r2data->loops++;
res = gettimeofday(&end, NULL);
if (start.tv_sec) {
ms = ((end.tv_sec - start.tv_sec) * 1000)
+ ((( 1000000 + end.tv_usec - start.tv_usec) / 1000) - 1000);
+ if (ms < 0) {
+ ms = 0;
+ }
if (ms > r2data->jobmax) {
r2data->jobmax = ms;
}
+ index = (ms / 10);
+ index = (index > 10) ? 10 : index;
+ r2data->loops[index]++;
+ r2data->total_loops++;
}
#ifndef WIN32
/* figure out what event to poll each channel for. POLLPRI when the channel is down,
* POLLPRI|POLLIN|POLLOUT otherwise */
memset(poll_events, 0, sizeof(short)*span->chan_count);
- for (i = 0; i < span->chan_count; i++) {
- r2chan = R2CALL(span->channels[(i+1)])->r2chan;
- ftdmchan = openr2_chan_get_client_data(r2chan);
- poll_events[i] = ftdmchan->state == FTDM_CHANNEL_STATE_DOWN ? POLLPRI : (POLLPRI | POLLIN | POLLOUT);
+ chaniter = ftdm_span_get_chan_iterator(span, chaniter);
+ for (i = 0; chaniter; chaniter = ftdm_iterator_next(chaniter), i++) {
+ ftdmchan = ftdm_iterator_current(chaniter);
+ r2chan = R2CALL(ftdmchan)->r2chan;
+ poll_events[i] = POLLPRI;
+ if (openr2_chan_get_read_enabled(r2chan)) {
+ poll_events[i] |= POLLIN;
+ }
}
status = ftdm_span_poll_event(span, waitms, poll_events);
@@ -1401,70 +1630,37 @@ static void *ftdm_r2_run(ftdm_thread_t *me, void *obj)
continue;
}
- if (FTDM_SUCCESS == status) {
- ftdm_event_t *event;
- while (ftdm_span_next_event(span, &event) == FTDM_SUCCESS) {
- if (event->enum_id == FTDM_OOB_CAS_BITS_CHANGE) {
- r2call = R2CALL(event->channel);
- r2chan = r2call->r2chan;
+ /* this main loop takes care of MF and CAS signaling during call setup and tear down
+ * for every single channel in the span, do not perform blocking operations here! */
+ chaniter = ftdm_span_get_chan_iterator(span, chaniter);
+ for ( ; chaniter; chaniter = ftdm_iterator_next(chaniter)) {
+ ftdmchan = ftdm_iterator_current(chaniter);
- ftdm_log(FTDM_LOG_DEBUG, "Handling CAS on channel %d.\n", openr2_chan_get_number(r2chan));
- // we only expect CAS and other OOB events on this thread/loop, once a call is started
- // the MF events (in-band signaling) are handled in the call thread
- openr2_chan_process_cas_signaling(r2chan);
- } else {
- ftdm_log(FTDM_LOG_DEBUG, "Ignoring event %d on channel %d.\n", event->enum_id, openr2_chan_get_number(r2chan));
- // XXX TODO: handle alarms here XXX
- }
- }
+ ftdm_mutex_lock(ftdmchan->mutex);
- /* XXX
- * when ftdm_span_poll_event() returns FTDM_SUCCESS, means there are events pending on the span.
- * is it possible to know on which channels those events are pending, without traversing the span?
- * XXX */
- for (i = 1; i <= span->chan_count; i++) {
- r2chan = R2CALL(span->channels[i])->r2chan;
- ftdmchan = openr2_chan_get_client_data(r2chan);
- r2call = R2CALL(ftdmchan);
+ ftdm_r2_state_advance_all(ftdmchan);
- ftdm_mutex_lock(ftdmchan->mutex);
- ftdm_set_flag(r2call, FTDM_R2_PROCESSING);
+ r2chan = R2CALL(ftdmchan)->r2chan;
+ openr2_chan_process_signaling(r2chan);
- if (ftdm_r2_state_advance(ftdmchan)) {
- ftdm_clear_flag(r2call, FTDM_R2_PROCESSING);
- ftdm_mutex_unlock(ftdmchan->mutex);
- continue;
- }
+ ftdm_r2_state_advance_all(ftdmchan);
- /* handle timeout events first if any */
- openr2_chan_run_schedule(r2chan);
-
- /* process mf tones, if any */
- if (openr2_chan_get_read_enabled(r2chan)) {
- openr2_chan_process_mf_signaling(r2chan);
- }
-
- if (ftdm_r2_state_advance(ftdmchan)) {
- ftdm_clear_flag(r2call, FTDM_R2_PROCESSING);
- ftdm_mutex_unlock(ftdmchan->mutex);
- continue;
- }
-
- ftdm_clear_flag(r2call, FTDM_R2_PROCESSING);
- ftdm_mutex_unlock(ftdmchan->mutex);
- }
- } else if (status != FTDM_TIMEOUT) {
- ftdm_log(FTDM_LOG_ERROR, "ftdm_span_poll_event returned %d.\n", status);
+ ftdm_mutex_unlock(ftdmchan->mutex);
}
+ /* deliver the actual events to the user now without any channel locking */
ftdm_span_trigger_signals(span);
- ftdm_sleep(20);
}
-
- for (i = 1; i <= span->chan_count; i++) {
- r2chan = R2CALL(span->channels[i])->r2chan;
+
+ chaniter = ftdm_span_get_chan_iterator(span, chaniter);
+ for ( ; chaniter; chaniter = ftdm_iterator_next(chaniter)) {
+ ftdmchan = ftdm_iterator_current(chaniter);
+ r2chan = R2CALL(ftdmchan)->r2chan;
openr2_chan_set_blocked(r2chan);
}
+ ftdm_iterator_free(chaniter);
+ ftdm_safe_free(poll_events);
+
ftdm_clear_flag(r2data, FTDM_R2_RUNNING);
ftdm_log(FTDM_LOG_DEBUG, "R2 thread ending.\n");
@@ -1520,8 +1716,8 @@ static FIO_API_FUNCTION(ftdm_r2_api)
char *mycmd = NULL, *argv[10] = { 0 };
int argc = 0;
int span_id = 0;
- int chan_id = 0;
- int i = 0;
+ unsigned int chan_id = 0;
+ unsigned int i = 0;
ftdm_r2_data_t *r2data = NULL;
openr2_chan_t *r2chan = NULL;
openr2_context_t *r2context = NULL;
@@ -1604,7 +1800,7 @@ static FIO_API_FUNCTION(ftdm_r2_api)
goto done;
}
if (!(r2data = span->signal_data)) {
- stream->write_function(stream, "-ERR invalid span. No R2 singal data in span.\n");
+ stream->write_function(stream, "-ERR invalid span. No R2 signal data in span.\n");
goto done;
}
r2context = r2data->r2context;
@@ -1615,19 +1811,17 @@ static FIO_API_FUNCTION(ftdm_r2_api)
"Max DNIS: %d\n"
"ANI First: %s\n"
"Immediate Accept: %s\n"
- "Side: %s\n"
+ "Job Thread: %lu\n"
"Job Max ms: %d\n"
- "Job Loops: %lu\n"
- "Monitor Thread: %lu\n",
+ "Job Loops: %lu\n",
openr2_proto_get_variant_string(r2variant),
openr2_context_get_max_ani(r2context),
openr2_context_get_max_dnis(r2context),
openr2_context_get_ani_first(r2context) ? "Yes" : "No",
openr2_context_get_immediate_accept(r2context) ? "Yes" : "No",
- "no side",
+ r2data->monitor_thread_id,
r2data->jobmax,
- r2data->loops,
- r2data->monitor_thread_id);
+ r2data->total_loops);
stream->write_function(stream, "\n");
stream->write_function(stream, "%4s %-12.12s %-12.12s\n", "Channel", "Tx CAS", "Rx CAS");
for (i = 1; i <= span->chan_count; i++) {
@@ -1646,6 +1840,39 @@ static FIO_API_FUNCTION(ftdm_r2_api)
}
}
+ if (!strcasecmp(argv[0], "loopstats")) {
+ int range;
+ float pct;
+ span_id = atoi(argv[1]);
+
+ if (ftdm_span_find_by_name(argv[1], &span) == FTDM_SUCCESS || ftdm_span_find(span_id, &span) == FTDM_SUCCESS) {
+ if (span->start != ftdm_r2_start) {
+ stream->write_function(stream, "-ERR not an R2 span.\n");
+ goto done;
+ }
+ if (!(r2data = span->signal_data)) {
+ stream->write_function(stream, "-ERR invalid span. No R2 signal data in span.\n");
+ goto done;
+ }
+ range = 0;
+ for (i = 0; i < ftdm_array_len(r2data->loops); i++) {
+ pct = 100*(float)r2data->loops[i]/r2data->total_loops;
+ if ((i + 1) == ftdm_array_len(r2data->loops)) {
+ stream->write_function(stream, ">= %dms: %llu - %.03lf%%\n", range, r2data->loops[i], pct);
+ } else {
+ stream->write_function(stream, "%d-%dms: %llu - %.03lf%%\n", range, range + 9, r2data->loops[i], pct);
+ }
+ range += 10;
+ }
+ stream->write_function(stream, "\n");
+ stream->write_function(stream, "+OK.\n");
+ goto done;
+ } else {
+ stream->write_function(stream, "-ERR invalid span.\n");
+ goto done;
+ }
+ }
+
}
if (argc == 1) {
@@ -1735,12 +1962,13 @@ static FIO_SIG_UNLOAD_FUNCTION(ftdm_r2_destroy)
}
EX_DECLARE_DATA ftdm_module_t ftdm_module = {
- "r2",
- ftdm_r2_io_init,
- NULL,
- ftdm_r2_init,
- ftdm_r2_configure_span,
- ftdm_r2_destroy
+ /* .name */ "r2",
+ /* .io_load */ ftdm_r2_io_init,
+ /* .io_unload */ NULL,
+ /* .sig_load */ ftdm_r2_init,
+ /* .sig_configure */ NULL,
+ /* .sig_unload */ ftdm_r2_destroy,
+ /* .configure_span_signaling */ ftdm_r2_configure_span_signaling
};
diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_boost/ftmod_sangoma_boost.2008.vcproj b/libs/freetdm/src/ftmod/ftmod_sangoma_boost/ftmod_sangoma_boost.2008.vcproj
index e7fc1d6549..73e421818f 100644
--- a/libs/freetdm/src/ftmod/ftmod_sangoma_boost/ftmod_sangoma_boost.2008.vcproj
+++ b/libs/freetdm/src/ftmod/ftmod_sangoma_boost/ftmod_sangoma_boost.2008.vcproj
@@ -95,83 +95,6 @@
Name="VCPostBuildEventTool"
/>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_boost/ftmod_sangoma_boost.2010.vcxproj b/libs/freetdm/src/ftmod/ftmod_sangoma_boost/ftmod_sangoma_boost.2010.vcxproj
index 1dd09211e2..78689c36db 100644
--- a/libs/freetdm/src/ftmod/ftmod_sangoma_boost/ftmod_sangoma_boost.2010.vcxproj
+++ b/libs/freetdm/src/ftmod/ftmod_sangoma_boost/ftmod_sangoma_boost.2010.vcxproj
@@ -172,7 +172,7 @@
Level4
- true
+ false
ProgramDatabase
4100;%(DisableSpecificWarnings)
diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.2010.vcxproj b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.2010.vcxproj
index b4d234cc7d..b0a51786f5 100644
--- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.2010.vcxproj
+++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.2010.vcxproj
@@ -5,10 +5,18 @@
Debug
Win32
+
+ Debug
+ x64
+
Release
Win32
+
+ Release
+ x64
+
ftmod_sangoma_isdn
@@ -21,33 +29,58 @@
DynamicLibrary
true
+
+ DynamicLibrary
+ true
+
DynamicLibrary
+
+ DynamicLibrary
+
+
+
+
+
+
+
<_ProjectFileVersion>10.0.30319.1
- $(SolutionDir)$(Configuration)\
- $(Configuration)\
+ $(SolutionDir)$(Platform)\$(Configuration)\
+ $(SolutionDir)$(Platform)\$(Configuration)\
+ $(Platform)\$(Configuration)\
+ $(Platform)\$(Configuration)\
true
- $(SolutionDir)$(Configuration)\
- $(Configuration)\
+ true
+ $(SolutionDir)$(Platform)\$(Configuration)\
+ $(SolutionDir)$(Platform)\$(Configuration)\
+ $(Platform)\$(Configuration)\
+ $(Configuration)\
true
+ true
AllRules.ruleset
+ AllRules.ruleset
+
+
AllRules.ruleset
+ AllRules.ruleset
+
+
@@ -74,6 +107,29 @@
MachineX86
+
+
+ Disabled
+ C:\Program Files\libsng_isdn\include;C:\Program Files\libsng_isdn\include\sng_isdn;../../include;C:\Program Files\Sangoma\include;%(AdditionalIncludeDirectories)
+ WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
+
+
+ EnableFastChecks
+
+
+ Level3
+ ProgramDatabase
+
+
+ freetdm.lib;libsng_isdn.lib;%(AdditionalDependencies)
+ $(OutDir);C:\Program Files\libsng_isdn\lib;C:\Program Files\Sangoma\api\lib\x86;%(AdditionalLibraryDirectories)
+ true
+ Console
+ false
+
+
+
+
WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
@@ -93,6 +149,23 @@
MachineX86
+
+
+ WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ EnableFastChecks
+ MultiThreadedDebugDLL
+
+
+ Level3
+ ProgramDatabase
+
+
+ true
+ Windows
+ true
+ true
+
+
diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_hndl.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_hndl.c
index d557ca3ba0..16b22a5da1 100644
--- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_hndl.c
+++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_hndl.c
@@ -33,6 +33,7 @@
*/
#include "ftmod_sangoma_isdn.h"
+ftdm_status_t sngisdn_cause_val_requires_disconnect(ftdm_channel_t *ftdmchan, CauseDgn *causeDgn);
/* Remote side transmit a SETUP */
void sngisdn_process_con_ind (sngisdn_event_data_t *sngisdn_event)
@@ -131,11 +132,13 @@ void sngisdn_process_con_ind (sngisdn_event_data_t *sngisdn_event)
get_called_num(ftdmchan, &conEvnt->cdPtyNmb);
get_redir_num(ftdmchan, &conEvnt->redirNmb);
get_calling_subaddr(ftdmchan, &conEvnt->cgPtySad);
+ get_prog_ind_ie(ftdmchan, &conEvnt->progInd);
+ get_facility_ie(ftdmchan, &conEvnt->facilityStr);
if (get_calling_name_from_display(ftdmchan, &conEvnt->display) != FTDM_SUCCESS) {
get_calling_name_from_usr_usr(ftdmchan, &conEvnt->usrUsr);
}
- get_prog_ind_ie(ftdmchan, &conEvnt->progInd);
+
ftdm_log_chan(sngisdn_info->ftdmchan, FTDM_LOG_INFO, "Incoming call: Called No:[%s] Calling No:[%s]\n", ftdmchan->caller_data.dnis.digits, ftdmchan->caller_data.cid_num.digits);
@@ -151,40 +154,34 @@ void sngisdn_process_con_ind (sngisdn_event_data_t *sngisdn_event)
}
}
- if (conEvnt->facilityStr.eh.pres) {
- if (signal_data->facility_ie_decode == SNGISDN_OPT_FALSE) {
- get_facility_ie(ftdmchan, &conEvnt->facilityStr);
- } else if (signal_data->facility == SNGISDN_OPT_TRUE) {
- if (signal_data->switchtype == SNGISDN_SWITCH_NI2) {
- /* Verify whether the Caller Name will come in a subsequent FACILITY message */
- uint16_t ret_val;
- char retrieved_str[255];
+ /* this should be in get_facility_ie function, fix this later */
+ if (signal_data->facility == SNGISDN_OPT_TRUE && conEvnt->facilityStr.eh.pres) {
+ /* Verify whether the Caller Name will come in a subsequent FACILITY message */
+ uint16_t ret_val;
+ char retrieved_str[255];
- ret_val = sng_isdn_retrieve_facility_caller_name(conEvnt->facilityStr.facilityStr.val, conEvnt->facilityStr.facilityStr.len, retrieved_str);
- /*
- return values for "sng_isdn_retrieve_facility_information_following":
- If there will be no information following, or fails to decode IE, returns -1
- If there will be no information following, but current FACILITY IE contains a caller name, returns 0
- If there will be information following, returns 1
- */
+ ret_val = sng_isdn_retrieve_facility_caller_name(conEvnt->facilityStr.facilityStr.val, conEvnt->facilityStr.facilityStr.len, retrieved_str);
+ /*
+ return values for "sng_isdn_retrieve_facility_information_following":
+ If there will be no information following, or fails to decode IE, returns -1
+ If there will be no information following, but current FACILITY IE contains a caller name, returns 0
+ If there will be information following, returns 1
+ */
- if (ret_val == 1) {
- ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Expecting Caller name in FACILITY\n");
- ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_GET_CALLERID);
- /* Launch timer in case we never get a FACILITY msg */
- if (signal_data->facility_timeout) {
- ftdm_sched_timer(signal_data->sched, "facility_timeout", signal_data->facility_timeout,
- sngisdn_facility_timeout, (void*) sngisdn_info, &sngisdn_info->timers[SNGISDN_TIMER_FACILITY]);
- }
- break;
- } else if (ret_val == 0) {
- strcpy(ftdmchan->caller_data.cid_name, retrieved_str);
- }
- break;
+ if (ret_val == 1) {
+ ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Expecting Caller name in FACILITY\n");
+ ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_GET_CALLERID);
+ /* Launch timer in case we never get a FACILITY msg */
+ if (signal_data->facility_timeout) {
+ ftdm_sched_timer(signal_data->sched, "facility_timeout", signal_data->facility_timeout,
+ sngisdn_facility_timeout, (void*) sngisdn_info, &sngisdn_info->timers[SNGISDN_TIMER_FACILITY]);
}
+ break;
+ } else if (ret_val == 0) {
+ strcpy(ftdmchan->caller_data.cid_name, retrieved_str);
}
}
-
+
if (signal_data->overlap_dial == SNGISDN_OPT_TRUE && !conEvnt->sndCmplt.eh.pres) {
ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_COLLECT);
} else {
@@ -284,6 +281,7 @@ void sngisdn_process_con_cfm (sngisdn_event_data_t *sngisdn_event)
case FTDM_CHANNEL_STATE_PROGRESS_MEDIA:
case FTDM_CHANNEL_STATE_DIALING:
get_prog_ind_ie(ftdmchan, &cnStEvnt->progInd);
+ get_facility_ie(ftdmchan, &cnStEvnt->facilityStr);
ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_UP);
break;
case FTDM_CHANNEL_STATE_HANGUP_COMPLETE:
@@ -351,34 +349,17 @@ void sngisdn_process_cnst_ind (sngisdn_event_data_t *sngisdn_event)
case MI_PROGRESS:
case MI_ALERTING:
get_prog_ind_ie(ftdmchan, &cnStEvnt->progInd);
+ get_facility_ie(ftdmchan, &cnStEvnt->facilityStr);
- if (signal_data->ignore_cause_value != SNGISDN_OPT_TRUE &&
- cnStEvnt->causeDgn[0].eh.pres && cnStEvnt->causeDgn[0].causeVal.pres) {
-
- switch(cnStEvnt->causeDgn[0].causeVal.val) {
- case 17: /* User Busy */
- case 18: /* No User responding */
- case 19: /* User alerting, no answer */
- case 21: /* Call rejected, the called party does not with to accept this call */
- case 27: /* Destination out of order */
- case 31: /* Normal, unspecified */
- case 34: /* Circuit/Channel congestion */
- case 41: /* Temporary failure */
- case 42: /* Switching equipment is experiencing a period of high traffic */
- case 47: /* Resource unavailable */
- case 58: /* Bearer Capability not available */
- case 63: /* Service or option not available */
- case 65: /* Bearer Cap not implemented, not supported */
- case 79: /* Service or option not implemented, unspecified */
- ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Cause requires disconnect (cause:%d)\n", cnStEvnt->causeDgn[0].causeVal.val);
- ftdmchan->caller_data.hangup_cause = cnStEvnt->causeDgn[0].causeVal.val;
+ if (sngisdn_cause_val_requires_disconnect(ftdmchan, &cnStEvnt->causeDgn[0]) == FTDM_SUCCESS) {
+ ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Cause requires disconnect (cause:%d)\n", cnStEvnt->causeDgn[0].causeVal.val);
+ ftdmchan->caller_data.hangup_cause = cnStEvnt->causeDgn[0].causeVal.val;
- sngisdn_set_flag(sngisdn_info, FLAG_SEND_DISC);
- ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING);
- goto sngisdn_process_cnst_ind_end;
- }
+ sngisdn_set_flag(sngisdn_info, FLAG_SEND_DISC);
+ ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING);
+ goto sngisdn_process_cnst_ind_end;
}
-
+
switch(ftdmchan->state) {
case FTDM_CHANNEL_STATE_DIALING:
case FTDM_CHANNEL_STATE_PROCEED:
@@ -461,7 +442,6 @@ void sngisdn_process_disc_ind (sngisdn_event_data_t *sngisdn_event)
uint32_t spInstId = sngisdn_event->spInstId;
sngisdn_chan_data_t *sngisdn_info = sngisdn_event->sngisdn_info;
ftdm_channel_t *ftdmchan = sngisdn_info->ftdmchan;
- sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) ftdmchan->span->signal_data;
DiscEvnt *discEvnt = &sngisdn_event->event.discEvnt;
@@ -476,14 +456,9 @@ void sngisdn_process_disc_ind (sngisdn_event_data_t *sngisdn_event)
case FTDM_CHANNEL_STATE_PROCEED:
case FTDM_CHANNEL_STATE_PROGRESS:
case FTDM_CHANNEL_STATE_PROGRESS_MEDIA:
- case FTDM_CHANNEL_STATE_UP:
- if (discEvnt->facilityStr.eh.pres) {
- if (signal_data->facility_ie_decode == SNGISDN_OPT_FALSE) {
- get_facility_ie(ftdmchan, &discEvnt->facilityStr);
- } else {
- /* Call libsng_isdn facility decode function and copy variables here */
- }
- }
+ case FTDM_CHANNEL_STATE_UP:
+ get_facility_ie(ftdmchan, &discEvnt->facilityStr);
+
if (discEvnt->causeDgn[0].eh.pres && discEvnt->causeDgn[0].causeVal.pres) {
ftdmchan->caller_data.hangup_cause = discEvnt->causeDgn[0].causeVal.val;
} else {
@@ -527,7 +502,6 @@ void sngisdn_process_rel_ind (sngisdn_event_data_t *sngisdn_event)
uint32_t spInstId = sngisdn_event->spInstId;
sngisdn_chan_data_t *sngisdn_info = sngisdn_event->sngisdn_info;
ftdm_channel_t *ftdmchan = sngisdn_info->ftdmchan;
- sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) ftdmchan->span->signal_data;
RelEvnt *relEvnt = &sngisdn_event->event.relEvnt;
@@ -574,13 +548,7 @@ void sngisdn_process_rel_ind (sngisdn_event_data_t *sngisdn_event)
if (((sngisdn_chan_data_t*)ftdmchan->call_data)->suInstId == suInstId ||
((sngisdn_chan_data_t*)ftdmchan->call_data)->spInstId == spInstId) {
- if (relEvnt->facilityStr.eh.pres) {
- if (signal_data->facility_ie_decode == SNGISDN_OPT_FALSE) {
- get_facility_ie(ftdmchan, &relEvnt->facilityStr);
- } else {
- /* Call libsng_isdn facility decode function and copy variables here */
- }
- }
+ get_facility_ie(ftdmchan, &relEvnt->facilityStr);
if (relEvnt->causeDgn[0].eh.pres && relEvnt->causeDgn[0].causeVal.pres) {
ftdmchan->caller_data.hangup_cause = relEvnt->causeDgn[0].causeVal.val;
@@ -791,11 +759,7 @@ void sngisdn_process_fac_ind (sngisdn_event_data_t *sngisdn_event)
{
ftdm_sigmsg_t sigev;
if (facEvnt->facElmt.facStr.pres) {
- if (signal_data->facility_ie_decode == SNGISDN_OPT_FALSE) {
- get_facility_ie_str(ftdmchan, &facEvnt->facElmt.facStr.val[2], facEvnt->facElmt.facStr.len);
- } else {
- /* Call libsng_isdn facility decode function and copy variables here */
- }
+ get_facility_ie_str(ftdmchan, &facEvnt->facElmt.facStr.val[2], facEvnt->facElmt.facStr.len);
}
memset(&sigev, 0, sizeof(sigev));
sigev.chan_id = ftdmchan->chan_id;
@@ -1119,8 +1083,44 @@ void sngisdn_process_rst_ind (sngisdn_event_data_t *sngisdn_event)
(evntType == IN_LNK_DWN)?"LNK_DOWN":
(evntType == IN_LNK_UP)?"LNK_UP":
(evntType == IN_INDCHAN)?"b-channel":
- (evntType == IN_LNK_DWN_DM_RLS)?"Nfas service procedures":
+ (evntType == IN_LNK_DWN_DM_RLS)?"NFAS service procedures":
(evntType == IN_SWCHD_BU_DCHAN)?"NFAS switchover to backup":"Unknown");
ISDN_FUNC_TRACE_EXIT(__FUNCTION__);
return;
}
+
+ftdm_status_t sngisdn_cause_val_requires_disconnect(ftdm_channel_t *ftdmchan, CauseDgn *causeDgn)
+{
+ sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) ftdmchan->span->signal_data;
+
+ if (signal_data->ignore_cause_value == SNGISDN_OPT_TRUE) {
+ return FTDM_FAIL;
+ }
+
+ /* By default, we only evaluate cause value on 5ESS switches */
+ if (signal_data->ignore_cause_value == SNGISDN_OPT_DEFAULT &&
+ signal_data->switchtype != SNGISDN_SWITCH_5ESS) {
+
+ return FTDM_FAIL;
+ }
+
+ /* ignore_cause_value = SNGISDN_OPT_FALSE or switchtype == 5ESS */
+ switch(causeDgn->causeVal.val) {
+ case 17: /* User Busy */
+ case 18: /* No User responding */
+ case 19: /* User alerting, no answer */
+ case 21: /* Call rejected, the called party does not with to accept this call */
+ case 27: /* Destination out of order */
+ case 31: /* Normal, unspecified */
+ case 34: /* Circuit/Channel congestion */
+ case 41: /* Temporary failure */
+ case 42: /* Switching equipment is experiencing a period of high traffic */
+ case 47: /* Resource unavailable */
+ case 58: /* Bearer Capability not available */
+ case 63: /* Service or option not available */
+ case 65: /* Bearer Cap not implemented, not supported */
+ case 79: /* Service or option not implemented, unspecified */
+ return FTDM_SUCCESS;
+ }
+ return FTDM_FAIL;
+}
diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_out.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_out.c
index 752ac40641..38bbdb6968 100644
--- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_out.c
+++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_out.c
@@ -310,6 +310,7 @@ void sngisdn_snd_proceed(ftdm_channel_t *ftdmchan)
cnStEvnt.chanId.chanNmbSlotMap.val[0] = ftdmchan->physical_chan_id;
}
+ set_facility_ie(ftdmchan, &cnStEvnt.facilityStr);
ftdm_log_chan(ftdmchan, FTDM_LOG_INFO, "Sending PROCEED (suId:%d suInstId:%u spInstId:%u dchan:%d ces:%d)\n", signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId, signal_data->dchan_id, sngisdn_info->ces);
diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_support.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_support.c
index 565781aa41..fae25c9ad6 100644
--- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_support.c
+++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_support.c
@@ -283,7 +283,7 @@ ftdm_status_t get_calling_subaddr(ftdm_channel_t *ftdmchan, CgPtySad *cgPtySad)
}
ftdm_status_t get_facility_ie(ftdm_channel_t *ftdmchan, FacilityStr *facilityStr)
-{
+{
if (!facilityStr->eh.pres) {
return FTDM_FAIL;
}
@@ -294,18 +294,25 @@ ftdm_status_t get_facility_ie(ftdm_channel_t *ftdmchan, FacilityStr *facilityStr
ftdm_status_t get_facility_ie_str(ftdm_channel_t *ftdmchan, uint8_t *data, ftdm_size_t data_len)
{
ftdm_caller_data_t *caller_data = &ftdmchan->caller_data;
- if (data_len > sizeof(caller_data->raw_data)-2) {
- ftdm_log(FTDM_LOG_CRIT, "Length of Facility IE exceeds maximum length\n");
- return FTDM_FAIL;
- }
-
- memset(caller_data->raw_data, 0, sizeof(caller_data->raw_data));
- /* Always include Facility IE identifier + len so this can be used as a sanity check by the user */
- caller_data->raw_data[0] = SNGISDN_Q931_FACILITY_IE_ID;
- caller_data->raw_data[1] = data_len;
+ sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) ftdmchan->span->signal_data;
- memcpy(&caller_data->raw_data[2], data, data_len);
- caller_data->raw_data_len = data_len+2;
+ if (signal_data->facility_ie_decode == SNGISDN_OPT_FALSE) {
+ if (data_len > sizeof(caller_data->raw_data)-2) {
+ ftdm_log(FTDM_LOG_CRIT, "Length of Facility IE exceeds maximum length\n");
+ return FTDM_FAIL;
+ }
+
+ memset(caller_data->raw_data, 0, sizeof(caller_data->raw_data));
+ /* Always include Facility IE identifier + len so this can be used as a sanity check by the user */
+ caller_data->raw_data[0] = SNGISDN_Q931_FACILITY_IE_ID;
+ caller_data->raw_data[1] = data_len;
+
+ memcpy(&caller_data->raw_data[2], data, data_len);
+ caller_data->raw_data_len = data_len+2;
+ ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Raw Facility IE copied available\n");
+ } else {
+ /* Call libsng_isdn to process facility IE's here */
+ }
return FTDM_SUCCESS;
}
@@ -394,10 +401,19 @@ ftdm_status_t set_calling_num(ftdm_channel_t *ftdmchan, CgPtyNmb *cgPtyNmb)
cgPtyNmb->presInd0.val = caller_data->pres;
cgPtyNmb->nmbPlanId.pres = PRSNT_NODEF;
- cgPtyNmb->nmbPlanId.val = caller_data->cid_num.plan;
+ if (caller_data->cid_num.plan >= FTDM_NPI_INVALID) {
+ cgPtyNmb->nmbPlanId.val = FTDM_NPI_UNKNOWN;
+ } else {
+ cgPtyNmb->nmbPlanId.val = caller_data->cid_num.plan;
+ }
cgPtyNmb->typeNmb1.pres = PRSNT_NODEF;
- cgPtyNmb->typeNmb1.val = caller_data->cid_num.type;
+
+ if (caller_data->cid_num.type >= FTDM_TON_INVALID) {
+ cgPtyNmb->typeNmb1.val = FTDM_TON_UNKNOWN;
+ } else {
+ cgPtyNmb->typeNmb1.val = caller_data->cid_num.type;
+ }
cgPtyNmb->nmbDigits.pres = PRSNT_NODEF;
cgPtyNmb->nmbDigits.len = len;
@@ -418,14 +434,14 @@ ftdm_status_t set_called_num(ftdm_channel_t *ftdmchan, CdPtyNmb *cdPtyNmb)
cdPtyNmb->eh.pres = PRSNT_NODEF;
cdPtyNmb->nmbPlanId.pres = PRSNT_NODEF;
- if (caller_data->dnis.plan == FTDM_NPI_INVALID) {
+ if (caller_data->dnis.plan >= FTDM_NPI_INVALID) {
cdPtyNmb->nmbPlanId.val = FTDM_NPI_UNKNOWN;
} else {
cdPtyNmb->nmbPlanId.val = caller_data->dnis.plan;
}
cdPtyNmb->typeNmb0.pres = PRSNT_NODEF;
- if (caller_data->dnis.type == FTDM_TON_INVALID) {
+ if (caller_data->dnis.type >= FTDM_TON_INVALID) {
cdPtyNmb->typeNmb0.val = FTDM_TON_UNKNOWN;
} else {
cdPtyNmb->typeNmb0.val = caller_data->dnis.type;
@@ -450,14 +466,14 @@ ftdm_status_t set_redir_num(ftdm_channel_t *ftdmchan, RedirNmb *redirNmb)
redirNmb->eh.pres = PRSNT_NODEF;
redirNmb->nmbPlanId.pres = PRSNT_NODEF;
- if (caller_data->rdnis.plan == FTDM_NPI_INVALID) {
+ if (caller_data->rdnis.plan >= FTDM_NPI_INVALID) {
redirNmb->nmbPlanId.val = FTDM_NPI_UNKNOWN;
} else {
redirNmb->nmbPlanId.val = caller_data->rdnis.plan;
}
redirNmb->typeNmb.pres = PRSNT_NODEF;
- if (caller_data->rdnis.type == FTDM_TON_INVALID) {
+ if (caller_data->rdnis.type >= FTDM_TON_INVALID) {
redirNmb->typeNmb.val = FTDM_TON_UNKNOWN;
} else {
redirNmb->typeNmb.val = caller_data->rdnis.type;
diff --git a/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c b/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c
index 0ac628a260..c8b8868acd 100644
--- a/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c
+++ b/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c
@@ -35,6 +35,7 @@
* Moises Silva
* David Yat Sin
* Nenad Corbic
+ * Arnaldo Pereira
*
*/
@@ -99,7 +100,8 @@ static struct {
/* a bunch of this stuff should go into the wanpipe_tdm_api_iface.h */
FIO_SPAN_POLL_EVENT_FUNCTION(wanpipe_poll_event);
-FIO_SPAN_NEXT_EVENT_FUNCTION(wanpipe_next_event);
+FIO_SPAN_NEXT_EVENT_FUNCTION(wanpipe_span_next_event);
+FIO_CHANNEL_NEXT_EVENT_FUNCTION(wanpipe_channel_next_event);
/**
* \brief Poll for event on a wanpipe socket
@@ -794,7 +796,7 @@ static void wanpipe_write_stats(ftdm_channel_t *ftdmchan, wp_tdm_api_tx_hdr_t *t
/* we don't test for 80% full in tx since is typically full for voice channels, should we test tx 80% full for D-channels? */
if (ftdmchan->iostats.tx.queue_len >= ftdmchan->iostats.tx.queue_size) {
ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "Tx Queue Full (%d/%d)\n",
- ftdmchan->iostats.rx.queue_len, ftdmchan->iostats.tx.queue_size);
+ ftdmchan->iostats.tx.queue_len, ftdmchan->iostats.tx.queue_size);
ftdm_set_flag(&(ftdmchan->iostats.tx), FTDM_IOSTATS_ERROR_QUEUE_FULL);
} else if (ftdm_test_flag(&(ftdmchan->iostats.tx), FTDM_IOSTATS_ERROR_QUEUE_FULL)){
ftdm_log_chan(ftdmchan, FTDM_LOG_NOTICE, "Tx Queue no longer full (%d/%d)\n",
@@ -861,7 +863,6 @@ static void wanpipe_read_stats(ftdm_channel_t *ftdmchan, wp_tdm_api_rx_hdr_t *rx
ftdmchan->iostats.rx.queue_len, ftdmchan->iostats.rx.queue_size);
ftdm_set_flag(&(ftdmchan->iostats.rx), FTDM_IOSTATS_ERROR_QUEUE_THRES);
} else if (ftdm_test_flag(&(ftdmchan->iostats.rx), FTDM_IOSTATS_ERROR_QUEUE_THRES)){
- /* any reason we have wanpipe_tdm_api_iface.h in ftmod_wanpipe/ dir? */
ftdm_log_chan(ftdmchan, FTDM_LOG_NOTICE, "Rx Queue length reduced 80% threshold (%d/%d)\n",
ftdmchan->iostats.rx.queue_len, ftdmchan->iostats.rx.queue_size);
ftdm_clear_flag(&(ftdmchan->iostats.rx), FTDM_IOSTATS_ERROR_QUEUE_THRES);
@@ -944,7 +945,10 @@ static FIO_WRITE_FUNCTION(wanpipe_write)
if (bsent > 0) {
*datalen = bsent;
if (ftdm_channel_test_feature(ftdmchan, FTDM_CHANNEL_FEATURE_IO_STATS)) {
- wanpipe_write_stats(ftdmchan, &hdrframe);
+ /* BRI cards do not support TX queues for now */
+ if(!FTDM_SPAN_IS_BRI(ftdmchan->span)) {
+ wanpipe_write_stats(ftdmchan, &hdrframe);
+ }
}
return FTDM_SUCCESS;
}
@@ -1181,13 +1185,155 @@ static FIO_GET_ALARMS_FUNCTION(wanpipe_get_alarms)
return FTDM_SUCCESS;
}
+/**
+ * \brief Retrieves an event from a wanpipe channel
+ * \param channel Channel to retrieve event from
+ * \param event FreeTDM event to return
+ * \return Success or failure
+ */
+FIO_CHANNEL_NEXT_EVENT_FUNCTION(wanpipe_channel_next_event)
+{
+ ftdm_status_t status;
+ ftdm_oob_event_t event_id;
+ wanpipe_tdm_api_t tdm_api;
+ ftdm_span_t *span = ftdmchan->span;
+
+ if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_EVENT))
+ ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_EVENT);
+
+ memset(&tdm_api, 0, sizeof(tdm_api));
+ status = sangoma_tdm_read_event(ftdmchan->sockfd, &tdm_api);
+ if (status != FTDM_SUCCESS) {
+ snprintf(span->last_error, sizeof(span->last_error), "%s", strerror(errno));
+ ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Failed to read event from channel: %s\n", strerror(errno));
+ return FTDM_FAIL;
+ }
+
+ ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "read wanpipe event %d\n", tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_type);
+ switch(tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_type) {
+
+ case WP_TDMAPI_EVENT_LINK_STATUS:
+ {
+ switch(tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_link_status) {
+ case WP_TDMAPI_EVENT_LINK_STATUS_CONNECTED:
+ event_id = FTDM_OOB_ALARM_CLEAR;
+ break;
+ default:
+ event_id = FTDM_OOB_ALARM_TRAP;
+ break;
+ };
+ }
+ break;
+
+ case WP_TDMAPI_EVENT_RXHOOK:
+ {
+ if (ftdmchan->type == FTDM_CHAN_TYPE_FXS) {
+ event_id = tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_hook_state & WP_TDMAPI_EVENT_RXHOOK_OFF ? FTDM_OOB_OFFHOOK : FTDM_OOB_ONHOOK;
+ if (event_id == FTDM_OOB_OFFHOOK) {
+ if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_FLASH)) {
+ ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_FLASH);
+ ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_WINK);
+ event_id = FTDM_OOB_FLASH;
+ goto event;
+ } else {
+ ftdm_set_flag_locked(ftdmchan, FTDM_CHANNEL_WINK);
+ }
+ } else {
+ if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_WINK)) {
+ ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_WINK);
+ ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_FLASH);
+ event_id = FTDM_OOB_WINK;
+ goto event;
+ } else {
+ ftdm_set_flag_locked(ftdmchan, FTDM_CHANNEL_FLASH);
+ }
+ }
+ break;
+ } else {
+ wanpipe_tdm_api_t onhook_tdm_api;
+ memset(&onhook_tdm_api, 0, sizeof(onhook_tdm_api));
+ status = sangoma_tdm_txsig_onhook(ftdmchan->sockfd, &onhook_tdm_api);
+ if (status) {
+ snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "ONHOOK Failed");
+ return FTDM_FAIL;
+ }
+ event_id = onhook_tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_hook_state & WP_TDMAPI_EVENT_RXHOOK_OFF ? FTDM_OOB_ONHOOK : FTDM_OOB_NOOP;
+ }
+ }
+ break;
+ case WP_TDMAPI_EVENT_RING_DETECT:
+ {
+ event_id = tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_ring_state == WP_TDMAPI_EVENT_RING_PRESENT ? FTDM_OOB_RING_START : FTDM_OOB_RING_STOP;
+ }
+ break;
+ /*
+ disabled this ones when configuring, we don't need them, do we?
+ case WP_TDMAPI_EVENT_RING_TRIP_DETECT:
+ {
+ event_id = tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_ring_state == WP_TDMAPI_EVENT_RING_PRESENT ? FTDM_OOB_ONHOOK : FTDM_OOB_OFFHOOK;
+ }
+ break;
+ */
+ case WP_TDMAPI_EVENT_RBS:
+ {
+ event_id = FTDM_OOB_CAS_BITS_CHANGE;
+ ftdmchan->rx_cas_bits = wanpipe_swap_bits(tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_rbs_bits);
+ }
+ break;
+ case WP_TDMAPI_EVENT_DTMF:
+ {
+ char tmp_dtmf[2] = { tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_dtmf_digit, 0 };
+ event_id = FTDM_OOB_NOOP;
+
+ if (tmp_dtmf[0] == 'f') {
+ ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Ignoring wanpipe DTMF: %c, fax tones will be passed through!\n", tmp_dtmf[0]);
+ break;
+ }
+
+ if (tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_dtmf_type == WAN_EC_TONE_PRESENT) {
+ ftdm_set_flag_locked(ftdmchan, FTDM_CHANNEL_MUTE);
+ }
+
+ if (tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_dtmf_type == WAN_EC_TONE_STOP) {
+ ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_MUTE);
+ if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_INUSE)) {
+ ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Queuing wanpipe DTMF: %c\n", tmp_dtmf[0]);
+ ftdm_channel_queue_dtmf(ftdmchan, tmp_dtmf);
+ }
+ }
+ }
+ break;
+ case WP_TDMAPI_EVENT_ALARM:
+ {
+ ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Got wanpipe alarms %d\n", tdm_api.wp_tdm_cmd.event.wp_api_event_alarm);
+ event_id = FTDM_OOB_ALARM_TRAP;
+ }
+ break;
+ default:
+ {
+ ftdm_log_chan(ftdmchan, FTDM_LOG_WARNING, "Unhandled wanpipe event %d\n", tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_type);
+ event_id = FTDM_OOB_INVALID;
+ }
+ break;
+ }
+
+event:
+
+ ftdmchan->last_event_time = 0;
+ span->event_header.e_type = FTDM_EVENT_OOB;
+ span->event_header.enum_id = event_id;
+ span->event_header.channel = ftdmchan;
+ *event = &span->event_header;
+ return FTDM_SUCCESS;
+}
+
/**
* \brief Retrieves an event from a wanpipe span
* \param span Span to retrieve event from
* \param event FreeTDM event to return
* \return Success or failure
*/
-FIO_SPAN_NEXT_EVENT_FUNCTION(wanpipe_next_event)
+FIO_SPAN_NEXT_EVENT_FUNCTION(wanpipe_span_next_event)
{
uint32_t i,err;
ftdm_oob_event_t event_id;
@@ -1419,7 +1565,8 @@ static FIO_IO_LOAD_FUNCTION(wanpipe_init)
wanpipe_interface.read = wanpipe_read;
wanpipe_interface.write = wanpipe_write;
wanpipe_interface.poll_event = wanpipe_poll_event;
- wanpipe_interface.next_event = wanpipe_next_event;
+ wanpipe_interface.next_event = wanpipe_span_next_event;
+ wanpipe_interface.channel_next_event = wanpipe_channel_next_event;
wanpipe_interface.channel_destroy = wanpipe_channel_destroy;
wanpipe_interface.get_alarms = wanpipe_get_alarms;
*fio = &wanpipe_interface;
diff --git a/libs/freetdm/src/include/freetdm.h b/libs/freetdm/src/include/freetdm.h
index 45254e817f..41e7f50ed8 100644
--- a/libs/freetdm/src/include/freetdm.h
+++ b/libs/freetdm/src/include/freetdm.h
@@ -351,6 +351,7 @@ typedef struct ftdm_channel_config {
ftdm_chan_type_t type;
float rxgain;
float txgain;
+ uint8_t debugdtmf;
} ftdm_channel_config_t;
/*!
@@ -431,9 +432,38 @@ typedef enum {
FTDM_COMMAND_WINK,
FTDM_COMMAND_ENABLE_PROGRESS_DETECT,
FTDM_COMMAND_DISABLE_PROGRESS_DETECT,
+
+ /*!< Start tracing input and output from channel to the given file */
FTDM_COMMAND_TRACE_INPUT,
FTDM_COMMAND_TRACE_OUTPUT,
+
+ /*!< Stop both Input and Output trace, closing the files */
FTDM_COMMAND_TRACE_END_ALL,
+
+ /*!< Enable DTMF debugging */
+ FTDM_COMMAND_ENABLE_DEBUG_DTMF,
+
+ /*!< Disable DTMF debugging (if not disabled explicitly, it is disabled automatically when calls hangup) */
+ FTDM_COMMAND_DISABLE_DEBUG_DTMF,
+
+ /*!< Start dumping all input to a circular buffer. The size of the circular buffer can be specified, default used otherwise */
+ FTDM_COMMAND_ENABLE_INPUT_DUMP,
+
+ /*!< Stop dumping all input to a circular buffer. */
+ FTDM_COMMAND_DISABLE_INPUT_DUMP,
+
+ /*!< Start dumping all output to a circular buffer. The size of the circular buffer can be specified, default used otherwise */
+ FTDM_COMMAND_ENABLE_OUTPUT_DUMP,
+
+ /*!< Stop dumping all output to a circular buffer. */
+ FTDM_COMMAND_DISABLE_OUTPUT_DUMP,
+
+ /*!< Dump the current input circular buffer to the specified FILE* structure */
+ FTDM_COMMAND_DUMP_INPUT,
+
+ /*!< Dump the current output circular buffer to the specified FILE* structure */
+ FTDM_COMMAND_DUMP_OUTPUT,
+
FTDM_COMMAND_ENABLE_CALLERID_DETECT,
FTDM_COMMAND_DISABLE_CALLERID_DETECT,
FTDM_COMMAND_ENABLE_ECHOCANCEL,
@@ -483,6 +513,7 @@ struct ftdm_memory_handler {
#define FIO_SPAN_GET_SIG_STATUS_ARGS (ftdm_span_t *span, ftdm_signaling_status_t *status)
#define FIO_SPAN_POLL_EVENT_ARGS (ftdm_span_t *span, uint32_t ms, short *poll_events)
#define FIO_SPAN_NEXT_EVENT_ARGS (ftdm_span_t *span, ftdm_event_t **event)
+#define FIO_CHANNEL_NEXT_EVENT_ARGS (ftdm_channel_t *ftdmchan, ftdm_event_t **event)
#define FIO_SIGNAL_CB_ARGS (ftdm_sigmsg_t *sigmsg)
#define FIO_EVENT_CB_ARGS (ftdm_channel_t *ftdmchan, ftdm_event_t *event)
#define FIO_CONFIGURE_SPAN_ARGS (ftdm_span_t *span, const char *str, ftdm_chan_type_t type, char *name, char *number)
@@ -514,6 +545,7 @@ typedef ftdm_status_t (*fio_span_set_sig_status_t) FIO_SPAN_SET_SIG_STATUS_ARGS;
typedef ftdm_status_t (*fio_span_get_sig_status_t) FIO_SPAN_GET_SIG_STATUS_ARGS;
typedef ftdm_status_t (*fio_span_poll_event_t) FIO_SPAN_POLL_EVENT_ARGS ;
typedef ftdm_status_t (*fio_span_next_event_t) FIO_SPAN_NEXT_EVENT_ARGS ;
+typedef ftdm_status_t (*fio_channel_next_event_t) FIO_CHANNEL_NEXT_EVENT_ARGS ;
typedef ftdm_status_t (*fio_signal_cb_t) FIO_SIGNAL_CB_ARGS ;
typedef ftdm_status_t (*fio_event_cb_t) FIO_EVENT_CB_ARGS ;
typedef ftdm_status_t (*fio_configure_span_t) FIO_CONFIGURE_SPAN_ARGS ;
@@ -546,6 +578,7 @@ typedef ftdm_status_t (*fio_api_t) FIO_API_ARGS ;
#define FIO_SPAN_GET_SIG_STATUS_FUNCTION(name) ftdm_status_t name FIO_SPAN_GET_SIG_STATUS_ARGS
#define FIO_SPAN_POLL_EVENT_FUNCTION(name) ftdm_status_t name FIO_SPAN_POLL_EVENT_ARGS
#define FIO_SPAN_NEXT_EVENT_FUNCTION(name) ftdm_status_t name FIO_SPAN_NEXT_EVENT_ARGS
+#define FIO_CHANNEL_NEXT_EVENT_FUNCTION(name) ftdm_status_t name FIO_CHANNEL_NEXT_EVENT_ARGS
#define FIO_SIGNAL_CB_FUNCTION(name) ftdm_status_t name FIO_SIGNAL_CB_ARGS
#define FIO_EVENT_CB_FUNCTION(name) ftdm_status_t name FIO_EVENT_CB_ARGS
#define FIO_CONFIGURE_SPAN_FUNCTION(name) ftdm_status_t name FIO_CONFIGURE_SPAN_ARGS
@@ -584,6 +617,7 @@ struct ftdm_io_interface {
fio_write_t write; /*!< Write data to the channel */
fio_span_poll_event_t poll_event; /*!< Poll for events on the whole span */
fio_span_next_event_t next_event; /*!< Retrieve an event from the span */
+ fio_channel_next_event_t channel_next_event; /*!< Retrieve an event from channel */
fio_api_t api; /*!< Execute a text command */
};
@@ -902,6 +936,23 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_add_to_group(const char* name, ftdm_chann
/*! \brief Remove the channel from a hunt group */
FT_DECLARE(ftdm_status_t) ftdm_channel_remove_from_group(ftdm_group_t* group, ftdm_channel_t* ftdmchan);
+/*!
+ * \brief Retrieves an event from the span
+ *
+ * \note
+ * This function is non-reentrant and not thread-safe.
+ * The event returned may be modified if the function is called again
+ * from a different thread or even the same. It is recommended to
+ * handle events from the same span in a single thread.
+ *
+ * \param ftdmchan The channel to retrieve the event from
+ * \param event Pointer to store the pointer to the event
+ *
+ * \retval FTDM_SUCCESS success (at least one event available)
+ * \retval FTDM_FAIL failure
+ */
+FT_DECLARE(ftdm_status_t) ftdm_channel_read_event(ftdm_channel_t *ftdmchan, ftdm_event_t **event);
+
/*! \brief Find a hunt group by id */
FT_DECLARE(ftdm_status_t) ftdm_group_find(uint32_t id, ftdm_group_t **group);
diff --git a/libs/freetdm/src/include/private/ftdm_core.h b/libs/freetdm/src/include/private/ftdm_core.h
index 7683ec7145..f1058d8e48 100644
--- a/libs/freetdm/src/include/private/ftdm_core.h
+++ b/libs/freetdm/src/include/private/ftdm_core.h
@@ -342,21 +342,24 @@ typedef enum {
FTDM_TYPE_CHANNEL
} ftdm_data_type_t;
-#ifdef FTDM_DEBUG_DTMF
-/* number of bytes for the circular buffer (5 seconds worth of audio) */
-#define DTMF_DEBUG_SIZE 8 * 5000
-/* number of 20ms cycles before timeout and close the debug dtmf file (5 seconds) */
-#define DTMF_DEBUG_TIMEOUT 250
+/* number of bytes for the IO dump circular buffer (5 seconds worth of audio by default) */
+#define FTDM_IO_DUMP_DEFAULT_BUFF_SIZE 8 * 5000
typedef struct {
- FILE *file;
- char buffer[DTMF_DEBUG_SIZE];
+ char *buffer;
+ ftdm_size_t size;
int windex;
int wrapped;
- int closetimeout;
+} ftdm_io_dump_t;
+
+/* number of interval cycles before timeout and close the debug dtmf file (5 seconds if interval is 20) */
+#define DTMF_DEBUG_TIMEOUT 250
+typedef struct {
+ uint8_t enabled;
+ uint8_t requested;
+ FILE *file;
+ int32_t closetimeout;
ftdm_mutex_t *mutex;
} ftdm_dtmf_debug_t;
-#endif
-
typedef struct {
const char *file;
@@ -471,9 +474,9 @@ struct ftdm_channel {
void *user_private;
ftdm_timer_id_t hangup_timer;
ftdm_channel_iostats_t iostats;
-#ifdef FTDM_DEBUG_DTMF
ftdm_dtmf_debug_t dtmfdbg;
-#endif
+ ftdm_io_dump_t rxdump;
+ ftdm_io_dump_t txdump;
};
struct ftdm_span {
diff --git a/libs/freetdm/src/include/private/ftdm_types.h b/libs/freetdm/src/include/private/ftdm_types.h
index f265cb1a3d..db1428c962 100644
--- a/libs/freetdm/src/include/private/ftdm_types.h
+++ b/libs/freetdm/src/include/private/ftdm_types.h
@@ -58,6 +58,7 @@ typedef int ftdm_filehandle_t;
extern "C" {
#endif
+#define FTDM_COMMAND_OBJ_SIZE *((ftdm_size_t *)obj)
#define FTDM_COMMAND_OBJ_INT *((int *)obj)
#define FTDM_COMMAND_OBJ_CHAR_P (char *)obj
#define FTDM_COMMAND_OBJ_FLOAT *(float *)obj
diff --git a/libs/freetdm/src/testsangomaboost.c b/libs/freetdm/src/testsangomaboost.c
index 85b5332635..84ff287830 100644
--- a/libs/freetdm/src/testsangomaboost.c
+++ b/libs/freetdm/src/testsangomaboost.c
@@ -49,7 +49,9 @@
#include
#include
#ifdef __linux__
+#ifndef __USE_BSD
#define __USE_BSD
+#endif
#include
#endif
#include "freetdm.h"
diff --git a/src/include/switch_ivr.h b/src/include/switch_ivr.h
index d277bd030f..da366c5b8d 100644
--- a/src/include/switch_ivr.h
+++ b/src/include/switch_ivr.h
@@ -878,6 +878,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_dmachine_set_realm(switch_ivr_dmachin
SWITCH_DECLARE(switch_status_t) switch_ivr_get_file_handle(switch_core_session_t *session, switch_file_handle_t **fh);
SWITCH_DECLARE(switch_status_t) switch_ivr_release_file_handle(switch_core_session_t *session, switch_file_handle_t **fh);
SWITCH_DECLARE(switch_status_t) switch_ivr_process_fh(switch_core_session_t *session, const char *cmd, switch_file_handle_t *fhp);
+SWITCH_DECLARE(switch_status_t) switch_ivr_insert_file(switch_core_session_t *session, const char *file, const char *insert_file, switch_size_t sample_point);
/** @} */
diff --git a/src/mod/applications/mod_spandsp/mod_spandsp_dsp.c b/src/mod/applications/mod_spandsp/mod_spandsp_dsp.c
index 005924194f..f576b7dd01 100644
--- a/src/mod/applications/mod_spandsp/mod_spandsp_dsp.c
+++ b/src/mod/applications/mod_spandsp/mod_spandsp_dsp.c
@@ -495,7 +495,7 @@ switch_status_t callprogress_detector_stop(switch_core_session_t *session)
switch_channel_t *channel = switch_core_session_get_channel(session);
switch_media_bug_t *bug = switch_channel_get_private(channel, TONE_PRIVATE);
if (bug) {
- switch_core_media_bug_close(&bug);
+ switch_core_media_bug_remove(session, &bug);
switch_channel_set_private(channel, TONE_PRIVATE, NULL);
}
return SWITCH_STATUS_SUCCESS;
diff --git a/src/mod/endpoints/mod_h323/changes.txt b/src/mod/endpoints/mod_h323/changes.txt
index 19aca46dc8..4f75aef8b4 100644
--- a/src/mod/endpoints/mod_h323/changes.txt
+++ b/src/mod/endpoints/mod_h323/changes.txt
@@ -1,3 +1,6 @@
+Adds an extra switch_rtp_destroy or switch_rtp_release_port when a session ends
+ - to make sure the port is returned to FS. thx to Peter Olsson.
+fix issues with Progress message type if pre_answer enabled
fix crashes on FSH323Connection calls in on_hangup routine in different threads.
move PTrace level set to FSH323EndPoint::Initialise
partially apply patch from from Peter Olsson, Remove UnLock() when TryLock() failed and DEBUG_RTP_PACKETS directive.
diff --git a/src/mod/endpoints/mod_h323/mod_h323.cpp b/src/mod/endpoints/mod_h323/mod_h323.cpp
index 142506dd92..74fb6ae11a 100644
--- a/src/mod/endpoints/mod_h323/mod_h323.cpp
+++ b/src/mod/endpoints/mod_h323/mod_h323.cpp
@@ -343,7 +343,7 @@ PString GetH245CodecName(const H323Capability* cap)
}
FSProcess::FSProcess()
- : PLibraryProcess("Test", "mod_h323", 1, 0, AlphaCode, 1)
+ : PLibraryProcess("FreeSWITCH", "mod_h323", 1, 0, AlphaCode, 1)
, m_h323endpoint(NULL){
}
@@ -742,6 +742,14 @@ FSH323Connection::~FSH323Connection()
switch_core_session_unlock_codec_write(m_fsSession);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,"------------->switch_core_session_unlock_codec_write [%p]\n",m_fsSession);
}
+
+ if (tech_pvt->rtp_session) {
+ switch_rtp_destroy(&tech_pvt->rtp_session);
+ tech_pvt->rtp_session = NULL;
+ } else if (m_RTPlocalPort) {
+ switch_rtp_release_port((const char *)m_RTPlocalIP.AsString(), m_RTPlocalPort);
+ }
+
tech_pvt->me = NULL;
// switch_mutex_unlock(tech_pvt->h323_mutex);
// switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,"------------->h323_mutex_unlock\n");
@@ -1148,7 +1156,7 @@ void FSH323Connection::AnsweringCall(AnswerCallResponse response)
if (!mediaWaitForConnect) {
// create a new facility PDU if doing AnswerDeferredWithMedia
H323SignalPDU want245PDU;
- //H225_Progress_UUIE & prog = want245PDU.BuildProgress(*this);
+ want245PDU.BuildProgress(*this);
PBoolean sendPDU = TRUE;
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE,"mediaWaitForConnect = FALSE\n");
/* if (SendFastStartAcknowledge(prog.m_fastStart)){
diff --git a/src/mod/endpoints/mod_khomp/Install/files/khomp.conf.xml b/src/mod/endpoints/mod_khomp/Install/files/khomp.conf.xml
index 45268f304b..79c00516b9 100644
--- a/src/mod/endpoints/mod_khomp/Install/files/khomp.conf.xml
+++ b/src/mod/endpoints/mod_khomp/Install/files/khomp.conf.xml
@@ -95,16 +95,6 @@ should be opened for the channel. Limited to 25ms min, 500ms max.
-->
-
-
-
-
-
-
-
-
-
-
diff --git a/src/mod/endpoints/mod_khomp/Makefile b/src/mod/endpoints/mod_khomp/Makefile
index 94923c7cda..db1a6fe4e4 100644
--- a/src/mod/endpoints/mod_khomp/Makefile
+++ b/src/mod/endpoints/mod_khomp/Makefile
@@ -1,6 +1,9 @@
MODNAME := mod_khomp
VERBOSE := 1
+#FreeSWITCH source PATH is needed:
+# Set FREESWITCH_PATH
+
ifeq ($(strip $(FREESWITCH_PATH)),)
BASE := ../../../../
else
@@ -11,12 +14,12 @@ curr_dir := $(shell pwd)
versions := -DFS_VERSION_MAJOR=$(shell bash $(curr_dir)/tools/getversion.sh "SWITCH_VERSION_MAJOR" $(BASE)) -DFS_VERSION_MINOR=$(shell bash $(curr_dir)/tools/getversion.sh "SWITCH_VERSION_MINOR" $(BASE)) -DFS_VERSION_MICRO=$(shell bash $(curr_dir)/tools/getversion.sh "SWITCH_VERSION_MICRO" $(BASE))
-LOCAL_CFLAGS = -I./ -I./include -I./commons -I./support -D_REENTRANT -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -DK3L_HOSTSYSTEM -DCOMMONS_LIBRARY_USING_FREESWITCH -g -ggdb #-DDEBUG_FLAGS
+LOCAL_CFLAGS = -I./ -I./include -I./commons -I./commons/base -I./support -D_REENTRANT -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -DK3L_HOSTSYSTEM -DCOMMONS_LIBRARY_USING_FREESWITCH -g -ggdb #-DDEBUG_FLAGS
LOCAL_CFLAGS += $(versions)
LOCAL_LDFLAGS = -lk3l
-LOCAL_OBJS = ./commons/k3lapi.o ./commons/k3lutil.o ./commons/config_options.o ./commons/format.o ./commons/strings.o ./commons/ringbuffer.o ./commons/verbose.o ./commons/saved_condition.o ./commons/regex.o ./commons/timer.o ./commons/configurator/configfile.o ./commons/configurator/option.o ./commons/configurator/section.o ./commons/configurator/restriction.o
+LOCAL_OBJS = ./commons/base/k3lapi.o ./commons/base/k3lutil.o ./commons/base/config_options.o ./commons/base/format.o ./commons/base/strings.o ./commons/base/ringbuffer.o ./commons/base/verbose.o ./commons/base/saved_condition.o ./commons/base/regex.o ./commons/base/timer.o ./commons/base/configurator/configfile.o ./commons/base/configurator/option.o ./commons/base/configurator/section.o ./commons/base/configurator/restriction.o ./commons/base/verbose_traits.o
LOCAL_OBJS += ./support/klog-config.o ./support/klog-options.o ./support/config_defaults.o
LOCAL_OBJS += ./src/globals.o ./src/opt.o ./src/frame.o ./src/utils.o ./src/lock.o ./src/spec.o ./src/applications.o ./src/khomp_pvt_fxo.o ./src/khomp_pvt_gsm.o ./src/khomp_pvt_kxe1.o ./src/khomp_pvt_passive.o ./src/khomp_pvt.o ./src/logger.o ./src/cli.o
@@ -27,7 +30,20 @@ conf_file_install = $(sysconfdir)/autoload_configs
include $(BASE)/build/modmake.rules
+local_depend:
+ @if test ! -f $(curr_dir)/commons/base/verbose_traits.hpp || test ! -f $(curr_dir)/commons/base/verbose_traits.cpp ; then \
+ echo "Generating verbose_traits" ;\
+ bash $(curr_dir)/commons/tools/generate-verbose-headers.sh commons/base/ include/k3l.h ;\
+ fi;
+
depend_install:
+ @if test "w`kserver --version 2>/dev/null | grep 2.1`" == "w" ; then \
+ echo "###############################################################################" ;\
+ echo "Install k3l from KHOMP." ;\
+ echo "Run: $(curr_dir)/tools/getk3l.sh" ;\
+ echo "###############################################################################" ;\
+ exit 1;\
+ fi;
@echo "Copy $(conf_file_name)"
@if test -d $(conf_file_install) ; then \
if test -f $(conf_file_dir)/$(conf_file_name) ; then \
diff --git a/src/mod/endpoints/mod_khomp/commons/atomic.hpp b/src/mod/endpoints/mod_khomp/commons/base/atomic.hpp
similarity index 90%
rename from src/mod/endpoints/mod_khomp/commons/atomic.hpp
rename to src/mod/endpoints/mod_khomp/commons/base/atomic.hpp
index daa598c9b4..02278b390c 100644
--- a/src/mod/endpoints/mod_khomp/commons/atomic.hpp
+++ b/src/mod/endpoints/mod_khomp/commons/base/atomic.hpp
@@ -64,17 +64,31 @@ namespace Atomic
PunnedType pval; pval.valtype = VAL; \
unsigned long long vexp = *(pexp.podtype); \
unsigned long long vval = *(pval.podtype); \
- unsigned long long res = (unsigned long long)exp; \
+ unsigned long vval32 = (unsigned long)vval; \
unsigned char chg = 0; \
- asm volatile("lock; cmpxchg8b %2; sete %1;" \
+ asm volatile( \
+ "xchgl %%ebx, %4;" \
+ "lock; cmpxchg8b %2; sete %1;" \
+ "movl %4, %%ebx; " \
: "+A" (vexp), /* 0 (result) */ \
- "=q" (chg) /* 1 */ \
+ "=c" (chg) /* 1 */ \
: "m" (*(unsigned char**)(PTR)), /* 2 */ \
- "b" ((unsigned long)(vval)), \
- "c" ((unsigned long)(vval >> 32))); \
+ "c" ((unsigned long)(vval >> 32)), \
+ "m" (vval32)); \
*(pexp.podtype) = vexp; \
return (chg != 0 ? true : false);
+// "movl %%ecx, %4;"
+//
+// "m" (*((unsigned long*)(*(pval.podtype)))),
+// "m" ((unsigned long)(vval >> 32))
+//
+// "m" (*((unsigned long*)(&vval))),
+// "m" ((unsigned long)(vval >> 32))
+//
+// unsigned long long vval = *(pval.podtype);
+// unsigned long long res = (unsigned long long)exp;
+//
// Types used for making CMPXCHG instructions independent from base type.
template < typename ValType, typename PodType >
diff --git a/src/mod/endpoints/mod_khomp/commons/config_commons.hpp b/src/mod/endpoints/mod_khomp/commons/base/config_commons.hpp
similarity index 92%
rename from src/mod/endpoints/mod_khomp/commons/config_commons.hpp
rename to src/mod/endpoints/mod_khomp/commons/base/config_commons.hpp
index de8f327df4..dad16f4e92 100644
--- a/src/mod/endpoints/mod_khomp/commons/config_commons.hpp
+++ b/src/mod/endpoints/mod_khomp/commons/base/config_commons.hpp
@@ -63,7 +63,12 @@
#error Unknown implementation selected. Please define COMMONS_LIBRARY_USING_* correctly.
#endif
-#define COMMONS_INCLUDE(file)
+#define COMMONS_INCLUDE(file)
+
+#define COMMONS_VERSION_MAJOR 1
+#define COMMONS_VERSION_MINOR 1
+
+#define COMMONS_AT_LEAST(x,y) \
+ (COMMONS_VERSION_MAJOR > x || (COMMONS_VERSION_MAJOR == x && COMMONS_VERSION_MINOR >= y))
#endif /* _CONFIG_COMMONS_HPP_ */
-
diff --git a/src/mod/endpoints/mod_khomp/commons/base/config_options.cpp b/src/mod/endpoints/mod_khomp/commons/base/config_options.cpp
new file mode 100644
index 0000000000..7412b4b1a0
--- /dev/null
+++ b/src/mod/endpoints/mod_khomp/commons/base/config_options.cpp
@@ -0,0 +1,302 @@
+/*
+ KHOMP generic endpoint/channel library.
+ Copyright (C) 2007-2009 Khomp Ind. & Com.
+
+ The contents of this file are subject to the Mozilla Public License Version 1.1
+ (the "License"); you may not use this file except in compliance with the
+ License. You may obtain a copy of the License at http://www.mozilla.org/MPL/
+
+ Software distributed under the License is distributed on an "AS IS" basis,
+ WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
+ the specific language governing rights and limitations under the License.
+
+ Alternatively, the contents of this file may be used under the terms of the
+ "GNU Lesser General Public License 2.1" license (the “LGPL" License), in which
+ case the provisions of "LGPL License" are applicable instead of those above.
+
+ If you wish to allow use of your version of this file only under the terms of
+ the LGPL License and not to allow others to use your version of this file under
+ the MPL, indicate your decision by deleting the provisions above and replace them
+ with the notice and other provisions required by the LGPL License. If you do not
+ delete the provisions above, a recipient may use your version of this file under
+ either the MPL or the LGPL License.
+
+ The LGPL header follows below:
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this library; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+*/
+
+#include
+
+void Config::Restriction::checkRange(const std::string & name, const SIntType value, const Range < SIntType > & range)
+{
+ if (value < range.minimum)
+ throw Failure(STG(FMT("value '%d' out-of-range for option '%s' (too low)") % value % name));
+
+ if (value > range.maximum)
+ throw Failure(STG(FMT("value '%d' out-of-range for option '%s' (too high)") % value % name));
+
+ if (((value - range.minimum) % range.step) != 0)
+ throw Failure(STG(FMT("value '%d' out-of-range for option '%s' (outside allowed step)") % value % name));
+}
+
+void Config::Restriction::checkRange(const std::string & name, const UIntType value, const Range < UIntType > & range)
+{
+ if (value < range.minimum)
+ throw Failure(STG(FMT("value '%d' out-of-range for option '%s' (too low)") % value % name));
+
+ if (value > range.maximum)
+ throw Failure(STG(FMT("value '%d' out-of-range for option '%s' (too high)") % value % name));
+
+ if (((value - range.minimum) % range.step) != 0)
+ throw Failure(STG(FMT("value '%d' out-of-range for option '%s' (outside allowed step)") % value % name));
+}
+
+void Config::Restriction::checkStringSet(const std::string & name, const StringType & value, const StringSet & allowed)
+{
+ if (allowed.empty())
+ return;
+
+ if (allowed.find(value) != allowed.end())
+ return;
+
+ std::string strlist;
+
+ for (StringSet::const_iterator i = allowed.begin(); i != allowed.end(); i++)
+ {
+ strlist += " '";
+ strlist += (*i);
+ strlist += "'";
+ }
+
+ throw Failure(STG(FMT("value '%s' not allowed for option '%s' (allowed values:%s)")
+ % value % name % strlist));
+}
+
+Config::Option::Option(std::string name, Config::Option::StringMemberType value, const StringType defvalue, StringSet & allowed, bool listme)
+: _myname(name), _option(InnerStringType(name, value, defvalue, allowed)), _listme(listme), _values(NULL)
+{};
+
+Config::Option::Option(std::string name, Config::Option::StringMemberType value, const StringType defvalue, bool listme)
+: _myname(name), _option(InnerStringType(name, value, defvalue)), _listme(listme), _values(NULL)
+{};
+
+Config::Option::Option(std::string name, Config::Option::BooleanMemberType value, const BooleanType defvalue, bool listme)
+: _myname(name), _option(InnerBooleanType(name, value, defvalue)), _listme(listme), _values(NULL)
+{};
+
+Config::Option::Option(std::string name, Config::Option::SIntMemberType value, const SIntType defvalue,
+ SIntType min, SIntType max, SIntType step, bool listme)
+: _myname(name), _option(InnerSIntType(name, value, defvalue, min, max, step)), _listme(listme), _values(NULL)
+{};
+
+Config::Option::Option(std::string name, Config::Option::UIntMemberType value, const UIntType defvalue,
+ UIntType min, UIntType max, UIntType step, bool listme)
+: _myname(name), _option(InnerUIntType(name, value, defvalue, min, max, step)), _listme(listme), _values(NULL)
+{};
+
+Config::Option::Option(const Config::Option & o)
+: _myname(o._myname), _option(o._option), _listme(o._listme), _values(o._values)
+{};
+
+Config::Option::Option(std::string name, Config::Option::FunctionMemberType value, const StringType defvalue, StringSet & allowed, bool listme)
+: _myname(name), _option(InnerFunctionType(name, value, defvalue, allowed)), _listme(listme), _values(NULL)
+{};
+
+Config::Option::Option(std::string name, Config::Option::FunctionMemberType value, const StringType defvalue, bool listme)
+: _myname(name), _option(InnerFunctionType(name, value, defvalue)), _listme(listme), _values(NULL)
+{};
+
+Config::Option::~Option(void)
+{
+ if (_values)
+ {
+ for (unsigned int i = 0; _values[i] != NULL; i++)
+ delete _values[i];
+
+ delete[] _values;
+ _values = NULL;
+ }
+};
+
+const char ** Config::Option::values(void)
+{
+ if (_values != NULL)
+ return _values;
+
+ /**/ if (_option.check())
+ {
+ _values = new const char*[3];
+
+ _values[0] = strdup("yes");
+ _values[1] = strdup("no");
+ _values[2] = NULL;
+
+ }
+ else if (_option.check())
+ {
+ const InnerSIntType & tmp = _option.get();
+
+ unsigned int count = ((tmp._range.maximum - tmp._range.minimum) / tmp._range.step) + 1;
+ unsigned int index = 0;
+
+ _values = new const char*[count + 1];
+
+ for (SIntType i = tmp._range.minimum; i <= tmp._range.maximum; i += tmp._range.step, ++index)
+ _values[index] = strdup(STG(FMT("%d") % i).c_str());
+
+ _values[index] = NULL;
+ }
+ else if (_option.check())
+ {
+ const InnerUIntType & tmp = _option.get();
+
+ unsigned int count = ((tmp._range.maximum - tmp._range.minimum) / tmp._range.step) + 1;
+ unsigned int index = 0;
+
+ _values = new const char*[count + 1];
+
+ for (UIntType i = tmp._range.minimum; i <= tmp._range.maximum; i += tmp._range.step, ++index)
+ _values[index] = strdup(STG(FMT("%d") % i).c_str());
+
+ _values[index] = NULL;
+ }
+ else if (_option.check())
+ {
+ const InnerStringType & tmp = _option.get();
+
+ _values = new const char*[ tmp._allowed.size() + 1 ];
+
+ unsigned int index = 0;
+
+ for (StringSet::iterator i = tmp._allowed.begin(); i != tmp._allowed.end(); ++i, ++index)
+ _values[index] = strdup((*i).c_str());
+
+ _values[index] = NULL;
+ }
+ else if (_option.check())
+ {
+ const InnerFunctionType & tmp = _option.get();
+
+ _values = new const char*[ tmp._allowed.size() + 1 ];
+
+ unsigned int index = 0;
+
+ for (StringSet::iterator i = tmp._allowed.begin(); i != tmp._allowed.end(); ++i, ++index)
+ _values[index] = strdup((*i).c_str());
+
+ _values[index] = NULL;
+ }
+ else
+ {
+ throw Failure(STG(FMT("values() not implemented for type used in option '%s'") % _myname));
+ }
+
+ return _values;
+};
+
+/*********************************/
+
+Config::Options::Options(void)
+: _values(NULL)
+{};
+
+Config::Options::~Options()
+{
+ if (_values)
+ {
+ for (unsigned int i = 0; _values[i] != NULL; i++)
+ free((void*)(_values[i]));
+
+ delete[] _values;
+ _values = NULL;
+ }
+};
+
+bool Config::Options::add(Config::Option option)
+{
+ std::pair ret = _map.insert(OptionPair(option.name(), option));
+
+ return ret.second;
+}
+
+bool Config::Options::synonym(std::string equiv_opt, std::string main_opt)
+{
+ std::pair ret = _syn_map.insert(SynOptionPair(equiv_opt, main_opt));
+
+ return ret.second;
+}
+
+Config::StringSet Config::Options::options(void)
+{
+ StringSet res;
+
+ for (OptionMap::iterator i = _map.begin(); i != _map.end(); i++)
+ res.insert(i->first);
+
+ return res;
+}
+
+const char ** Config::Options::values(const char * name)
+{
+ OptionMap::iterator iter = find_option(name);
+
+ if (iter == _map.end())
+ throw Failure(STG(FMT("unknown option '%s'") % name));
+
+ return iter->second.values();
+}
+
+const char ** Config::Options::values(void)
+{
+ if (_values != NULL)
+ return _values;
+
+ unsigned int count = 0;
+
+ for (OptionMap::iterator i = _map.begin(); i != _map.end(); ++i)
+ if (i->second.listme())
+ ++count;
+
+ _values = new const char*[ count + 1 ];
+
+ unsigned int index = 0;
+
+ for (OptionMap::iterator i = _map.begin(); i != _map.end(); ++i)
+ {
+ if (i->second.listme())
+ {
+ _values[index] = strdup(i->first.c_str());
+ ++index;
+ }
+ }
+
+ _values[index] = NULL;
+
+ return _values;
+}
+
+Config::Options::OptionMap::iterator Config::Options::find_option(std::string name)
+{
+ SynOptionMap::iterator syn_iter = _syn_map.find(name);
+
+ if (syn_iter != _syn_map.end())
+ name = syn_iter->second;
+
+ OptionMap::iterator iter = _map.find(name);
+
+ return iter;
+}
diff --git a/src/mod/endpoints/mod_khomp/commons/base/config_options.hpp b/src/mod/endpoints/mod_khomp/commons/base/config_options.hpp
new file mode 100644
index 0000000000..59e381f893
--- /dev/null
+++ b/src/mod/endpoints/mod_khomp/commons/base/config_options.hpp
@@ -0,0 +1,772 @@
+/*
+ KHOMP generic endpoint/channel library.
+ Copyright (C) 2007-2009 Khomp Ind. & Com.
+
+ The contents of this file are subject to the Mozilla Public License Version 1.1
+ (the "License"); you may not use this file except in compliance with the
+ License. You may obtain a copy of the License at http://www.mozilla.org/MPL/
+
+ Software distributed under the License is distributed on an "AS IS" basis,
+ WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
+ the specific language governing rights and limitations under the License.
+
+ Alternatively, the contents of this file may be used under the terms of the
+ "GNU Lesser General Public License 2.1" license (the “LGPL" License), in which
+ case the provisions of "LGPL License" are applicable instead of those above.
+
+ If you wish to allow use of your version of this file only under the terms of
+ the LGPL License and not to allow others to use your version of this file under
+ the MPL, indicate your decision by deleting the provisions above and replace them
+ with the notice and other provisions required by the LGPL License. If you do not
+ delete the provisions above, a recipient may use your version of this file under
+ either the MPL or the LGPL License.
+
+ The LGPL header follows below:
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this library; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+*/
+
+#ifndef _CONFIG_OPTIONS_HPP_
+#define _CONFIG_OPTIONS_HPP_
+
+#include
+#include