diff --git a/libs/freetdm/CMakeLists.txt b/libs/freetdm/CMakeLists.txt new file mode 100644 index 0000000000..24cbf7c9eb --- /dev/null +++ b/libs/freetdm/CMakeLists.txt @@ -0,0 +1,244 @@ +# +# cmake file that generate build files for freetdm. +# this automatically includes the tests and also +# mod_freetdm +# +# Arnaldo M Pereira +# +CMAKE_MINIMUM_REQUIRED(VERSION 2.6) +PROJECT(freetdm) + +ADD_SUBDIRECTORY(sample) +ADD_SUBDIRECTORY(mod_freetdm) + +# includes +SET(freetdm_INCLUDES + ${PROJECT_SOURCE_DIR}/src/include + ${PROJECT_SOURCE_DIR}/src/isdn/include + ${PROJECT_SOURCE_DIR}/src/include/private + ${PROJECT_SOURCE_DIR}/src/ftmod/ftmod_sangoma_boost +) +INCLUDE_DIRECTORIES(${freetdm_INCLUDES}) +LINK_DIRECTORIES(${freetdm_BINARY_DIR}) + +# optional includes +IF(DEFINED SNGSS7) + SET(freetdm_INCLUDES ${freetdm_INCLUDES} /usr/include/sng_ss7) +ENDIF(DEFINED SNGSS7) + +IF(DEFINED SNGISDN) + SET(freetdm_INCLUDES ${freetdm_INCLUDES} /usr/include/sng_isdn) +ENDIF(DEFINED SNGISDN) + +# definitions / CFLAGS +ADD_DEFINITIONS(-DFTDM_CONFIG_DIR="/FIXME" -DFTDM_MOD_DIR="/FIXME") +IF(DEFINED WIN32) + ADD_DEFINITIONS(-DFREETDM_EXPORTS -DTELETONE_EXPORTS -DMOD_EXPORTS -DDLL_EXPORTS) +ENDIF(DEFINED WIN32) +IF(DEFINED SNGISDN) + SET(freetdm_INCLUDES ${freetdm_INCLUDES} /usr/include/sng_isdn) +ENDIF(DEFINED SNGISDN) + +# lib sources +SET(freetdm_SOURCES + ${PROJECT_SOURCE_DIR}/src/hashtable.c + ${PROJECT_SOURCE_DIR}/src/hashtable_itr.c + ${PROJECT_SOURCE_DIR}/src/ftdm_io.c + ${PROJECT_SOURCE_DIR}/src/ftdm_queue.c + ${PROJECT_SOURCE_DIR}/src/ftdm_sched.c + ${PROJECT_SOURCE_DIR}/src/ftdm_call_utils.c + ${PROJECT_SOURCE_DIR}/src/ftdm_config.c + ${PROJECT_SOURCE_DIR}/src/ftdm_callerid.c + ${PROJECT_SOURCE_DIR}/src/fsk.c + ${PROJECT_SOURCE_DIR}/src/uart.c + ${PROJECT_SOURCE_DIR}/src/g711.c + ${PROJECT_SOURCE_DIR}/src/libteletone_detect.c + ${PROJECT_SOURCE_DIR}/src/libteletone_generate.c + ${PROJECT_SOURCE_DIR}/src/ftdm_buffer.c + ${PROJECT_SOURCE_DIR}/src/ftdm_threadmutex.c + ${PROJECT_SOURCE_DIR}/src/ftdm_dso.c + ${PROJECT_SOURCE_DIR}/src/ftdm_cpu_monitor.c +) + +# libfreetdm.so +ADD_LIBRARY(${PROJECT_NAME} SHARED ${freetdm_SOURCES}) + +IF(NOT DEFINED WIN32) + TARGET_LINK_LIBRARIES(${PROJECT_NAME} m pthread dl) +ENDIF(NOT DEFINED WIN32) + +REMOVE_DEFINITIONS(-DLL_EXPORTS) + +# tools & tests +IF(NOT DEFINED WIN32) + FOREACH(TOOL testtones testpri testr2 testapp testcid) + ADD_EXECUTABLE(${TOOL} ${PROJECT_SOURCE_DIR}/src/${TOOL}.c) + TARGET_LINK_LIBRARIES(${TOOL} -l${PROJECT_NAME}) + ADD_DEPENDENCIES(${TOOL} ${PROJECT_NAME}) + ENDFOREACH(TOOL) + + ADD_EXECUTABLE(detect_dtmf + ${PROJECT_SOURCE_DIR}/src/detect_dtmf.c + ${PROJECT_SOURCE_DIR}/src/libteletone_detect.c + ) + TARGET_LINK_LIBRARIES(detect_dtmf ${PROJECT_NAME}) + ADD_DEPENDENCIES(detect_dtmf ${PROJECT_NAME}) + + ADD_EXECUTABLE(detect_tones + ${PROJECT_SOURCE_DIR}/src/detect_tones.c + ${PROJECT_SOURCE_DIR}/src/libteletone_detect.c + ) + TARGET_LINK_LIBRARIES(detect_tones ${PROJECT_NAME}) + ADD_DEPENDENCIES(detect_tones ${PROJECT_NAME}) + + ADD_EXECUTABLE(testanalog + ${PROJECT_SOURCE_DIR}/src/testanalog.c + ) + TARGET_LINK_LIBRARIES(testanalog -l${PROJECT_NAME}) + ADD_DEPENDENCIES(testanalog ${PROJECT_NAME}) + + # optional tests/tools + IF(HAVE_SCTP) + ADD_EXECUTABLE(testboost src/testboost.c) + TARGET_LINK_LIBRARIES(testboost ${PROJECT_NAME}) + ENDIF(HAVE_SCTP) +ELSE(NOT DEFINED WIN32) + MESSAGE(WARNING "Not building tools/tests on WIN32 yet.") +ENDIF(NOT DEFINED WIN32) + +# +# ftmod modules +# +SET(ftmod_DIR ${PROJECT_SOURCE_DIR}/src/ftmod) + +IF(DEFINED WIN32) + SET(ftmod_ADDITIONAL_SOURCES + ${PROJECT_SOURCE_DIR}/src/ftdm_io.c + ${PROJECT_SOURCE_DIR}/src/ftdm_config.c + ${PROJECT_SOURCE_DIR}/src/ftdm_queue.c + ${PROJECT_SOURCE_DIR}/src/g711.c + ) + SET(module_list skel analog analog_em) +ELSE(DEFINED WIN32) + SET(module_list skel analog analog_em zt) +ENDIF(DEFINED WIN32) + +# build default modules +FOREACH(module ${module_list}) + ADD_LIBRARY(ftmod_${module} MODULE ${ftmod_DIR}/ftmod_${module}/ftmod_${module}.c ${ftmod_ADDITIONAL_SOURCES}) + TARGET_LINK_LIBRARIES(ftmod_${module} ${PROJECT_NAME}) +ENDFOREACH(module) + +# build isdn ftmod +IF(DEFINED BUILD_FTMOD_ISDN) + SET(ftmod_isdn_SOURCES + ${PROJECT_SOURCE_DIR}/src/isdn/EuroISDNStateNT.c + ${PROJECT_SOURCE_DIR}/src/isdn/EuroISDNStateTE.c + ${PROJECT_SOURCE_DIR}/src/isdn/mfifo.c + ${PROJECT_SOURCE_DIR}/src/isdn/Q921.c + ${PROJECT_SOURCE_DIR}/src/isdn/Q931api.c + ${PROJECT_SOURCE_DIR}/src/isdn/Q931.c + ${PROJECT_SOURCE_DIR}/src/isdn/Q931ie.c + ${PROJECT_SOURCE_DIR}/src/isdn/Q931mes.c + ${PROJECT_SOURCE_DIR}/src/isdn/Q931StateNT.c + ${PROJECT_SOURCE_DIR}/src/isdn/Q931StateTE.c + ${PROJECT_SOURCE_DIR}/src/isdn/nationalmes.c + ${PROJECT_SOURCE_DIR}/src/isdn/nationalStateNT.c + ${PROJECT_SOURCE_DIR}/src/isdn/nationalStateTE.c + ${PROJECT_SOURCE_DIR}/src/isdn/DMSmes.c + ${PROJECT_SOURCE_DIR}/src/isdn/DMSStateNT.c + ${PROJECT_SOURCE_DIR}/src/isdn/DMSStateTE.c + ${PROJECT_SOURCE_DIR}/src/isdn/5ESSmes.c + ${PROJECT_SOURCE_DIR}/src/isdn/5ESSStateNT.c + ${PROJECT_SOURCE_DIR}/src/isdn/5ESSStateTE.c + ${PROJECT_SOURCE_DIR}/src/isdn/Q932mes.c + ${ftmod_DIR}/ftmod_isdn/ftmod_isdn.c + ) + IF(NOT DEFINED WIN32) + ADD_DEFINITIONS(-D_GNU_SOURCE) + ENDIF(NOT DEFINED WIN32) + ADD_LIBRARY(ftmod_isdn MODULE ${ftmod_isdn_SOURCES}) + TARGET_LINK_LIBRARIES(ftmod_isdn ${PROJECT_NAME}) +ENDIF(DEFINED BUILD_FTMOD_ISDN) + +# from now on, optionals +IF(DEFINED LIBSANGOMA) + ADD_LIBRARY(ftmod_wanpipe MODULE ${ftmod_DIR}/ftmod_wanpipe/ftmod_wanpipe.c) + IF(DEFINED WIN32) + MESSAGE(WARNING "FIXME: look for wanpipe headers on win32") + ELSE(DEFINED WIN32) + ADD_DEFINITIONS(-D__LINUX__) + INCLUDE_DIRECTORIES(/usr/include/wanpipe) + ENDIF(DEFINED WIN32) + TARGET_LINK_LIBRARIES(ftmod_wanpipe sangoma ${PROJECT_NAME}) +ENDIF(DEFINED LIBSANGOMA) + +IF(DEFINED HAVE_SCTP) + ADD_LIBRARY(ftmod_sangoma_boost MODULE + ${ftmod_DIR}/ftmod_sangoma_boost/sangoma_boost_client.c + ${ftmod_DIR}/ftmod_sangoma_boost/ftmod_sangoma_boost.c + ) + TARGET_LINK_LIBRARIES(ftmod_sangoma_boost ${PROJECT_NAME}) +ENDIF(DEFINED HAVE_SCTP) + +IF(DEFINED LIBPRI) + ADD_LIBRARY(ftmod_libpri MODULE + ${ftmod_DIR}/ftmod_libpri/libpri_client.c + ${ftmod_DIR}/ftmod_libpri/ftmod_libpri.c + ) + TARGET_LINK_LIBRARIES(ftmod_libpri ${PROJECT_NAME}) +ENDIF(DEFINED LIBPRI) + +IF(DEFINED PRITAP) + ADD_LIBRARY(ftmod_pritap MODULE + ${ftmod_DIR}/ftmod_pritap/pritap_client.c + ${ftmod_DIR}/ftmod_pritap/ftmod_pritap.c + ) + TARGET_LINK_LIBRARIES(ftmod_pritap ${PROJECT_NAME} pri) +ENDIF(DEFINED PRITAP) + +IF(DEFINED SNGSS7) + ADD_LIBRARY(ftmod_sangoma_ss7 MODULE + ${ftmod_DIR}/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c + ${ftmod_DIR}/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c + ${ftmod_DIR}/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c + ${ftmod_DIR}/ftmod_sangoma_ss7/ftmod_sangoma_ss7_in.c + ${ftmod_DIR}/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c + ${ftmod_DIR}/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cntrl.c + ${ftmod_DIR}/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c + ${ftmod_DIR}/ftmod_sangoma_ss7/ftmod_sangoma_ss7_timers.c + ${ftmod_DIR}/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c + ${ftmod_DIR}/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cfg.c + ${ftmod_DIR}/ftmod_sangoma_ss7/ftmod_sangoma_ss7_sta.c + ${ftmod_DIR}/ftmod_sangoma_ss7/ftmod_sangoma_ss7_sts.c + ${ftmod_DIR}/ftmod_sangoma_ss7/ftmod_sangoma_ss7_logger.c + ) + IF(NOT DEFINED WIN32) + ADD_DEFINITIONS(-D_GNU_SOURCE) + ENDIF(NOT DEFINED WIN32) + TARGET_LINK_LIBRARIES(ftmod_sangoma_ss7 ${PROJECT_NAME} sng_ss7) +ENDIF(DEFINED SNGSS7) + +IF(DEFINED SNGISDN) + ADD_LIBRARY(ftmod_sangoma_isdn MODULE + ${ftmod_DIR}/ftmod_sangoma_isdn/ftmod_sangoma_isdn.c + ${ftmod_DIR}/ftmod_sangoma_isdn/ftmod_sangoma_isdn_cfg.c + ${ftmod_DIR}/ftmod_sangoma_isdn/ftmod_sangoma_isdn_cntrl.c + ${ftmod_DIR}/ftmod_sangoma_isdn/ftmod_sangoma_isdn_trace.c + ${ftmod_DIR}/ftmod_sangoma_isdn/ftmod_sangoma_isdn_support.c + ${ftmod_DIR}/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_cntrl.c + ${ftmod_DIR}/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_cfg.c + ${ftmod_DIR}/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_rcv.c + ${ftmod_DIR}/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_hndl.c + ${ftmod_DIR}/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_out.c + ) + IF(NOT DEFINED WIN32) + ADD_DEFINITIONS(-D_GNU_SOURCE) + ENDIF(NOT DEFINED WIN32) + TARGET_LINK_LIBRARIES(ftmod_sangoma_isdn ${PROJECT_NAME} sng_isdn) +ENDIF(DEFINED SNGISDN) + +IF(DEFINED OPENR2) + ADD_LIBRARY(ftmod_r2 MODULE ${ftmod_DIR}/ftmod_r2/ftmod_r2.c) + TARGET_LINK_LIBRARIES(ftmod_r2 ${PROJECT_NAME} openr2) +ENDIF(DEFINED OPENR2) diff --git a/libs/freetdm/cyginstall.sh b/libs/freetdm/cyginstall.sh index 93ba624156..9d486b7dce 100644 --- a/libs/freetdm/cyginstall.sh +++ b/libs/freetdm/cyginstall.sh @@ -7,7 +7,7 @@ cp Debug/mod/*.dll $fsdir/Debug/mod/ cp mod_freetdm/Debug/*.pdb $fsdir/Debug/mod/ cp Debug/*.dll $fsdir/Debug/ cp Debug/*.pdb $fsdir/Debug/ -cp Debug/testsangomaboost.exe $fsdir/Debug/ +#cp Debug/testsangomaboost.exe $fsdir/Debug/ echo "FRIENDLY REMINDER: RECOMPILE ftmod_wanpipe WHENEVER YOU INSTALL NEW DRIVERS" set +x diff --git a/libs/freetdm/freetdm.2008.sln b/libs/freetdm/freetdm.2008.sln index 66ea2920a2..f059d941d3 100644 --- a/libs/freetdm/freetdm.2008.sln +++ b/libs/freetdm/freetdm.2008.sln @@ -58,6 +58,13 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testsangomaboost", "msvc\te {93B8812C-3EC4-4F78-8970-FFBFC99E167D} = {93B8812C-3EC4-4F78-8970-FFBFC99E167D} EndProjectSection EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ftmod_sangoma_isdn", "src\ftmod\ftmod_sangoma_isdn\ftmod_sangoma_isdn.2008.vcproj", "{B2AF4EA6-0CD7-4529-9EB5-5AF43DB90395}" + ProjectSection(ProjectDependencies) = postProject + {93B8812C-3EC4-4F78-8970-FFBFC99E167D} = {93B8812C-3EC4-4F78-8970-FFBFC99E167D} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ftmod_r2", "src\ftmod\ftmod_r2\ftmod_r2.2008.vcproj", "{08C3EA27-A51D-47F8-B47D-B189C649CF30}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 @@ -119,6 +126,7 @@ Global {E886B4D5-AB4F-4092-B8F4-3B06E1E462EF}.Release|Win32.ActiveCfg = Release|Win32 {E886B4D5-AB4F-4092-B8F4-3B06E1E462EF}.Release|x64.ActiveCfg = Release|x64 {1A145EE9-BBD8-45E5-98CD-EB4BE99E1DCD}.Debug|Win32.ActiveCfg = Debug|Win32 + {1A145EE9-BBD8-45E5-98CD-EB4BE99E1DCD}.Debug|Win32.Build.0 = Debug|Win32 {1A145EE9-BBD8-45E5-98CD-EB4BE99E1DCD}.Debug|x64.ActiveCfg = Debug|x64 {1A145EE9-BBD8-45E5-98CD-EB4BE99E1DCD}.Release|Win32.ActiveCfg = Release|Win32 {1A145EE9-BBD8-45E5-98CD-EB4BE99E1DCD}.Release|x64.ActiveCfg = Release|x64 @@ -146,6 +154,18 @@ Global {0DA69C18-4FA1-4E8C-89CE-12498637C5BE}.Release|Win32.Build.0 = Release|Win32 {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 HideSolutionNode = FALSE diff --git a/libs/freetdm/mod_freetdm/CMakeLists.txt b/libs/freetdm/mod_freetdm/CMakeLists.txt new file mode 100644 index 0000000000..25847e713f --- /dev/null +++ b/libs/freetdm/mod_freetdm/CMakeLists.txt @@ -0,0 +1,32 @@ +# +# Arnaldo M Pereira +# +CMAKE_MINIMUM_REQUIRED(VERSION 2.6) +PROJECT(mod_freetdm) + +IF(NOT DEFINED WIN32) + ADD_DEFINITIONS(-g -O2 -ffast-math -Wall -Werror -Wunused-variable -Wwrite-strings -Wstrict-prototypes -Wmissing-prototypes -O0 -g -ggdb -DPACKAGE_NAME=\"freetdm\" -DPACKAGE_TARNAME=\"freetdm\" -DPACKAGE_VERSION=\"pre-alpha\" -DPACKAGE_STRING=\"freetdm\ pre-alpha\" -DPACKAGE_BUGREPORT=\"bugs@freeswitch.org\" -DPACKAGE_URL=\"\" -DPACKAGE=\"libfreetdm\" -DVERSION=\"0.1\" -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DHAVE_DLFCN_H=1 -DLT_OBJDIR=\".libs/\" -DHAVE_LIBDL=1 -DHAVE_LIBPTHREAD=1 -DHAVE_LIBM=1 -DSIZEOF_LONG=8 -DHAVE_NETINET_SCTP_H=1 -DHAVE_NETDB_H=1 -DHAVE_SYS_SELECT_H=1 -DHAVE_GETHOSTBYNAME_R=1) # -DDEBUG=/\*\*/) +ENDIF(NOT DEFINED WIN32) + +# includes +SET(mod_freetdm_INCLUDES + ${PROJECT_SOURCE_DIR}/../src/include + ${PROJECT_SOURCE_DIR}/../src/isdn/include + ${PROJECT_SOURCE_DIR}/../../libteletone/src + ${PROJECT_SOURCE_DIR}/../../../src/include +) +INCLUDE_DIRECTORIES(${mod_freetdm_INCLUDES}) + +LINK_DIRECTORIES(${PROJECT_SOURCE_DIR}/..) +ADD_LIBRARY(${PROJECT_NAME} SHARED mod_freetdm.c) +TARGET_LINK_LIBRARIES(${PROJECT_NAME} freetdm -fPIC -Werror -fvisibility=hidden) + +IF(DEFINED WIN32) + SET(EXT lib) +ELSE(DEFINED WIN32) + SET(EXT so) +ENDIF(DEFINED WIN32) + +ADD_CUSTOM_COMMAND(TARGET ${PROJECT_NAME} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E rename lib${PROJECT_NAME}.${EXT} ${PROJECT_NAME}.${EXT} +) diff --git a/libs/freetdm/mod_freetdm/mod_freetdm.c b/libs/freetdm/mod_freetdm/mod_freetdm.c index 3b74f2e884..0a35913ec4 100755 --- a/libs/freetdm/mod_freetdm/mod_freetdm.c +++ b/libs/freetdm/mod_freetdm/mod_freetdm.c @@ -2007,6 +2007,7 @@ static FIO_SIGNAL_CB_FUNCTION(on_r2_signal) break; case FTDM_SIGEVENT_PROGRESS: + case FTDM_SIGEVENT_PROGRESS_MEDIA: { if ((session = ftdm_channel_get_session(sigmsg->channel, 0))) { channel = switch_core_session_get_channel(session); diff --git a/libs/freetdm/sample/CMakeLists.txt b/libs/freetdm/sample/CMakeLists.txt new file mode 100644 index 0000000000..330d590fd4 --- /dev/null +++ b/libs/freetdm/sample/CMakeLists.txt @@ -0,0 +1,8 @@ +# +# Arnaldo M Pereira +# +CMAKE_MINIMUM_REQUIRED(VERSION 2.6) +PROJECT(sample) + +ADD_SUBDIRECTORY(boost) +#ADD_SUBDIRECTORY(sched) FIXME: this code doesnt compile diff --git a/libs/freetdm/sample/boost/CMakeLists.txt b/libs/freetdm/sample/boost/CMakeLists.txt new file mode 100644 index 0000000000..6f36f106a5 --- /dev/null +++ b/libs/freetdm/sample/boost/CMakeLists.txt @@ -0,0 +1,12 @@ +# +# Arnaldo M Pereira +# +CMAKE_MINIMUM_REQUIRED(VERSION 2.6) +PROJECT(boost) + +IF(NOT DEFINED WIN32) + INCLUDE_DIRECTORIES(/usr/local/freeswitch/include) + ADD_DEFINITIONS(-Wall) + ADD_EXECUTABLE(ftdmstart ftdmstart.c) + TARGET_LINK_LIBRARIES(ftdmstart freetdm) +ENDIF(NOT DEFINED WIN32) diff --git a/libs/freetdm/sample/dso/CMakeLists.txt b/libs/freetdm/sample/dso/CMakeLists.txt new file mode 100644 index 0000000000..defcc5c7f5 --- /dev/null +++ b/libs/freetdm/sample/dso/CMakeLists.txt @@ -0,0 +1,12 @@ +# +# Arnaldo M Pereira +# +CMAKE_MINIMUM_REQUIRED(VERSION 2.6) +PROJECT(dso) + +IF(NOT DEFINED WIN32) + INCLUDE_DIRECTORIES(/usr/local/freeswitch/include) + ADD_DEFINITIONS(-Wall) + ADD_EXECUTABLE(ftdmload ftdmload.c) + TARGET_LINK_LIBRARIES(ftdmload freetdm) +ENDIF(NOT DEFINED WIN32) diff --git a/libs/freetdm/sample/sched/CMakeLists.txt b/libs/freetdm/sample/sched/CMakeLists.txt new file mode 100644 index 0000000000..d769925be0 --- /dev/null +++ b/libs/freetdm/sample/sched/CMakeLists.txt @@ -0,0 +1,12 @@ +# +# Arnaldo M Pereira +# +CMAKE_MINIMUM_REQUIRED(VERSION 2.6) +PROJECT(sched) + +IF(NOT DEFINED WIN32) + INCLUDE_DIRECTORIES(/usr/local/freeswitch/include) + ADD_DEFINITIONS(-Wall) + ADD_EXECUTABLE(ftdmsched ftdmsched.c) + TARGET_LINK_LIBRARIES(ftdmsched freetdm) +ENDIF(NOT DEFINED WIN32) diff --git a/libs/freetdm/src/ftdm_io.c b/libs/freetdm/src/ftdm_io.c index 99c0c86ed5..f02c9c48db 100644 --- a/libs/freetdm/src/ftdm_io.c +++ b/libs/freetdm/src/ftdm_io.c @@ -928,12 +928,12 @@ FT_DECLARE(ftdm_status_t) ftdm_span_find(uint32_t id, ftdm_span_t **span) } -FT_DECLARE(ftdm_status_t) ftdm_span_poll_event(ftdm_span_t *span, uint32_t ms) +FT_DECLARE(ftdm_status_t) ftdm_span_poll_event(ftdm_span_t *span, uint32_t ms, short *poll_events) { assert(span->fio != NULL); if (span->fio->poll_event) { - return span->fio->poll_event(span, ms); + return span->fio->poll_event(span, ms, poll_events); } else { ftdm_log(FTDM_LOG_ERROR, "poll_event method not implemented in module %s!", span->fio->name); } diff --git a/libs/freetdm/src/ftdm_sched.c b/libs/freetdm/src/ftdm_sched.c index 00a303aae6..c48c3e9433 100644 --- a/libs/freetdm/src/ftdm_sched.c +++ b/libs/freetdm/src/ftdm_sched.c @@ -34,6 +34,40 @@ #include "private/ftdm_core.h" +#ifdef __WINDOWS__ +struct ftdm_timezone { + int tz_minuteswest; /* minutes W of Greenwich */ + int tz_dsttime; /* type of dst correction */ +}; +int gettimeofday(struct timeval *tv, struct ftdm_timezone *tz) +{ + FILETIME ft; + unsigned __int64 tmpres = 0; + static int tzflag; + if (NULL != tv) { + GetSystemTimeAsFileTime(&ft); + tmpres |= ft.dwHighDateTime; + tmpres <<= 32; + tmpres |= ft.dwLowDateTime; + + /*converting file time to unix epoch */ + tmpres /= 10; /*convert into microseconds */ + tmpres -= DELTA_EPOCH_IN_MICROSECS; + tv->tv_sec = (long) (tmpres / 1000000UL); + tv->tv_usec = (long) (tmpres % 1000000UL); + } + if (NULL != tz) { + if (!tzflag) { + _tzset(); + tzflag++; + } + tz->tz_minuteswest = _timezone / 60; + tz->tz_dsttime = _daylight; + } + return 0; +} +#endif /* __WINDOWS__ */ + typedef struct ftdm_timer ftdm_timer_t; static struct { @@ -55,9 +89,7 @@ struct ftdm_sched { struct ftdm_timer { char name[80]; ftdm_timer_id_t id; -#if defined(__linux__) || defined(__FreeBSD__) struct timeval time; -#endif void *usrdata; ftdm_sched_callback_t callback; ftdm_timer_t *next; @@ -234,7 +266,6 @@ failed: FT_DECLARE(ftdm_status_t) ftdm_sched_run(ftdm_sched_t *sched) { ftdm_status_t status = FTDM_FAIL; -#if defined(__linux__) || defined(__FreeBSD__) ftdm_timer_t *runtimer; ftdm_timer_t *timer; ftdm_sched_callback_t callback; @@ -300,10 +331,6 @@ tryagain: done: ftdm_mutex_unlock(sched->mutex); -#else - ftdm_log(FTDM_LOG_CRIT, "Not implemented in this platform\n"); - status = FTDM_NOTIMPL; -#endif #ifdef __WINDOWS__ UNREFERENCED_PARAMETER(sched); #endif @@ -315,7 +342,6 @@ FT_DECLARE(ftdm_status_t) ftdm_sched_timer(ftdm_sched_t *sched, const char *name int ms, ftdm_sched_callback_t callback, void *data, ftdm_timer_id_t *timerid) { ftdm_status_t status = FTDM_FAIL; -#if defined(__linux__) || defined(__FreeBSD__) struct timeval now; int rc = 0; ftdm_timer_t *newtimer; @@ -378,10 +404,6 @@ FT_DECLARE(ftdm_status_t) ftdm_sched_timer(ftdm_sched_t *sched, const char *name done: ftdm_mutex_unlock(sched->mutex); -#else - ftdm_log(FTDM_LOG_CRIT, "Not implemented in this platform\n"); - status = FTDM_NOTIMPL; -#endif #ifdef __WINDOWS__ UNREFERENCED_PARAMETER(sched); UNREFERENCED_PARAMETER(name); @@ -396,7 +418,6 @@ done: FT_DECLARE(ftdm_status_t) ftdm_sched_get_time_to_next_timer(const ftdm_sched_t *sched, int32_t *timeto) { ftdm_status_t status = FTDM_FAIL; -#if defined(__linux__) || defined(__FreeBSD__) int res = -1; int ms = 0; struct timeval currtime; @@ -445,10 +466,6 @@ FT_DECLARE(ftdm_status_t) ftdm_sched_get_time_to_next_timer(const ftdm_sched_t * done: ftdm_mutex_unlock(sched->mutex); -#else - ftdm_log(FTDM_LOG_ERROR, "Implement me!\n"); - status = FTDM_NOTIMPL; -#endif #ifdef __WINDOWS__ UNREFERENCED_PARAMETER(timeto); UNREFERENCED_PARAMETER(sched); diff --git a/libs/freetdm/src/ftmod/ftmod_analog/ftmod_analog.c b/libs/freetdm/src/ftmod/ftmod_analog/ftmod_analog.c index 4dce1904ac..dacda7e448 100644 --- a/libs/freetdm/src/ftmod/ftmod_analog/ftmod_analog.c +++ b/libs/freetdm/src/ftmod/ftmod_analog/ftmod_analog.c @@ -966,7 +966,7 @@ static void *ftdm_analog_run(ftdm_thread_t *me, void *obj) int waitms = 1000; ftdm_status_t status; - if ((status = ftdm_span_poll_event(span, waitms)) != FTDM_FAIL) { + if ((status = ftdm_span_poll_event(span, waitms, NULL)) != FTDM_FAIL) { errs = 0; } diff --git a/libs/freetdm/src/ftmod/ftmod_analog_em/ftmod_analog_em.c b/libs/freetdm/src/ftmod/ftmod_analog_em/ftmod_analog_em.c index 081665b3fc..199bba43a3 100644 --- a/libs/freetdm/src/ftmod/ftmod_analog_em/ftmod_analog_em.c +++ b/libs/freetdm/src/ftmod/ftmod_analog_em/ftmod_analog_em.c @@ -657,7 +657,7 @@ static void *ftdm_analog_em_run(ftdm_thread_t *me, void *obj) int waitms = 10; ftdm_status_t status; - status = ftdm_span_poll_event(span, waitms); + status = ftdm_span_poll_event(span, waitms, NULL); switch(status) { case FTDM_SUCCESS: diff --git a/libs/freetdm/src/ftmod/ftmod_isdn/ftmod_isdn.c b/libs/freetdm/src/ftmod/ftmod_isdn/ftmod_isdn.c index 7a2810757c..2b34552950 100644 --- a/libs/freetdm/src/ftmod/ftmod_isdn/ftmod_isdn.c +++ b/libs/freetdm/src/ftmod/ftmod_isdn/ftmod_isdn.c @@ -1741,7 +1741,7 @@ static __inline__ void check_events(ftdm_span_t *span) { ftdm_status_t status; - status = ftdm_span_poll_event(span, 5); + status = ftdm_span_poll_event(span, 5, NULL); switch(status) { case FTDM_SUCCESS: diff --git a/libs/freetdm/src/ftmod/ftmod_libpri/ftmod_libpri.c b/libs/freetdm/src/ftmod/ftmod_libpri/ftmod_libpri.c index d8acf7e176..ed6acda4bf 100644 --- a/libs/freetdm/src/ftmod/ftmod_libpri/ftmod_libpri.c +++ b/libs/freetdm/src/ftmod/ftmod_libpri/ftmod_libpri.c @@ -909,7 +909,11 @@ static __inline__ ftdm_status_t process_event(ftdm_span_t *span, ftdm_event_t *e */ static __inline__ void check_events(ftdm_span_t *span) { - switch (ftdm_span_poll_event(span, 5)) { + ftdm_status_t status; + + status = ftdm_span_poll_event(span, 5, NULL); + + switch(status) { case FTDM_SUCCESS: { ftdm_event_t *event; diff --git a/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.2008.vcproj b/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.2008.vcproj new file mode 100644 index 0000000000..9ea351ba6a --- /dev/null +++ b/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.2008.vcproj @@ -0,0 +1,192 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c b/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c index 564a812496..086656128e 100644 --- a/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c +++ b/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c @@ -32,23 +32,36 @@ */ #include +#ifdef __linux__ +#include +#include +#endif #include +#include "freetdm.h" #include "private/ftdm_core.h" /* debug thread count for r2 legs */ static ftdm_mutex_t* g_thread_count_mutex; static int32_t g_thread_count = 0; +typedef int openr2_call_status_t; + /* when the users kills a span we clear this flag to kill the signaling thread */ /* FIXME: what about the calls that are already up-and-running? */ 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; + openr2_chan_t *r2chan; + ftdm_r2_call_flag_t flags; int accepted:1; int answer_pending:1; int state_ack_pending:1; @@ -58,6 +71,7 @@ typedef struct ftdm_r2_call_t { ftdm_size_t dnis_index; ftdm_size_t ani_index; char name[10]; + unsigned long txdrops; } ftdm_r2_call_t; /* this is just used as place holder in the stack when configuring the span to avoid using bunch of locals */ @@ -82,6 +96,7 @@ typedef struct ft_r2_conf_s { int skip_category; int get_ani_first; int call_files; + int mf_files; int double_answer; int charge_calls; int forced_release; @@ -104,6 +119,12 @@ 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; + /* max time spent in ms doing real work in a single loop */ + int jobmax; + /* total working loops */ + unsigned long loops; + /* LWP */ + unsigned long monitor_thread_id; } ftdm_r2_data_t; /* one element per span will be stored in g_mod_data_hash global var to keep track of them @@ -116,9 +137,6 @@ typedef struct ftdm_r2_span_pvt_s { /* span monitor thread */ static void *ftdm_r2_run(ftdm_thread_t *me, void *obj); -/* channel monitor thread */ -static void *ftdm_r2_channel_run(ftdm_thread_t *me, void *obj); - /* hash of all the private span allocations we need to keep track of them to destroy them when unloading the module since freetdm does not notify signaling modules when destroying a span @@ -128,6 +146,150 @@ static ftdm_hash_t *g_mod_data_hash; /* IO interface for the command API */ static ftdm_io_interface_t g_ftdm_r2_interface; +static int ftdm_r2_state_advance(ftdm_channel_t *ftdmchan); + + +/* functions not available on windows */ +#ifdef WIN32 +#include + +static __inline int gettimeofday(struct timeval *tp, void *nothing) +{ +#ifdef WITHOUT_MM_LIB + SYSTEMTIME st; + time_t tt; + struct tm tmtm; + /* mktime converts local to UTC */ + GetLocalTime (&st); + tmtm.tm_sec = st.wSecond; + tmtm.tm_min = st.wMinute; + tmtm.tm_hour = st.wHour; + tmtm.tm_mday = st.wDay; + tmtm.tm_mon = st.wMonth - 1; + tmtm.tm_year = st.wYear - 1900; tmtm.tm_isdst = -1; + tt = mktime (&tmtm); + tp->tv_sec = tt; + tp->tv_usec = st.wMilliseconds * 1000; +#else + /** + ** The earlier time calculations using GetLocalTime + ** had a time resolution of 10ms.The timeGetTime, part + ** of multimedia apis offer a better time resolution + ** of 1ms.Need to link against winmm.lib for this + **/ + unsigned long Ticks = 0; + unsigned long Sec =0; + unsigned long Usec = 0; + Ticks = timeGetTime(); + + Sec = Ticks/1000; + Usec = (Ticks - (Sec*1000))*1000; + tp->tv_sec = Sec; + tp->tv_usec = Usec; +#endif /* WITHOUT_MM_LIB */ + (void)nothing; + return 0; +} + +static char *strsep(char **stringp, const char *delim) +{ + char *start = *stringp; + char *ptr; + + if (!start) + return NULL; + + if (!*delim) + ptr = start + strlen(start); + else { + ptr = strpbrk(start, delim); + if (!ptr) { + *stringp = NULL; + return start; + } + } + + *ptr = '\0'; + *stringp = ptr + 1; + + return start; +} +#endif /* WIN32 */ + +static ftdm_call_cause_t ftdm_r2_cause_to_ftdm_cause(ftdm_channel_t *fchan, openr2_call_disconnect_cause_t cause) +{ + switch (cause) { + + case OR2_CAUSE_NORMAL_CLEARING: + return FTDM_CAUSE_NORMAL_CLEARING; + + case OR2_CAUSE_BUSY_NUMBER: + return FTDM_CAUSE_USER_BUSY; + + case OR2_CAUSE_NETWORK_CONGESTION: + return FTDM_CAUSE_SWITCH_CONGESTION; + + case OR2_CAUSE_UNALLOCATED_NUMBER: + return FTDM_CAUSE_NO_ROUTE_DESTINATION; + + case OR2_CAUSE_NUMBER_CHANGED: + return FTDM_CAUSE_NUMBER_CHANGED; + + case OR2_CAUSE_OUT_OF_ORDER: + return FTDM_CAUSE_NETWORK_OUT_OF_ORDER; + + case OR2_CAUSE_NO_ANSWER: + return FTDM_CAUSE_NO_ANSWER; + + case OR2_CAUSE_UNSPECIFIED: + return FTDM_CAUSE_NORMAL_UNSPECIFIED; + + case OR2_CAUSE_COLLECT_CALL_REJECTED: + return FTDM_CAUSE_CALL_REJECTED; + + case OR2_CAUSE_FORCED_RELEASE: + return FTDM_CAUSE_NORMAL_CLEARING; + } + ftdm_log_chan(fchan, FTDM_LOG_WARNING, "Mapping openr2 cause %d to unspecified\n", cause); + return FTDM_CAUSE_NORMAL_UNSPECIFIED; +} + +static openr2_call_disconnect_cause_t ftdm_r2_ftdm_cause_to_openr2_cause(ftdm_channel_t *fchan) +{ + switch (fchan->caller_data.hangup_cause) { + + case FTDM_CAUSE_NORMAL_CLEARING: + return OR2_CAUSE_NORMAL_CLEARING; + + case FTDM_CAUSE_USER_BUSY: + return OR2_CAUSE_BUSY_NUMBER; + + case FTDM_CAUSE_SWITCH_CONGESTION: + return OR2_CAUSE_NETWORK_CONGESTION; + + case FTDM_CAUSE_NO_ROUTE_DESTINATION: + return OR2_CAUSE_UNALLOCATED_NUMBER; + + case FTDM_CAUSE_NUMBER_CHANGED: + return OR2_CAUSE_NUMBER_CHANGED; + + case FTDM_CAUSE_NETWORK_OUT_OF_ORDER: + case FTDM_CAUSE_SERVICE_UNAVAILABLE: + return OR2_CAUSE_OUT_OF_ORDER; + + case FTDM_CAUSE_NO_ANSWER: + case FTDM_CAUSE_NO_USER_RESPONSE: + return OR2_CAUSE_NO_ANSWER; + + case FTDM_CAUSE_NORMAL_UNSPECIFIED: + return OR2_CAUSE_UNSPECIFIED; + + } + ftdm_log_chan(fchan, FTDM_LOG_WARNING, "freetdm hangup cause %d mapped to openr2 cause %s\n", + fchan->caller_data.hangup_cause, openr2_proto_get_disconnect_string(OR2_CAUSE_UNSPECIFIED)); + return OR2_CAUSE_UNSPECIFIED; +} + static void ft_r2_clean_call(ftdm_r2_call_t *call) { openr2_chan_t *r2chan = call->r2chan; @@ -143,7 +305,6 @@ static void ft_r2_accept_call(ftdm_channel_t *ftdmchan) // hanging up the call with protocol error as the reason, this openr2 API will fail only when there something // wrong at the I/O layer or the library itself openr2_chan_accept_call(r2chan, OR2_CALL_NO_CHARGE); - R2CALL(ftdmchan)->accepted = 1; } static void ft_r2_answer_call(ftdm_channel_t *ftdmchan) @@ -157,37 +318,46 @@ static void ft_r2_answer_call(ftdm_channel_t *ftdmchan) R2CALL(ftdmchan)->answer_pending = 0; } +/* this function must be called with the chan mutex held! */ static FIO_CHANNEL_OUTGOING_CALL_FUNCTION(r2_outgoing_call) { - ftdm_status_t status; - ftdm_mutex_lock(ftdmchan->mutex); + openr2_call_status_t callstatus; + ftdm_r2_data_t *r2data; - /* the channel may be down but the thread not quite done */ - ftdm_wait_for_flag_cleared(ftdmchan, FTDM_CHANNEL_INTHREAD, 200); + r2data = ftdmchan->span->signal_data; - if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_INTHREAD)) { - ftdm_log(FTDM_LOG_ERROR, "%d:%d Yay! R2 outgoing call in channel that is already in thread.\n", - ftdmchan->span_id, ftdmchan->chan_id); - ftdm_mutex_unlock(ftdmchan->mutex); + if (ftdmchan->state != FTDM_CHANNEL_STATE_DOWN) { + /* collision, an incoming seized the channel between our take and use timing */ + ftdm_log_chan(ftdmchan, + FTDM_LOG_CRIT, "R2 cannot dial out in channel in state %s, try another channel!.\n", ftdm_channel_state2str(ftdmchan->state)); return FTDM_FAIL; } ft_r2_clean_call(ftdmchan->call_data); - R2CALL(ftdmchan)->chanstate = FTDM_CHANNEL_STATE_DOWN; - ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DIALING); - ftdm_set_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND); R2CALL(ftdmchan)->ftdm_started = 1; - ftdm_mutex_unlock(ftdmchan->mutex); + R2CALL(ftdmchan)->chanstate = FTDM_CHANNEL_STATE_DOWN; + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DIALING); - status = ftdm_thread_create_detached(ftdm_r2_channel_run, ftdmchan); - if (status == FTDM_FAIL) { - ftdm_log(FTDM_LOG_ERROR, "%d:%d Cannot handle request to start call in channel, failed to create thread!\n", - ftdmchan->span_id, ftdmchan->chan_id); - ftdm_channel_done(ftdmchan); - return FTDM_FAIL; + 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 (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; } - return FTDM_SUCCESS; + /* 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; } static ftdm_status_t ftdm_r2_start(ftdm_span_t *span) @@ -197,91 +367,110 @@ static ftdm_status_t ftdm_r2_start(ftdm_span_t *span) return ftdm_thread_create_detached(ftdm_r2_run, span); } +static ftdm_status_t ftdm_r2_stop(ftdm_span_t *span) +{ + ftdm_r2_data_t *r2_data = span->signal_data; + while (ftdm_test_flag(r2_data, FTDM_R2_RUNNING)) { + ftdm_log(FTDM_LOG_DEBUG, "Waiting for R2 span %s\n", span->name); + ftdm_sleep(100); + } + return FTDM_SUCCESS; +} + +static ftdm_status_t ftdm_r2_sig_read(ftdm_channel_t *ftdmchan, void *data, ftdm_size_t size) +{ + 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); + } + return FTDM_SUCCESS; +} + /* always called from the monitor thread */ static void ftdm_r2_on_call_init(openr2_chan_t *r2chan) { + //ftdm_status_t status; + ftdm_r2_call_t *r2call; ftdm_channel_t *ftdmchan = openr2_chan_get_client_data(r2chan); - ftdm_status_t status; - ftdm_log(FTDM_LOG_NOTICE, "Received request to start call on chan %d\n", openr2_chan_get_number(r2chan)); + //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(FTDM_LOG_ERROR, "Cannot handle request to start call in channel %d, invalid state (%d)\n", - openr2_chan_get_number(r2chan), ftdmchan->state); + 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; } - /* the channel may be down but the thread not quite done */ - ftdm_wait_for_flag_cleared(ftdmchan, FTDM_CHANNEL_INTHREAD, 200); - - if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_INTHREAD)) { - ftdm_log(FTDM_LOG_ERROR, "Cannot handle request to start call in channel %d, already in thread!\n", - openr2_chan_get_number(r2chan)); + 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; } + + /* mark the channel in use (so no outgoing calls can be placed here) */ + ftdm_channel_use(ftdmchan); + + memset(ftdmchan->caller_data.dnis.digits, 0, sizeof(ftdmchan->caller_data.collected)); + memset(ftdmchan->caller_data.ani.digits, 0, sizeof(ftdmchan->caller_data.collected)); + + /* clean the call data structure but keep the R2 processing flag on! */ ft_r2_clean_call(ftdmchan->call_data); - R2CALL(ftdmchan)->chanstate = FTDM_CHANNEL_STATE_DOWN; + 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; + } + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_COLLECT); ftdm_mutex_unlock(ftdmchan->mutex); - - status = ftdm_thread_create_detached(ftdm_r2_channel_run, ftdmchan); - if (status == FTDM_FAIL) { - ftdm_log(FTDM_LOG_ERROR, "Cannot handle request to start call in channel %d, failed to create thread!\n", - openr2_chan_get_number(r2chan)); - } } /* 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_sigmsg_t sigev; ftdm_channel_t *ftdmchan = openr2_chan_get_client_data(r2chan); - ftdm_log(FTDM_LOG_NOTICE, "Call offered on chan %d, ANI = %s, DNIS = %s, Category = %s\n", openr2_chan_get_number(r2chan), - ani, dnis, openr2_proto_get_category_string(category)); - - /* notify the user about the new call */ - 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_START; - - if (ftdm_span_send_signal(ftdmchan->span, &sigev) != FTDM_SUCCESS) { - ftdm_log(FTDM_LOG_NOTICE, "Failed to handle call offered on chan %d\n", openr2_chan_get_number(r2chan)); - openr2_chan_disconnect_call(r2chan, OR2_CAUSE_OUT_OF_ORDER); - ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_CANCEL); - return; - } - ftdm_channel_use(ftdmchan); - R2CALL(ftdmchan)->ftdm_started = 1; + 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); } 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(FTDM_LOG_NOTICE, "Call accepted on chan %d\n", openr2_chan_get_number(r2chan)); + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_NOTICE, "Call accepted\n"); /* 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(FTDM_LOG_DEBUG, "Answer was pending on chan %d, answering now.\n", openr2_chan_get_number(r2chan)); + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Answer was pending, answering now.\n"); ft_r2_answer_call(ftdmchan); return; } } else { - ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_PROGRESS); + ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_PROGRESS_MEDIA); } } static void ftdm_r2_on_call_answered(openr2_chan_t *r2chan) { ftdm_channel_t *ftdmchan = openr2_chan_get_client_data(r2chan); - ftdm_log(FTDM_LOG_NOTICE, "Call answered on chan %d\n", openr2_chan_get_number(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); @@ -294,14 +483,19 @@ static void ftdm_r2_on_call_disconnect(openr2_chan_t *r2chan, openr2_call_discon ftdm_sigmsg_t sigev; ftdm_r2_data_t *r2data; ftdm_channel_t *ftdmchan = openr2_chan_get_client_data(r2chan); - ftdm_log(FTDM_LOG_NOTICE, "Call disconnected on chan %d\n", openr2_chan_get_number(r2chan)); - ftdm_log(FTDM_LOG_DEBUG, "Got openr2 disconnection, clearing call on channel %d\n", ftdmchan->physical_chan_id); + 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"); R2CALL(ftdmchan)->disconnect_rcvd = 1; - /* acknowledge the hangup, cause will be ignored. From here to -> HANGUP once the freetdm side hangs up as well */ - openr2_chan_disconnect_call(r2chan, OR2_CAUSE_NORMAL_CLEARING); + 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 */ + 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) { @@ -309,8 +503,7 @@ static void ftdm_r2_on_call_disconnect(openr2_chan_t *r2chan, openr2_call_discon return; } - /* FIXME: use the cause received from openr2 and map it to ftdm cause */ - ftdmchan->caller_data.hangup_cause = FTDM_CAUSE_NORMAL_CLEARING; + 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)); @@ -326,27 +519,32 @@ static void ftdm_r2_on_call_disconnect(openr2_chan_t *r2chan, openr2_call_discon static void ftdm_r2_on_call_end(openr2_chan_t *r2chan) { ftdm_channel_t *ftdmchan = openr2_chan_get_client_data(r2chan); - ftdm_log(FTDM_LOG_NOTICE, "Call finished on chan %d\n", openr2_chan_get_number(r2chan)); - /* this means the freetdm side disconnected the call, therefore we must move to DOWN here */ - if (!R2CALL(ftdmchan)->disconnect_rcvd) { - ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN); - return; - } + 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); + + /* 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); } static void ftdm_r2_on_call_read(openr2_chan_t *r2chan, const unsigned char *buf, int buflen) { +#if 0 ftdm_log(FTDM_LOG_NOTICE, "Call read data on chan %d\n", openr2_chan_get_number(r2chan)); +#endif } static void ftdm_r2_on_hardware_alarm(openr2_chan_t *r2chan, int alarm) { - ftdm_log(FTDM_LOG_NOTICE, "Alarm on chan %d (%d)\n", openr2_chan_get_number(r2chan), alarm); + ftdm_channel_t *ftdmchan = openr2_chan_get_client_data(r2chan); + ftdm_log_chan(ftdmchan, FTDM_LOG_WARNING, "Alarm notification: %d\n", alarm); } static void ftdm_r2_on_os_error(openr2_chan_t *r2chan, int errorcode) { - ftdm_log(FTDM_LOG_ERROR, "OS error on chan %d: %s\n", openr2_chan_get_number(r2chan), strerror(errorcode)); + ftdm_channel_t *ftdmchan = openr2_chan_get_client_data(r2chan); + ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "OS error: %s\n", strerror(errorcode)); } static void ftdm_r2_on_protocol_error(openr2_chan_t *r2chan, openr2_protocol_error_t reason) @@ -355,18 +553,26 @@ static void ftdm_r2_on_protocol_error(openr2_chan_t *r2chan, openr2_protocol_err ftdm_r2_data_t *r2data; ftdm_channel_t *ftdmchan = openr2_chan_get_client_data(r2chan); - ftdm_log(FTDM_LOG_ERROR, "Protocol error on chan %d\n", openr2_chan_get_number(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); + } + + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "Protocol error\n"); R2CALL(ftdmchan)->disconnect_rcvd = 1; if (!R2CALL(ftdmchan)->ftdm_started) { - ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP); + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_HANGUP); + ftdm_mutex_unlock(ftdmchan->mutex); return; } ftdmchan->caller_data.hangup_cause = FTDM_CAUSE_PROTOCOL_ERROR; - /* notify the user of the call terminating */ + /* 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; @@ -375,63 +581,76 @@ static void ftdm_r2_on_protocol_error(openr2_chan_t *r2chan, openr2_protocol_err r2data = ftdmchan->span->signal_data; ftdm_span_send_signal(ftdmchan->span, &sigev); + + ftdm_mutex_unlock(ftdmchan->mutex); } static void ftdm_r2_on_line_blocked(openr2_chan_t *r2chan) { - ftdm_log(FTDM_LOG_NOTICE, "Far end blocked on chan %d\n", openr2_chan_get_number(r2chan)); + ftdm_channel_t *ftdmchan = openr2_chan_get_client_data(r2chan); + ftdm_log_chan(ftdmchan, FTDM_LOG_NOTICE, "Far end blocked in state %s\n", ftdm_channel_state2str(ftdmchan->state)); + ftdm_set_flag(ftdmchan, FTDM_CHANNEL_SUSPENDED); } static void ftdm_r2_on_line_idle(openr2_chan_t *r2chan) { - ftdm_log(FTDM_LOG_NOTICE, "Far end unblocked on chan %d\n", openr2_chan_get_number(r2chan)); + ftdm_channel_t *ftdmchan = openr2_chan_get_client_data(r2chan); + ftdm_log_chan(ftdmchan, FTDM_LOG_NOTICE, "Far end unblocked in state %s\n", ftdm_channel_state2str(ftdmchan->state)); + ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_SUSPENDED); + + /* XXX when should we set/unset this flag? XXX */ + ftdm_set_flag(ftdmchan, FTDM_CHANNEL_SIG_UP); } -static void ftdm_r2_write_log(openr2_log_level_t level, const char *message) +static void ftdm_r2_write_log(openr2_log_level_t level, const char *file, const char *function, int line, const char *message) { switch (level) { case OR2_LOG_NOTICE: - ftdm_log(FTDM_LOG_NOTICE, "%s", message); + ftdm_log(file, function, line, FTDM_LOG_LEVEL_NOTICE, "%s", message); break; case OR2_LOG_WARNING: - ftdm_log(FTDM_LOG_WARNING, "%s", message); + ftdm_log(file, function, line, FTDM_LOG_LEVEL_WARNING, "%s", message); break; case OR2_LOG_ERROR: - ftdm_log(FTDM_LOG_ERROR, "%s", message); + ftdm_log(file, function, line, FTDM_LOG_LEVEL_ERROR, "%s", message); break; case OR2_LOG_STACK_TRACE: case OR2_LOG_MF_TRACE: case OR2_LOG_CAS_TRACE: case OR2_LOG_DEBUG: case OR2_LOG_EX_DEBUG: - ftdm_log(FTDM_LOG_DEBUG, "%s", message); + ftdm_log(file, function, line, FTDM_LOG_LEVEL_DEBUG, "%s", message); break; default: ftdm_log(FTDM_LOG_WARNING, "We should handle logging level %d here.\n", level); - ftdm_log(FTDM_LOG_DEBUG, "%s", message); + ftdm_log(file, function, line, FTDM_LOG_LEVEL_DEBUG, "%s", message); break; } } -static void ftdm_r2_on_context_log(openr2_context_t *r2context, openr2_log_level_t level, const char *fmt, va_list ap) +static void ftdm_r2_on_context_log(openr2_context_t *r2context, const char *file, const char *function, unsigned int line, + openr2_log_level_t level, const char *fmt, va_list ap) { #define CONTEXT_TAG "Context -" char logmsg[256]; char completemsg[sizeof(logmsg) + sizeof(CONTEXT_TAG) - 1]; vsnprintf(logmsg, sizeof(logmsg), fmt, ap); snprintf(completemsg, sizeof(completemsg), CONTEXT_TAG "%s", logmsg); - ftdm_r2_write_log(level, completemsg); + ftdm_r2_write_log(level, file, function, line, completemsg); #undef CONTEXT_TAG } -static void ftdm_r2_on_chan_log(openr2_chan_t *r2chan, openr2_log_level_t level, const char *fmt, va_list ap) +static void ftdm_r2_on_chan_log(openr2_chan_t *r2chan, const char *file, const char *function, unsigned int line, + 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[256]; + char logmsg[512]; char completemsg[sizeof(logmsg) + sizeof(CHAN_TAG) - 1]; vsnprintf(logmsg, sizeof(logmsg), fmt, ap); - snprintf(completemsg, sizeof(completemsg), CHAN_TAG "%d: %s", openr2_chan_get_number(r2chan), logmsg); - ftdm_r2_write_log(level, completemsg); + snprintf(completemsg, sizeof(completemsg), CHAN_TAG "%d:%d [%s] %s", + ftdmchan->span_id, ftdmchan->chan_id, ftdm_channel_state2str(ftdmchan->state), logmsg); + ftdm_r2_write_log(level, file, function, line, completemsg); #undef CHAN_TAG } @@ -442,7 +661,7 @@ static int ftdm_r2_on_dnis_digit_received(openr2_chan_t *r2chan, char digit) ftdm_channel_t *ftdmchan = openr2_chan_get_client_data(r2chan); ftdm_size_t collected_len = R2CALL(ftdmchan)->dnis_index; - ftdm_log(FTDM_LOG_DEBUG, "DNIS digit %d received chan %d\n", digit, openr2_chan_get_number(r2chan)); + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "DNIS digit %c received\n", digit); /* save the digit we just received */ ftdmchan->caller_data.dnis.digits[collected_len] = digit; @@ -458,13 +677,13 @@ static int ftdm_r2_on_dnis_digit_received(openr2_chan_t *r2chan, char digit) sigev.event_id = FTDM_SIGEVENT_COLLECTED_DIGIT; r2data = ftdmchan->span->signal_data; if (ftdm_span_send_signal(ftdmchan->span, &sigev) == FTDM_BREAK) { - ftdm_log(FTDM_LOG_NOTICE, "Requested to stop getting DNIS. Current DNIS = %s on chan %d\n", ftdmchan->caller_data.dnis.digits, openr2_chan_get_number(r2chan)); + ftdm_log_chan(ftdmchan, FTDM_LOG_NOTICE, "Requested to stop getting DNIS. Current DNIS = %s\n", ftdmchan->caller_data.dnis.digits); return OR2_STOP_DNIS_REQUEST; } /* the only other reason to stop requesting DNIS is that there is no more room to save it */ if (collected_len == (sizeof(ftdmchan->caller_data.dnis.digits) - 1)) { - ftdm_log(FTDM_LOG_NOTICE, "No more room for DNIS. Current DNIS = %s on chan %d\n", ftdmchan->caller_data.dnis.digits, openr2_chan_get_number(r2chan)); + ftdm_log_chan(ftdmchan, FTDM_LOG_WARNING, "No more room for DNIS. Current DNIS = %s\n", ftdmchan->caller_data.dnis.digits); return OR2_STOP_DNIS_REQUEST; } @@ -478,35 +697,39 @@ static void ftdm_r2_on_ani_digit_received(openr2_chan_t *r2chan, char digit) /* check if we should drop ANI */ if (collected_len == (sizeof(ftdmchan->caller_data.ani.digits) - 1)) { - ftdm_log(FTDM_LOG_NOTICE, "No more room for ANI %c on chan %d, digit dropped.\n", digit, openr2_chan_get_number(r2chan)); + ftdm_log_chan(ftdmchan, FTDM_LOG_WARNING, "No more room for ANI, digit dropped: %c\n", digit); return; } - ftdm_log(FTDM_LOG_DEBUG, "ANI digit %c received chan %d\n", digit, openr2_chan_get_number(r2chan)); + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "ANI digit %c received\n", digit); /* save the digit we just received */ - ftdmchan->caller_data.ani.digits[collected_len++] = digit; + ftdmchan->caller_data.ani.digits[collected_len] = digit; + collected_len++; ftdmchan->caller_data.ani.digits[collected_len] = '\0'; + R2CALL(ftdmchan)->ani_index = collected_len; } static openr2_event_interface_t ftdm_r2_event_iface = { - .on_call_init = ftdm_r2_on_call_init, - .on_call_offered = ftdm_r2_on_call_offered, - .on_call_accepted = ftdm_r2_on_call_accepted, - .on_call_answered = ftdm_r2_on_call_answered, - .on_call_disconnect = ftdm_r2_on_call_disconnect, - .on_call_end = ftdm_r2_on_call_end, - .on_call_read = ftdm_r2_on_call_read, - .on_hardware_alarm = ftdm_r2_on_hardware_alarm, - .on_os_error = ftdm_r2_on_os_error, - .on_protocol_error = ftdm_r2_on_protocol_error, - .on_line_blocked = ftdm_r2_on_line_blocked, - .on_line_idle = ftdm_r2_on_line_idle, + /* .on_call_init */ ftdm_r2_on_call_init, + /* .on_call_offered */ ftdm_r2_on_call_offered, + /* .on_call_accepted */ ftdm_r2_on_call_accepted, + /* .on_call_answered */ ftdm_r2_on_call_answered, + /* .on_call_disconnect */ ftdm_r2_on_call_disconnect, + /* .on_call_end */ ftdm_r2_on_call_end, + /* .on_call_read */ ftdm_r2_on_call_read, + /* .on_hardware_alarm */ ftdm_r2_on_hardware_alarm, + /* .on_os_error */ ftdm_r2_on_os_error, + /* .on_protocol_error */ ftdm_r2_on_protocol_error, + /* .on_line_blocked */ ftdm_r2_on_line_blocked, + /* .on_line_idle */ ftdm_r2_on_line_idle, + /* cast seems to be needed to get rid of the annoying warning regarding format attribute */ - .on_context_log = (openr2_handle_context_logging_func)ftdm_r2_on_context_log, - .on_dnis_digit_received = ftdm_r2_on_dnis_digit_received, - .on_ani_digit_received = ftdm_r2_on_ani_digit_received, + /* .on_context_log */ (openr2_handle_context_logging_func)ftdm_r2_on_context_log, + /* .on_dnis_digit_received */ ftdm_r2_on_dnis_digit_received, + /* .on_ani_digit_received */ ftdm_r2_on_ani_digit_received, + /* so far we do nothing with billing pulses */ - .on_billing_pulse_received = NULL + /* .on_billing_pulse_received */ NULL, }; static int ftdm_r2_io_set_cas(openr2_chan_t *r2chan, int cas) @@ -564,10 +787,11 @@ static int ftdm_r2_io_read(openr2_chan_t *r2chan, const void *buf, int size) static int ftdm_r2_io_wait(openr2_chan_t *r2chan, int *flags, int block) { ftdm_status_t status; + int32_t timeout; ftdm_wait_flag_t ftdmflags = 0; ftdm_channel_t *ftdm_chan = openr2_chan_get_fd(r2chan); - int32_t timeout = block ? -1 : 0; + timeout = block ? -1 : 0; if (*flags & OR2_IO_READ) { ftdmflags |= FTDM_READ; @@ -578,10 +802,10 @@ static int ftdm_r2_io_wait(openr2_chan_t *r2chan, int *flags, int block) if (*flags & OR2_IO_OOB_EVENT) { ftdmflags |= FTDM_EVENTS; } - + status = ftdm_channel_wait(ftdm_chan, &ftdmflags, timeout); - if (FTDM_SUCCESS != status) { + if (FTDM_SUCCESS != status && FTDM_TIMEOUT != status) { return -1; } @@ -610,18 +834,19 @@ static openr2_io_fd_t ftdm_r2_io_open(openr2_context_t *r2context, int channo) /* since freetdm takes care of closing the file descriptor and uses openr2_chan_new_from_fd, openr2 should never call this hook */ static int ftdm_r2_io_close(openr2_chan_t *r2chan) { - ftdm_log(FTDM_LOG_ERROR, "I should not be called (I/O close)!!\n"); + ftdm_channel_t *fchan = openr2_chan_get_client_data(r2chan); + ftdm_log_chan_msg(fchan, FTDM_LOG_ERROR, "I should not be called (I/O close)!!\n"); return 0; } /* since freetdm takes care of opening the file descriptor and using openr2_chan_new_from_fd, openr2 should never call this hook */ static int ftdm_r2_io_setup(openr2_chan_t *r2chan) { - ftdm_log(FTDM_LOG_ERROR, "I should not be called (I/O Setup)!!\n"); + ftdm_channel_t *fchan = openr2_chan_get_client_data(r2chan); + ftdm_log_chan_msg(fchan, FTDM_LOG_ERROR, "I should not be called (I/O Setup)!!\n"); return 0; } -/* since the signaling thread calls openr2_chan_process_cas_signaling directly, openr2 should never call this hook */ static int ftdm_r2_io_get_oob_event(openr2_chan_t *r2chan, openr2_oob_event_t *event) { *event = 0; @@ -630,16 +855,16 @@ static int ftdm_r2_io_get_oob_event(openr2_chan_t *r2chan, openr2_oob_event_t *e } static openr2_io_interface_t ftdm_r2_io_iface = { - .open = ftdm_r2_io_open, /* never called */ - .close = ftdm_r2_io_close, /* never called */ - .set_cas = ftdm_r2_io_set_cas, - .get_cas = ftdm_r2_io_get_cas, - .flush_write_buffers = ftdm_r2_io_flush_write_buffers, - .write = ftdm_r2_io_write, - .read = ftdm_r2_io_read, - .setup = ftdm_r2_io_setup, /* never called */ - .wait = ftdm_r2_io_wait, - .get_oob_event = ftdm_r2_io_get_oob_event /* never called */ + /* .open */ ftdm_r2_io_open, /* never called */ + /* .close */ ftdm_r2_io_close, /* never called */ + /* .set_cas */ ftdm_r2_io_set_cas, + /* .get_cas */ ftdm_r2_io_get_cas, + /* .flush_write_buffers */ ftdm_r2_io_flush_write_buffers, + /* .write */ ftdm_r2_io_write, + /* .read */ ftdm_r2_io_read, + /* .setup */ ftdm_r2_io_setup, /* never called */ + /* .wait */ ftdm_r2_io_wait, + /* .get_oob_event */ ftdm_r2_io_get_oob_event /* never called */ }; static FIO_SIG_CONFIGURE_FUNCTION(ftdm_r2_configure_span) @@ -653,29 +878,32 @@ static FIO_SIG_CONFIGURE_FUNCTION(ftdm_r2_configure_span) ftdm_r2_span_pvt_t *spanpvt = NULL; ftdm_r2_call_t *r2call = NULL; openr2_chan_t *r2chan = NULL; - - assert(sig_cb != NULL); + openr2_log_level_t tmplevel; + char *clevel; + char *logval = NULL; ft_r2_conf_t r2conf = { - .variant = OR2_VAR_ITU, - .category = OR2_CALLING_PARTY_CATEGORY_NATIONAL_SUBSCRIBER, - .loglevel = OR2_LOG_ERROR | OR2_LOG_WARNING, - .max_ani = 10, - .max_dnis = 4, - .mfback_timeout = -1, - .metering_pulse_timeout = -1, - .allow_collect_calls = -1, - .immediate_accept = -1, - .skip_category = -1, - .forced_release = -1, - .charge_calls = -1, - .get_ani_first = -1, - .call_files = -1, - .logdir = NULL, - .advanced_protocol_file = NULL + /* .variant */ OR2_VAR_ITU, + /* .category */ OR2_CALLING_PARTY_CATEGORY_NATIONAL_SUBSCRIBER, + /* .loglevel */ OR2_LOG_ERROR | OR2_LOG_WARNING, + /* .max_ani */ 10, + /* .max_dnis */ 4, + /* .mfback_timeout */ -1, + /* .metering_pulse_timeout */ -1, + /* .allow_collect_calls */ -1, + /* .immediate_accept */ -1, + /* .skip_category */ -1, + /* .forced_release */ -1, + /* .charge_calls */ -1, + /* .get_ani_first */ -1, + /* .call_files */ 0, + /* .mf_files */ 0, + /* .logdir */ NULL, + /* .advanced_protocol_file */ NULL }; + assert(sig_cb != NULL); if (span->signal_type) { snprintf(span->last_error, sizeof(span->last_error), "Span is already configured for signalling."); @@ -732,9 +960,7 @@ static FIO_SIG_CONFIGURE_FUNCTION(ftdm_r2_configure_span) ftdm_log(FTDM_LOG_NOTICE, "Ignoring empty R2 logging parameter\n"); continue; } - openr2_log_level_t tmplevel; - char *clevel; - char *logval = ftdm_malloc(strlen(val)+1); /* alloca man page scared me, so better to use good ol' malloc */ + 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; @@ -756,6 +982,15 @@ static FIO_SIG_CONFIGURE_FUNCTION(ftdm_r2_configure_span) } if (ftdm_strlen_zero_buf(val)) { ftdm_log(FTDM_LOG_NOTICE, "Ignoring empty R2 advanced_protocol_file parameter\n"); + /* + * TODO: investigate this + * + * despite the fact advanced_protocol_file was initialized as NULL, it's now a bad + * pointer - hence, this workaround. + * this seems to happen only on windows. + * + */ + r2conf.advanced_protocol_file = NULL; continue; } r2conf.advanced_protocol_file = val; @@ -784,6 +1019,9 @@ static FIO_SIG_CONFIGURE_FUNCTION(ftdm_r2_configure_span) } 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); } 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); @@ -834,7 +1072,9 @@ static FIO_SIG_CONFIGURE_FUNCTION(ftdm_r2_configure_span) openr2_context_set_metering_pulse_timeout(r2data->r2context, r2conf.metering_pulse_timeout); openr2_context_set_double_answer(r2data->r2context, r2conf.double_answer); openr2_context_set_immediate_accept(r2data->r2context, r2conf.immediate_accept); - if (r2conf.logdir) { + + 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); } if (r2conf.advanced_protocol_file) { @@ -853,9 +1093,14 @@ static FIO_SIG_CONFIGURE_FUNCTION(ftdm_r2_configure_span) snprintf(span->last_error, sizeof(span->last_error), "Cannot create all openr2 channels for span."); goto fail; } + openr2_chan_set_log_level(r2chan, r2conf.loglevel); if (r2conf.call_files) { openr2_chan_enable_call_files(r2chan); - openr2_chan_set_log_level(r2chan, r2conf.loglevel); +#if 0 + if (r2conf.mf_files) { + openr2_chan_enable_mf_files(r2chan); + } +#endif } r2call = ftdm_malloc(sizeof(*r2call)); @@ -867,20 +1112,23 @@ static FIO_SIG_CONFIGURE_FUNCTION(ftdm_r2_configure_span) memset(r2call, 0, sizeof(*r2call)); openr2_chan_set_logging_func(r2chan, ftdm_r2_on_chan_log); openr2_chan_set_client_data(r2chan, span->channels[i]); - r2call->r2chan = r2chan; + r2call->r2chan = r2chan; span->channels[i]->call_data = r2call; /* value and key are the same so just free one of them */ snprintf(r2call->name, sizeof(r2call->name), "chancall%d", i); hashtable_insert(spanpvt->r2calls, (void *)r2call->name, r2call, HASHTABLE_FLAG_FREE_VALUE); } + r2data->flags = 0; spanpvt->r2context = r2data->r2context; /* just the value must be freed by the hash */ hashtable_insert(g_mod_data_hash, (void *)span->name, spanpvt, HASHTABLE_FLAG_FREE_VALUE); span->start = ftdm_r2_start; - r2data->flags = 0; + span->stop = ftdm_r2_stop; + span->sig_read = ftdm_r2_sig_read; + span->signal_cb = sig_cb; span->signal_type = FTDM_SIGTYPE_R2; span->signal_data = r2data; @@ -902,245 +1150,251 @@ fail: } -static void *ftdm_r2_channel_run(ftdm_thread_t *me, void *obj) +/* the channel must be locked when calling this function */ +static int ftdm_r2_state_advance(ftdm_channel_t *ftdmchan) { - ftdm_channel_t *closed_chan; - uint32_t interval = 0; ftdm_sigmsg_t sigev; - ftdm_channel_t *ftdmchan = (ftdm_channel_t *)obj; + int ret; openr2_chan_t *r2chan = R2CALL(ftdmchan)->r2chan; - ftdm_set_flag_locked(ftdmchan, FTDM_CHANNEL_INTHREAD); - - ftdm_mutex_lock(g_thread_count_mutex); - g_thread_count++; - ftdm_mutex_unlock(g_thread_count_mutex); - - ftdm_log(FTDM_LOG_DEBUG, "R2 CHANNEL thread starting on %d in state %s.\n", - ftdmchan->physical_chan_id, - ftdm_channel_state2str(ftdmchan->state)); - - if (ftdm_channel_open_chan(ftdmchan) != FTDM_SUCCESS) { - ftdm_log(FTDM_LOG_ERROR, "OPEN ERROR [%s]\n", ftdmchan->last_error); - goto endthread; - } - - ftdm_channel_command(ftdmchan, FTDM_COMMAND_GET_INTERVAL, &interval); - - assert(interval != 0); - ftdm_log(FTDM_LOG_DEBUG, "Got %d interval for chan %d\n", interval, ftdmchan->physical_chan_id); - - if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) { - /* FIXME: is this needed? */ - memset(ftdmchan->caller_data.dnis.digits, 0, sizeof(ftdmchan->caller_data.collected)); - memset(ftdmchan->caller_data.ani.digits, 0, sizeof(ftdmchan->caller_data.collected)); - } - memset(&sigev, 0, sizeof(sigev)); sigev.chan_id = ftdmchan->chan_id; sigev.span_id = ftdmchan->span_id; sigev.channel = ftdmchan; - while (ftdm_running()) { - int32_t read_enabled = openr2_chan_get_read_enabled(r2chan); - ftdm_wait_flag_t flags = read_enabled ? ( FTDM_READ | FTDM_WRITE ) : 0; - - if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE) && (R2CALL(ftdmchan)->chanstate != ftdmchan->state)) { - - ftdm_log(FTDM_LOG_DEBUG, "Executing state handler on %d:%d for %s\n", ftdmchan->span_id, ftdmchan->chan_id, 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 */ - ftdm_log(FTDM_LOG_DEBUG, "State ack in chan %d:%d for state %s will have to wait a bit\n", ftdmchan->span_id, ftdmchan->chan_id, ftdm_channel_state2str(ftdmchan->state)); - } else if (ftdmchan->state != FTDM_CHANNEL_STATE_DOWN){ - /* the down state will be completed in ftdm_channel_done below */ - ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_STATE_CHANGE); - ftdm_channel_complete_state(ftdmchan); - } - - switch (ftdmchan->state) { - - /* starting an incoming call */ - case FTDM_CHANNEL_STATE_COLLECT: - { - ftdm_log(FTDM_LOG_DEBUG, "COLLECT: Starting processing of incoming call in channel %d with interval %d\n", ftdmchan->physical_chan_id, interval); - } - break; - - /* starting an outgoing call */ - case FTDM_CHANNEL_STATE_DIALING: - { - // FIXME: use user defined calling party - ftdm_channel_use(ftdmchan); - ftdm_log(FTDM_LOG_DEBUG, "DIALING: Starting processing of outgoing call in channel %d with interval %d\n", ftdmchan->physical_chan_id, interval); - if (openr2_chan_make_call(r2chan, ftdmchan->caller_data.cid_num.digits, ftdmchan->caller_data.dnis.digits, OR2_CALLING_PARTY_CATEGORY_NATIONAL_SUBSCRIBER)) { - ftdm_log(FTDM_LOG_ERROR, "%d:%d Failed to make call in R2 channel, openr2_chan_make_call failed\n", ftdmchan->span_id, ftdmchan->chan_id); - ftdmchan->caller_data.hangup_cause = FTDM_CAUSE_DESTINATION_OUT_OF_ORDER; - ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP); - } - } - break; - - /* the call is ringing */ - case FTDM_CHANNEL_STATE_PROGRESS: - case FTDM_CHANNEL_STATE_PROGRESS_MEDIA: - { - if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) { - if (!R2CALL(ftdmchan)->accepted) { - ftdm_log(FTDM_LOG_DEBUG, "PROGRESS: Accepting call on channel %d\n", ftdmchan->physical_chan_id); - ft_r2_accept_call(ftdmchan); - } - } else { - ftdm_log(FTDM_LOG_DEBUG, "PROGRESS: Notifying progress in channel %d\n", ftdmchan->physical_chan_id); - sigev.event_id = FTDM_SIGEVENT_PROGRESS; - if (ftdm_span_send_signal(ftdmchan->span, &sigev) != FTDM_SUCCESS) { - ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP); - } - } - } - break; - - /* the call was answered */ - case FTDM_CHANNEL_STATE_UP: - { - ftdm_log(FTDM_LOG_DEBUG, "UP: Call was answered on channel %d\n", ftdmchan->physical_chan_id); - if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) { - if (!R2CALL(ftdmchan)->accepted) { - ftdm_log(FTDM_LOG_DEBUG, "UP: Call has not been accepted, need to accept first\n"); - // the answering will be done in the on_call_accepted handler - ft_r2_accept_call(ftdmchan); - R2CALL(ftdmchan)->answer_pending = 1; - } else { - ft_r2_answer_call(ftdmchan); - } - } else { - ftdm_log(FTDM_LOG_DEBUG, "UP: Notifying of call answered in channel %d\n", ftdmchan->physical_chan_id); - sigev.event_id = FTDM_SIGEVENT_UP; - if (ftdm_span_send_signal(ftdmchan->span, &sigev) != FTDM_SUCCESS) { - ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP); - } - } - } - break; - - /* just got hangup */ - case FTDM_CHANNEL_STATE_HANGUP: - { - /* FIXME: the cause should be retrieved from ftdmchan->caller_data.hangup_cause and translated from Q931 to R2 cause */ - ftdm_log(FTDM_LOG_DEBUG, "HANGUP: Clearing call on channel %d\n", ftdmchan->physical_chan_id); - if (!R2CALL(ftdmchan)->disconnect_rcvd) { - /* this will disconnect the call, but need to wait for the call end before moving to DOWN */ - openr2_chan_disconnect_call(r2chan, OR2_CAUSE_NORMAL_CLEARING); - } else { - /* at this point on_call_end possibly was already called, - * but we needed to wait for the freetdm confirmation before moving to DOWN */ - ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN); - } - } - break; - - /* just got hangup from the freetdm side due to abnormal failure */ - case FTDM_CHANNEL_STATE_CANCEL: - { - ftdm_log(FTDM_LOG_DEBUG, "CANCEL: Unable to receive call on channel %d\n", ftdmchan->physical_chan_id); - openr2_chan_disconnect_call(r2chan, OR2_CAUSE_OUT_OF_ORDER); - } - break; - - /* finished call for good */ - case FTDM_CHANNEL_STATE_DOWN: - { - ftdm_log(FTDM_LOG_DEBUG, "DOWN: Placing channel %d back to the pool of available channels\n", ftdmchan->physical_chan_id); - ftdm_channel_done(ftdmchan); - goto endthread; - } - break; - - default: - { - ftdm_log(FTDM_LOG_ERROR, "%s: Unhandled channel state change in channel %d\n", ftdm_channel_state2str(ftdmchan->state), ftdmchan->physical_chan_id); - } - break; - - } - } - - if (flags) { - if (ftdm_channel_wait(ftdmchan, &flags, interval * 2) != FTDM_SUCCESS) { - ftdm_log(FTDM_LOG_DEBUG, "ftdm_channel_wait did not return FTDM_SUCCESS\n"); - continue; - } - - /* handle timeout events first if any */ - openr2_chan_run_schedule(r2chan); - - /* openr2 will now try to detect MF tones, make sense out of them, reply if necessary with another tone and trigger - * telephony events via the call event interface we provided when creating the R2 context. - * openr2 will also call our I/O callbacks to retrieve audio from the channel and call our wait poll I/O registered callback - * and will not return from this function until the I/O poll callback returns no pending events - * */ - openr2_chan_process_mf_signaling(r2chan); - if (R2CALL(ftdmchan)->state_ack_pending) { - ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_STATE_CHANGE); - ftdm_channel_complete_state(ftdmchan); - R2CALL(ftdmchan)->state_ack_pending = 0; - } - } else { - /* once the MF signaling has end we just loop here waiting for state changes */ - ftdm_sleep(interval); - } + 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; } -endthread: + if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE) && (R2CALL(ftdmchan)->chanstate != ftdmchan->state)) { - closed_chan = ftdmchan; - ftdm_channel_close(&closed_chan); - ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_INTHREAD); - ftdm_log(FTDM_LOG_DEBUG, "R2 channel %d thread ended.\n", ftdmchan->physical_chan_id); + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Executing state handler for %s\n", ftdm_channel_state2str(ftdmchan->state)); + R2CALL(ftdmchan)->chanstate = ftdmchan->state; - ftdm_mutex_lock(g_thread_count_mutex); - g_thread_count--; - ftdm_mutex_unlock(g_thread_count_mutex); + 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 */ + 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); + ftdm_channel_complete_state(ftdmchan); + } - return NULL; + switch (ftdmchan->state) { + + /* starting an incoming call */ + case FTDM_CHANNEL_STATE_COLLECT: + { + uint32_t interval = 0; + 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); + } + break; + + /* starting an outgoing call */ + case FTDM_CHANNEL_STATE_DIALING: + { + uint32_t interval = 0; + 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 outgoing call in channel with interval %d\n", interval); + } + break; + + /* incoming call was offered */ + case FTDM_CHANNEL_STATE_RING: + + /* notify the user about the new call */ + sigev.event_id = FTDM_SIGEVENT_START; + + if (ftdm_span_send_signal(ftdmchan->span, &sigev) != FTDM_SUCCESS) { + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_NOTICE, "Failed to handle call offered\n"); + openr2_chan_disconnect_call(r2chan, OR2_CAUSE_OUT_OF_ORDER); + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_CANCEL); + break; + } + R2CALL(ftdmchan)->ftdm_started = 1; + + break; + + /* the call is making progress */ + case FTDM_CHANNEL_STATE_PROGRESS: + case FTDM_CHANNEL_STATE_PROGRESS_MEDIA: + { + if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) { + if (!R2CALL(ftdmchan)->accepted) { + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Accepting call\n"); + ft_r2_accept_call(ftdmchan); + } + } else { + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Notifying progress\n"); + 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); + } + } + } + break; + + /* the call was answered */ + case FTDM_CHANNEL_STATE_UP: + { + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Call was answered\n"); + if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) { + if (!R2CALL(ftdmchan)->accepted) { + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Call has not been accepted, need to accept first\n"); + // the answering will be done in the on_call_accepted handler + ft_r2_accept_call(ftdmchan); + R2CALL(ftdmchan)->answer_pending = 1; + } else { + ft_r2_answer_call(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); + } + } + } + break; + + /* just got 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) { + /* 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 { + /* just ack the hangup, on_call_end will be called by openr2 right after */ + openr2_chan_disconnect_call(r2chan, disconnect_cause); + } + } + break; + + /* just got hangup from the freetdm side due to abnormal failure */ + 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; + + /* finished call for good */ + case FTDM_CHANNEL_STATE_DOWN: + { + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Call is down\n"); + if (R2CALL(ftdmchan)->txdrops) { + ftdm_log_chan(ftdmchan, FTDM_LOG_WARNING, "dropped %d tx packets\n", R2CALL(ftdmchan)->txdrops); + } + ret = 1; + } + break; + + default: + { + ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Unhandled channel state change: %s\n", ftdm_channel_state2str(ftdmchan->state)); + } + break; + + } + } + + if (ret) { + ftdm_channel_t *closed_chan; + closed_chan = ftdmchan; + ftdm_channel_close(&closed_chan); + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "State processing ended.\n"); + } + return ret; } 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 = 1000; - int i; + int waitms = 20; + int i, res; + int ms; + struct timeval start, end; + short *poll_events = ftdm_malloc(sizeof(short)*span->chan_count); - ftdm_log(FTDM_LOG_DEBUG, "OpenR2 monitor thread started.\n"); - r2chan = NULL; +#ifdef __linux__ + r2data->monitor_thread_id = syscall(SYS_gettid); +#endif + + ftdm_log(FTDM_LOG_DEBUG, "OpenR2 monitor thread %lu started.\n", r2data->monitor_thread_id); + r2chan = NULL; for (i = 1; i <= span->chan_count; i++) { r2chan = R2CALL(span->channels[i])->r2chan; openr2_chan_set_idle(r2chan); openr2_chan_process_cas_signaling(r2chan); } + memset(&start, 0, sizeof(start)); + memset(&end, 0, sizeof(end)); while (ftdm_running() && ftdm_test_flag(r2data, FTDM_R2_RUNNING)) { - status = ftdm_span_poll_event(span, waitms); + 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 > r2data->jobmax) { + r2data->jobmax = ms; + } + } + +#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); + } + + status = ftdm_span_poll_event(span, waitms, poll_events); +#else + status = ftdm_span_poll_event(span, waitms, NULL); +#endif + + res = gettimeofday(&start, NULL); + if (res) { + ftdm_log(FTDM_LOG_CRIT, "Failure gettimeofday [%s]\n", strerror(errno)); + } + if (FTDM_FAIL == status) { - ftdm_log(FTDM_LOG_ERROR, "Failure Polling event! [%s]\n", span->last_error); + ftdm_log(FTDM_LOG_CRIT, "Failure waiting I/O! [%s]\n", span->channels[1]->last_error); continue; } - if (FTDM_SUCCESS == status) { + + 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) { - r2chan = R2CALL(event->channel)->r2chan; + r2call = R2CALL(event->channel); + r2chan = r2call->r2chan; + 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 @@ -1150,53 +1404,144 @@ static void *ftdm_r2_run(ftdm_thread_t *me, void *obj) // XXX TODO: handle alarms here XXX } } + + /* 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_mutex_lock(ftdmchan->mutex); + ftdm_set_flag(r2call, FTDM_R2_PROCESSING); + + if (ftdm_r2_state_advance(ftdmchan)) { + ftdm_clear_flag(r2call, FTDM_R2_PROCESSING); + ftdm_mutex_unlock(ftdmchan->mutex); + continue; + } + + /* 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); - } else { - //ftdm_log(FTDM_LOG_DEBUG, "timed out waiting for event on span %d\n", span->span_id); } + ftdm_sleep(20); } - /* - FIXME: we should set BLOCKED but at this point I/O routines of freetdm caused segfault for (i = 1; i <= span->chan_count; i++) { r2chan = R2CALL(span->channels[i])->r2chan; openr2_chan_set_blocked(r2chan); } - */ ftdm_clear_flag(r2data, FTDM_R2_RUNNING); ftdm_log(FTDM_LOG_DEBUG, "R2 thread ending.\n"); return NULL; +} +static void __inline__ block_channel(ftdm_channel_t *fchan, ftdm_stream_handle_t *stream) +{ + openr2_chan_t *r2chan = R2CALL(fchan)->r2chan; + ftdm_mutex_lock(fchan->mutex); + if (fchan->state != FTDM_CHANNEL_STATE_DOWN) { + stream->write_function(stream, "cannot block channel %d:%d because has a call in progress\n", + fchan->span_id, fchan->chan_id); + } else if (ftdm_test_flag(fchan, FTDM_CHANNEL_SUSPENDED)) { + stream->write_function(stream, "cannot block channel %d:%d because is already blocked\n", + fchan->span_id, fchan->chan_id); + } else { + if (!openr2_chan_set_blocked(r2chan)) { + ftdm_set_flag(fchan, FTDM_CHANNEL_SUSPENDED); + stream->write_function(stream, "blocked channel %d:%d\n", + fchan->span_id, fchan->chan_id); + } else { + stream->write_function(stream, "failed to block channel %d:%d\n", + fchan->span_id, fchan->chan_id); + } + } + ftdm_mutex_unlock(fchan->mutex); +} + +static void __inline__ unblock_channel(ftdm_channel_t *fchan, ftdm_stream_handle_t *stream) +{ + openr2_chan_t *r2chan = R2CALL(fchan)->r2chan; + ftdm_mutex_lock(fchan->mutex); + if (ftdm_test_flag(fchan, FTDM_CHANNEL_SUSPENDED)) { + if (!openr2_chan_set_idle(r2chan)) { + ftdm_clear_flag(fchan, FTDM_CHANNEL_SUSPENDED); + stream->write_function(stream, "unblocked channel %d:%d\n", + fchan->span_id, fchan->chan_id); + } else { + stream->write_function(stream, "failed to unblock channel %d:%d\n", + fchan->span_id, fchan->chan_id); + } + } else { + stream->write_function(stream, "cannot unblock channel %d:%d because is not blocked\n", + fchan->span_id, fchan->chan_id); + } + ftdm_mutex_unlock(fchan->mutex); } static FIO_API_FUNCTION(ftdm_r2_api) { + ftdm_span_t *span = NULL; char *mycmd = NULL, *argv[10] = { 0 }; int argc = 0; + int span_id = 0; + int chan_id = 0; + int i = 0; + ftdm_r2_data_t *r2data = NULL; + openr2_chan_t *r2chan = NULL; + openr2_context_t *r2context = NULL; + openr2_variant_t r2variant; if (data) { mycmd = ftdm_strdup(data); argc = ftdm_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0]))); } - if (argc == 2) { - if (!strcasecmp(argv[0], "kill")) { + if (argc >= 2) { + if (!strcasecmp(argv[0], "block")) { int span_id = atoi(argv[1]); - ftdm_span_t *span = NULL; if (ftdm_span_find_by_name(argv[1], &span) == FTDM_SUCCESS || ftdm_span_find(span_id, &span) == FTDM_SUCCESS) { - ftdm_r2_data_t *r2data = span->signal_data; if (span->start != ftdm_r2_start) { stream->write_function(stream, "-ERR invalid span.\n"); goto done; } - ftdm_clear_flag(r2data, FTDM_R2_RUNNING); - stream->write_function(stream, "+OK killed.\n"); + if (argc > 2) { + chan_id = atoi(argv[2]); + if (chan_id && chan_id <= span->chan_count) { + block_channel(span->channels[chan_id], stream); + } else { + stream->write_function(stream, "-ERR invalid chan %d.\n", chan_id); + } + } else { + for (i = 1; i <= span->chan_count; i++) { + block_channel(span->channels[i], stream); + } + } + stream->write_function(stream, "+OK blocked.\n"); goto done; } else { stream->write_function(stream, "-ERR invalid span.\n"); @@ -1204,13 +1549,40 @@ static FIO_API_FUNCTION(ftdm_r2_api) } } + if (!strcasecmp(argv[0], "unblock")) { + 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 invalid span.\n"); + goto done; + } + + if (argc > 2) { + chan_id = atoi(argv[2]); + if (chan_id && chan_id <= span->chan_count) { + unblock_channel(span->channels[chan_id], stream); + } else { + stream->write_function(stream, "-ERR invalid chan %d.\n", chan_id); + } + } else { + for (i = 1; i <= span->chan_count; i++) { + unblock_channel(span->channels[i], stream); + } + } + + stream->write_function(stream, "+OK.\n"); + goto done; + } else { + stream->write_function(stream, "-ERR invalid span.\n"); + goto done; + } + + } + if (!strcasecmp(argv[0], "status")) { - int span_id = atoi(argv[1]); - ftdm_r2_data_t *r2data = NULL; - ftdm_span_t *span = NULL; - openr2_chan_t *r2chan = NULL; - openr2_context_t *r2context = NULL; - int i = 0; + //openr2_chan_stats_t stats; + 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) { @@ -1222,27 +1594,43 @@ static FIO_API_FUNCTION(ftdm_r2_api) goto done; } r2context = r2data->r2context; - openr2_variant_t r2variant = openr2_context_get_variant(r2context); + r2variant = openr2_context_get_variant(r2context); stream->write_function(stream, "Variant: %s\n" "Max ANI: %d\n" "Max DNIS: %d\n" "ANI First: %s\n" - "Immediate Accept: %s\n", + "Immediate Accept: %s\n" + "Side: %s\n" + "Job Max ms: %d\n" + "Job Loops: %lu\n" + "Monitor Thread: %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"); + openr2_context_get_immediate_accept(r2context) ? "Yes" : "No", + "no side", + r2data->jobmax, + r2data->loops, + r2data->monitor_thread_id); stream->write_function(stream, "\n"); - stream->write_function(stream, "%4s %-12.12s %-12.12s\n", "Channel", "Tx CAS", "Rx CAS"); + stream->write_function(stream, "%4s %-12.12s %-12.12s %6s %6s %6s %6s\n", "Channel", "Tx CAS", "Rx CAS", + "Rx Avg", "Tx Avg", "Rx", "Tx"); for (i = 1; i <= span->chan_count; i++) { - if (i == 16) continue; + char rx_str[25]; + char tx_str[25]; + char rxavg_str[25]; + char txavg_str[25]; r2chan = R2CALL(span->channels[i])->r2chan; - stream->write_function(stream, "%4d %-12.12s %-12.12s\n", - span->channels[i]->physical_chan_id, + stream->write_function(stream, "%4d %-12.12s %-12.12s %6s %6s %6s %6s\n", + span->channels[i]->chan_id, openr2_chan_get_tx_cas_string(r2chan), - openr2_chan_get_rx_cas_string(r2chan)); + openr2_chan_get_rx_cas_string(r2chan), + rxavg_str, + txavg_str, + rx_str, + tx_str); } stream->write_function(stream, "\n"); stream->write_function(stream, "+OK.\n"); @@ -1341,7 +1729,7 @@ static FIO_SIG_UNLOAD_FUNCTION(ftdm_r2_destroy) return FTDM_SUCCESS; } -ftdm_module_t ftdm_module = { +EX_DECLARE_DATA ftdm_module_t ftdm_module = { "r2", ftdm_r2_io_init, NULL, diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_boost/ftmod_sangoma_boost.c b/libs/freetdm/src/ftmod/ftmod_sangoma_boost/ftmod_sangoma_boost.c index 7234e67183..a975204b62 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_boost/ftmod_sangoma_boost.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_boost/ftmod_sangoma_boost.c @@ -1725,7 +1725,7 @@ static __inline__ ftdm_status_t check_events(ftdm_span_t *span, int ms_timeout) ftdm_status_t status; ftdm_sangoma_boost_data_t *sangoma_boost_data = span->signal_data; - status = ftdm_span_poll_event(span, ms_timeout); + status = ftdm_span_poll_event(span, ms_timeout, NULL); switch(status) { case FTDM_SUCCESS: diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.2008.vcproj b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.2008.vcproj new file mode 100644 index 0000000000..e3930d8188 --- /dev/null +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.2008.vcproj @@ -0,0 +1,241 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.c index 89626a203a..22c89cb920 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.c @@ -300,7 +300,7 @@ static void *ftdm_sangoma_isdn_run(ftdm_thread_t *me, void *obj) } /* Poll for events, e.g HW DTMF */ - ret_status = ftdm_span_poll_event(span, 0); + ret_status = ftdm_span_poll_event(span, 0, NULL); switch(ret_status) { case FTDM_SUCCESS: { @@ -913,7 +913,8 @@ static FIO_SIG_LOAD_FUNCTION(ftdm_sangoma_isdn_init) } /* initalize sng_isdn library */ - sng_isdn_init(&g_sngisdn_event_interface); + + ftdm_assert_return(!sng_isdn_init(&g_sngisdn_event_interface), FTDM_FAIL, "Failed to initialize stack\n"); return FTDM_SUCCESS; } @@ -1029,7 +1030,7 @@ static FIO_IO_LOAD_FUNCTION(ftdm_sangoma_isdn_io_init) return FTDM_SUCCESS; } -ftdm_module_t ftdm_module = +EX_DECLARE_DATA ftdm_module_t ftdm_module = { "sangoma_isdn", /* char name[256]; */ ftdm_sangoma_isdn_io_init, /* fio_io_load_t */ diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.h b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.h index bc928354a7..e84392e22a 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.h +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.h @@ -38,8 +38,12 @@ #include #include #include +#ifdef HAVE_STDINT_H #include +#endif +#ifdef HAVE_UNISTD_H #include +#endif #include #include "private/ftdm_core.h" @@ -262,16 +266,16 @@ extern ftdm_sngisdn_data_t g_sngisdn_data; ftdm_status_t ftmod_isdn_parse_cfg(ftdm_conf_parameter_t *ftdm_parameters, ftdm_span_t *span); /* Support functions */ -uint32_t get_unique_suInstId(uint8_t cc_id); -void clear_call_data(sngisdn_chan_data_t *sngisdn_info); -void clear_call_glare_data(sngisdn_chan_data_t *sngisdn_info); +FT_DECLARE_INLINE(uint32_t) get_unique_suInstId(int16_t cc_id); +FT_DECLARE_INLINE(void) clear_call_data(sngisdn_chan_data_t *sngisdn_info); +FT_DECLARE_INLINE(void) clear_call_glare_data(sngisdn_chan_data_t *sngisdn_info); void stack_hdr_init(Header *hdr); void stack_pst_init(Pst *pst); -ftdm_status_t get_ftdmchan_by_spInstId(uint8_t cc_id, uint32_t spInstId, sngisdn_chan_data_t **sngisdn_data); -ftdm_status_t get_ftdmchan_by_suInstId(uint8_t cc_id, uint32_t suInstId, sngisdn_chan_data_t **sngisdn_data); -ftdm_status_t sng_isdn_set_avail_rate(ftdm_span_t *ftdmspan, sngisdn_avail_t avail); +FT_DECLARE_INLINE(ftdm_status_t) get_ftdmchan_by_spInstId(int16_t cc_id, uint32_t spInstId, sngisdn_chan_data_t **sngisdn_data); +FT_DECLARE_INLINE(ftdm_status_t) get_ftdmchan_by_suInstId(int16_t cc_id, uint32_t suInstId, sngisdn_chan_data_t **sngisdn_data); +FT_DECLARE_INLINE(ftdm_status_t) sng_isdn_set_avail_rate(ftdm_span_t *ftdmspan, sngisdn_avail_t avail); /* Outbound Call Control functions */ void sngisdn_snd_setup(ftdm_channel_t *ftdmchan); diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_cfg.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_cfg.c index 7f3c4c3d07..bb46fb7fba 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_cfg.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_cfg.c @@ -198,7 +198,7 @@ ftdm_status_t sng_isdn_stack_cfg_phy_psap(ftdm_span_t *span) L1Mngmt cfg; Pst pst; - S32 d_channel_fd = -1; + int32_t d_channel_fd = -1; sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*)span->signal_data; /* initalize the post structure */ @@ -227,7 +227,7 @@ ftdm_status_t sng_isdn_stack_cfg_phy_psap(ftdm_span_t *span) for (curr = chaniter; curr; curr = ftdm_iterator_next(curr)) { ftdm_channel_t *ftdmchan = (ftdm_channel_t*)ftdm_iterator_current(curr); if (ftdmchan->type == FTDM_CHAN_TYPE_DQ921) { - d_channel_fd = ftdmchan->sockfd; + d_channel_fd = (int32_t)ftdmchan->sockfd; break; } } diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_cntrl.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_cntrl.c index cea8ac0173..27c16c2a51 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_cntrl.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_cntrl.c @@ -158,7 +158,7 @@ ftdm_status_t sng_isdn_deactivate_phy(ftdm_span_t *span) ftdm_status_t sng_isdn_activate_cc(ftdm_span_t *span) { - CcMngmt cntrl;; + CcMngmt cntrl; Pst pst; sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*)span->signal_data; @@ -239,7 +239,7 @@ ftdm_status_t sng_isdn_activate_trace(ftdm_span_t *span, sngisdn_tracetype_t tra ftdm_status_t sng_isdn_cntrl_q931(ftdm_span_t *span, uint8_t action, uint8_t subaction) { - InMngmt cntrl;; + InMngmt cntrl; Pst pst; sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*)span->signal_data; 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 41833c54d3..7ca408538a 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 @@ -42,7 +42,6 @@ extern ftdm_status_t cpy_calling_name_from_stack(ftdm_caller_data_t *ftdm, Displ /* Remote side transmit a SETUP */ void sngisdn_process_con_ind (sngisdn_event_data_t *sngisdn_event) { - ISDN_FUNC_TRACE_ENTER(__FUNCTION__); unsigned i; int16_t suId = sngisdn_event->suId; uint32_t suInstId = sngisdn_event->suInstId; @@ -54,6 +53,8 @@ void sngisdn_process_con_ind (sngisdn_event_data_t *sngisdn_event) sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) ftdmchan->span->signal_data; ConEvnt *conEvnt = &sngisdn_event->event.conEvnt; + ISDN_FUNC_TRACE_ENTER(__FUNCTION__); + ftdm_assert(!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE), "State change flag pending\n"); ftdm_log_chan(sngisdn_info->ftdmchan, FTDM_LOG_DEBUG, "Processing SETUP (suId:%u suInstId:%u spInstId:%u)\n", suId, suInstId, spInstId); @@ -240,8 +241,6 @@ void sngisdn_process_con_ind (sngisdn_event_data_t *sngisdn_event) /* Remote side transmit a CONNECT or CONNECT ACK */ void sngisdn_process_con_cfm (sngisdn_event_data_t *sngisdn_event) { - ISDN_FUNC_TRACE_ENTER(__FUNCTION__); - int16_t suId = sngisdn_event->suId; uint32_t suInstId = sngisdn_event->suInstId; uint32_t spInstId = sngisdn_event->spInstId; @@ -249,6 +248,8 @@ void sngisdn_process_con_cfm (sngisdn_event_data_t *sngisdn_event) sngisdn_chan_data_t *sngisdn_info = sngisdn_event->sngisdn_info; ftdm_channel_t *ftdmchan = sngisdn_info->ftdmchan; + ISDN_FUNC_TRACE_ENTER(__FUNCTION__); + /* Function does not require any info from conStEvnt struct for now */ /* CnStEvnt *cnStEvnt = &sngisdn_event->event.cnStEvnt; */ @@ -312,8 +313,6 @@ void sngisdn_process_con_cfm (sngisdn_event_data_t *sngisdn_event) void sngisdn_process_cnst_ind (sngisdn_event_data_t *sngisdn_event) { - ISDN_FUNC_TRACE_ENTER(__FUNCTION__); - int16_t suId = sngisdn_event->suId; uint32_t suInstId = sngisdn_event->suInstId; uint32_t spInstId = sngisdn_event->spInstId; @@ -327,6 +326,8 @@ void sngisdn_process_cnst_ind (sngisdn_event_data_t *sngisdn_event) CnStEvnt *cnStEvnt = &sngisdn_event->event.cnStEvnt; + ISDN_FUNC_TRACE_ENTER(__FUNCTION__); + ftdm_assert(!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE), "State change flag pending\n"); ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Processing %s (suId:%u suInstId:%u spInstId:%u ces:%d)\n", @@ -444,8 +445,6 @@ sngisdn_process_cnst_ind_end: void sngisdn_process_disc_ind (sngisdn_event_data_t *sngisdn_event) { - ISDN_FUNC_TRACE_ENTER(__FUNCTION__); - int16_t suId = sngisdn_event->suId; uint32_t suInstId = sngisdn_event->suInstId; uint32_t spInstId = sngisdn_event->spInstId; @@ -454,6 +453,8 @@ void sngisdn_process_disc_ind (sngisdn_event_data_t *sngisdn_event) DiscEvnt *discEvnt = &sngisdn_event->event.discEvnt; + ISDN_FUNC_TRACE_ENTER(__FUNCTION__); + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Processing DISCONNECT (suId:%u suInstId:%u spInstId:%u)\n", suId, suInstId, spInstId); ftdm_assert(!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE), "State change flag pending\n"); @@ -501,7 +502,6 @@ void sngisdn_process_disc_ind (sngisdn_event_data_t *sngisdn_event) void sngisdn_process_rel_ind (sngisdn_event_data_t *sngisdn_event) { - ISDN_FUNC_TRACE_ENTER(__FUNCTION__); int16_t suId = sngisdn_event->suId; uint32_t suInstId = sngisdn_event->suInstId; uint32_t spInstId = sngisdn_event->spInstId; @@ -510,6 +510,8 @@ void sngisdn_process_rel_ind (sngisdn_event_data_t *sngisdn_event) RelEvnt *relEvnt = &sngisdn_event->event.relEvnt; + ISDN_FUNC_TRACE_ENTER(__FUNCTION__); + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Processing RELEASE/RELEASE COMPLETE (suId:%u suInstId:%u spInstId:%u)\n", suId, suInstId, spInstId); ftdm_assert(!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE), "State change flag pending\n"); @@ -596,7 +598,6 @@ void sngisdn_process_rel_ind (sngisdn_event_data_t *sngisdn_event) void sngisdn_process_dat_ind (sngisdn_event_data_t *sngisdn_event) { - ISDN_FUNC_TRACE_ENTER(__FUNCTION__); int16_t suId = sngisdn_event->suId; uint32_t suInstId = sngisdn_event->suInstId; uint32_t spInstId = sngisdn_event->spInstId; @@ -604,6 +605,8 @@ void sngisdn_process_dat_ind (sngisdn_event_data_t *sngisdn_event) sngisdn_chan_data_t *sngisdn_info = sngisdn_event->sngisdn_info; ftdm_channel_t *ftdmchan = sngisdn_info->ftdmchan; + ISDN_FUNC_TRACE_ENTER(__FUNCTION__); + /* Function does not require any info from infoEvnt struct for now */ /* InfoEvnt *infoEvnt = &sngisdn_event->event.infoEvnt; */ @@ -614,7 +617,6 @@ void sngisdn_process_dat_ind (sngisdn_event_data_t *sngisdn_event) void sngisdn_process_sshl_ind (sngisdn_event_data_t *sngisdn_event) { - ISDN_FUNC_TRACE_ENTER(__FUNCTION__); int16_t suId = sngisdn_event->suId; uint32_t suInstId = sngisdn_event->suInstId; uint32_t spInstId = sngisdn_event->spInstId; @@ -622,6 +624,8 @@ void sngisdn_process_sshl_ind (sngisdn_event_data_t *sngisdn_event) sngisdn_chan_data_t *sngisdn_info = sngisdn_event->sngisdn_info; ftdm_channel_t *ftdmchan = sngisdn_info->ftdmchan; + ISDN_FUNC_TRACE_ENTER(__FUNCTION__); + /* Function does not require any info from ssHlEvnt struct for now */ /* SsHlEvnt *ssHlEvnt = &sngisdn_event->event.ssHlEvnt; */ @@ -632,14 +636,15 @@ void sngisdn_process_sshl_ind (sngisdn_event_data_t *sngisdn_event) void sngisdn_process_sshl_cfm (sngisdn_event_data_t *sngisdn_event) { - ISDN_FUNC_TRACE_ENTER(__FUNCTION__); int16_t suId = sngisdn_event->suId; uint32_t suInstId = sngisdn_event->suInstId; uint32_t spInstId = sngisdn_event->spInstId; - + sngisdn_chan_data_t *sngisdn_info = sngisdn_event->sngisdn_info; ftdm_channel_t *ftdmchan = sngisdn_info->ftdmchan; + ISDN_FUNC_TRACE_ENTER(__FUNCTION__); + /* Function does not require any info from ssHlEvnt struct for now */ /* SsHlEvnt *ssHlEvnt = &sngisdn_event->event.ssHlEvnt; */ @@ -650,7 +655,6 @@ void sngisdn_process_sshl_cfm (sngisdn_event_data_t *sngisdn_event) void sngisdn_process_rmrt_ind (sngisdn_event_data_t *sngisdn_event) { - ISDN_FUNC_TRACE_ENTER(__FUNCTION__); int16_t suId = sngisdn_event->suId; uint32_t suInstId = sngisdn_event->suInstId; uint32_t spInstId = sngisdn_event->spInstId; @@ -658,6 +662,8 @@ void sngisdn_process_rmrt_ind (sngisdn_event_data_t *sngisdn_event) sngisdn_chan_data_t *sngisdn_info = sngisdn_event->sngisdn_info; ftdm_channel_t *ftdmchan = sngisdn_info->ftdmchan; + ISDN_FUNC_TRACE_ENTER(__FUNCTION__); + /* Function does not require any info from ssHlEvnt struct for now */ /* RmRtEvnt *rmRtEvnt = &sngisdn_event->event.rmRtEvnt; */ @@ -668,7 +674,6 @@ void sngisdn_process_rmrt_ind (sngisdn_event_data_t *sngisdn_event) void sngisdn_process_rmrt_cfm (sngisdn_event_data_t *sngisdn_event) { - ISDN_FUNC_TRACE_ENTER(__FUNCTION__); int16_t suId = sngisdn_event->suId; uint32_t suInstId = sngisdn_event->suInstId; uint32_t spInstId = sngisdn_event->spInstId; @@ -676,6 +681,8 @@ void sngisdn_process_rmrt_cfm (sngisdn_event_data_t *sngisdn_event) sngisdn_chan_data_t *sngisdn_info = sngisdn_event->sngisdn_info; ftdm_channel_t *ftdmchan = sngisdn_info->ftdmchan; + ISDN_FUNC_TRACE_ENTER(__FUNCTION__); + /* Function does not require any info from ssHlEvnt struct for now */ /* RmRtEvnt *rmRtEvnt = &sngisdn_event->event.rmRtEvnt; */ @@ -686,7 +693,6 @@ void sngisdn_process_rmrt_cfm (sngisdn_event_data_t *sngisdn_event) void sngisdn_process_flc_ind (sngisdn_event_data_t *sngisdn_event) { - ISDN_FUNC_TRACE_ENTER(__FUNCTION__); int16_t suId = sngisdn_event->suId; uint32_t suInstId = sngisdn_event->suInstId; uint32_t spInstId = sngisdn_event->spInstId; @@ -694,6 +700,8 @@ void sngisdn_process_flc_ind (sngisdn_event_data_t *sngisdn_event) sngisdn_chan_data_t *sngisdn_info = sngisdn_event->sngisdn_info; ftdm_channel_t *ftdmchan = sngisdn_info->ftdmchan; + ISDN_FUNC_TRACE_ENTER(__FUNCTION__); + /* Function does not require any info from ssHlEvnt struct for now */ /* StaEvnt *staEvnt = &sngisdn_event->event.staEvnt; */ @@ -704,8 +712,6 @@ void sngisdn_process_flc_ind (sngisdn_event_data_t *sngisdn_event) void sngisdn_process_fac_ind (sngisdn_event_data_t *sngisdn_event) { - ISDN_FUNC_TRACE_ENTER(__FUNCTION__); - int16_t suId = sngisdn_event->suId; uint32_t suInstId = sngisdn_event->suInstId; uint32_t spInstId = sngisdn_event->spInstId; @@ -716,6 +722,8 @@ void sngisdn_process_fac_ind (sngisdn_event_data_t *sngisdn_event) FacEvnt *facEvnt = &sngisdn_event->event.facEvnt; + ISDN_FUNC_TRACE_ENTER(__FUNCTION__); + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Processing FACILITY IND (suId:%u suInstId:%u spInstId:%u)\n", suId, suInstId, spInstId); switch (ftdmchan->state) { @@ -757,8 +765,6 @@ void sngisdn_process_fac_ind (sngisdn_event_data_t *sngisdn_event) void sngisdn_process_sta_cfm (sngisdn_event_data_t *sngisdn_event) { - ISDN_FUNC_TRACE_ENTER(__FUNCTION__); - int16_t suId = sngisdn_event->suId; uint32_t suInstId = sngisdn_event->suInstId; uint32_t spInstId = sngisdn_event->spInstId; @@ -769,6 +775,8 @@ void sngisdn_process_sta_cfm (sngisdn_event_data_t *sngisdn_event) uint8_t call_state = 0; + ISDN_FUNC_TRACE_ENTER(__FUNCTION__); + if (staEvnt->callSte.eh.pres && staEvnt->callSte.callGlblSte.pres) { call_state = staEvnt->callSte.callGlblSte.val; } @@ -968,6 +976,18 @@ void sngisdn_process_sta_cfm (sngisdn_event_data_t *sngisdn_event) //ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_RESTART); break; } + break; + case 25: /* Overlap receiving */ + switch (ftdmchan->state) { + case FTDM_CHANNEL_STATE_COLLECT: + /* do nothing */ + break; + default: + ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "Don't know how to handle incompatible state. remote call state:%d our state:%s\n", call_state, ftdm_channel_state2str(ftdmchan->state)); + //ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_RESTART); + break; + } + break; default: ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "Don't know how to handle incompatible state. remote call state:%d our state:%s\n", call_state, ftdm_channel_state2str(ftdmchan->state)); //ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_RESTART); @@ -982,11 +1002,12 @@ void sngisdn_process_sta_cfm (sngisdn_event_data_t *sngisdn_event) void sngisdn_process_srv_ind (sngisdn_event_data_t *sngisdn_event) { - ISDN_FUNC_TRACE_ENTER(__FUNCTION__); int16_t suId = sngisdn_event->suId; int16_t dChan = sngisdn_event->dChan; uint8_t ces = sngisdn_event->ces; + ISDN_FUNC_TRACE_ENTER(__FUNCTION__); + /* Function does not require any info from ssHlEvnt struct for now */ /*Srv *srvEvnt = &sngisdn_event->event.srvEvnt;*/ @@ -997,11 +1018,12 @@ void sngisdn_process_srv_ind (sngisdn_event_data_t *sngisdn_event) void sngisdn_process_srv_cfm (sngisdn_event_data_t *sngisdn_event) { - ISDN_FUNC_TRACE_ENTER(__FUNCTION__); int16_t suId = sngisdn_event->suId; int16_t dChan = sngisdn_event->dChan; uint8_t ces = sngisdn_event->ces; + ISDN_FUNC_TRACE_ENTER(__FUNCTION__); + /* Function does not require any info from ssHlEvnt struct for now */ /*Srv *srvEvnt = &sngisdn_event->event.srvEvnt;*/ @@ -1012,12 +1034,13 @@ void sngisdn_process_srv_cfm (sngisdn_event_data_t *sngisdn_event) void sngisdn_process_rst_cfm (sngisdn_event_data_t *sngisdn_event) { - ISDN_FUNC_TRACE_ENTER(__FUNCTION__); int16_t suId = sngisdn_event->suId; int16_t dChan = sngisdn_event->dChan; uint8_t ces = sngisdn_event->ces; uint8_t evntType = sngisdn_event->evntType; + ISDN_FUNC_TRACE_ENTER(__FUNCTION__); + /* Function does not require any info from ssHlEvnt struct for now */ /*Rst *rstEvnt = &sngisdn_event->event.rstEvnt;*/ @@ -1029,12 +1052,13 @@ void sngisdn_process_rst_cfm (sngisdn_event_data_t *sngisdn_event) void sngisdn_process_rst_ind (sngisdn_event_data_t *sngisdn_event) { - ISDN_FUNC_TRACE_ENTER(__FUNCTION__); int16_t suId = sngisdn_event->suId; int16_t dChan = sngisdn_event->dChan; uint8_t ces = sngisdn_event->ces; uint8_t evntType = sngisdn_event->evntType; + ISDN_FUNC_TRACE_ENTER(__FUNCTION__); + /* Function does not require any info from ssHlEvnt struct for now */ /*Rst *rstEvnt = &sngisdn_event->event.rstEvnt;*/ diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_rcv.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_rcv.c index 9bf60537fe..5580f3a950 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_rcv.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_rcv.c @@ -43,11 +43,12 @@ extern void get_memory_info(void); void sngisdn_rcv_con_ind (int16_t suId, uint32_t suInstId, uint32_t spInstId, ConEvnt *conEvnt, int16_t dChan, uint8_t ces) { - ISDN_FUNC_TRACE_ENTER(__FUNCTION__); uint8_t bchan_no = 0; sngisdn_chan_data_t *sngisdn_info = NULL; sngisdn_event_data_t *sngisdn_event = NULL; + ISDN_FUNC_TRACE_ENTER(__FUNCTION__); + ftdm_assert(g_sngisdn_data.ccs[suId].activation_done != 0, "Con Ind on unconfigured cc\n"); ftdm_assert(g_sngisdn_data.dchans[dChan].num_spans != 0, "Con Ind on unconfigured dchan\n"); @@ -103,10 +104,11 @@ void sngisdn_rcv_con_ind (int16_t suId, uint32_t suInstId, uint32_t spInstId, Co void sngisdn_rcv_con_cfm (int16_t suId, uint32_t suInstId, uint32_t spInstId, CnStEvnt *cnStEvnt, int16_t dChan, uint8_t ces) { - ISDN_FUNC_TRACE_ENTER(__FUNCTION__); sngisdn_chan_data_t *sngisdn_info = NULL; sngisdn_event_data_t *sngisdn_event = NULL; + ISDN_FUNC_TRACE_ENTER(__FUNCTION__); + ftdm_assert(g_sngisdn_data.ccs[suId].activation_done != 0, "Con Cfm on unconfigured cc\n"); ftdm_assert(g_sngisdn_data.dchans[dChan].num_spans != 0, "Con Cfm on unconfigured dchan\n"); @@ -146,10 +148,11 @@ void sngisdn_rcv_con_cfm (int16_t suId, uint32_t suInstId, uint32_t spInstId, Cn void sngisdn_rcv_cnst_ind (int16_t suId, uint32_t suInstId, uint32_t spInstId, CnStEvnt *cnStEvnt, uint8_t evntType, int16_t dChan, uint8_t ces) { - ISDN_FUNC_TRACE_ENTER(__FUNCTION__); sngisdn_chan_data_t *sngisdn_info = NULL; sngisdn_event_data_t *sngisdn_event = NULL; + ISDN_FUNC_TRACE_ENTER(__FUNCTION__); + ftdm_assert(g_sngisdn_data.ccs[suId].activation_done != 0, "Cnst Ind on unconfigured cc\n"); ftdm_assert(g_sngisdn_data.dchans[dChan].num_spans != 0, "Cnst Ind on unconfigured dchan\n"); @@ -196,10 +199,11 @@ void sngisdn_rcv_cnst_ind (int16_t suId, uint32_t suInstId, uint32_t spInstId, C void sngisdn_rcv_disc_ind (int16_t suId, uint32_t suInstId, uint32_t spInstId, DiscEvnt *discEvnt) { - ISDN_FUNC_TRACE_ENTER(__FUNCTION__); sngisdn_chan_data_t *sngisdn_info = NULL; sngisdn_event_data_t *sngisdn_event = NULL; + ISDN_FUNC_TRACE_ENTER(__FUNCTION__); + ftdm_assert(spInstId != 0, "Received DISCONNECT with invalid id"); if (!(spInstId && get_ftdmchan_by_spInstId(suId, spInstId, &sngisdn_info) == FTDM_SUCCESS) && @@ -231,9 +235,10 @@ void sngisdn_rcv_disc_ind (int16_t suId, uint32_t suInstId, uint32_t spInstId, D void sngisdn_rcv_rel_ind (int16_t suId, uint32_t suInstId, uint32_t spInstId, RelEvnt *relEvnt) { - ISDN_FUNC_TRACE_ENTER(__FUNCTION__); sngisdn_chan_data_t *sngisdn_info = NULL; sngisdn_event_data_t *sngisdn_event = NULL; + + ISDN_FUNC_TRACE_ENTER(__FUNCTION__); if (!(spInstId && get_ftdmchan_by_spInstId(suId, spInstId, &sngisdn_info) == FTDM_SUCCESS) && !(suInstId && get_ftdmchan_by_suInstId(suId, suInstId, &sngisdn_info) == FTDM_SUCCESS)) { @@ -264,10 +269,11 @@ void sngisdn_rcv_rel_ind (int16_t suId, uint32_t suInstId, uint32_t spInstId, Re void sngisdn_rcv_dat_ind (int16_t suId, uint32_t suInstId, uint32_t spInstId, InfoEvnt *infoEvnt) { - ISDN_FUNC_TRACE_ENTER(__FUNCTION__); sngisdn_chan_data_t *sngisdn_info; sngisdn_event_data_t *sngisdn_event = NULL; + ISDN_FUNC_TRACE_ENTER(__FUNCTION__); + if (!(spInstId && get_ftdmchan_by_spInstId(suId, spInstId, &sngisdn_info) == FTDM_SUCCESS) && !(suInstId && get_ftdmchan_by_suInstId(suId, suInstId, &sngisdn_info) == FTDM_SUCCESS)) { @@ -296,9 +302,10 @@ void sngisdn_rcv_dat_ind (int16_t suId, uint32_t suInstId, uint32_t spInstId, In void sngisdn_rcv_sshl_ind (int16_t suId, uint32_t suInstId, uint32_t spInstId, SsHlEvnt *ssHlEvnt, uint8_t action) { - ISDN_FUNC_TRACE_ENTER(__FUNCTION__); sngisdn_chan_data_t *sngisdn_info; sngisdn_event_data_t *sngisdn_event = NULL; + + ISDN_FUNC_TRACE_ENTER(__FUNCTION__); if (!(spInstId && get_ftdmchan_by_spInstId(suId, spInstId, &sngisdn_info) == FTDM_SUCCESS) && !(suInstId && get_ftdmchan_by_suInstId(suId, suInstId, &sngisdn_info) == FTDM_SUCCESS)) { @@ -329,9 +336,10 @@ void sngisdn_rcv_sshl_ind (int16_t suId, uint32_t suInstId, uint32_t spInstId, S void sngisdn_rcv_sshl_cfm (int16_t suId, uint32_t suInstId, uint32_t spInstId, SsHlEvnt *ssHlEvnt, uint8_t action) { - ISDN_FUNC_TRACE_ENTER(__FUNCTION__); sngisdn_chan_data_t *sngisdn_info; sngisdn_event_data_t *sngisdn_event = NULL; + + ISDN_FUNC_TRACE_ENTER(__FUNCTION__); if (!(spInstId && get_ftdmchan_by_spInstId(suId, spInstId, &sngisdn_info) == FTDM_SUCCESS) && !(suInstId && get_ftdmchan_by_suInstId(suId, suInstId, &sngisdn_info) == FTDM_SUCCESS)) { @@ -361,9 +369,10 @@ void sngisdn_rcv_sshl_cfm (int16_t suId, uint32_t suInstId, uint32_t spInstId, S } void sngisdn_rcv_rmrt_ind (int16_t suId, uint32_t suInstId, uint32_t spInstId, RmRtEvnt *rmRtEvnt, uint8_t action) { - ISDN_FUNC_TRACE_ENTER(__FUNCTION__); sngisdn_chan_data_t *sngisdn_info; sngisdn_event_data_t *sngisdn_event = NULL; + + ISDN_FUNC_TRACE_ENTER(__FUNCTION__); if (!(spInstId && get_ftdmchan_by_spInstId(suId, spInstId, &sngisdn_info) == FTDM_SUCCESS) && !(suInstId && get_ftdmchan_by_suInstId(suId, suInstId, &sngisdn_info) == FTDM_SUCCESS)) { @@ -394,9 +403,10 @@ void sngisdn_rcv_rmrt_ind (int16_t suId, uint32_t suInstId, uint32_t spInstId, R void sngisdn_rcv_rmrt_cfm (int16_t suId, uint32_t suInstId, uint32_t spInstId, RmRtEvnt *rmRtEvnt, uint8_t action) { - ISDN_FUNC_TRACE_ENTER(__FUNCTION__); sngisdn_chan_data_t *sngisdn_info; sngisdn_event_data_t *sngisdn_event = NULL; + + ISDN_FUNC_TRACE_ENTER(__FUNCTION__); if (!(spInstId && get_ftdmchan_by_spInstId(suId, spInstId, &sngisdn_info) == FTDM_SUCCESS) && !(suInstId && get_ftdmchan_by_suInstId(suId, suInstId, &sngisdn_info) == FTDM_SUCCESS)) { @@ -427,9 +437,10 @@ void sngisdn_rcv_rmrt_cfm (int16_t suId, uint32_t suInstId, uint32_t spInstId, R void sngisdn_rcv_flc_ind (int16_t suId, uint32_t suInstId, uint32_t spInstId, StaEvnt *staEvnt) { - ISDN_FUNC_TRACE_ENTER(__FUNCTION__); sngisdn_chan_data_t *sngisdn_info; sngisdn_event_data_t *sngisdn_event = NULL; + + ISDN_FUNC_TRACE_ENTER(__FUNCTION__); if (!(spInstId && get_ftdmchan_by_spInstId(suId, spInstId, &sngisdn_info) == FTDM_SUCCESS) && !(suInstId && get_ftdmchan_by_suInstId(suId, suInstId, &sngisdn_info) == FTDM_SUCCESS)) { @@ -460,9 +471,10 @@ void sngisdn_rcv_flc_ind (int16_t suId, uint32_t suInstId, uint32_t spInstId, St void sngisdn_rcv_fac_ind (int16_t suId, uint32_t suInstId, uint32_t spInstId, FacEvnt *facEvnt, uint8_t evntType, int16_t dChan, uint8_t ces) { - ISDN_FUNC_TRACE_ENTER(__FUNCTION__); sngisdn_chan_data_t *sngisdn_info; sngisdn_event_data_t *sngisdn_event = NULL; + + ISDN_FUNC_TRACE_ENTER(__FUNCTION__); if (!(spInstId && get_ftdmchan_by_spInstId(suId, spInstId, &sngisdn_info) == FTDM_SUCCESS) && !(suInstId && get_ftdmchan_by_suInstId(suId, suInstId, &sngisdn_info) == FTDM_SUCCESS)) { @@ -493,9 +505,10 @@ void sngisdn_rcv_fac_ind (int16_t suId, uint32_t suInstId, uint32_t spInstId, Fa void sngisdn_rcv_sta_cfm (int16_t suId, uint32_t suInstId, uint32_t spInstId, StaEvnt *staEvnt) { - ISDN_FUNC_TRACE_ENTER(__FUNCTION__); sngisdn_chan_data_t *sngisdn_info; sngisdn_event_data_t *sngisdn_event = NULL; + + ISDN_FUNC_TRACE_ENTER(__FUNCTION__); if (!(spInstId && get_ftdmchan_by_spInstId(suId, spInstId, &sngisdn_info) == FTDM_SUCCESS) && !(suInstId && get_ftdmchan_by_suInstId(suId, suInstId, &sngisdn_info) == FTDM_SUCCESS)) { @@ -525,11 +538,12 @@ void sngisdn_rcv_sta_cfm (int16_t suId, uint32_t suInstId, uint32_t spInstId, St void sngisdn_rcv_srv_ind (int16_t suId, Srv *srvEvnt, int16_t dChan, uint8_t ces) { - ISDN_FUNC_TRACE_ENTER(__FUNCTION__); unsigned i; sngisdn_span_data_t *signal_data; sngisdn_event_data_t *sngisdn_event = NULL; + ISDN_FUNC_TRACE_ENTER(__FUNCTION__); + ftdm_log(FTDM_LOG_INFO, "Received SERVICE IND (dChan:%d ces:%u)\n", dChan, ces); /* Enqueue the event to each span within the dChan */ @@ -554,11 +568,12 @@ void sngisdn_rcv_srv_ind (int16_t suId, Srv *srvEvnt, int16_t dChan, uint8_t ces void sngisdn_rcv_srv_cfm (int16_t suId, Srv *srvEvnt, int16_t dChan, uint8_t ces) { - ISDN_FUNC_TRACE_ENTER(__FUNCTION__); unsigned i; sngisdn_span_data_t *signal_data = NULL; sngisdn_event_data_t *sngisdn_event = NULL; + ISDN_FUNC_TRACE_ENTER(__FUNCTION__); + ftdm_log(FTDM_LOG_INFO, "Received SERVICE CFM (dChan:%d ces:%u)\n", dChan, ces); /* Enqueue the event to each span within the dChan */ @@ -582,11 +597,12 @@ void sngisdn_rcv_srv_cfm (int16_t suId, Srv *srvEvnt, int16_t dChan, uint8_t ces void sngisdn_rcv_rst_ind (int16_t suId, Rst *rstEvnt, int16_t dChan, uint8_t ces, uint8_t evntType) { - ISDN_FUNC_TRACE_ENTER(__FUNCTION__); unsigned i; sngisdn_span_data_t *signal_data = NULL; sngisdn_event_data_t *sngisdn_event = NULL; + ISDN_FUNC_TRACE_ENTER(__FUNCTION__); + ftdm_log(FTDM_LOG_INFO, "Received RESTART IND (dChan:%d ces:%u type:%u)\n", dChan, ces, evntType); /* Enqueue the event to each span within the dChan */ @@ -612,11 +628,12 @@ void sngisdn_rcv_rst_ind (int16_t suId, Rst *rstEvnt, int16_t dChan, uint8_t ces void sngisdn_rcv_rst_cfm (int16_t suId, Rst *rstEvnt, int16_t dChan, uint8_t ces, uint8_t evntType) { - ISDN_FUNC_TRACE_ENTER(__FUNCTION__); unsigned i; sngisdn_span_data_t *signal_data; sngisdn_event_data_t *sngisdn_event = NULL; + ISDN_FUNC_TRACE_ENTER(__FUNCTION__); + ftdm_log(FTDM_LOG_INFO, "Received RESTART CFM (dChan:%d ces:%u type:%u)\n", dChan, ces, evntType); /* Enqueue the event to each span within the dChan */ 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 a77fb05383..f54f7db61c 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 @@ -49,7 +49,7 @@ ftdm_status_t sngisdn_check_free_ids(void); extern ftdm_sngisdn_data_t g_sngisdn_data; void get_memory_info(void); -void __inline__ clear_call_data(sngisdn_chan_data_t *sngisdn_info) +FT_DECLARE_INLINE(void) clear_call_data(sngisdn_chan_data_t *sngisdn_info) { uint32_t cc_id = ((sngisdn_span_data_t*)sngisdn_info->ftdmchan->span->signal_data)->cc_id; @@ -66,7 +66,7 @@ void __inline__ clear_call_data(sngisdn_chan_data_t *sngisdn_info) return; } -void __inline__ clear_call_glare_data(sngisdn_chan_data_t *sngisdn_info) +FT_DECLARE_INLINE(void) clear_call_glare_data(sngisdn_chan_data_t *sngisdn_info) { ftdm_log_chan(sngisdn_info->ftdmchan, FTDM_LOG_DEBUG, "Clearing glare data (suId:%d suInstId:%u spInstId:%u actv-suInstId:%u actv-spInstId:%u)\n", sngisdn_info->glare.suId, @@ -91,9 +91,10 @@ void __inline__ clear_call_glare_data(sngisdn_chan_data_t *sngisdn_info) } -uint32_t __inline__ get_unique_suInstId(uint8_t cc_id) +FT_DECLARE_INLINE(uint32_t) get_unique_suInstId(int16_t cc_id) { uint32_t suInstId; + ftdm_assert_return((cc_id > 0 && cc_id <=MAX_VARIANTS), FTDM_FAIL, "Invalid cc_id\n"); ftdm_mutex_lock(g_sngisdn_data.ccs[cc_id].mutex); suInstId = g_sngisdn_data.ccs[cc_id].last_suInstId; @@ -112,8 +113,9 @@ uint32_t __inline__ get_unique_suInstId(uint8_t cc_id) return 0; } -ftdm_status_t __inline__ get_ftdmchan_by_suInstId(uint8_t cc_id, uint32_t suInstId, sngisdn_chan_data_t **sngisdn_data) +FT_DECLARE_INLINE(ftdm_status_t) get_ftdmchan_by_suInstId(int16_t cc_id, uint32_t suInstId, sngisdn_chan_data_t **sngisdn_data) { + ftdm_assert_return((cc_id > 0 && cc_id <=MAX_VARIANTS), FTDM_FAIL, "Invalid cc_id\n"); ftdm_assert_return(g_sngisdn_data.ccs[cc_id].activation_done, FTDM_FAIL, "Trying to find call on unconfigured CC\n"); if (g_sngisdn_data.ccs[cc_id].active_suInstIds[suInstId] == NULL) { @@ -123,8 +125,9 @@ ftdm_status_t __inline__ get_ftdmchan_by_suInstId(uint8_t cc_id, uint32_t suInst return FTDM_SUCCESS; } -ftdm_status_t __inline__ get_ftdmchan_by_spInstId(uint8_t cc_id, uint32_t spInstId, sngisdn_chan_data_t **sngisdn_data) +FT_DECLARE_INLINE(ftdm_status_t) get_ftdmchan_by_spInstId(int16_t cc_id, uint32_t spInstId, sngisdn_chan_data_t **sngisdn_data) { + ftdm_assert_return((cc_id > 0 && cc_id <=MAX_VARIANTS), FTDM_FAIL, "Invalid cc_id\n"); ftdm_assert_return(g_sngisdn_data.ccs[cc_id].activation_done, FTDM_FAIL, "Trying to find call on unconfigured CC\n"); if (g_sngisdn_data.ccs[cc_id].active_spInstIds[spInstId] == NULL) { diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_trace.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_trace.c index 7d4d347eab..624d35c147 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_trace.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_trace.c @@ -100,7 +100,7 @@ uint8_t get_bits(uint8_t octet, uint8_t bitLo, uint8_t bitHi) void sngisdn_trace_q921(char* str, uint8_t* data, uint32_t data_len) { int str_len; - int i; + uint32_t i; uint8_t sapi, cr, ea, tei, ns, nr, pf, p, cmd; uint8_t frame_format = 0; @@ -649,7 +649,7 @@ uint32_t sngisdn_decode_ie(char *str, uint32_t *str_len, uint8_t current_codeset void print_hex_dump(char* str, uint32_t *str_len, uint8_t* data, uint32_t index_start, uint32_t index_end) { - int k; + uint32_t k; *str_len += sprintf(&str[*str_len], " [ "); for(k=index_start; k <= index_end; k++) { if (k && !(k%32)) { diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c index 807b3b62c7..af3b9edbae 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c @@ -216,8 +216,23 @@ ftdm_status_t handle_con_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circ sprintf(nadi, "%d", siConEvnt->cdPtyNum.natAddrInd.val); ftdm_channel_add_var(ftdmchan, "ss7_cld_nadi", nadi); - /* set the state of the channel to collecting...the rest is done by the chan monitor */ - ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_COLLECT); + + /* check if a COT test is requested */ + if ((siConEvnt->natConInd.eh.pres) && + (siConEvnt->natConInd.contChkInd.pres) && + (siConEvnt->natConInd.contChkInd.val)) { + + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Found COT Request\n", sngss7_info->circuit->cic); + + /* tell the core to loop the channel */ + ftdm_channel_command(ftdmchan, FTDM_COMMAND_ENABLE_LOOP, NULL); + + /* move to in loop state */ + ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_IN_LOOP); + } else { + /* set the state of the channel to collecting...the rest is done by the chan monitor */ + ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_COLLECT); + } } /* if (channel is usable */ @@ -256,6 +271,9 @@ handle_glare: default: /* should not have gotten an IAM while in this state */ SS7_ERROR_CHAN(ftdmchan, "Got IAM on channel in invalid state(%s)...reset!\n", ftdm_channel_state2str (ftdmchan->state)); + /* reset the cic */ + sngss7_set_flag(sngss7_info, FLAG_RESET_TX); + /* move the state of the channel to RESTART to force a reset */ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_RESTART); @@ -292,6 +310,7 @@ ftdm_status_t handle_con_sta(uint32_t suInstId, uint32_t spInstId, uint32_t circ /**************************************************************************/ case (ADDRCMPLT): SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Rx ACM\n", sngss7_info->circuit->cic); + switch (ftdmchan->state) { /**********************************************************************/ case FTDM_CHANNEL_STATE_DIALING: @@ -315,14 +334,22 @@ ftdm_status_t handle_con_sta(uint32_t suInstId, uint32_t spInstId, uint32_t circ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_PROGRESS_MEDIA); } - break; + break; /**********************************************************************/ default: /* incorrect state...reset the CIC */ + SS7_ERROR_CHAN(ftdmchan, "RX ACM in invalid state :%s...resetting CIC\n", + ftdm_channel_state2str (ftdmchan->state)); + + /* reset the cic */ + sngss7_set_flag(sngss7_info, FLAG_RESET_TX); + /* go to RESTART */ - ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_PROGRESS); - break; + ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_RESTART); + break; /**********************************************************************/ } /* switch (ftdmchan->state) */ + + break; /**************************************************************************/ case (MODIFY): SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Rx MODIFY\n", sngss7_info->circuit->cic); @@ -354,6 +381,34 @@ ftdm_status_t handle_con_sta(uint32_t suInstId, uint32_t spInstId, uint32_t circ /**************************************************************************/ case (SUBSADDR): SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Rx SAM\n", sngss7_info->circuit->cic); + + /* check the channel state */ + switch (ftdmchan->state) { + /**********************************************************************/ + case (FTDM_CHANNEL_STATE_COLLECT): + + /* confirm that the event contains the subsquent number field */ + if (siCnStEvnt->subNum.eh.pres && siCnStEvnt->subNum.addrSig.pres) { + /* add the digits to the ftdm channel variable */ + append_tknStr_from_sngss7(siCnStEvnt->subNum.addrSig, + ftdmchan->caller_data.dnis.digits, + siCnStEvnt->subNum.oddEven); + } else { + SS7_INFO_CHAN(ftdmchan,"No Called party (DNIS) information in SAM!%s\n", " "); + } + + /* go to idle so that collect state is processed again */ + ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_IDLE); + + break; + /**********************************************************************/ + default: + SS7_ERROR_CHAN(ftdmchan, "RX SAM in invalid state :%s...ignoring\n", + ftdm_channel_state2str (ftdmchan->state)); + break; + /**********************************************************************/ + } /* switch (ftdmchan->state) */ + break; /**************************************************************************/ case (EXIT): @@ -543,7 +598,7 @@ ftdm_status_t handle_rel_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circ /* this is a remote hangup request */ sngss7_set_flag(sngss7_info, FLAG_REMOTE_REL); - +ftdm_channel_command(ftdmchan, FTDM_COMMAND_DISABLE_LOOP, NULL); /* move the state of the channel to CANCEL to end the call */ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING); @@ -558,7 +613,7 @@ ftdm_status_t handle_rel_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circ if (siRelEvnt->causeDgn.causeVal.pres) { ftdmchan->caller_data.hangup_cause = siRelEvnt->causeDgn.causeVal.val; } else { - SS7_ERROR("REL does not have a cause code!\n"); + SS7_ERROR("REL does not have a cause ftdm_channel_command(ftdmchan, FTDM_COMMAND_DISABLE_LOOP, NULL);code!\n"); ftdmchan->caller_data.hangup_cause = 0; } @@ -570,6 +625,23 @@ ftdm_status_t handle_rel_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circ break; /**************************************************************************/ + case FTDM_CHANNEL_STATE_IN_LOOP: + + /* inform the core to unloop the channel*/ + ftdm_channel_command(ftdmchan, FTDM_COMMAND_DISABLE_LOOP, NULL); + + /* since we need to acknowledge the hang up set the flag for remote release */ + sngss7_set_flag(sngss7_info, FLAG_REMOTE_REL); + + /* go to hangup complete to send the RLC */ + ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP_COMPLETE); + + /* save the call info for the RLC */ + sngss7_info->suInstId = get_unique_id(); + sngss7_info->spInstId = spInstId; + + break; + /**************************************************************************/ default: /* throw the reset flag */ @@ -830,7 +902,7 @@ ftdm_status_t handle_sta_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circ break; /**************************************************************************/ case SIT_STA_CONTCHK: /* continuity check */ - SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Rx COT start\n", sngss7_info->circuit->cic); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Rx CCR start\n", sngss7_info->circuit->cic); handle_cot_start(suInstId, spInstId, circuit, globalFlg, evntType, siStaEvnt); break; /**************************************************************************/ @@ -840,7 +912,7 @@ ftdm_status_t handle_sta_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circ break; /**************************************************************************/ case SIT_STA_STPCONTIN: /* stop continuity */ - SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Rx COT stop\n", sngss7_info->circuit->cic); + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Rx CCR stop\n", sngss7_info->circuit->cic); handle_cot_stop(suInstId, spInstId, circuit, globalFlg, evntType, siStaEvnt); break; /**************************************************************************/ @@ -1225,7 +1297,7 @@ ftdm_status_t handle_cot_start(uint32_t suInstId, uint32_t spInstId, uint32_t ci /* open the channel if it is not open */ if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OPEN)) { if (ftdm_channel_open_chan(ftdmchan) != FTDM_SUCCESS) { - SS7_ERROR("Failed to open CIC %d for COT test!\n", sngss7_info->circuit->cic); + SS7_ERROR("Failed to open CIC %d for CCR test!\n", sngss7_info->circuit->cic); /* KONRAD FIX ME */ SS7_FUNC_TRACE_EXIT(__FUNCTION__); return FTDM_FAIL; @@ -1238,15 +1310,6 @@ ftdm_status_t handle_cot_start(uint32_t suInstId, uint32_t spInstId, uint32_t ci /* switch to the IN_LOOP state */ ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_IN_LOOP); - /* store the sngss7 ids */ - if (suInstId == 0) { - sngss7_info->suInstId = get_unique_id(); - } else { - sngss7_info->suInstId = suInstId; - } - sngss7_info->spInstId = spInstId; - sngss7_info->globalFlg = globalFlg; - /* unlock the channel again before we exit */ ftdm_mutex_unlock(ftdmchan->mutex); @@ -1290,6 +1353,38 @@ ftdm_status_t handle_cot(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, { SS7_FUNC_TRACE_ENTER(__FUNCTION__); + sngss7_chan_data_t *sngss7_info = NULL; + ftdm_channel_t *ftdmchan = NULL; + + /* get the ftdmchan and ss7_chan_data from the circuit */ + if (extract_chan_data(circuit, &sngss7_info, &ftdmchan)) { + SS7_ERROR("Failed to extract channel data for circuit = %d!\n", circuit); + SS7_FUNC_TRACE_EXIT(__FUNCTION__); + return FTDM_FAIL; + } + + /* lock the channel */ + ftdm_mutex_lock(ftdmchan->mutex); + + switch (ftdmchan->state) { + /**************************************************************************/ + case (FTDM_CHANNEL_STATE_IN_LOOP): + /* tell the core to stop looping the channel */ + ftdm_channel_command(ftdmchan, FTDM_COMMAND_DISABLE_LOOP, NULL); + + /* exit out of the LOOP state and go to collect */ + ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_COLLECT); + + break; + /**************************************************************************/ + default: + /* exit out of the LOOP state to the last state */ + ftdm_set_state_locked(ftdmchan, ftdmchan->last_state); + + break; + /**************************************************************************/ + } /* switch (ftdmchan->state) */ + if ( (siStaEvnt->contInd.eh.pres > 0) && (siStaEvnt->contInd.contInd.pres > 0)) { SS7_INFO("Continuity Test result for CIC = %d (span %d, chan %d) is: \"%s\"\n", g_ftdm_sngss7_data.cfg.isupCkt[circuit].cic, @@ -1300,13 +1395,13 @@ ftdm_status_t handle_cot(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, SS7_ERROR("Recieved Continuity report containing no results!\n"); } + /* unlock the channel again before we exit */ + ftdm_mutex_unlock(ftdmchan->mutex); + SS7_FUNC_TRACE_EXIT(__FUNCTION__); return FTDM_SUCCESS; } -/******************************************************************************/ - - /******************************************************************************/ ftdm_status_t handle_blo_req(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, uint8_t globalFlg, uint8_t evntType, SiStaEvnt *siStaEvnt) { @@ -1575,7 +1670,7 @@ ftdm_status_t handle_rsc_rsp(uint32_t suInstId, uint32_t spInstId, uint32_t circ sngss7_set_flag(sngss7_info, FLAG_RESET_TX_RSP); /* go to DOWN */ - ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN); + /*ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN);*/ break; /**********************************************************************/ diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c index 587242d94e..7612f3dd74 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.c @@ -79,7 +79,7 @@ ftdm_state_map_t sangoma_ss7_state_map = { ZSD_INBOUND, ZSM_UNACCEPTABLE, {FTDM_CHANNEL_STATE_IDLE, FTDM_END}, - {FTDM_CHANNEL_STATE_RESTART, FTDM_END} + {FTDM_CHANNEL_STATE_RESTART, FTDM_CHANNEL_STATE_COLLECT, FTDM_END} }, { ZSD_INBOUND, @@ -93,14 +93,16 @@ ftdm_state_map_t sangoma_ss7_state_map = { ZSM_UNACCEPTABLE, {FTDM_CHANNEL_STATE_IN_LOOP, FTDM_END}, {FTDM_CHANNEL_STATE_SUSPENDED, FTDM_CHANNEL_STATE_RESTART, - FTDM_CHANNEL_STATE_COLLECT, FTDM_CHANNEL_STATE_DOWN, FTDM_END} + FTDM_CHANNEL_STATE_COLLECT, FTDM_CHANNEL_STATE_DOWN, + FTDM_CHANNEL_STATE_HANGUP_COMPLETE, FTDM_END} }, { ZSD_INBOUND, ZSM_UNACCEPTABLE, {FTDM_CHANNEL_STATE_COLLECT, FTDM_END}, {FTDM_CHANNEL_STATE_SUSPENDED, FTDM_CHANNEL_STATE_RESTART, - FTDM_CHANNEL_STATE_CANCEL, FTDM_CHANNEL_STATE_RING, FTDM_END} + FTDM_CHANNEL_STATE_CANCEL, FTDM_CHANNEL_STATE_RING, + FTDM_CHANNEL_STATE_IDLE, FTDM_END} }, { ZSD_INBOUND, @@ -526,29 +528,32 @@ void ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) ftdm_set_state_locked (ftdmchan, FTDM_CHANNEL_STATE_RING); } else { - SS7_INFO_CHAN(ftdmchan,"Received %d out of %d so far: %s...starting T35\n", - i, - g_ftdm_sngss7_data.min_digits, - ftdmchan->caller_data.dnis.digits); - - /* start ISUP t35 */ - if (ftdm_sched_timer (sngss7_info->t35.sched, - "t35", - sngss7_info->t35.beat, - sngss7_info->t35.callback, - &sngss7_info->t35, - &sngss7_info->t35.hb_timer_id)) { - - SS7_ERROR ("Unable to schedule timer, hanging up call!\n"); - - ftdmchan->caller_data.hangup_cause = 41; - - /* set the flag to indicate this hangup is started from the local side */ - sngss7_set_flag (sngss7_info, FLAG_LOCAL_REL); - - /* end the call */ - ftdm_set_state_locked (ftdmchan, FTDM_CHANNEL_STATE_CANCEL); - } /* if (ftdm_sched_timer(sngss7_info->t35.sched, */ + /* if we are coming from idle state then we have already been here once before */ + if (ftdmchan->last_state != FTDM_CHANNEL_STATE_IDLE) { + SS7_INFO_CHAN(ftdmchan,"Received %d out of %d so far: %s...starting T35\n", + i, + g_ftdm_sngss7_data.min_digits, + ftdmchan->caller_data.dnis.digits); + + /* start ISUP t35 */ + if (ftdm_sched_timer (sngss7_info->t35.sched, + "t35", + sngss7_info->t35.beat, + sngss7_info->t35.callback, + &sngss7_info->t35, + &sngss7_info->t35.hb_timer_id)) { + + SS7_ERROR ("Unable to schedule timer, hanging up call!\n"); + + ftdmchan->caller_data.hangup_cause = 41; + + /* set the flag to indicate this hangup is started from the local side */ + sngss7_set_flag (sngss7_info, FLAG_LOCAL_REL); + + /* end the call */ + ftdm_set_state_locked (ftdmchan, FTDM_CHANNEL_STATE_CANCEL); + } /* if (ftdm_sched_timer(sngss7_info->t35.sched, */ + } /* if (ftdmchan->last_state != FTDM_CHANNEL_STATE_IDLE) */ } /* checking ST/#digits */ break; @@ -966,6 +971,14 @@ void ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) ftdm_set_state_locked (ftdmchan, ftdmchan->last_state); break; /******************************************************************/ + case (FTDM_CHANNEL_STATE_IN_LOOP): + /* we screwed up in a COT/CCR, remove the loop */ + ftdm_channel_command(ftdmchan, FTDM_COMMAND_DISABLE_LOOP, NULL); + + /* go to down */ + ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN); + break; + /******************************************************************/ default: /* KONRAD: find out what the cause code should be */ ftdmchan->caller_data.hangup_cause = 41; diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h index 27833cb2a2..378b50e0ad 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h @@ -581,6 +581,8 @@ uint8_t copy_cgPtyNum_to_sngss7(ftdm_caller_data_t *ftdm, SiCgPtyNum *cgPtyNum); uint8_t copy_cdPtyNum_from_sngss7(ftdm_caller_data_t *ftdm, SiCdPtyNum *cdPtyNum); uint8_t copy_cdPtyNum_to_sngss7(ftdm_caller_data_t *ftdm, SiCdPtyNum *cdPtyNum); uint8_t copy_tknStr_from_sngss7(TknStr str, char *ftdm, TknU8 oddEven); +uint8_t append_tknStr_from_sngss7(TknStr str, char *ftdm, TknU8 oddEven); + int check_for_state_change(ftdm_channel_t *ftdmchan); int check_cics_in_range(sngss7_chan_data_t *sngss7_info); int check_for_reset(sngss7_chan_data_t *sngss7_info); diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c index 8cbe6d9498..970d006756 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c @@ -335,15 +335,35 @@ void ft_to_sngss7_acm (ftdm_channel_t * ftdmchan) acm.bckCallInd.isdnAccInd.pres = PRSNT_NODEF; acm.bckCallInd.isdnAccInd.val = ISDNACC_NONISDN; acm.bckCallInd.echoCtrlDevInd.pres = PRSNT_NODEF; - acm.bckCallInd.echoCtrlDevInd.val = 0x1; /* ec device present */ + switch (ftdmchan->caller_data.bearer_capability) { + /**********************************************************************/ + case (FTDM_BEARER_CAP_SPEECH): + acm.bckCallInd.echoCtrlDevInd.val = 0x1; + break; + /**********************************************************************/ + case (FTDM_BEARER_CAP_64K_UNRESTRICTED): + acm.bckCallInd.echoCtrlDevInd.val = 0x0; + break; + /**********************************************************************/ + case (FTDM_BEARER_CAP_3_1KHZ_AUDIO): + acm.bckCallInd.echoCtrlDevInd.val = 0x1; + break; + /**********************************************************************/ + default: + SS7_ERROR_CHAN(ftdmchan, "Unknown Bearer capability falling back to speech%s\n", " "); + acm.bckCallInd.echoCtrlDevInd.val = 0x1; + break; + /**********************************************************************/ + } /* switch (ftdmchan->caller_data.bearer_capability) */ acm.bckCallInd.sccpMethInd.pres = PRSNT_NODEF; acm.bckCallInd.sccpMethInd.val = SCCPMTH_NOIND; /* fill in any optional parameters */ if (sngss7_test_options(isup_intf, SNGSS7_ACM_OBCI_BITA)) { + SS7_DEBUG_CHAN(ftdmchan, "Found ACM_OBCI_BITA flag:0x%X\n", isup_intf->options); acm.optBckCalInd.eh.pres = PRSNT_NODEF; acm.optBckCalInd.inbndInfoInd.pres = PRSNT_NODEF; - acm.optBckCalInd.inbndInfoInd.val = sngss7_test_options(isup_intf, SNGSS7_ACM_OBCI_BITA); + acm.optBckCalInd.inbndInfoInd.val = 0x1; acm.optBckCalInd.caFwdMayOcc.pres = PRSNT_DEF; acm.optBckCalInd.simpleSegmInd.pres = PRSNT_DEF; acm.optBckCalInd.mlppUserInd.pres = PRSNT_DEF; diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c index 718663950a..4d497b599d 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c @@ -44,6 +44,7 @@ uint32_t sngss7_id; /* PROTOTYPES *****************************************************************/ uint8_t copy_tknStr_from_sngss7(TknStr str, char *ftdm, TknU8 oddEven); +uint8_t append_tknStr_from_sngss7(TknStr str, char *ftdm, TknU8 oddEven); uint8_t copy_cgPtyNum_from_sngss7(ftdm_caller_data_t *ftdm, SiCgPtyNum *cgPtyNum); uint8_t copy_cgPtyNum_to_sngss7(ftdm_caller_data_t *ftdm, SiCgPtyNum *cgPtyNum); uint8_t copy_cdPtyNum_from_sngss7(ftdm_caller_data_t *ftdm, SiCdPtyNum *cdPtyNum); @@ -131,7 +132,8 @@ uint8_t copy_cgPtyNum_to_sngss7(ftdm_caller_data_t *ftdm, SiCgPtyNum *cgPtyNum) tmp[0] = ftdm->cid_num.digits[k]; /* check if the digit is a number and that is not null */ - while (!(isdigit(tmp[0])) && (tmp[0] != '\0')) { + while (!(isxdigit(tmp[0])) && (tmp[0] != '\0')) { + SS7_INFO("Dropping invalid digit: %c\n", tmp[0]); /* move on to the next value */ k++; tmp[0] = ftdm->cid_num.digits[k]; @@ -140,14 +142,15 @@ uint8_t copy_cgPtyNum_to_sngss7(ftdm_caller_data_t *ftdm, SiCgPtyNum *cgPtyNum) /* check if tmp is null or a digit */ if (tmp[0] != '\0') { /* push it into the lower nibble */ - lower = atoi(&tmp[0]); + lower = strtol(&tmp[0], (char **)NULL, 16); /* move to the next digit */ k++; /* grab a digit from the ftdm digits */ tmp[0] = ftdm->cid_num.digits[k]; /* check if the digit is a number and that is not null */ - while (!(isdigit(tmp[0])) && (tmp[0] != '\0')) { + while (!(isxdigit(tmp[0])) && (tmp[0] != '\0')) { + SS7_INFO("Dropping invalid digit: %c\n", tmp[0]); k++; tmp[0] = ftdm->cid_num.digits[k]; } /* while(!(isdigit(tmp))) */ @@ -155,7 +158,7 @@ uint8_t copy_cgPtyNum_to_sngss7(ftdm_caller_data_t *ftdm, SiCgPtyNum *cgPtyNum) /* check if tmp is null or a digit */ if (tmp[0] != '\0') { /* push the digit into the upper nibble */ - upper = (atoi(&tmp[0])) << 4; + upper = (strtol(&tmp[0], (char **)NULL, 16)) << 4; } else { /* there is no upper ... fill in 0 */ upper = 0x0; @@ -242,7 +245,8 @@ uint8_t copy_cdPtyNum_to_sngss7(ftdm_caller_data_t *ftdm, SiCdPtyNum *cdPtyNum) tmp[0] = ftdm->dnis.digits[k]; /* check if the digit is a number and that is not null */ - while (!(isdigit(tmp[0])) && (tmp[0] != '\0')) { + while (!(isxdigit(tmp[0])) && (tmp[0] != '\0')) { + SS7_INFO("Dropping invalid digit: %c\n", tmp[0]); /* move on to the next value */ k++; tmp[0] = ftdm->dnis.digits[k]; @@ -251,14 +255,15 @@ uint8_t copy_cdPtyNum_to_sngss7(ftdm_caller_data_t *ftdm, SiCdPtyNum *cdPtyNum) /* check if tmp is null or a digit */ if (tmp[0] != '\0') { /* push it into the lower nibble */ - lower = atoi(&tmp[0]); + lower = strtol(&tmp[0], (char **)NULL, 16); /* move to the next digit */ k++; /* grab a digit from the ftdm digits */ tmp[0] = ftdm->dnis.digits[k]; /* check if the digit is a number and that is not null */ - while (!(isdigit(tmp[0])) && (tmp[0] != '\0')) { + while (!(isxdigit(tmp[0])) && (tmp[0] != '\0')) { + SS7_INFO("Dropping invalid digit: %c\n", tmp[0]); k++; tmp[0] = ftdm->dnis.digits[k]; } /* while(!(isdigit(tmp))) */ @@ -266,7 +271,7 @@ uint8_t copy_cdPtyNum_to_sngss7(ftdm_caller_data_t *ftdm, SiCdPtyNum *cdPtyNum) /* check if tmp is null or a digit */ if (tmp[0] != '\0') { /* push the digit into the upper nibble */ - upper = (atoi(&tmp[0])) << 4; + upper = (strtol(&tmp[0], (char **)NULL, 16)) << 4; } else { /* there is no upper ... fill in ST */ upper = 0xF0; @@ -343,6 +348,49 @@ uint8_t copy_tknStr_from_sngss7(TknStr str, char *ftdm, TknU8 oddEven) return 0; } +/******************************************************************************/ +uint8_t append_tknStr_from_sngss7(TknStr str, char *ftdm, TknU8 oddEven) +{ + int i = 0; + int j = 0; + + /* check if the token string is present */ + if (str.pres == 1) { + /* find the length of the digits so far */ + j = strlen(ftdm); + + /* confirm that we found an acceptable length */ + if ( j > 25 ) { + SS7_ERROR("string length exceeds maxium value...aborting append!\n"); + return 1; + } /* if ( j > 25 ) */ + + /* copy in digits */ + for (i = 0; i < str.len; i++) { + /* convert 4 bit integer to char and copy into lower nibblet*/ + sprintf(&ftdm[j], "%X", (str.val[i] & 0x0F)); + /* move along */ + j++; + /* convert 4 bit integer to char and copy into upper nibblet */ + sprintf(&ftdm[j], "%X", ((str.val[i] & 0xF0) >> 4)); + /* move along */ + j++; + } /* for (i = 0; i < str.len; i++) */ + + /* if the odd flag is up the last digit is a fake "0" */ + if ((oddEven.pres == 1) && (oddEven.val == 1)) { + ftdm[j-1] = '\0'; + } else { + ftdm[j] = '\0'; + } /* if ((oddEven.pres == 1) && (oddEven.val == 1)) */ + } else { + SS7_ERROR("Asked to copy tknStr that is not present!\n"); + return 1; + } /* if (str.pres == 1) */ + + return 0; +} + /******************************************************************************/ int check_for_state_change(ftdm_channel_t *ftdmchan) { @@ -940,6 +988,7 @@ ftdm_status_t encode_subAddrIE_nsap(const char *subAddr, char *subAddrIE, int ty /* confirm it is a digit */ if (!isdigit(tmp[0])) { + SS7_INFO("Dropping invalid digit: %c\n", tmp[0]); /* move to the next character in subAddr */ x++; @@ -1024,6 +1073,7 @@ ftdm_status_t encode_subAddrIE_nat(const char *subAddr, char *subAddrIE, int typ /* confirm it is a hex digit */ while ((!isxdigit(tmp[0])) && (tmp[0] != '\0')) { + SS7_INFO("Dropping invalid digit: %c\n", tmp[0]); /* move to the next character in subAddr */ x++; tmp[0] = subAddr[x]; @@ -1040,6 +1090,7 @@ ftdm_status_t encode_subAddrIE_nat(const char *subAddr, char *subAddrIE, int typ /* check if the digit is a hex digit and that is not null */ while (!(isxdigit(tmp[0])) && (tmp[0] != '\0')) { + SS7_INFO("Dropping invalid digit: %c\n", tmp[0]); x++; tmp[0] = subAddr[x]; } /* while(!(isdigit(tmp))) */ diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c index 0f81d61f25..74d37b53d1 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c @@ -626,6 +626,10 @@ static int ftmod_ss7_parse_mtp_link(ftdm_conf_node_t *mtp_link, sng_mtp_link_t * mtpLink->mtp3.ssf = SSF_NAT; } else if (!strcasecmp(parm->val, "int")) { mtpLink->mtp3.ssf = SSF_INTL; + } else if (!strcasecmp(parm->val, "spare")) { + mtpLink->mtp3.ssf = SSF_SPARE; + } else if (!strcasecmp(parm->val, "res")) { + mtpLink->mtp3.ssf = SSF_RES; } else { SS7_ERROR("\tFound an invalid ssf of \"%s\"!\n", parm->val); return FTDM_FAIL; @@ -1050,6 +1054,12 @@ static int ftmod_ss7_parse_isup_interface(ftdm_conf_node_t *isup_interface) } else if (!strcasecmp(parm->val, "int")) { sng_isup.ssf = SSF_INTL; sng_isap.ssf = SSF_INTL; + } else if (!strcasecmp(parm->val, "spare")) { + sng_isup.ssf = SSF_SPARE; + sng_isap.ssf = SSF_SPARE; + } else if (!strcasecmp(parm->val, "res")) { + sng_isup.ssf = SSF_RES; + sng_isap.ssf = SSF_RES; } else { SS7_ERROR("\tFound an invalid ssf of \"%s\"!\n", parm->val); return FTDM_FAIL; diff --git a/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c b/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c index 314a34a091..d2da1ac07a 100644 --- a/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c +++ b/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c @@ -899,11 +899,11 @@ FIO_SPAN_POLL_EVENT_FUNCTION(wanpipe_poll_event) continue; /* should never happen but happens when shutting down */ } pfds[j] = ftdmchan->mod_data; - inflags[j] = POLLPRI; + inflags[j] = poll_events ? poll_events[j] : POLLPRI; #else memset(&pfds[j], 0, sizeof(pfds[j])); pfds[j].fd = span->channels[i]->sockfd; - pfds[j].events = POLLPRI; + pfds[j].events = poll_events ? poll_events[j] : POLLPRI; #endif /* The driver probably should be able to do this wink/flash/ringing by itself this is sort of a hack to make it work! */ @@ -1011,6 +1011,16 @@ static FIO_GET_ALARMS_FUNCTION(wanpipe_get_alarms) } alarms = tdm_api.wp_tdm_cmd.fe_alarms; #endif +#if 1 + /* DAVIDY - Temporary fix: in the current trunk of libsangoma, for BRI, + WAN_TE_BIT_ALARM_RED bit is set if the card is in disconnected state, but this has + not been ported to Windows-libsangoma yet */ + if (alarms) { + ftdmchan->alarm_flags |= FTDM_ALARM_RED; + alarms = 0; + } +#endif + ftdmchan->alarm_flags = FTDM_ALARM_NONE; if (alarms & WAN_TE_BIT_ALARM_RED) { diff --git a/libs/freetdm/src/include/freetdm.h b/libs/freetdm/src/include/freetdm.h index 1efe459032..64ecc2e357 100644 --- a/libs/freetdm/src/include/freetdm.h +++ b/libs/freetdm/src/include/freetdm.h @@ -459,7 +459,7 @@ struct ftdm_memory_handler { #define FIO_CHANNEL_GET_SIG_STATUS_ARGS (ftdm_channel_t *ftdmchan, ftdm_signaling_status_t *status) #define FIO_SPAN_SET_SIG_STATUS_ARGS (ftdm_span_t *span, ftdm_signaling_status_t status) #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) +#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_SIGNAL_CB_ARGS (ftdm_sigmsg_t *sigmsg) #define FIO_EVENT_CB_ARGS (ftdm_channel_t *ftdmchan, ftdm_event_t *event) @@ -817,12 +817,13 @@ FT_DECLARE(void) ftdm_channel_flush_dtmf(ftdm_channel_t *ftdmchan); * * \param span The span to wait events for * \param ms Milliseconds timeout + * \param poll_events Array of events to poll for, for each channel on the span * * \retval FTDM_SUCCESS success (at least one event available) * \retval FTDM_TIMEOUT Timed out waiting for events * \retval FTDM_FAIL failure */ -FT_DECLARE(ftdm_status_t) ftdm_span_poll_event(ftdm_span_t *span, uint32_t ms); +FT_DECLARE(ftdm_status_t) ftdm_span_poll_event(ftdm_span_t *span, uint32_t ms, short *poll_events); /*! * \brief Find a span by its id diff --git a/libs/freetdm/src/include/ftdm_declare.h b/libs/freetdm/src/include/ftdm_declare.h index 03071a60bb..ab3b5c8966 100644 --- a/libs/freetdm/src/include/ftdm_declare.h +++ b/libs/freetdm/src/include/ftdm_declare.h @@ -70,6 +70,7 @@ extern "C" { #define FT_DECLARE_NONSTD(type) __declspec(dllimport) type __cdecl #define FT_DECLARE_DATA __declspec(dllimport) #endif +#define FT_DECLARE_INLINE(type) extern __inline__ type /* why extern? see http://support.microsoft.com/kb/123768 */ #define EX_DECLARE_DATA __declspec(dllexport) #else #if (defined(__GNUC__) || defined(__SUNPRO_CC) || defined (__SUNPRO_C)) && defined(HAVE_VISIBILITY) @@ -81,6 +82,7 @@ extern "C" { #define FT_DECLARE_NONSTD(type) type #define FT_DECLARE_DATA #endif +#define FT_DECLARE_INLINE(type) __inline__ type #define EX_DECLARE_DATA #endif @@ -156,7 +158,12 @@ typedef __int64 int64_t; typedef __int32 int32_t; typedef __int16 int16_t; typedef __int8 int8_t; +#if defined(_MSC_VER) || defined(_MSC_EXTENSIONS) +#define DELTA_EPOCH_IN_MICROSECS 11644473600000000Ui64 #else +#define DELTA_EPOCH_IN_MICROSECS 11644473600000000ULL +#endif /* _MSC_VER */ +#else /* __WINDOWS__ */ #define FTDM_INVALID_SOCKET -1 typedef int ftdm_socket_t; #include diff --git a/libs/stfu/stfu.c b/libs/stfu/stfu.c index f305a0f3df..7c30ab2ad4 100644 --- a/libs/stfu/stfu.c +++ b/libs/stfu/stfu.c @@ -38,7 +38,6 @@ struct stfu_queue { uint32_t array_size; uint32_t array_len; uint32_t wr_len; - uint32_t last_index; }; typedef struct stfu_queue stfu_queue_t; @@ -47,10 +46,12 @@ struct stfu_instance { struct stfu_queue b_queue; struct stfu_queue *in_queue; struct stfu_queue *out_queue; - uint32_t last_ts; + struct stfu_frame *last_frame; + uint32_t last_wr_ts; + uint32_t last_rd_ts; uint32_t interval; uint32_t miss_count; - uint8_t running; + uint32_t max_plc; }; @@ -112,7 +113,7 @@ stfu_status_t stfu_n_resize(stfu_instance_t *i, uint32_t qlen) return s; } -stfu_instance_t *stfu_n_init(uint32_t qlen) +stfu_instance_t *stfu_n_init(uint32_t qlen, uint32_t max_plc) { struct stfu_instance *i; @@ -125,6 +126,13 @@ stfu_instance_t *stfu_n_init(uint32_t qlen) stfu_n_init_aqueue(&i->b_queue, qlen); i->in_queue = &i->a_queue; i->out_queue = &i->b_queue; + + if (max_plc) { + i->max_plc = max_plc; + } else { + i->max_plc = qlen / 2; + } + return i; } @@ -135,10 +143,9 @@ void stfu_n_reset(stfu_instance_t *i) i->in_queue->array_len = 0; i->out_queue->array_len = 0; i->out_queue->wr_len = 0; - i->out_queue->last_index = 0; + i->last_frame = NULL; i->miss_count = 0; - i->last_ts = 0; - i->running = 0; + i->last_wr_ts = 0; i->miss_count = 0; i->interval = 0; } @@ -197,7 +204,7 @@ stfu_status_t stfu_n_add_data(stfu_instance_t *i, uint32_t ts, uint32_t pt, void i->in_queue->array_len = 0; i->out_queue->wr_len = 0; - i->out_queue->last_index = 0; + i->last_frame = NULL; i->miss_count = 0; if (stfu_n_process(i, i->out_queue) < 0) { @@ -222,6 +229,8 @@ stfu_status_t stfu_n_add_data(stfu_instance_t *i, uint32_t ts, uint32_t pt, void cplen = sizeof(frame->data); } + i->last_rd_ts = ts; + memcpy(frame->data, data, cplen); frame->pt = pt; frame->ts = ts; @@ -231,88 +240,71 @@ stfu_status_t stfu_n_add_data(stfu_instance_t *i, uint32_t ts, uint32_t pt, void return STFU_IT_WORKED; } +static int stfu_n_find_frame(stfu_queue_t *queue, uint32_t ts, stfu_frame_t **r_frame, uint32_t *index) +{ + uint32_t i = 0; + stfu_frame_t *frame = NULL; + + assert(r_frame); + assert(index); + + *r_frame = NULL; + + for(i = 0; i < queue->array_len; i++) { + frame = &queue->array[i]; + + if (frame->ts == ts) { + *r_frame = frame; + *index = i; + frame->was_read = 1; + return 1; + } + } + + return 0; +} + stfu_frame_t *stfu_n_read_a_frame(stfu_instance_t *i) { - uint32_t index, index2; + uint32_t index; uint32_t should_have = 0; - stfu_frame_t *frame = NULL, *rframe = NULL; + stfu_frame_t *rframe = NULL; if (((i->out_queue->wr_len == i->out_queue->array_len) || !i->out_queue->array_len)) { return NULL; } - if (i->running) { - should_have = i->last_ts + i->interval; + if (i->last_wr_ts) { + should_have = i->last_wr_ts + i->interval; } else { should_have = i->out_queue->array[0].ts; } - for(index = 0; index < i->out_queue->array_len; index++) { - if (i->out_queue->array[index].was_read) { - continue; - } - - frame = &i->out_queue->array[index]; - - if (frame->ts != should_have) { - unsigned int tried = 0; - for (index2 = 0; index2 < i->out_queue->array_len; index2++) { - if (i->out_queue->array[index2].was_read) { - continue; - } - tried++; - if (i->out_queue->array[index2].ts == should_have) { - rframe = &i->out_queue->array[index2]; - i->out_queue->last_index = index2; - goto done; - } - } - for (index2 = 0; index2 < i->in_queue->array_len; index2++) { - if (i->in_queue->array[index2].was_read) { - continue; - } - tried++; - if (i->in_queue->array[index2].ts == should_have) { - rframe = &i->in_queue->array[index2]; - goto done; - } - } - - i->miss_count++; - - if (i->miss_count > 10 || (i->in_queue->array_len == i->in_queue->array_size) || - tried >= (i->in_queue->array_size + i->out_queue->array_size)) { - i->running = 0; - i->interval = 0; - i->out_queue->wr_len = i->out_queue->array_size; - return NULL; - } - - i->last_ts = should_have; - rframe = &i->out_queue->int_frame; - rframe->dlen = i->out_queue->array[i->out_queue->last_index].dlen; - /* poor man's plc.. Copy the last frame, but we flag it so you can use a better one if you wish */ - memcpy(rframe->data, i->out_queue->array[i->out_queue->last_index].data, rframe->dlen); - rframe->ts = should_have; - i->out_queue->wr_len++; - i->running = 1; - return rframe; - } else { - rframe = &i->out_queue->array[index]; - i->out_queue->last_index = index; - goto done; - } - } - -done: - - if (rframe) { + if (stfu_n_find_frame(i->out_queue, should_have, &rframe, &index) || stfu_n_find_frame(i->in_queue, should_have, &rframe, &index)) { + i->last_frame = rframe; i->out_queue->wr_len++; - i->last_ts = rframe->ts; + i->last_wr_ts = rframe->ts; rframe->was_read = 1; - i->running = 1; i->miss_count = 0; - } + } else { + i->last_wr_ts = should_have; + rframe = &i->out_queue->int_frame; + + if (i->last_frame && i->last_frame != rframe) { + rframe->dlen = i->last_frame->dlen; + /* poor man's plc.. Copy the last frame, but we flag it so you can use a better one if you wish */ + memcpy(rframe->data, i->last_frame->data, rframe->dlen); + } + + rframe->ts = should_have; + + if (++i->miss_count > i->max_plc) { + i->interval = 0; + i->out_queue->wr_len = i->out_queue->array_size; + i->last_wr_ts = 0; + rframe = NULL; + } + } return rframe; } diff --git a/libs/stfu/stfu.h b/libs/stfu/stfu.h index 17f01e3256..900db6f9ac 100644 --- a/libs/stfu/stfu.h +++ b/libs/stfu/stfu.h @@ -96,7 +96,7 @@ typedef struct { void stfu_n_report(stfu_instance_t *i, stfu_report_t *r); void stfu_n_destroy(stfu_instance_t **i); -stfu_instance_t *stfu_n_init(uint32_t qlen); +stfu_instance_t *stfu_n_init(uint32_t qlen, uint32_t max_plc); stfu_status_t stfu_n_resize(stfu_instance_t *i, uint32_t qlen); stfu_status_t stfu_n_add_data(stfu_instance_t *i, uint32_t ts, uint32_t pt, void *data, size_t datalen, int last); stfu_frame_t *stfu_n_read_a_frame(stfu_instance_t *i); diff --git a/src/mod/applications/mod_commands/mod_commands.c b/src/mod/applications/mod_commands/mod_commands.c index 6c43f25d44..ba4b6d310d 100644 --- a/src/mod/applications/mod_commands/mod_commands.c +++ b/src/mod/applications/mod_commands/mod_commands.c @@ -4324,7 +4324,7 @@ SWITCH_STANDARD_API(uuid_loglevel) #define SQL_ESCAPE_SYNTAX "" SWITCH_STANDARD_API(sql_escape) { - if (zstr(cmd)) { + if (!cmd) { stream->write_function(stream, "-USAGE: %s\n", SQL_ESCAPE_SYNTAX); } else { stream->write_function(stream, "%q", cmd); diff --git a/src/mod/applications/mod_fifo/mod_fifo.c b/src/mod/applications/mod_fifo/mod_fifo.c index 33697a0ca6..3943ac6ea6 100644 --- a/src/mod/applications/mod_fifo/mod_fifo.c +++ b/src/mod/applications/mod_fifo/mod_fifo.c @@ -308,6 +308,8 @@ struct fifo_node { int outbound_per_cycle; char *outbound_name; outbound_strategy_t outbound_strategy; + int ring_timeout; + int default_lag; }; typedef struct fifo_node fifo_node_t; @@ -1213,7 +1215,7 @@ static void *SWITCH_THREAD_FUNC ringall_thread_run(switch_thread_t *thread, void switch_event_create_brackets(h->originate_string, '{', '}', ',', &ovars, &parsed); switch_event_del_header(ovars, "fifo_outbound_uuid"); - if (!h->timeout) h->timeout = 60; + if (!h->timeout) h->timeout = node->ring_timeout; if (timeout < h->timeout) timeout = h->timeout; stream.write_function(&stream, "[leg_timeout=%d,fifo_outbound_uuid=%s,fifo_name=%s]%s,", @@ -3518,6 +3520,12 @@ static void list_node(fifo_node_t *node, switch_xml_t x_report, int *off, int ve switch_snprintf(tmp, sizeof(buffer), "%u", node->outbound_per_cycle); switch_xml_set_attr_d(x_fifo, "outbound_per_cycle", tmp); + switch_snprintf(tmp, sizeof(buffer), "%u", node->ring_timeout); + switch_xml_set_attr_d(x_fifo, "ring_timeout", tmp); + + switch_snprintf(tmp, sizeof(buffer), "%u", node->default_lag); + switch_xml_set_attr_d(x_fifo, "default_lag", tmp); + switch_snprintf(tmp, sizeof(buffer), "%u", node->outbound_priority); switch_xml_set_attr_d(x_fifo, "outbound_priority", tmp); @@ -3928,6 +3936,8 @@ static switch_status_t load_config(int reload, int del_all) int taking_calls_i = 1; int timeout_i = 60; int lag_i = 10; + int ring_timeout = 60; + int default_lag = 30; name = switch_xml_attr(fifo, "name"); @@ -3981,11 +3991,29 @@ static switch_status_t load_config(int reload, int del_all) node->has_outbound = 1; } - + if ((val = switch_xml_attr(fifo, "outbound_ring_timeout"))) { + int tmp = atoi(val); + if (tmp > 10) { + ring_timeout = tmp; + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Invalid ring_timeout: must be > 10 for queue %s\n", node->name); + } + } + + if ((val = switch_xml_attr(fifo, "outbound_default_lag"))) { + int tmp = atoi(val); + if (tmp > 10) { + default_lag = tmp; + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Invalid default_lag: must be > 10 for queue %s\n", node->name); + } + } + + node->ring_timeout = ring_timeout; node->outbound_per_cycle = outbound_per_cycle; node->outbound_priority = outbound_priority; + node->default_lag = default_lag; - if (outbound_strategy) { node->outbound_strategy = parse_strat(outbound_strategy); node->has_outbound = 1; @@ -4017,14 +4045,14 @@ static switch_status_t load_config(int reload, int del_all) if (timeout) { if ((timeout_i = atoi(timeout)) < 10) { - timeout_i = 60; + timeout_i = ring_timeout; } } if (lag) { if ((lag_i = atoi(lag)) < 0) { - lag_i = 10; + lag_i = default_lag; } } diff --git a/src/mod/codecs/mod_sangoma_codec/mod_sangoma_codec.c b/src/mod/codecs/mod_sangoma_codec/mod_sangoma_codec.c index 21bfb958d4..63073ed189 100644 --- a/src/mod/codecs/mod_sangoma_codec/mod_sangoma_codec.c +++ b/src/mod/codecs/mod_sangoma_codec/mod_sangoma_codec.c @@ -98,6 +98,7 @@ vocallo_codec_t g_codec_map[] = /* FIXME: sampling rate seems wrong with this, audioooo soooundssssss sloooooow ... */ { SNGTC_CODEC_G722, 9, "G722", "Sangoma G722", 20, 64000, 20000, 160, 640, 160, 0 }, #endif + { SNGTC_CODEC_AMR_1220, 96, "AMR", "Sangoma AMR", 20, 12200, 20000, 160, 320, 0, 0}, { -1, -1, NULL, NULL, -1, -1, -1, -1, -1, -1 }, }; @@ -1227,12 +1228,14 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_sangoma_codec_load) /* Now add as many codec implementations as needed, just up to 40ms for now */ if (g_codec_map[c].autoinit) { + int ms = 0; for (i = 1; i <= 4; i++) { - - if ((g_codec_map[c].maxms/10) < i) { - continue; + ms = i * 10; + if (g_codec_map[c].maxms < ms) { + break; } + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Adding %dms implementation of codec %s\n", ms, g_codec_map[c].fs_name); switch_core_codec_add_implementation(pool, codec_interface, /* the codec interface we allocated and we want to register with the core */ SWITCH_CODEC_TYPE_AUDIO, /* enumeration defining the type of the codec */ g_codec_map[c].iana, /* the IANA code number, ie http://www.iana.org/assignments/rtp-parameters */ @@ -1253,7 +1256,6 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_sangoma_codec_load) switch_sangoma_destroy); /* deinitalize a codec handle using this implementation */ } - } else { /* custom implementation for some codecs */ @@ -1369,6 +1371,27 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_sangoma_codec_load) switch_sangoma_destroy); /* deinitalize a codec handle using this implementation */ break; + case SNGTC_CODEC_AMR_1220: + switch_core_codec_add_implementation(pool, codec_interface, /* the codec interface we allocated and we want to register with the core */ + SWITCH_CODEC_TYPE_AUDIO, /* enumeration defining the type of the codec */ + g_codec_map[c].iana, /* the IANA code number, ie http://www.iana.org/assignments/rtp-parameters */ + g_codec_map[c].iana_name, /* the IANA code name */ + NULL, /* default fmtp to send (can be overridden by the init function), fmtp is used in SDP for format specific parameters */ + 8000, /* samples transferred per second */ + 8000, /* actual samples transferred per second */ + g_codec_map[c].bps, /* bits transferred per second */ + g_codec_map[c].mpf, /* microseconds per frame */ + g_codec_map[c].spf, /* samples per frame */ + g_codec_map[c].bpfd, /* number of bytes per frame decompressed */ + g_codec_map[c].bpfc, /* number of bytes per frame compressed */ + 1, /* number of channels represented */ + g_codec_map[c].spf, /* number of frames per network packet (I dont think this is used at all) */ + switch_sangoma_init, /* function to initialize a codec session using this implementation */ + switch_sangoma_encode, /* function to encode slinear data into encoded data */ + switch_sangoma_decode, /* function to decode encoded data into slinear data */ + switch_sangoma_destroy); /* deinitalize a codec handle using this implementation */ + break; + default: break; } diff --git a/src/switch_ivr.c b/src/switch_ivr.c index 744072c145..948401e53a 100644 --- a/src/switch_ivr.c +++ b/src/switch_ivr.c @@ -2190,7 +2190,7 @@ SWITCH_DECLARE(void) switch_ivr_delay_echo(switch_core_session_t *session, uint3 qlen = delay_ms / (interval); switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Setting delay to %dms (%d frames)\n", delay_ms, qlen); - jb = stfu_n_init(qlen); + jb = stfu_n_init(qlen, 0); write_frame.codec = switch_core_session_get_read_codec(session); diff --git a/src/switch_rtp.c b/src/switch_rtp.c index 6a2fa51910..1792de08b3 100644 --- a/src/switch_rtp.c +++ b/src/switch_rtp.c @@ -1616,7 +1616,7 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_activate_stun_ping(switch_rtp_t *rtp_ SWITCH_DECLARE(switch_status_t) switch_rtp_activate_jitter_buffer(switch_rtp_t *rtp_session, uint32_t queue_frames) { - rtp_session->jb = stfu_n_init(queue_frames); + rtp_session->jb = stfu_n_init(queue_frames, 0); return SWITCH_STATUS_SUCCESS; }