diff --git a/Freeswitch.2008.express.sln b/Freeswitch.2008.express.sln index 672406bda2..ad3cafe5cd 100644 --- a/Freeswitch.2008.express.sln +++ b/Freeswitch.2008.express.sln @@ -1,6 +1,6 @@  Microsoft Visual Studio Solution File, Format Version 10.00 -# Visual Studio 2008 +# Visual C++ Express 2008 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FreeSwitchConsole", "w32\Console\FreeSwitchConsole.2008.vcproj", "{1AF3A893-F7BE-43DD-B697-8AB2397C0D67}" ProjectSection(ProjectDependencies) = postProject {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF} @@ -11,6 +11,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FreeSwitchCoreLib", "w32\Li ProjectSection(ProjectDependencies) = postProject {8D04B550-D240-4A44-8A18-35DA3F7038D9} = {8D04B550-D240-4A44-8A18-35DA3F7038D9} {89385C74-5860-4174-9CAF-A39E7C48909C} = {89385C74-5860-4174-9CAF-A39E7C48909C} + {1CBB0077-18C5-455F-801C-0A0CE7B0BBF5} = {1CBB0077-18C5-455F-801C-0A0CE7B0BBF5} {F057DA7F-79E5-4B00-845C-EF446EF055E3} = {F057DA7F-79E5-4B00-845C-EF446EF055E3} {03207781-0D1C-4DB3-A71D-45C608F28DBD} = {03207781-0D1C-4DB3-A71D-45C608F28DBD} {F6C55D93-B927-4483-BB69-15AEF3DD2DFF} = {F6C55D93-B927-4483-BB69-15AEF3DD2DFF} diff --git a/Freeswitch.2008.sln b/Freeswitch.2008.sln index 01a4cf43c1..e171ffe418 100644 --- a/Freeswitch.2008.sln +++ b/Freeswitch.2008.sln @@ -381,6 +381,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FreeSwitchCoreLib", "w32\Li ProjectSection(ProjectDependencies) = postProject {8D04B550-D240-4A44-8A18-35DA3F7038D9} = {8D04B550-D240-4A44-8A18-35DA3F7038D9} {89385C74-5860-4174-9CAF-A39E7C48909C} = {89385C74-5860-4174-9CAF-A39E7C48909C} + {1CBB0077-18C5-455F-801C-0A0CE7B0BBF5} = {1CBB0077-18C5-455F-801C-0A0CE7B0BBF5} {F057DA7F-79E5-4B00-845C-EF446EF055E3} = {F057DA7F-79E5-4B00-845C-EF446EF055E3} {03207781-0D1C-4DB3-A71D-45C608F28DBD} = {03207781-0D1C-4DB3-A71D-45C608F28DBD} {F6C55D93-B927-4483-BB69-15AEF3DD2DFF} = {F6C55D93-B927-4483-BB69-15AEF3DD2DFF} diff --git a/Freeswitch.2010.sln b/Freeswitch.2010.sln index 186969891a..edee701d51 100644 --- a/Freeswitch.2010.sln +++ b/Freeswitch.2010.sln @@ -707,6 +707,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_distributor", "src\mod\ EndProject Project("{930C7802-8A8C-48F9-8165-68863BCCD9DD}") = "Setup", "w32\Setup\Setup.wixproj", "{47213370-B933-487D-9F45-BCA26D7E2B6F}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_say_pt", "src\mod\say\mod_say_pt\mod_say_pt.2010.vcxproj", "{7C22BDFF-CC09-400C-8A09-660733980028}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution All|Win32 = All|Win32 @@ -3619,6 +3621,23 @@ Global {47213370-B933-487D-9F45-BCA26D7E2B6F}.Release|x64 Setup.Build.0 = Release|x64 {47213370-B933-487D-9F45-BCA26D7E2B6F}.Release|x86 Setup.ActiveCfg = Release|x86 {47213370-B933-487D-9F45-BCA26D7E2B6F}.Release|x86 Setup.Build.0 = Release|x86 + {7C22BDFF-CC09-400C-8A09-660733980028}.All|Win32.ActiveCfg = Release|x64 + {7C22BDFF-CC09-400C-8A09-660733980028}.All|x64.ActiveCfg = Release|x64 + {7C22BDFF-CC09-400C-8A09-660733980028}.All|x64.Build.0 = Release|x64 + {7C22BDFF-CC09-400C-8A09-660733980028}.All|x64 Setup.ActiveCfg = Release|x64 + {7C22BDFF-CC09-400C-8A09-660733980028}.All|x86 Setup.ActiveCfg = Release|x64 + {7C22BDFF-CC09-400C-8A09-660733980028}.Debug|Win32.ActiveCfg = Debug|Win32 + {7C22BDFF-CC09-400C-8A09-660733980028}.Debug|Win32.Build.0 = Debug|Win32 + {7C22BDFF-CC09-400C-8A09-660733980028}.Debug|x64.ActiveCfg = Debug|x64 + {7C22BDFF-CC09-400C-8A09-660733980028}.Debug|x64.Build.0 = Debug|x64 + {7C22BDFF-CC09-400C-8A09-660733980028}.Debug|x64 Setup.ActiveCfg = Debug|x64 + {7C22BDFF-CC09-400C-8A09-660733980028}.Debug|x86 Setup.ActiveCfg = Debug|x64 + {7C22BDFF-CC09-400C-8A09-660733980028}.Release|Win32.ActiveCfg = Release|Win32 + {7C22BDFF-CC09-400C-8A09-660733980028}.Release|Win32.Build.0 = Release|Win32 + {7C22BDFF-CC09-400C-8A09-660733980028}.Release|x64.ActiveCfg = Release|x64 + {7C22BDFF-CC09-400C-8A09-660733980028}.Release|x64.Build.0 = Release|x64 + {7C22BDFF-CC09-400C-8A09-660733980028}.Release|x64 Setup.ActiveCfg = Release|x64 + {7C22BDFF-CC09-400C-8A09-660733980028}.Release|x86 Setup.ActiveCfg = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -3769,6 +3788,7 @@ Global {A4B122CF-5196-476B-8C0E-D8BD59AC3C14} = {6CD61A1D-797C-470A-BE08-8C31B68BB336} {B6A9FB7A-1CC4-442B-812D-EC33E4E4A36E} = {6CD61A1D-797C-470A-BE08-8C31B68BB336} {0382E8FD-CFDC-41C0-8B03-792C7C84FC31} = {6CD61A1D-797C-470A-BE08-8C31B68BB336} + {7C22BDFF-CC09-400C-8A09-660733980028} = {6CD61A1D-797C-470A-BE08-8C31B68BB336} {3B08FEFD-4D3D-4C16-BA94-EE83509E32A0} = {57D119DC-484F-420F-B9E9-8589FD9A8DF8} {7BFD517E-7F8F-4A40-A78E-8D3632738227} = {57D119DC-484F-420F-B9E9-8589FD9A8DF8} {6374D55C-FABE-4A02-9CF1-4145308A56C5} = {57D119DC-484F-420F-B9E9-8589FD9A8DF8} diff --git a/Makefile.am b/Makefile.am index aeb31eca01..df1ee2e0d0 100644 --- a/Makefile.am +++ b/Makefile.am @@ -90,6 +90,8 @@ $(RECURSIVE_TARGETS): fi; \ if test -z "$$fail" ; then \ cd $(top_builddir)/build && $(MAKE) $(AM_MAKEFLAGS) $$target || exit 1; \ + else \ + exit 1; \ fi ; CORE_CFLAGS = `$(switch_builddir)/libs/apr/apr-1-config --cflags --cppflags --includes` @@ -100,6 +102,7 @@ CORE_CFLAGS += -I$(switch_srcdir)/libs/pcre CORE_CFLAGS += -I$(switch_srcdir)/libs/speex/include -Ilibs/speex/include CORE_CFLAGS += -I$(switch_srcdir)/libs/srtp/include CORE_CFLAGS += -I$(switch_srcdir)/libs/srtp/crypto/include -Ilibs/srtp/crypto/include +CORE_CFLAGS += -I$(switch_srcdir)/libs/spandsp/src -I$(switch_srcdir)/libs/tiff-3.8.2/libtiff CORE_LIBS = libs/apr-util/libaprutil-1.la libs/apr/libapr-1.la CORE_LIBS += libs/sqlite/libsqlite3.la libs/pcre/libpcre.la libs/speex/libspeex/libspeexdsp.la @@ -247,7 +250,8 @@ libfreeswitch_la_SOURCES = \ libs/miniupnpc/minissdpc.c \ libs/miniupnpc/upnperrors.c \ libs/libnatpmp/natpmp.c \ - libs/libnatpmp/getgateway.c + libs/libnatpmp/getgateway.c\ + libs/spandsp/src/plc.c if ENABLE_CPP libfreeswitch_la_SOURCES += src/switch_cpp.cpp @@ -272,7 +276,8 @@ bin_PROGRAMS = freeswitch fs_cli fs_ivrd tone2wav fs_encode ## ## fs_cli () ## -fs_cli_SOURCES = libs/esl/src/esl.c libs/esl/src/esl_config.c libs/esl/src/esl_event.c libs/esl/src/esl_threadmutex.c libs/esl/fs_cli.c libs/esl/src/esl_json.c +fs_cli_SOURCES = libs/esl/src/esl.c libs/esl/src/esl_config.c libs/esl/src/esl_event.c \ + libs/esl/src/esl_threadmutex.c libs/esl/fs_cli.c libs/esl/src/esl_json.c libs/esl/src/esl_buffer.c fs_cli_CFLAGS = $(AM_CFLAGS) -I$(switch_srcdir)/libs/esl/src/include fs_cli_LDFLAGS = $(AM_LDFLAGS) -lpthread $(ESL_LDFLAGS) -lm @@ -300,7 +305,8 @@ tone2wav_LDADD = libfreeswitch.la ## ## fs_ivrd () ## -fs_ivrd_SOURCES = libs/esl/src/esl.c libs/esl/src/esl_config.c libs/esl/src/esl_event.c libs/esl/src/esl_threadmutex.c libs/esl/ivrd.c libs/esl/src/esl_json.c +fs_ivrd_SOURCES = libs/esl/src/esl.c libs/esl/src/esl_config.c libs/esl/src/esl_event.c \ + libs/esl/src/esl_threadmutex.c libs/esl/ivrd.c libs/esl/src/esl_json.c libs/esl/src/esl_buffer.c fs_ivrd_CFLAGS = $(AM_CFLAGS) -I$(switch_srcdir)/libs/esl/src/include fs_ivrd_LDFLAGS = $(AM_LDFLAGS) -lpthread $(ESL_LDFLAGS) -lm diff --git a/build/modules.conf.in b/build/modules.conf.in index 13e655672c..bd5d49a7ad 100644 --- a/build/modules.conf.in +++ b/build/modules.conf.in @@ -100,6 +100,7 @@ say/mod_say_en #say/mod_say_fr #say/mod_say_it #say/mod_say_nl +#say/mod_say_pt say/mod_say_ru #say/mod_say_zh #say/mod_say_hu diff --git a/configure.in b/configure.in index 77df2a614c..d91cf11419 100644 --- a/configure.in +++ b/configure.in @@ -205,10 +205,14 @@ if test "x${ax_cv_c_compiler_vendor}" = "xsun" ; then APR_ADDTO(SWITCH_AM_CFLAGS, -DPIC) APR_ADDTO(SWITCH_AM_CFLAGS, -erroff=E_END_OF_LOOP_CODE_NOT_REACHED) APR_ADDTO(SWITCH_AM_CFLAGS, -errtags=yes) + APR_ADDTO(SWITCH_AM_CFLAGS, -D__FUNCTION__=__func__ ) + APR_ADDTO(SWITCH_AM_CFLAGS, -mt) APR_ADDTO(SWITCH_AM_CXXFLAGS, -errtags=yes) APR_ADDTO(SWITCH_AM_CXXFLAGS, -KPIC) APR_ADDTO(SWITCH_AM_CXXFLAGS, -DPIC) APR_ADDTO(SWITCH_AM_CXXFLAGS, "-features=extensions") + APR_ADDTO(SWITCH_AM_CXXFLAGS, -D__FUNCTION__=__func__) + APR_ADDTO(SWITCH_AM_CXXFLAGS, -mt) APR_ADDTO(SWITCH_AM_LDFLAGS, -R${prefix}/lib) if test "${enable_64}" = "yes"; then diff --git a/docs/ChangeLog b/docs/ChangeLog index 6037c14ec7..0ca48c0e81 100644 --- a/docs/ChangeLog +++ b/docs/ChangeLog @@ -20,6 +20,7 @@ freeswitch (1.0.7) build: Remove mod_spidermonkey from windows 2008 x64 builds - does not work (r:280e894d) build: fix warnings on windows x64 builds src and mods projects - only libsofia included on the libs side (r:45ecbc2f) build: Patch debian init.d script to set ulimit values (r:0eb33e57/FS-2844) + build: add plc to core (r:b7c80a84) codec2: working prototype, still for testing only (r:04ca0751) config: move limit.conf to db.conf config: Update VM phrase macros to voice option then action on main, config menus @@ -32,6 +33,8 @@ freeswitch (1.0.7) config: default example to resolve some issues with SCA in cases where host and ip are mixed causing the phone to be confused. (r:0279261b) config: Fix phrase files, still missing a sound file (r:6741f350/FS-2742) config: Disallow global-intercept and group-intercept can intercept an outbound call in default dialplan (r:890871ba/FS-2777) + config: fix single domain assumption in default config to be more portable *cough* bkw *cough* (r:f987903e) + config: Bump Doxygen.conf version to 1.0.6... belatedly (r:cfeae1ba) core: Add RTCP support (FSRTP-14) core: handle some errors on missing db handle conditions core: add ... and shutdown as a fail-safe when no modules are loaded @@ -134,6 +137,25 @@ freeswitch (1.0.7) core: Better handling of progress and answering to prevent sip profile from locking up at higher volumes (r:04e57577/FS-2801) core: ACL for IPv6 address and swigall to boot (r:db91f0e8/FS-2842) core: add intercept_unanswered_only var akin to intercept_unbridged_only (r:68f18efe) + core: switch_odbc_handle_exec_string duplication SQLExecute (r:8b0e7d24/FS-2880) + core: Fix timeout while bridge is waiting for CF_BRIDGED flag (r:2572621b/FS-2368) + core: don't parse events for b legs from a leg thread in case they are using a monolothic python script as a group_confirm exec over socket to send it messages while the call is ringing (r:ed5266d3) + core: add new function to check when messages need parsing to improve performance on parsing messages during originate (r:8b0421ff) + core: run execute_on_answer on_media _on_ring apps async (r:ef4a4ed0) + core: add switch_ivr_insert_file to insert one file into another at an arbitrary sample point (r:82394b37) + core: Slow reload cause calls to hang (r:1ba98b02/FS-2852) + core: Application intercept causes FS to stop processing calls (r:12fc65f7/FS-2872) + core: fix edge cases for endless loop in sql thread (r:5d7c09ed) + core: prevent race while changing codecs mid call (r:7aa72b67) + core: Fix crash in ODBC when SQL Server kills TCP connection (r:5aba96e3/FS-2910) + core: Fix fallback to CORE_DB when MSSQL fails init (r:3406d05b) + core: add new function to init an empty switch_sockaddr_t to avoid an unnecessary dns lookup on 0.0.0.0 (r:009c41d4) + core: fix endless RTP loop in Windows (r:cb2d0736/FS-2924) + core: play_and_get_digits should actually timeout, not last forever... (r:28cab5ed/FS-2923) + core: Fix crash w/o core dump (r:00046ee0/FS-2933) + core: normalize tests for outbound channels to use switch_channel_direction instead of testing for CF_OUTBOUND (r:93cc3dc5) + core: add CF_DIALPLAN (r:3ff07445) + core: tweak on calle[re] id (r:9db4a826) lang: Improve French phrase files (FSCONFIG-23) libapr: Fix issue where after a bridge with a member, uuid of Agent is set to single quote character ' (r:3fee704d/FS-2738) libdingaling: fix race on shutdown causing crash (FSMOD-47) @@ -151,6 +173,9 @@ freeswitch (1.0.7) libesl: Fix SEGV when using serialize function without any arguments (r:910729b5/ESL-44) libesl: fix leak-on-error in esl_connect_timeout() (r:4263d60e) libesl: Call close on connection handle if the connection fails (r:413dcc4c/ESL-50) + libesl: allow fs_cli -x to have args up to 1024 chars (was 256) (r:7039ba47) + libesl: Make last_event pointer last longer (r:a15f51d5/ESL-37) + libesl: use a packet buffer for ESL (r:2081bf97) libfreetdm: implemented freetdm config nodes and ss7 initial configuration libfreetdm: fix codec for CAS signaling (r:b76e7f18) libfreetdm: freetdm: ss7- added support for incoming group blocks, started adding support for ansi (r:c219a73c) @@ -189,7 +214,8 @@ freeswitch (1.0.7) mod_callcenter: Fix invalid update of agent field (r:426a448f/FS-2738) mod_callcenter: Allow to get queue info via api (r:70d592ae) mod_callcenter: Fix bad return type so it compile on archlinux, thx bougyman (r:3a475986) - mod_callcenter: Make callcenter_config agent get return the value of the item requested. Also added queue param max-wait-time-with-no-agent-time-reached: If the max-wai-time-with-no-agent is already reached for the queue, then new caller can wait for x ammount of second before it kicked out of the queue rather than get rejected automaticly. (r:81a03869) + mod_callcenter: Make callcenter_config agent get return the value of the item requested. Also added queue param max-wait-time-with-no-agent-time-reached: If the max-wai-time-with-no-agent is already reached for the queue, then new caller can wait for x amount of second before it kicked out of the queue rather than get rejected automatically. (r:81a03869) + mod_callcenter: Add new event socket agent-offering. Plus some documentation and better handling of bad agent type -- FS-2869 (r:80174cf3/FS-2869) mod_cidlookup: null xml is bad (r:095815f8) mod_cid_lookup: honor skipcitystate when using whitepages (r:a66654de/FSMOD-53) mod_commands: make break uuid_break and add cascade flag @@ -205,6 +231,10 @@ freeswitch (1.0.7) mod_commands: ***BEHAVIOUR CHANGE*** reloadacl, load , reload will now explicitly call reloadxml (r:42c9df72) mod_commands: add nat_map usage (r:7577b8aa) mod_commands: add escaping empty strings to sql_escape (r:7bd0a5a6/FS-2833) + mod_commands: add uuid_fileman : <-- same vals as the callbacks in js and lua to control the currently playing file of a channel from the cli or ESL (for the people who were ignoring me on the conference call so I decided to implement it instead of try to explain it ) (r:c4369fc8) + mod_commands: FS-2210 Add support for auto completion for uuid_simplify (r:72bcc01b/FS-2210) + mod_commands: allow epoch in strftime_tz (r:bbf1cd1f) + mod_commands: Dramatic jitterbuffer changes (r:d5470961) mod_conference: Fix reporting of volume up/down (MODAPP-419) mod_conference: add last talking time per member to conference xml list mod_conference: add terminate-on-silence conference param @@ -214,6 +244,7 @@ freeswitch (1.0.7) mod_conference: Fix floor change events not always firing (r:8f1767d3/MODAPP-424) mod_conference: refactor conference to use switch_ivr_dmachine for the digit parsing controls are now bound to each member separately based on conference_controls channel var, then the caller-controls param in the profile or a default to "default" (r:ac19f73c) mod_conference: Fix crash on dtmf action (r:4d5389bd/FS-2781) + mod_conference: revert to the last transfered conference on recover (r:d11c83b1) mod_curl: use method=post when post requested (r:c6a4ddd0/FSMOD-69) mod_db: fix stack corruption (MODAPP-407) mod_dialplan_xml: Add in the INFO log the caller id number when processing a request (Currenly only show the caller name) (r:e1df5e13) @@ -221,6 +252,8 @@ freeswitch (1.0.7) mod_dingaling: make dingaling work with google voice inbound too (r:4ee68141) mod_dingaling: Fix crash when testing the new gv-dingaling with around 24 concurrent calls (r:73e1ec5e/FSCORE-667) mod_dingaling: Fix NULL pointer (r:e3eff816/FS-1103) + mod_dingaling: fix leak in chat_send (r:eb109a85) + mod_dingaling: use the login as message source when not in component mode. (chat_send) (r:58c28aab) mod_directory: Add variable directory_search_order to allow to search by first name by default is set to "first_name" (r:163ca31f) mod_distributor: Add mod_distributor to VS2010 - not built by default (r:bac79ba1) mod_dptools: add eavesdrop_enable_dtmf chan var (r:596c0012) @@ -279,8 +312,10 @@ freeswitch (1.0.7) mod_freetdm: lock the channel when placing call (r:705dd237) mod_freetdm: created cmake files for freetdm (r:fc55997b) mod_freetdm: ss7 - added support to control mtp2, mtp3, and isup timers via freetdm.conf.xml (r:4455d581) + mod_freetdm: made ftmod_r2 use FTDM_SPAN_USE_SIGNALS_QUEUE and properly send FTDM_SIGEVENT_SIGSTATUS_CHANGED (r:af5f0a4a) mod_gsmopen: copy from branch mod_gsmopen: fix FS-2793, compilation stops (r:355c0dbb/FS-2793) + mod_gsmopen: retry serial initialization if failed, zeroing audio buffers, slower retry on soundcard busy (EAGAIN) (r:c7aefe93) mod_hash: free all hashtables on shutdown (r:e76d7d92) mod_hash: remove unneeded initializer (r:10d468a6) mod_hash: begin working on remote support (r:c5ad49da) @@ -324,6 +359,7 @@ freeswitch (1.0.7) mod_lua: Added SAF_ROUTING_EXEC flag to lua app, so it can be run inline (r:7d5ca1c0) mod_managed: Added wrapper for switch_event_bind for .net (r:a5f07a80/MODLANG-165) mod_managed: add additional support (r:5be58aac) + mod_managed: add mono 2.8 patch file see FS-2774 (r:6a948bd9/FS-2774) mod_mp4v: MP4V-ES passthru for washibechi on IRC mod_mp4: New module. Supports playback of MP4 files. Depends on libmp4v2 (originally compiled against v1.6.1) mod_nibblebill: free allocated mem at shutdown; free properly if using custom_sql @@ -472,6 +508,19 @@ freeswitch (1.0.7) mod_sofia: fix missing name and potential segfault in gateway status (r:40ac860a) mod_sofia: Add missing RTP info for early SDP in bypass media (r:10119e9e/FS-2824) mod_sofia: add manual_rtp_bugs to profile and chan var and 3 new RTP bugs SEND_LINEAR_TIMESTAMPS|START_SEQ_AT_ZERO|NEVER_SEND_MARKER (r:b278dd23) + mod_sofia: apparently some sip device vendors did not read the RFC (who knew?) adding verbose_sdp=true var to add needless a= lines for standard iana codecs that explicitly do not require them (r:6c4f49a8) + mod_sofia: Fix registering a gateway, sofia always places a Via header with ext-sip-ip, even if this gateway is local (r:cf398e1a/FS-535) + mod_sofia: add presence-probe-on-register sofia param to send a probe on register instead of presence to deal with some broken phones and add some general improvements to allow multi homed presence (r:14394994) + mod_sofia: Fix issue when fs_path is used so we pick the correct media IP in our outbound invite this was soemthing that wouldn't work correctly over ATT on the iphone. (r:a669f76f) + mod_sofia: Default T38 Options (r:92f43440/FS-2892) + mod_sofia: Fix wrong IP in VIA and contact HEADER for MESSAGE method while fs run in private network (r:59ea4a1b/FS-2886) + mod_sofia: SIP-header History-Info might exist multiple times, but only last header is exposed as a channel variable (r:8cf15012/FS-2881) + mod_sofia: Add support to reboot Yealink phone remotely (r:fdc31908/FS-2897) + mod_sofia: Add reuse-connections sofia profile param to allow users to turn off TPTAG_REUSE, thus not re-using TCP connections (r:98ed05cc) + mod_sofia: Make sofia recover also work on custom uuid (r:3a645dee/FS-2913) + mod_sofia: remove check for va_list completely in sofia since i don't even think it happens ever (r:dfecc914) + mod_sofia: have mod_sofia always elect to be the session refresher so we know it will work, also make the session-expires set to 0 imply 100% disabled session timers (r:321013ef) + mod_sofia: Do not set nat mode when the device's network_ip is within the acl also so if your FS is behind nat and your phone is too then it will still make the right decisions (r:6c6eab8c) mod_spandsp: initial checkin of mod_fax/mod_voipcodecs merge into mod_spandsp (r:fa9a59a8) mod_spandsp: rework of new mod_spandsp to have functions broken up into different c files (r:65400642) mod_spandsp: improve duplicate digit detection and add 'min_dup_digit_spacing_ms' channel variable for use with the dtmf detector (r:eab4f246/FSMOD-45) @@ -487,6 +536,7 @@ freeswitch (1.0.7) mod_spidermonkey: fix seg in js hangup (r:7d554c11) mod_spidermonkey: Fix mod_spidermonkey build on FreeBSD, (Undefined symbol PR_LocalTimeParameters). (r:3edb8419) mod_spy: add support for loopback endpoint (MODAPP-416) + mod_spy: fix crash when session can't be located (r:c4154633/FS-2929) mod_tts_commandline: fix core dump, temp file problem. flush can be called several times (FSMOD-35) mod_unimrcp: fix fortify findings for mod_unimrcp (r:336f0b4e/FSMOD-67) mod_valet_parking: add event data to valet parking hold event @@ -508,6 +558,8 @@ freeswitch (1.0.7) mod_xml_cdr: fix minor memory leaks and config bug (r:19253d83/MODEVENT-62) mod_xml_rpc: Fix crash if unauthorized XML RPC is attempted (r:9835395c/FS-184) scripts: added honeypot.pl and blacklist.pl which add extra SIP security options (r:b6a81ba7) + scripts: do simple verification to make sure we are getting IP addresses from VoIP abuse blacklist (r:b0049160) + scripts: add_user - cmd line utility that lets admin create new users very easily. (r:ec8f2c2b) sofia-sip: fix null derefernce segfault in soa (r:f356c5e6) sofia-sip: extend timeout for session expires on short timeouts to be 90% of timeout instead of 1/3 to handle devices that do not refresh in time such as polycom (r:a7f48928/SFSIP-212) tools: Add fs_encode tool (r:89b17601) diff --git a/docs/Doxygen.conf b/docs/Doxygen.conf index ccdb3b8a47..2c06417833 100644 --- a/docs/Doxygen.conf +++ b/docs/Doxygen.conf @@ -31,7 +31,7 @@ PROJECT_NAME = FreeSWITCH # This could be handy for archiving the generated documentation or # if some version control system is used. -PROJECT_NUMBER = 1.0.4 +PROJECT_NUMBER = 1.0.6 # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) # base path where the generated documentation will be put. diff --git a/docs/phrase/phrase_en.xml b/docs/phrase/phrase_en.xml index a028a2aae0..41bc69cde1 100644 --- a/docs/phrase/phrase_en.xml +++ b/docs/phrase/phrase_en.xml @@ -221,6 +221,7 @@ + @@ -241,6 +242,8 @@ + + @@ -259,6 +262,12 @@ + + + + + + @@ -362,8 +371,6 @@ - - @@ -390,15 +397,10 @@ - - - - - @@ -409,10 +411,7 @@ - - - @@ -425,20 +424,10 @@ - - - - - - - - - - - - - + + + diff --git a/docs/phrase/phrase_es_ES.xml b/docs/phrase/phrase_es_ES.xml new file mode 100644 index 0000000000..ad99c1bf73 --- /dev/null +++ b/docs/phrase/phrase_es_ES.xml @@ -0,0 +1,994 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/phrase/phrase_es_MX.xml b/docs/phrase/phrase_es_MX.xml new file mode 100644 index 0000000000..527f8c3c89 --- /dev/null +++ b/docs/phrase/phrase_es_MX.xml @@ -0,0 +1,993 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/phrase/phrase_pt_BR.xml b/docs/phrase/phrase_pt_BR.xml new file mode 100644 index 0000000000..9cc400c76b --- /dev/null +++ b/docs/phrase/phrase_pt_BR.xml @@ -0,0 +1,987 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/phrase/phrase_pt_PT.xml b/docs/phrase/phrase_pt_PT.xml new file mode 100644 index 0000000000..a0e59deb85 --- /dev/null +++ b/docs/phrase/phrase_pt_PT.xml @@ -0,0 +1,987 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/libs/esl/Makefile b/libs/esl/Makefile index a180406bda..ab50bac4d9 100644 --- a/libs/esl/Makefile +++ b/libs/esl/Makefile @@ -9,9 +9,9 @@ CXXFLAGS=$(BASE_FLAGS) -Wall -Werror -Wno-unused-variable MYLIB=libesl.a LIBS=-lncurses -lpthread -lesl -lm LDFLAGS=-L. -OBJS=src/esl.o src/esl_event.o src/esl_threadmutex.o src/esl_config.o src/esl_json.o -SRC=src/esl.c src/esl_json.c src/esl_event.c src/esl_threadmutex.c src/esl_config.c src/esl_oop.cpp src/esl_json.c -HEADERS=src/include/esl_config.h src/include/esl_event.h src/include/esl.h src/include/esl_threadmutex.h src/include/esl_oop.h src/include/esl_json.h +OBJS=src/esl.o src/esl_event.o src/esl_threadmutex.o src/esl_config.o src/esl_json.o src/esl_buffer.o +SRC=src/esl.c src/esl_json.c src/esl_event.c src/esl_threadmutex.c src/esl_config.c src/esl_oop.cpp src/esl_json.c src/esl_buffer.c +HEADERS=src/include/esl_config.h src/include/esl_event.h src/include/esl.h src/include/esl_threadmutex.h src/include/esl_oop.h src/include/esl_json.h src/include/esl_buffer.h SOLINK=-shared -Xlinker -x # comment the next line to disable c++ (no swig mods for you then) OBJS += src/esl_oop.o diff --git a/libs/esl/src/esl.2008.vcproj b/libs/esl/src/esl.2008.vcproj index 101348dd59..89daa17d9e 100644 --- a/libs/esl/src/esl.2008.vcproj +++ b/libs/esl/src/esl.2008.vcproj @@ -290,6 +290,10 @@ RelativePath=".\esl.c" > + + @@ -316,6 +320,10 @@ RelativePath=".\include\esl.h" > + + diff --git a/libs/esl/src/esl.2010.vcxproj b/libs/esl/src/esl.2010.vcxproj index b215fe4bc8..fd5e3a8353 100644 --- a/libs/esl/src/esl.2010.vcxproj +++ b/libs/esl/src/esl.2010.vcxproj @@ -128,6 +128,7 @@ + @@ -135,6 +136,7 @@ + diff --git a/libs/esl/src/esl.c b/libs/esl/src/esl.c index 4a02a8fe38..f5bab62fcb 100644 --- a/libs/esl/src/esl.c +++ b/libs/esl/src/esl.c @@ -428,6 +428,10 @@ ESL_DECLARE(esl_status_t) esl_attach_handle(esl_handle_t *handle, esl_socket_t s esl_mutex_create(&handle->mutex); } + if (!handle->packet_buf) { + esl_buffer_create(&handle->packet_buf, BUF_CHUNK, BUF_START, 0); + } + handle->connected = 1; esl_send_recv(handle, "connect\n\n"); @@ -632,6 +636,10 @@ ESL_DECLARE(esl_status_t) esl_connect_timeout(esl_handle_t *handle, const char * if (!handle->mutex) { esl_mutex_create(&handle->mutex); } + + if (!handle->packet_buf) { + esl_buffer_create(&handle->packet_buf, BUF_CHUNK, BUF_START, 0); + } handle->sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); @@ -805,6 +813,11 @@ ESL_DECLARE(esl_status_t) esl_disconnect(esl_handle_t *handle) esl_mutex_destroy(&mutex); } + if (handle->packet_buf) { + esl_buffer_destroy(&handle->packet_buf); + } + + return status; } @@ -825,7 +838,7 @@ ESL_DECLARE(esl_status_t) esl_recv_event_timed(esl_handle_t *handle, uint32_t ms if (check_q) { esl_mutex_lock(handle->mutex); - if (handle->race_event) { + if (handle->race_event || esl_buffer_packet_count(handle->packet_buf)) { esl_mutex_unlock(handle->mutex); return esl_recv_event(handle, check_q, save_event); } @@ -894,12 +907,15 @@ ESL_DECLARE(esl_status_t) esl_recv_event_timed(esl_handle_t *handle, uint32_t ms } +static esl_ssize_t handle_recv(esl_handle_t *handle, void *data, esl_size_t datalen) +{ + return recv(handle->sock, data, datalen, 0); +} ESL_DECLARE(esl_status_t) esl_recv_event(esl_handle_t *handle, int check_q, esl_event_t **save_event) { char *c; esl_ssize_t rrval; - int crc = 0; esl_event_t *revent = NULL; char *beg; char *hname, *hval; @@ -907,7 +923,6 @@ ESL_DECLARE(esl_status_t) esl_recv_event(esl_handle_t *handle, int check_q, esl_ char *cl; esl_ssize_t len; int zc = 0; - int bread = 0; if (!handle || !handle->connected || handle->sock == ESL_SOCK_INVALID) { return ESL_FAIL; @@ -916,9 +931,7 @@ ESL_DECLARE(esl_status_t) esl_recv_event(esl_handle_t *handle, int check_q, esl_ esl_mutex_lock(handle->mutex); if (!handle->connected || handle->sock == ESL_SOCK_INVALID) { - handle->connected = 0; - esl_mutex_unlock(handle->mutex); - return ESL_FAIL; + goto fail; } esl_event_safe_destroy(&handle->last_event); @@ -932,76 +945,62 @@ ESL_DECLARE(esl_status_t) esl_recv_event(esl_handle_t *handle, int check_q, esl_ goto parse_event; } - memset(handle->header_buf, 0, sizeof(handle->header_buf)); + + while(!revent && handle->connected) { + esl_size_t len1; + + if ((len1 = esl_buffer_read_packet(handle->packet_buf, handle->socket_buf, sizeof(handle->socket_buf)))) { + char *data = (char *) handle->socket_buf; + char *p, *e; + + esl_event_create(&revent, ESL_EVENT_CLONE); + revent->event_id = ESL_EVENT_SOCKET_DATA; + esl_event_add_header_string(revent, ESL_STACK_BOTTOM, "Event-Name", "SOCKET_DATA"); + + hname = p = data; + while(p) { + hname = p; + p = NULL; - c = handle->header_buf; - beg = c; + if ((hval = strchr(hname, ':'))) { + *hval++ = '\0'; + while(*hval == ' ' || *hval == '\t') hval++; - while(handle->connected) { - if (bread + 2 >= sizeof(handle->header_buf)) { - esl_log(ESL_LOG_CRIT, "OUT OF BUFFER SPACE!\n"); - handle->connected = 0; - esl_mutex_unlock(handle->mutex); - return ESL_DISCONNECTED; + if ((e = strchr(hval, '\n'))) { + *e++ = '\0'; + while(*e == '\n' || *e == '\r') e++; + + if (hname && hval) { + esl_url_decode(hval); + esl_log(ESL_LOG_DEBUG, "RECV HEADER [%s] = [%s]\n", hname, hval); + esl_event_add_header_string(revent, ESL_STACK_BOTTOM, hname, hval); + } + + p = e; + } + } + } + + break; } - rrval = recv(handle->sock, c, 1, 0); + rrval = handle_recv(handle, handle->socket_buf, sizeof(handle->socket_buf)); + if (rrval == 0) { if (++zc >= 100) { - handle->connected = 0; - esl_mutex_unlock(handle->mutex); - return ESL_DISCONNECTED; + goto fail; } + continue; } else if (rrval < 0) { strerror_r(handle->errnum, handle->err, sizeof(handle->err)); goto fail; - } else { - zc = 0; - - if (*c == '\n') { - - *(c+1) = '\0'; - - if (++crc == 2) { - break; - } - - if (!revent) { - esl_event_create(&revent, ESL_EVENT_CLONE); - revent->event_id = ESL_EVENT_SOCKET_DATA; - esl_event_add_header_string(revent, ESL_STACK_BOTTOM, "Event-Name", "SOCKET_DATA"); - - } - - hname = beg; - hval = col = NULL; - - if (hname && (col = strchr(hname, ':'))) { - hval = col + 1; - *col = '\0'; - while(*hval == ' ') hval++; - } - - *c = '\0'; - - if (hname && hval) { - esl_url_decode(hval); - esl_log(ESL_LOG_DEBUG, "RECV HEADER [%s] = [%s]\n", hname, hval); - esl_event_add_header_string(revent, ESL_STACK_BOTTOM, hname, hval); - } - - c = beg; - bread = 0; - continue; - - } else { - crc = 0; - } - - c++; } - } + zc = 0; + + esl_buffer_write(handle->packet_buf, handle->socket_buf, rrval); + } + if (!revent) { goto fail; } @@ -1016,12 +1015,28 @@ ESL_DECLARE(esl_status_t) esl_recv_event(esl_handle_t *handle, int check_q, esl_ *(body + len) = '\0'; do { - esl_ssize_t r; - if ((r = recv(handle->sock, body + sofar, len - sofar, 0)) < 0) { - strerror_r(handle->errnum, handle->err, sizeof(handle->err)); - goto fail; + esl_ssize_t r,s = esl_buffer_inuse(handle->packet_buf); + + if (s >= len) { + sofar = esl_buffer_read(handle->packet_buf, body, len); + } else { + r = handle_recv(handle, handle->socket_buf, sizeof(handle->socket_buf)); + + if (r < 0) { + strerror_r(handle->errnum, handle->err, sizeof(handle->err)); + goto fail; + } else if (r == 0) { + if (++zc >= 100) { + goto fail; + } + continue; + } + + zc = 0; + + esl_buffer_write(handle->packet_buf, handle->socket_buf, r); } - sofar += r; + } while (sofar < len); revent->body = body; @@ -1123,6 +1138,8 @@ ESL_DECLARE(esl_status_t) esl_recv_event(esl_handle_t *handle, int check_q, esl_ fail: + esl_mutex_unlock(handle->mutex); + handle->connected = 0; return ESL_FAIL; @@ -1177,7 +1194,6 @@ ESL_DECLARE(esl_status_t) esl_send_recv_timed(esl_handle_t *handle, const char * return ESL_FAIL; } - esl_event_safe_destroy(&handle->last_event); esl_event_safe_destroy(&handle->last_sr_event); *handle->last_sr_reply = '\0'; diff --git a/libs/esl/src/esl_buffer.c b/libs/esl/src/esl_buffer.c new file mode 100644 index 0000000000..8032169fe3 --- /dev/null +++ b/libs/esl/src/esl_buffer.c @@ -0,0 +1,354 @@ +/* + * Copyright (c) 2010, Anthony Minessale II + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of the original author; nor the names of any contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#include "esl_buffer.h" + +static unsigned buffer_id = 0; + +struct esl_buffer { + unsigned char *data; + unsigned char *head; + esl_size_t used; + esl_size_t actually_used; + esl_size_t datalen; + esl_size_t max_len; + esl_size_t blocksize; + unsigned id; + int loops; +}; + + +ESL_DECLARE(esl_status_t) esl_buffer_create(esl_buffer_t **buffer, esl_size_t blocksize, esl_size_t start_len, esl_size_t max_len) +{ + esl_buffer_t *new_buffer; + + new_buffer = malloc(sizeof(*new_buffer)); + if (new_buffer) { + memset(new_buffer, 0, sizeof(*new_buffer)); + + if (start_len) { + new_buffer->data = malloc(start_len); + if (!new_buffer->data) { + free(new_buffer); + return ESL_FAIL; + } + memset(new_buffer->data, 0, start_len); + } + + new_buffer->max_len = max_len; + new_buffer->datalen = start_len; + new_buffer->id = buffer_id++; + new_buffer->blocksize = blocksize; + new_buffer->head = new_buffer->data; + + *buffer = new_buffer; + return ESL_SUCCESS; + } + + return ESL_FAIL; +} + +ESL_DECLARE(esl_size_t) esl_buffer_len(esl_buffer_t *buffer) +{ + + assert(buffer != NULL); + + return buffer->datalen; + +} + + +ESL_DECLARE(esl_size_t) esl_buffer_freespace(esl_buffer_t *buffer) +{ + assert(buffer != NULL); + + + if (buffer->max_len) { + return (esl_size_t) (buffer->max_len - buffer->used); + } + return 1000000; + +} + +ESL_DECLARE(esl_size_t) esl_buffer_inuse(esl_buffer_t *buffer) +{ + assert(buffer != NULL); + + return buffer->used; +} + +ESL_DECLARE(esl_size_t) esl_buffer_seek(esl_buffer_t *buffer, esl_size_t datalen) +{ + esl_size_t reading = 0; + + assert(buffer != NULL); + + if (buffer->used < 1) { + buffer->used = 0; + return 0; + } else if (buffer->used >= datalen) { + reading = datalen; + } else { + reading = buffer->used; + } + + buffer->used = buffer->actually_used - reading; + buffer->head = buffer->data + reading; + + return reading; +} + +ESL_DECLARE(esl_size_t) esl_buffer_toss(esl_buffer_t *buffer, esl_size_t datalen) +{ + esl_size_t reading = 0; + + assert(buffer != NULL); + + if (buffer->used < 1) { + buffer->used = 0; + return 0; + } else if (buffer->used >= datalen) { + reading = datalen; + } else { + reading = buffer->used; + } + + buffer->used -= reading; + buffer->head += reading; + + return buffer->used; +} + +ESL_DECLARE(void) esl_buffer_set_loops(esl_buffer_t *buffer, int loops) +{ + buffer->loops = loops; +} + +ESL_DECLARE(esl_size_t) esl_buffer_read_loop(esl_buffer_t *buffer, void *data, esl_size_t datalen) +{ + esl_size_t len; + if ((len = esl_buffer_read(buffer, data, datalen)) < datalen) { + if (buffer->loops == 0) { + return len; + } + buffer->head = buffer->data; + buffer->used = buffer->actually_used; + len = esl_buffer_read(buffer, (char*)data + len, datalen - len); + buffer->loops--; + } + return len; +} + +ESL_DECLARE(esl_size_t) esl_buffer_read(esl_buffer_t *buffer, void *data, esl_size_t datalen) +{ + esl_size_t reading = 0; + + assert(buffer != NULL); + assert(data != NULL); + + + if (buffer->used < 1) { + buffer->used = 0; + return 0; + } else if (buffer->used >= datalen) { + reading = datalen; + } else { + reading = buffer->used; + } + + memcpy(data, buffer->head, reading); + buffer->used -= reading; + buffer->head += reading; + + /* if (buffer->id == 4) printf("%u o %d = %d\n", buffer->id, (unsigned)reading, (unsigned)buffer->used); */ + return reading; +} + + +ESL_DECLARE(esl_size_t) esl_buffer_packet_count(esl_buffer_t *buffer) +{ + char *pe, *p, *e, *head = (char *) buffer->head; + esl_size_t x = 0; + + assert(buffer != NULL); + + e = (head + buffer->used); + + for (p = head; p && *p && p < e; p++) { + if (*p == '\n') { + pe = p+1; + if (*pe == '\r') pe++; + if (pe <= e && *pe == '\n') { + p = pe++; + x++; + } + } + } + + return x; +} + +ESL_DECLARE(esl_size_t) esl_buffer_read_packet(esl_buffer_t *buffer, void *data, esl_size_t maxlen) +{ + char *pe, *p, *e, *head = (char *) buffer->head; + esl_size_t datalen = 0; + + assert(buffer != NULL); + assert(data != NULL); + + e = (head + buffer->used); + + for (p = head; p && *p && p < e; p++) { + if (*p == '\n') { + pe = p+1; + if (*pe == '\r') pe++; + if (pe <= e && *pe == '\n') { + pe++; + datalen = pe - head; + if (datalen > maxlen) { + datalen = maxlen; + } + break; + } + } + } + + return esl_buffer_read(buffer, data, datalen); +} + +ESL_DECLARE(esl_size_t) esl_buffer_write(esl_buffer_t *buffer, const void *data, esl_size_t datalen) +{ + esl_size_t freespace, actual_freespace; + + assert(buffer != NULL); + assert(data != NULL); + assert(buffer->data != NULL); + + if (!datalen) { + return buffer->used; + } + + actual_freespace = buffer->datalen - buffer->actually_used; + if (actual_freespace < datalen && (!buffer->max_len || (buffer->used + datalen <= buffer->max_len))) { + memmove(buffer->data, buffer->head, buffer->used); + buffer->head = buffer->data; + buffer->actually_used = buffer->used; + } + + freespace = buffer->datalen - buffer->used; + + /* + if (buffer->data != buffer->head) { + memmove(buffer->data, buffer->head, buffer->used); + buffer->head = buffer->data; + } + */ + + if (freespace < datalen) { + esl_size_t new_size, new_block_size; + void *data1; + + new_size = buffer->datalen + datalen; + new_block_size = buffer->datalen + buffer->blocksize; + + if (new_block_size > new_size) { + new_size = new_block_size; + } + buffer->head = buffer->data; + data1 = realloc(buffer->data, new_size); + if (!data1) { + return 0; + } + buffer->data = data1; + buffer->head = buffer->data; + buffer->datalen = new_size; + } + + + freespace = buffer->datalen - buffer->used; + + if (freespace < datalen) { + return 0; + } else { + memcpy(buffer->head + buffer->used, data, datalen); + buffer->used += datalen; + buffer->actually_used += datalen; + } + /* if (buffer->id == 4) printf("%u i %d = %d\n", buffer->id, (unsigned)datalen, (unsigned)buffer->used); */ + + return buffer->used; +} + +ESL_DECLARE(void) esl_buffer_zero(esl_buffer_t *buffer) +{ + assert(buffer != NULL); + assert(buffer->data != NULL); + + buffer->used = 0; + buffer->actually_used = 0; + buffer->head = buffer->data; +} + +ESL_DECLARE(esl_size_t) esl_buffer_zwrite(esl_buffer_t *buffer, const void *data, esl_size_t datalen) +{ + esl_size_t w; + + if (!(w = esl_buffer_write(buffer, data, datalen))) { + esl_buffer_zero(buffer); + return esl_buffer_write(buffer, data, datalen); + } + + return w; +} + +ESL_DECLARE(void) esl_buffer_destroy(esl_buffer_t **buffer) +{ + if (*buffer) { + free((*buffer)->data); + free(*buffer); + } + + *buffer = NULL; +} + +/* For Emacs: + * Local Variables: + * mode:c + * indent-tabs-mode:t + * tab-width:4 + * c-basic-offset:4 + * End: + * For VIM: + * vim:set softtabstop=4 shiftwidth=4 tabstop=4: + */ diff --git a/libs/esl/src/include/esl.h b/libs/esl/src/include/esl.h index 9f28c3d925..99ab53ae95 100644 --- a/libs/esl/src/include/esl.h +++ b/libs/esl/src/include/esl.h @@ -251,6 +251,7 @@ typedef int esl_filehandle_t; #include "esl_json.h" typedef int16_t esl_port_t; +typedef size_t esl_size_t; typedef enum { ESL_SUCCESS, @@ -259,7 +260,11 @@ typedef enum { ESL_DISCONNECTED } esl_status_t; +#define BUF_CHUNK 65536 * 50 +#define BUF_START 65536 * 100 + #include +#include /*! \brief A handle that will hold the socket information and different events received. */ @@ -273,7 +278,8 @@ typedef struct { /*! The error number reported by the OS */ int errnum; /*! The inner contents received by the socket. Used only internally. */ - char header_buf[4196]; + esl_buffer_t *packet_buf; + char socket_buf[65536]; /*! Last command reply */ char last_reply[1024]; /*! Las command reply when called with esl_send_recv */ diff --git a/libs/esl/src/include/esl_buffer.h b/libs/esl/src/include/esl_buffer.h new file mode 100644 index 0000000000..c7901e4ede --- /dev/null +++ b/libs/esl/src/include/esl_buffer.h @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2010, Anthony Minessale II + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of the original author; nor the names of any contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "esl.h" +#ifndef ESL_BUFFER_H +#define ESL_BUFFER_H +/** + * @defgroup esl_buffer Buffer Routines + * @ingroup buffer + * The purpose of this module is to make a plain buffering interface that can be used for read/write buffers + * throughout the application. + * @{ + */ +struct esl_buffer; +typedef struct esl_buffer esl_buffer_t; + +/*! \brief Allocate a new dynamic esl_buffer + * \param buffer returned pointer to the new buffer + * \param blocksize length to realloc by as data is added + * \param start_len ammount of memory to reserve initially + * \param max_len length the buffer is allowed to grow to + * \return status + */ +ESL_DECLARE(esl_status_t) esl_buffer_create(esl_buffer_t **buffer, esl_size_t blocksize, esl_size_t start_len, esl_size_t max_len); + +/*! \brief Get the length of a esl_buffer_t + * \param buffer any buffer of type esl_buffer_t + * \return int size of the buffer. + */ +ESL_DECLARE(esl_size_t) esl_buffer_len(esl_buffer_t *buffer); + +/*! \brief Get the freespace of a esl_buffer_t + * \param buffer any buffer of type esl_buffer_t + * \return int freespace in the buffer. + */ +ESL_DECLARE(esl_size_t) esl_buffer_freespace(esl_buffer_t *buffer); + +/*! \brief Get the in use amount of a esl_buffer_t + * \param buffer any buffer of type esl_buffer_t + * \return int ammount of buffer curently in use + */ +ESL_DECLARE(esl_size_t) esl_buffer_inuse(esl_buffer_t *buffer); + +/*! \brief Read data from a esl_buffer_t up to the ammount of datalen if it is available. Remove read data from buffer. + * \param buffer any buffer of type esl_buffer_t + * \param data pointer to the read data to be returned + * \param datalen amount of data to be returned + * \return int ammount of data actually read + */ +ESL_DECLARE(esl_size_t) esl_buffer_read(esl_buffer_t *buffer, void *data, esl_size_t datalen); + +ESL_DECLARE(esl_size_t) esl_buffer_read_packet(esl_buffer_t *buffer, void *data, esl_size_t maxlen); +ESL_DECLARE(esl_size_t) esl_buffer_packet_count(esl_buffer_t *buffer); + +/*! \brief Read data endlessly from a esl_buffer_t + * \param buffer any buffer of type esl_buffer_t + * \param data pointer to the read data to be returned + * \param datalen amount of data to be returned + * \return int ammount of data actually read + * \note Once you have read all the data from the buffer it will loop around. + */ +ESL_DECLARE(esl_size_t) esl_buffer_read_loop(esl_buffer_t *buffer, void *data, esl_size_t datalen); + +/*! \brief Assign a number of loops to read + * \param buffer any buffer of type esl_buffer_t + * \param loops the number of loops (-1 for infinite) + */ +ESL_DECLARE(void) esl_buffer_set_loops(esl_buffer_t *buffer, int32_t loops); + +/*! \brief Write data into a esl_buffer_t up to the length of datalen + * \param buffer any buffer of type esl_buffer_t + * \param data pointer to the data to be written + * \param datalen amount of data to be written + * \return int amount of buffer used after the write, or 0 if no space available + */ +ESL_DECLARE(esl_size_t) esl_buffer_write(esl_buffer_t *buffer, const void *data, esl_size_t datalen); + +/*! \brief Remove data from the buffer + * \param buffer any buffer of type esl_buffer_t + * \param datalen amount of data to be removed + * \return int size of buffer, or 0 if unable to toss that much data + */ +ESL_DECLARE(esl_size_t) esl_buffer_toss(esl_buffer_t *buffer, esl_size_t datalen); + +/*! \brief Remove all data from the buffer + * \param buffer any buffer of type esl_buffer_t + */ +ESL_DECLARE(void) esl_buffer_zero(esl_buffer_t *buffer); + +/*! \brief Destroy the buffer + * \param buffer buffer to destroy + * \note only neccessary on dynamic buffers (noop on pooled ones) + */ +ESL_DECLARE(void) esl_buffer_destroy(esl_buffer_t **buffer); + +/*! \brief Seek to offset from the beginning of the buffer + * \param buffer buffer to seek + * \param datalen offset in bytes + * \return new position + */ +ESL_DECLARE(esl_size_t) esl_buffer_seek(esl_buffer_t *buffer, esl_size_t datalen); + +/** @} */ + +ESL_DECLARE(esl_size_t) esl_buffer_zwrite(esl_buffer_t *buffer, const void *data, esl_size_t datalen); + +#endif +/* For Emacs: + * Local Variables: + * mode:c + * indent-tabs-mode:t + * tab-width:4 + * c-basic-offset:4 + * End: + * For VIM: + * vim:set softtabstop=4 shiftwidth=4 tabstop=4: + */ diff --git a/libs/freetdm/Makefile.am b/libs/freetdm/Makefile.am index af26f7f2af..5e804b7505 100644 --- a/libs/freetdm/Makefile.am +++ b/libs/freetdm/Makefile.am @@ -49,6 +49,7 @@ if HAVE_SNG_ISDN INCS += -I/usr/include/sng_isdn endif +# we needed to separate CFLAGS in FTDM_COMPAT_CFLAGS and FTDM_CFLAGS due to -c99 which causes problems with wanpipe headers FTDM_COMPAT_CFLAGS = $(INCS) -DFTDM_CONFIG_DIR=\"@confdir@\" -DFTDM_MOD_DIR=\"$(moddir)\" @COMP_VENDOR_COMPAT_CFLAGS@ @DEFS@ FTDM_CFLAGS = $(INCS) -DFTDM_CONFIG_DIR=\"@confdir@\" -DFTDM_MOD_DIR=\"$(moddir)\" @COMP_VENDOR_CFLAGS@ @DEFS@ COMPILE = $(CC) $(FTDM_CFLAGS) @@ -183,8 +184,8 @@ ftmod_analog_em_la_LIBADD = libfreetdm.la if HAVE_LIBSANGOMA mod_LTLIBRARIES += ftmod_wanpipe.la ftmod_wanpipe_la_SOURCES = $(SRC)/ftmod/ftmod_wanpipe/ftmod_wanpipe.c -#some structures within Wanpipe drivers are not c99 compatible, so we need to compile ftmod_wanpipe -#without c99 flags +# some structures within Wanpipe drivers are not c99 compatible, so we need to compile ftmod_wanpipe +# without c99 flags, use FTDM_COMPAT_CFLAGS instead ftmod_wanpipe_la_CFLAGS = $(AM_CFLAGS) $(FTDM_COMPAT_CFLAGS) -D__LINUX__ -I/usr/include/wanpipe ftmod_wanpipe_la_LDFLAGS = -shared -module -avoid-version -lsangoma ftmod_wanpipe_la_LIBADD = libfreetdm.la diff --git a/libs/freetdm/configure.ac b/libs/freetdm/configure.ac index 592dfd82a3..e26f10b0b2 100644 --- a/libs/freetdm/configure.ac +++ b/libs/freetdm/configure.ac @@ -82,7 +82,7 @@ sun) fi ;; *) - COMP_VENDOR_COMPAT_CFLAGS="-Wall -Wunused-variable -Wwrite-strings -Wstrict-prototypes -Wmissing-prototypes" + COMP_VENDOR_COMPAT_CFLAGS="-Wall -Werror -Wunused-variable -Wwrite-strings -Wstrict-prototypes -Wmissing-prototypes" COMP_VENDOR_CFLAGS="-std=c99 $COMP_VENDOR_COMPAT_CFLAGS" ;; esac diff --git a/libs/freetdm/configure.gnu b/libs/freetdm/configure.gnu index 5785ffc0e7..d00cd18473 100755 --- a/libs/freetdm/configure.gnu +++ b/libs/freetdm/configure.gnu @@ -1,3 +1,3 @@ #! /bin/sh -./configure "$@" --with-pic - +srcpath=$(dirname $0 2>/dev/null ) || srcpath="." +$srcpath/configure "$@" --with-pic diff --git a/libs/freetdm/docs/sigstatus.txt b/libs/freetdm/docs/sigstatus.txt new file mode 100644 index 0000000000..10561bfb5b --- /dev/null +++ b/libs/freetdm/docs/sigstatus.txt @@ -0,0 +1,59 @@ +FreeTDM can both notify and set signaling status changes in the different protocols thru a unified interface. More +specific details on the C data types and function prototypes are found in freetdm.h + +The API provides the following functions and data types to do it: + +The signaling status in any channel/span is represented thru ftdm_signaling_status_t + + /* The signaling link is down (no d-chans up in the span/group, MFC-R2 bit pattern unidentified) */ + FTDM_SIG_STATE_DOWN, + /* The signaling link is suspended (MFC-R2 bit pattern blocked, PRI maintenance, ss7 blocked?) */ + FTDM_SIG_STATE_SUSPENDED, + /* The signaling link is ready and calls can be placed (ie: d-chan up, MFC-R2 both rx and tx in IDLE) */ + FTDM_SIG_STATE_UP, + /* Invalid status */ + FTDM_SIG_STATE_INVALID + +Changes in the signaling status are notified to the user using the standard callback notification function provided +during configuration using the sigevent type FTDM_SIGEVENT_SIGSTATUS_CHANGED which is sent when the line status changes. + +On startup the signalling status default is FTDM_SIG_STATE_DOWN, and no notification is provided until the state change, +so applications must assume the status is down unless told otherwise. + +When ftdm_span_start is called, the signaling stack takes care of attempting to bring the status to UP +but it will ultimately depend on the other side too. + +== Setting the signaling status == + +Users can set the signaling status on a given channel/span thru FreeTDM the following API functions: + +ftdm_channel_set_sig_status +ftdm_span_set_sig_status + +If the user calls ftdm_channel_set_sig_status(chan, FTDM_SIG_STATE_SUSPENDED), the signaling stack will try to set +the status of the line to the one requested, if successful, it will result in a SIGEVENT_SIGSTATUS_CHANGED notification +being sent with status FTDM_SIG_STATE_SUSPENDED. + +** MFC-R2 Signaling Notes ** +For MFC-R2, calling ftdm_span_start() results in setting the tx CAS bits to IDLE. However, if the rx bits are in BLOCKED state +the signaling status will be reported as SUSPENDED. + +If the user calls ftdm_channel_set_sig_status(chan, SUSPENDED), the tx CAS bits will be set to BLOCKED and, if, the current rx bits +are IDLE then a SIGEVENT_SIGSTATUS_CHANGED with state SUSPENDED will be sent. If the rx bits are already in blocked then no further +SIGEVENT_SIGSTATUS_CHANGED notification is needed (because it was already sent when the rx bits were initially detected as BLOCKED). + +If the user calls ftdm_channel_set_sig_status(chan, UP), the tx CAS bits will be set to IDLE and, if, the current rx bits +are IDLE, then SIGEVENT_SIGSTATUS_CHANGED with state UP will be sent. If the rx bits are BLOCKED, then no notification is +sent at all until the rx bits change. + +Bottom line is, for MFC-R2, SIGEVENT_SIGSTATUS_CHANGED UP is only sent to the user when both the rx and tx bits are in IDLE, and +SIGEVENT_SIGSTATUS_CHANGED SUSPENDED is only sent to the user when any of the rx or tx bits are in BLOCKED. + +== Getting the signaling status == +Users can get the signaling status on a given channel/span thru FreeTDM the following API functions: + +ftdm_channel_get_sig_status +ftdm_span_get_sig_status + +The line status returned should be the same as the last time a SIGEVENT_SIGSTATUS_CHANGED was reported. + diff --git a/libs/freetdm/freetdm.2010.sln b/libs/freetdm/freetdm.2010.sln index f4bd907a6d..44431d675a 100644 --- a/libs/freetdm/freetdm.2010.sln +++ b/libs/freetdm/freetdm.2010.sln @@ -119,10 +119,8 @@ Global {0DA69C18-4FA1-4E8C-89CE-12498637C5BE}.Release|x64.ActiveCfg = Release|x64 {0DA69C18-4FA1-4E8C-89CE-12498637C5BE}.Release|x64.Build.0 = Release|x64 {B2AF4EA6-0CD7-4529-9EB5-5AF43DB90395}.Debug|Win32.ActiveCfg = Debug|Win32 - {B2AF4EA6-0CD7-4529-9EB5-5AF43DB90395}.Debug|Win32.Build.0 = Debug|Win32 {B2AF4EA6-0CD7-4529-9EB5-5AF43DB90395}.Debug|x64.ActiveCfg = Debug|x64 {B2AF4EA6-0CD7-4529-9EB5-5AF43DB90395}.Release|Win32.ActiveCfg = Release|Win32 - {B2AF4EA6-0CD7-4529-9EB5-5AF43DB90395}.Release|Win32.Build.0 = Release|Win32 {B2AF4EA6-0CD7-4529-9EB5-5AF43DB90395}.Release|x64.ActiveCfg = Release|x64 {08C3EA27-A51D-47F8-B47D-B189C649CF30}.Debug|Win32.ActiveCfg = Debug|Win32 {08C3EA27-A51D-47F8-B47D-B189C649CF30}.Debug|x64.ActiveCfg = Debug|x64 diff --git a/libs/freetdm/mod_freetdm/mod_freetdm.2010.vcxproj b/libs/freetdm/mod_freetdm/mod_freetdm.2010.vcxproj new file mode 100644 index 0000000000..9f01a3b1a1 --- /dev/null +++ b/libs/freetdm/mod_freetdm/mod_freetdm.2010.vcxproj @@ -0,0 +1,217 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + mod_freetdm + {FE3540C5-3303-46E0-A69E-D92F775687F1} + mod_freetdm + Win32Proj + + + + DynamicLibrary + MultiByte + + + DynamicLibrary + MultiByte + + + DynamicLibrary + MultiByte + + + DynamicLibrary + MultiByte + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + $(SolutionDir)$(PlatformName)\$(Configuration)\mod\ + $(Platform)\$(Configuration)\ + true + $(SolutionDir)$(PlatformName)\$(Configuration)\mod\ + $(Platform)\$(Configuration)\ + false + $(SolutionDir)$(PlatformName)\$(Configuration)\mod\ + $(Platform)\$(Configuration)\ + true + $(SolutionDir)$(PlatformName)\$(Configuration)\mod\ + $(Platform)\$(Configuration)\ + false + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ../../../src/include;../src/include;../src/isdn/include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + + Level4 + true + ProgramDatabase + + + FreeSwitch.lib;%(AdditionalDependencies) + ../../../$(PlatformName)\$(Configuration);%(AdditionalLibraryDirectories) + true + $(OutDir)$(TargetName).pdb + Windows + false + + + $(OutDir)mod_freetdm.lib + MachineX86 + + + + + ../../../src/include;../src/include;../src/isdn/include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS;%(PreprocessorDefinitions) + MultiThreadedDLL + + + Level4 + true + ProgramDatabase + + + FreeSwitch.lib;%(AdditionalDependencies) + ../../../$(PlatformName)\$(Configuration);%(AdditionalLibraryDirectories) + true + $(OutDir)$(TargetName).pdb + Windows + true + true + UseLinkTimeCodeGeneration + false + + + $(OutDir)mod_freetdm.lib + MachineX86 + + + + + X64 + + + Disabled + ../../../src/include;../src/include;../src/isdn/include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + + Level4 + true + ProgramDatabase + + + FreeSwitchCore.lib;%(AdditionalDependencies) + ../../../$(PlatformName)\$(Configuration);%(AdditionalLibraryDirectories) + true + $(OutDir)$(TargetName).pdb + Windows + false + + + $(OutDir)mod_freetdm.lib + MachineX64 + + + + + X64 + + + ../../../src/include;../src/include;../src/isdn/include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS;%(PreprocessorDefinitions) + MultiThreadedDLL + + + Level4 + true + ProgramDatabase + + + FreeSwitchCore.lib;%(AdditionalDependencies) + ../../../$(PlatformName)\$(Configuration);%(AdditionalLibraryDirectories) + true + $(OutDir)$(TargetName).pdb + Windows + true + true + UseLinkTimeCodeGeneration + false + + + $(OutDir)mod_freetdm.lib + MachineX64 + + + + + + + + {93b8812c-3ec4-4f78-8970-ffbfc99e167d} + false + + + + + + \ No newline at end of file diff --git a/libs/freetdm/mod_freetdm/mod_freetdm.2010.vcxproj.filters b/libs/freetdm/mod_freetdm/mod_freetdm.2010.vcxproj.filters new file mode 100644 index 0000000000..92ac5ead47 --- /dev/null +++ b/libs/freetdm/mod_freetdm/mod_freetdm.2010.vcxproj.filters @@ -0,0 +1,14 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx + + + + + Source Files + + + \ No newline at end of file diff --git a/libs/freetdm/mod_freetdm/mod_freetdm.c b/libs/freetdm/mod_freetdm/mod_freetdm.c index 7ea6bb6d37..66bc532cbc 100755 --- a/libs/freetdm/mod_freetdm/mod_freetdm.c +++ b/libs/freetdm/mod_freetdm/mod_freetdm.c @@ -429,7 +429,7 @@ static switch_status_t channel_on_routing(switch_core_session_t *session) assert(tech_pvt->ftdmchan != NULL); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s CHANNEL ROUTING\n", switch_channel_get_name(channel)); - + ftdm_channel_call_indicate(tech_pvt->ftdmchan, FTDM_CHANNEL_INDICATE_PROCEED); return SWITCH_STATUS_SUCCESS; } @@ -802,7 +802,7 @@ static switch_status_t channel_receive_message_cas(switch_core_session_t *sessio phy_id = ftdm_channel_get_ph_id(tech_pvt->ftdmchan); ftdm_log(FTDM_LOG_DEBUG, "Got Freeswitch message in R2 channel %d [%d]\n", phy_id, msg->message_id); - if (switch_channel_test_flag(channel, CF_OUTBOUND)) { + if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) { return SWITCH_STATUS_SUCCESS; } @@ -849,7 +849,7 @@ static switch_status_t channel_receive_message_b(switch_core_session_t *session, return SWITCH_STATUS_SUCCESS; } - if (switch_channel_test_flag(channel, CF_OUTBOUND)) { + if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) { return SWITCH_STATUS_SUCCESS; } @@ -892,7 +892,7 @@ static switch_status_t channel_receive_message_fxo(switch_core_session_t *sessio return SWITCH_STATUS_FALSE; } - if (switch_channel_test_flag(channel, CF_OUTBOUND)) { + if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) { return SWITCH_STATUS_SUCCESS; } @@ -924,7 +924,7 @@ static switch_status_t channel_receive_message_fxs(switch_core_session_t *sessio return SWITCH_STATUS_FALSE; } - if (switch_channel_test_flag(channel, CF_OUTBOUND)) { + if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) { return SWITCH_STATUS_SUCCESS; } @@ -981,7 +981,7 @@ static switch_status_t channel_receive_message(switch_core_session_t *session, s switch (msg->message_id) { case SWITCH_MESSAGE_INDICATE_PROGRESS: case SWITCH_MESSAGE_INDICATE_ANSWER: - if (!switch_channel_test_flag(channel, CF_OUTBOUND)) { + if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_INBOUND) { if ((var = switch_channel_get_variable(channel, "freetdm_pre_buffer_size"))) { int tmp = atoi(var); if (tmp > -1) { @@ -1136,6 +1136,10 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi direction = FTDM_BOTTOM_UP; } else if (*argv[1] == 'a') { direction = FTDM_TOP_DOWN; + } else if (*argv[1] == 'r') { + direction = FTDM_RR_DOWN; + } else if (*argv[1] == 'R') { + direction = FTDM_RR_UP; } else { chan_id = atoi(argv[1]); } @@ -1278,6 +1282,10 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi caller_data.dnis.type = outbound_profile->destination_number_ton; } + if ((var = channel_get_variable(session, var_event, "freetdm_calling_party_category"))) { + ftdm_set_calling_party_category(var, (uint8_t *)&caller_data.cpc); + } + if ((var = channel_get_variable(session, var_event, "freetdm_custom_call_data"))) { ftdm_set_string(caller_data.raw_data, var); caller_data.raw_data_len = (uint32_t)strlen(var); @@ -1329,7 +1337,7 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi char *v = h->name + FREETDM_VAR_PREFIX_LEN; if (!zstr(v)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Adding outbound freetdm variable %s=%s to channel %d:%d\n", v, h->value, span_id, chan_id); - ftdm_channel_add_var(ftdmchan, v, h->value); + ftdm_call_add_var(&caller_data, v, h->value); } } } @@ -1363,7 +1371,6 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi tech_pvt->caller_profile = caller_profile; - switch_channel_set_flag(channel, CF_OUTBOUND); switch_channel_set_state(channel, CS_INIT); if (ftdm_channel_add_token(ftdmchan, switch_core_session_get_uuid(*new_session), ftdm_channel_get_token_count(ftdmchan)) != FTDM_SUCCESS) { switch_core_session_destroy(new_session); @@ -1528,6 +1535,7 @@ ftdm_status_t ftdm_channel_from_event(ftdm_sigmsg_t *sigmsg, switch_core_session switch_channel_set_variable_printf(channel, "freetdm_chan_number", "%d", chanid); switch_channel_set_variable_printf(channel, "freetdm_bearer_capability", "%d", channel_caller_data->bearer_capability); switch_channel_set_variable_printf(channel, "freetdm_bearer_layer1", "%d", channel_caller_data->bearer_layer1); + if (globals.sip_headers) { switch_channel_set_variable(channel, "sip_h_X-FreeTDM-SpanName", ftdm_channel_get_span_name(sigmsg->channel)); switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-SpanNumber", "%d", spanid); @@ -1561,8 +1569,18 @@ ftdm_status_t ftdm_channel_from_event(ftdm_sigmsg_t *sigmsg, switch_core_session ftdm_channel_get_current_var(curr, &var_name, &var_value); snprintf(name, sizeof(name), FREETDM_VAR_PREFIX "%s", var_name); switch_channel_set_variable_printf(channel, name, "%s", var_value); + } + + /* Add any call variable to the dial plan */ + iter = ftdm_call_get_var_iterator(channel_caller_data, iter); + for (curr = iter ; curr; curr = ftdm_iterator_next(curr)) { + ftdm_call_get_current_var(curr, &var_name, &var_value); + snprintf(name, sizeof(name), FREETDM_VAR_PREFIX "%s", var_name); + switch_channel_set_variable_printf(channel, name, "%s", var_value); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Call Variable: %s=%s\n", name, var_value); } ftdm_iterator_free(iter); + switch_channel_set_state(channel, CS_INIT); if (switch_core_session_thread_launch(session) != SWITCH_STATUS_SUCCESS) { @@ -1661,11 +1679,11 @@ static FIO_SIGNAL_CB_FUNCTION(on_fxo_signal) ftdm_status_t status; uint32_t spanid; uint32_t chanid; - ftdm_caller_data_t *callerdata; + ftdm_caller_data_t *caller_data; spanid = ftdm_channel_get_span_id(sigmsg->channel); chanid = ftdm_channel_get_id(sigmsg->channel); - callerdata = ftdm_channel_get_caller_data(sigmsg->channel); + caller_data = ftdm_channel_get_caller_data(sigmsg->channel); ftdm_log(FTDM_LOG_DEBUG, "got FXO sig %d:%d [%s]\n", spanid, chanid, ftdm_signal_event2str(sigmsg->event_id)); @@ -1688,7 +1706,7 @@ static FIO_SIGNAL_CB_FUNCTION(on_fxo_signal) switch_set_flag_locked(tech_pvt, TFLAG_DEAD); ftdm_channel_clear_token(sigmsg->channel, 0); channel = switch_core_session_get_channel(session); - switch_channel_hangup(channel, callerdata->hangup_cause); + switch_channel_hangup(channel, caller_data->hangup_cause); ftdm_channel_clear_token(sigmsg->channel, switch_core_session_get_uuid(session)); switch_core_session_rwunlock(session); } @@ -1712,8 +1730,9 @@ static FIO_SIGNAL_CB_FUNCTION(on_fxo_signal) } } break; - case FTDM_SIGEVENT_RELEASED: { /* twiddle */ } break; - + case FTDM_SIGEVENT_RELEASED: { /* twiddle */ } break; + case FTDM_SIGEVENT_SIGSTATUS_CHANGED: { /* twiddle */ } break; + default: { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Unhandled msg type %d for channel %d:%d\n", @@ -1767,7 +1786,8 @@ static FIO_SIGNAL_CB_FUNCTION(on_fxs_signal) } } break; - case FTDM_SIGEVENT_RELEASED: { /* twiddle */ } break; + case FTDM_SIGEVENT_RELEASED: { /* twiddle */ } break; + case FTDM_SIGEVENT_STOP: { private_t *tech_pvt = NULL; @@ -1799,7 +1819,9 @@ static FIO_SIGNAL_CB_FUNCTION(on_fxs_signal) switch_clear_flag_locked(tech_pvt, TFLAG_HOLD); } - if (channel_a && channel_b && !switch_channel_test_flag(channel_a, CF_OUTBOUND) && !switch_channel_test_flag(channel_b, CF_OUTBOUND)) { + if (channel_a && channel_b && switch_channel_direction(channel_a) == SWITCH_CALL_DIRECTION_INBOUND && + switch_channel_direction(channel_b) == SWITCH_CALL_DIRECTION_INBOUND) { + cause = SWITCH_CAUSE_ATTENDED_TRANSFER; if (br_a_uuid && br_b_uuid) { switch_ivr_uuid_bridge(br_a_uuid, br_b_uuid); @@ -1899,7 +1921,7 @@ static FIO_SIGNAL_CB_FUNCTION(on_fxs_signal) case FTDM_SIGEVENT_COLLECTED_DIGIT: { int span_id = ftdm_channel_get_span_id(sigmsg->channel); - char *dtmf = sigmsg->raw_data; + char *dtmf = sigmsg->ev_data.collected.digits; char *regex = SPAN_CONFIG[span_id].dial_regex; char *fail_regex = SPAN_CONFIG[span_id].fail_dial_regex; ftdm_caller_data_t *caller_data = ftdm_channel_get_caller_data(sigmsg->channel); @@ -1991,8 +2013,8 @@ static FIO_SIGNAL_CB_FUNCTION(on_r2_signal) } break; - case FTDM_SIGEVENT_RELEASED: { /* twiddle */ } break; - + case FTDM_SIGEVENT_RELEASED: { /* twiddle */ } break; + /* on DNIS received from the R2 forward side, return status == FTDM_BREAK to stop requesting DNIS */ case FTDM_SIGEVENT_COLLECTED_DIGIT: { @@ -2065,7 +2087,7 @@ static FIO_SIGNAL_CB_FUNCTION(on_r2_signal) case FTDM_SIGEVENT_SIGSTATUS_CHANGED: { - ftdm_signaling_status_t sigstatus = sigmsg->raw_data ? *((ftdm_signaling_status_t*)(sigmsg->raw_data)) : sigmsg->sigstatus; + ftdm_signaling_status_t sigstatus = sigmsg->ev_data.sigstatus.status; switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "%d:%d signalling changed to: %s\n", spanid, chanid, ftdm_signaling_status2str(sigstatus)); } @@ -2104,14 +2126,14 @@ static FIO_SIGNAL_CB_FUNCTION(on_clear_channel_signal) switch(sigmsg->event_id) { case FTDM_SIGEVENT_START: { - ftdm_channel_add_var(sigmsg->channel, "screening_ind", ftdm_screening2str(caller_data->screen)); - ftdm_channel_add_var(sigmsg->channel, "presentation_ind", ftdm_presentation2str(caller_data->pres)); + ftdm_call_add_var(caller_data, "screening_ind", ftdm_screening2str(caller_data->screen)); + ftdm_call_add_var(caller_data, "presentation_ind", ftdm_presentation2str(caller_data->pres)); return ftdm_channel_from_event(sigmsg, &session); } break; - case FTDM_SIGEVENT_RELEASED: { /* twiddle */ } break; - + case FTDM_SIGEVENT_RELEASED: { /* twiddle */ } break; + case FTDM_SIGEVENT_STOP: case FTDM_SIGEVENT_RESTART: { @@ -2155,6 +2177,7 @@ static FIO_SIGNAL_CB_FUNCTION(on_clear_channel_signal) } break; case FTDM_SIGEVENT_PROGRESS: + case FTDM_SIGEVENT_RINGING: { if ((session = ftdm_channel_get_session(sigmsg->channel, 0))) { channel = switch_core_session_get_channel(session); @@ -2170,13 +2193,13 @@ static FIO_SIGNAL_CB_FUNCTION(on_clear_channel_signal) break; case FTDM_SIGEVENT_SIGSTATUS_CHANGED: { - ftdm_signaling_status_t sigstatus = sigmsg->raw_data ? *((ftdm_signaling_status_t*)(sigmsg->raw_data)) : sigmsg->sigstatus; + ftdm_signaling_status_t sigstatus = sigmsg->ev_data.sigstatus.status; switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "%d:%d signalling changed to :%s\n", spanid, chanid, ftdm_signaling_status2str(sigstatus)); } break; case FTDM_SIGEVENT_PROCEED: - case FTDM_SIGEVENT_MSG: + case FTDM_SIGEVENT_FACILITY: /* FS does not have handlers for these messages, so ignore them for now */ break; default: @@ -3513,7 +3536,19 @@ void dump_chan_xml(ftdm_span_t *span, uint32_t chan_id, switch_stream_handle_t * switch_channel_cause2str(caller_data->hangup_cause)); } -#define FT_SYNTAX "list || dump [] || q931_pcap on|off [pcapfilename without suffix] || gains [] || dtmf on|off []" +#define FT_SYNTAX "USAGE:\n" \ +"--------------------------------------------------------------------------------\n" \ +"ftdm list\n" \ +"ftdm start|stop \n" \ +"ftdm restart \n" \ +"ftdm dump []\n" \ +"ftdm sigstatus get|set [] [] []\n" \ +"ftdm trace []\n" \ +"ftdm notrace []\n" \ +"ftdm q931_pcap on|off [pcapfilename without suffix]\n" \ +"ftdm gains []\n" \ +"ftdm dtmf on|off []\n" \ +"--------------------------------------------------------------------------------\n" SWITCH_STANDARD_API(ft_function) { char *mycmd = NULL, *argv[10] = { 0 }; @@ -3530,7 +3565,83 @@ SWITCH_STANDARD_API(ft_function) goto end; } - if (!strcasecmp(argv[0], "dump")) { + if (!strcasecmp(argv[0], "sigstatus")) { + ftdm_span_t *span = NULL; + ftdm_signaling_status_t sigstatus; + + if (argc < 3) { + stream->write_function(stream, "-ERR Usage: ftdm sigstatus get|set [] [] []\n"); + goto end; + } + if (!strcasecmp(argv[1], "get") && argc < 3) { + stream->write_function(stream, "-ERR sigstatus get usage: get \n"); + goto end; + } + if (!strcasecmp(argv[1], "set") && argc != 5) { + stream->write_function(stream, "-ERR sigstatus set usage: set |all \n"); + goto end; + } + + ftdm_span_find_by_name(argv[2], &span); + if (!span) { + stream->write_function(stream, "-ERR invalid span\n"); + goto end; + } + + if (!strcasecmp(argv[1], "get")) { + if (argc == 4) { + uint32_t chan_id = atol(argv[3]); + ftdm_channel_t *fchan = ftdm_span_get_channel(span, chan_id); + if (!fchan) { + stream->write_function(stream, "-ERR failed to get channel id '%d'\n", chan_id); + goto end; + } + + if ((FTDM_SUCCESS == ftdm_channel_get_sig_status(fchan, &sigstatus))) { + stream->write_function(stream, "channel %d signaling status: %s\n", chan_id, ftdm_signaling_status2str(sigstatus)); + } else { + stream->write_function(stream, "-ERR failed to get channel sigstatus\n"); + } + goto end; + } else { + if ((FTDM_SUCCESS == ftdm_span_get_sig_status(span, &sigstatus))) { + stream->write_function(stream, "signaling_status: %s\n", ftdm_signaling_status2str(sigstatus)); + } else { + stream->write_function(stream, "-ERR failed to read span status: %s\n", ftdm_span_get_last_error(span)); + } + } + goto end; + } + if (!strcasecmp(argv[1], "set")) { + sigstatus = ftdm_str2ftdm_signaling_status(argv[4]); + + if (!strcasecmp(argv[3], "all")) { + if ((FTDM_SUCCESS == ftdm_span_set_sig_status(span, sigstatus))) { + stream->write_function(stream, "Signaling status of all channels from span %s set to %s\n", + ftdm_span_get_name(span), ftdm_signaling_status2str(sigstatus)); + } else { + stream->write_function(stream, "-ERR failed to set span sigstatus to '%s'\n", ftdm_signaling_status2str(sigstatus)); + } + goto end; + } else { + uint32_t chan_id = atol(argv[3]); + ftdm_channel_t *fchan = ftdm_span_get_channel(span, chan_id); + if (!fchan) { + stream->write_function(stream, "-ERR failed to get channel id '%d'\n", chan_id); + goto end; + } + + if ((FTDM_SUCCESS == ftdm_channel_set_sig_status(fchan, sigstatus))) { + stream->write_function(stream, "Signaling status of channel %d set to %s\n", chan_id, + ftdm_signaling_status2str(sigstatus)); + } else { + stream->write_function(stream, "-ERR failed to set span sigstatus to '%s'\n", ftdm_signaling_status2str(sigstatus)); + } + goto end; + } + } + + } else if (!strcasecmp(argv[0], "dump")) { if (argc < 2) { stream->write_function(stream, "-ERR Usage: ftdm dump []\n"); goto end; @@ -3910,6 +4021,28 @@ SWITCH_STANDARD_API(ft_function) } } stream->write_function(stream, "+OK gains set to Rx %f and Tx %f\n", rxgain, txgain); + } else if (!strcasecmp(argv[0], "restart")) { + uint32_t chan_id = 0; + ftdm_channel_t *chan; + ftdm_span_t *span = NULL; + if (argc < 3) { + stream->write_function(stream, "-ERR Usage: ftdm restart \n"); + goto end; + } + ftdm_span_find_by_name(argv[1], &span); + if (!span) { + stream->write_function(stream, "-ERR invalid span\n"); + goto end; + } + + chan_id = atoi(argv[2]); + chan = ftdm_span_get_channel(span, chan_id); + if (!chan) { + stream->write_function(stream, "-ERR Could not find chan\n"); + goto end; + } + stream->write_function(stream, "Resetting channel %s:%s\n", argv[2], argv[3]); + ftdm_channel_reset(chan); } else { char *rply = ftdm_api_execute(cmd); diff --git a/libs/freetdm/src/ftdm_call_utils.c b/libs/freetdm/src/ftdm_call_utils.c index 69f2fb4fff..2b72f05b77 100644 --- a/libs/freetdm/src/ftdm_call_utils.c +++ b/libs/freetdm/src/ftdm_call_utils.c @@ -30,6 +30,12 @@ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Contributors: + * + * Moises Silva + * Ricardo Barroetaveña + * */ #include "private/ftdm_core.h" @@ -144,3 +150,20 @@ FT_DECLARE(ftdm_status_t) ftdm_is_number(const char *number) return FTDM_SUCCESS; } + +FT_DECLARE(ftdm_status_t) ftdm_set_calling_party_category(const char *string, uint8_t *target) +{ + uint8_t val; + ftdm_status_t status = FTDM_SUCCESS; + + val = ftdm_str2ftdm_calling_party_category(string); + if (val == FTDM_CPC_INVALID) { + ftdm_log(FTDM_LOG_WARNING, "Invalid category string (%s)\n", string); + val = FTDM_CPC_ORDINARY; + status = FTDM_FAIL; + } + + *target = val; + return status; +} + diff --git a/libs/freetdm/src/ftdm_io.c b/libs/freetdm/src/ftdm_io.c index 758681fdd5..c04dd85a17 100644 --- a/libs/freetdm/src/ftdm_io.c +++ b/libs/freetdm/src/ftdm_io.c @@ -57,10 +57,17 @@ struct tm *localtime_r(const time_t *clock, struct tm *result); #define SPAN_PENDING_SIGNALS_QUEUE_SIZE 1000 #define FTDM_READ_TRACE_INDEX 0 #define FTDM_WRITE_TRACE_INDEX 1 +#define MAX_CALLIDS 6000 ftdm_time_t time_last_throttle_log = 0; ftdm_time_t time_current_throttle_log = 0; +static ftdm_iterator_t *get_iterator(ftdm_iterator_type_t type, ftdm_iterator_t *iter); +static ftdm_status_t ftdm_call_set_call_id(ftdm_caller_data_t *caller_data); +static ftdm_status_t ftdm_call_clear_call_id(ftdm_caller_data_t *caller_data); +static ftdm_status_t ftdm_channel_clear_vars(ftdm_channel_t *ftdmchan); +static ftdm_status_t ftdm_channel_done(ftdm_channel_t *ftdmchan); + static int time_is_init = 0; static void time_init(void) @@ -128,8 +135,15 @@ static void write_chan_io_dump(ftdm_io_dump_t *dump, char *dataptr, int dlen) static void dump_chan_io_to_file(ftdm_channel_t *fchan, ftdm_io_dump_t *dump, FILE *file) { /* write the saved audio buffer */ - size_t rc = 0; - size_t towrite = dump->size - dump->windex; + ftdm_size_t rc = 0; + ftdm_size_t towrite = 0; + + if (!dump->buffer) { + return; + } + + towrite = dump->size - dump->windex; + if (dump->wrapped) { rc = fwrite(&dump->buffer[dump->windex], 1, towrite, file); if (rc != towrite) { @@ -226,6 +240,10 @@ static struct { ftdm_span_t *spans; ftdm_group_t *groups; cpu_monitor_t cpu_monitor; + + ftdm_caller_data_t *call_ids[MAX_CALLIDS+1]; + ftdm_mutex_t *call_id_mutex; + uint32_t last_call_id; } globals; enum ftdm_enum_cpu_alarm_action_flags @@ -262,6 +280,9 @@ FTDM_STR2ENUM(ftdm_str2ftdm_chan_type, ftdm_chan_type2str, ftdm_chan_type_t, CHA FTDM_ENUM_NAMES(SIGNALING_STATUS_NAMES, SIGSTATUS_STRINGS) FTDM_STR2ENUM(ftdm_str2ftdm_signaling_status, ftdm_signaling_status2str, ftdm_signaling_status_t, SIGNALING_STATUS_NAMES, FTDM_SIG_STATE_INVALID) +FTDM_ENUM_NAMES(TRACE_DIR_NAMES, TRACE_DIR_STRINGS) +FTDM_STR2ENUM(ftdm_str2ftdm_trace_dir, ftdm_trace_dir2str, ftdm_trace_dir_t, TRACE_DIR_NAMES, FTDM_TRACE_INVALID) + FTDM_ENUM_NAMES(TON_NAMES, TON_STRINGS) FTDM_STR2ENUM(ftdm_str2ftdm_ton, ftdm_ton2str, ftdm_ton_t, TON_NAMES, FTDM_TON_INVALID) @@ -280,6 +301,9 @@ FTDM_STR2ENUM(ftdm_str2ftdm_bearer_cap, ftdm_bearer_cap2str, ftdm_bearer_cap_t, FTDM_ENUM_NAMES(USER_LAYER1_PROT_NAMES, USER_LAYER1_PROT_STRINGS) FTDM_STR2ENUM(ftdm_str2ftdm_usr_layer1_prot, ftdm_user_layer1_prot2str, ftdm_user_layer1_prot_t, USER_LAYER1_PROT_NAMES, FTDM_USER_LAYER1_PROT_INVALID) +FTDM_ENUM_NAMES(CALLING_PARTY_CATEGORY_NAMES, CALLING_PARTY_CATEGORY_STRINGS) +FTDM_STR2ENUM(ftdm_str2ftdm_calling_party_category, ftdm_calling_party_category2str, ftdm_calling_party_category_t, CALLING_PARTY_CATEGORY_NAMES, FTDM_CPC_INVALID) + static ftdm_status_t ftdm_group_add_channels(ftdm_span_t* span, int currindex, const char* name); static const char *cut_path(const char *in) @@ -1681,6 +1705,33 @@ static ftdm_status_t __inline__ get_best_rated(ftdm_channel_t **fchan, ftdm_chan return FTDM_SUCCESS; } + +static uint32_t __inline__ rr_next(uint32_t last, uint32_t min, uint32_t max, ftdm_direction_t direction) +{ + uint32_t next = min; + + ftdm_log(FTDM_LOG_DEBUG, "last = %d, min = %d, max = %d\n", last, min, max); + + if (direction == FTDM_RR_DOWN) { + next = (last >= max) ? min : ++last; + } else { + next = (last <= min) ? max : --last; + } + return next; +} + + +FT_DECLARE(int) ftdm_channel_get_availability(ftdm_channel_t *ftdmchan) +{ + int availability = -1; + ftdm_channel_lock(ftdmchan); + if (ftdm_test_flag(ftdmchan->span, FTDM_SPAN_USE_AV_RATE)) { + availability = ftdmchan->availability_rate; + } + ftdm_channel_unlock(ftdmchan); + return availability; +} + FT_DECLARE(ftdm_status_t) ftdm_channel_open_by_group(uint32_t group_id, ftdm_direction_t direction, ftdm_caller_data_t *caller_data, ftdm_channel_t **ftdmchan) { ftdm_status_t status = FTDM_FAIL; @@ -1712,6 +1763,8 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_open_by_group(uint32_t group_id, ftdm_dir if (direction == FTDM_TOP_DOWN) { i = 0; + } else if (direction == FTDM_RR_DOWN || direction == FTDM_RR_UP) { + i = rr_next(group->last_used_index, 0, group->chan_count - 1, direction); } else { i = group->chan_count-1; } @@ -1726,16 +1779,24 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_open_by_group(uint32_t group_id, ftdm_dir if (request_voice_channel(check, ftdmchan, caller_data, direction)) { status = FTDM_SUCCESS; + if (direction == FTDM_RR_UP || direction == FTDM_RR_DOWN) { + group->last_used_index = i; + } break; } calculate_best_rate(check, &best_rated, &best_rate); if (direction == FTDM_TOP_DOWN) { - if (i >= group->chan_count) { + if (i >= (group->chan_count - 1)) { break; } i++; + } else if (direction == FTDM_RR_DOWN || direction == FTDM_RR_UP) { + if (check == best_rated) { + group->last_used_index = i; + } + i = rr_next(i, 0, group->chan_count - 1, direction); } else { if (i == 0) { break; @@ -1814,6 +1875,8 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_open_by_span(uint32_t span_id, ftdm_direc if (direction == FTDM_TOP_DOWN) { i = 1; + } else if (direction == FTDM_RR_DOWN || direction == FTDM_RR_UP) { + i = rr_next(span->last_used_index, 1, span->chan_count, direction); } else { i = span->chan_count; } @@ -1824,6 +1887,10 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_open_by_span(uint32_t span_id, ftdm_direc if (i > span->chan_count) { break; } + } else if (direction == FTDM_RR_DOWN || direction == FTDM_RR_UP) { + if (i == span->last_used_index) { + break; + } } else { if (i == 0) { break; @@ -1837,6 +1904,9 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_open_by_span(uint32_t span_id, ftdm_direc if (request_voice_channel(check, ftdmchan, caller_data, direction)) { status = FTDM_SUCCESS; + if (direction == FTDM_RR_UP || direction == FTDM_RR_DOWN) { + span->last_used_index = i; + } break; } @@ -1844,6 +1914,11 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_open_by_span(uint32_t span_id, ftdm_direc if (direction == FTDM_TOP_DOWN) { i++; + } else if (direction == FTDM_RR_DOWN || direction == FTDM_RR_UP) { + if (check == best_rated) { + span->last_used_index = i; + } + i = rr_next(i, 1, span->chan_count, direction); } else { i--; } @@ -1858,45 +1933,6 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_open_by_span(uint32_t span_id, ftdm_direc return status; } -static ftdm_status_t ftdm_channel_reset(ftdm_channel_t *ftdmchan) -{ - ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_OPEN); - ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_DTMF_DETECT); - ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_SUPRESS_DTMF); - ftdm_channel_done(ftdmchan); - ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_HOLD); - - memset(ftdmchan->tokens, 0, sizeof(ftdmchan->tokens)); - ftdmchan->token_count = 0; - - ftdm_channel_flush_dtmf(ftdmchan); - - if (ftdmchan->gen_dtmf_buffer) { - ftdm_buffer_zero(ftdmchan->gen_dtmf_buffer); - } - - if (ftdmchan->digit_buffer) { - ftdm_buffer_zero(ftdmchan->digit_buffer); - } - - if (!ftdmchan->dtmf_on) { - ftdmchan->dtmf_on = FTDM_DEFAULT_DTMF_ON; - } - - if (!ftdmchan->dtmf_off) { - ftdmchan->dtmf_off = FTDM_DEFAULT_DTMF_OFF; - } - - memset(ftdmchan->dtmf_hangup_buf, '\0', ftdmchan->span->dtmf_hangup_len); - - if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_TRANSCODE)) { - ftdmchan->effective_codec = ftdmchan->native_codec; - ftdmchan->packet_len = ftdmchan->native_interval * (ftdmchan->effective_codec == FTDM_CODEC_SLIN ? 16 : 8); - ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_TRANSCODE); - } - - return FTDM_SUCCESS; -} FT_DECLARE(ftdm_status_t) ftdm_channel_init(ftdm_channel_t *ftdmchan) { @@ -2202,31 +2238,31 @@ FT_DECLARE(ftdm_status_t) _ftdm_channel_call_answer(const char *file, const char goto done; } -#ifndef FREETDM_SKIP_SIG_STATES - /* We will fail RFC's if we not skip states, but some modules apart from ftmod_sangoma_isdn - * expect the call to always to go PROGRESS and PROGRESS MEDIA state before going to UP, so - * remove this only in netborder branch for now while we update the sig modules */ + if (!ftdm_test_flag(ftdmchan->span, FTDM_SPAN_USE_SKIP_STATES)) { + /* We will fail RFC's if we not skip states, but some modules apart from ftmod_sangoma_isdn + * expect the call to always to go PROGRESS and PROGRESS MEDIA state before going to UP, so + * use FTDM_SPAN_USE_SKIP_STATESfor now while we update the sig modules */ - if (ftdmchan->state < FTDM_CHANNEL_STATE_PROGRESS) { - ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_PROGRESS, 1); - } + if (ftdmchan->state < FTDM_CHANNEL_STATE_PROGRESS) { + ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_PROGRESS, 1); + } - /* set state unlocks the channel so we need to re-confirm that the channel hasn't gone to hell */ - if (ftdmchan->state == FTDM_CHANNEL_STATE_TERMINATING) { - ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Ignoring answer because the call has moved to TERMINATING while we're moving to PROGRESS\n"); - goto done; - } + /* set state unlocks the channel so we need to re-confirm that the channel hasn't gone to hell */ + if (ftdmchan->state == FTDM_CHANNEL_STATE_TERMINATING) { + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Ignoring answer because the call has moved to TERMINATING while we're moving to PROGRESS\n"); + goto done; + } - if (ftdmchan->state < FTDM_CHANNEL_STATE_PROGRESS_MEDIA) { - ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, 1); - } + if (ftdmchan->state < FTDM_CHANNEL_STATE_PROGRESS_MEDIA) { + ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, 1); + } - /* set state unlocks the channel so we need to re-confirm that the channel hasn't gone to hell */ - if (ftdmchan->state == FTDM_CHANNEL_STATE_TERMINATING) { - ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Ignoring answer because the call has moved to TERMINATING while we're moving to UP\n"); - goto done; + /* set state unlocks the channel so we need to re-confirm that the channel hasn't gone to hell */ + if (ftdmchan->state == FTDM_CHANNEL_STATE_TERMINATING) { + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Ignoring answer because the call has moved to TERMINATING while we're moving to UP\n"); + goto done; + } } -#endif ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_UP, 1); done: @@ -2400,14 +2436,16 @@ FT_DECLARE(ftdm_status_t) _ftdm_channel_call_indicate(const char *file, const ch ftdm_set_flag(ftdmchan, FTDM_CHANNEL_PROGRESS); ftdm_set_flag(ftdmchan, FTDM_CHANNEL_MEDIA); } else { - if (ftdmchan->state < FTDM_CHANNEL_STATE_PROGRESS) { - ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_PROGRESS, 1); - } + if (!ftdm_test_flag(ftdmchan->span, FTDM_SPAN_USE_SKIP_STATES)) { + if (ftdmchan->state < FTDM_CHANNEL_STATE_PROGRESS) { + ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_PROGRESS, 1); + } - /* set state unlocks the channel so we need to re-confirm that the channel hasn't gone to hell */ - if (ftdmchan->state == FTDM_CHANNEL_STATE_TERMINATING) { - ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Ignoring answer because the call has moved to TERMINATING while we're moving to PROGRESS\n"); - goto done; + /* set state unlocks the channel so we need to re-confirm that the channel hasn't gone to hell */ + if (ftdmchan->state == FTDM_CHANNEL_STATE_TERMINATING) { + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Ignoring answer because the call has moved to TERMINATING while we're moving to PROGRESS\n"); + goto done; + } } ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, 1); @@ -2425,6 +2463,37 @@ done: return FTDM_SUCCESS; } +FT_DECLARE(ftdm_status_t) _ftdm_channel_call_send_msg(const char *file, const char *func, int line, ftdm_channel_t *ftdmchan, ftdm_sigmsg_t *sigmsg) +{ + ftdm_status_t status = FTDM_FAIL; + ftdm_assert_return(ftdmchan != NULL, FTDM_FAIL, "null channel"); +#ifdef __WINDOWS__ + UNREFERENCED_PARAMETER(file); + UNREFERENCED_PARAMETER(func); + UNREFERENCED_PARAMETER(line); +#endif + + ftdm_channel_lock(ftdmchan); + if (ftdmchan->span->send_msg) { + status = ftdmchan->span->send_msg(ftdmchan, sigmsg); + } else { + status = FTDM_NOTIMPL; + ftdm_log(FTDM_LOG_ERROR, "send_msg method not implemented in this span!\n"); + } + ftdm_channel_unlock(ftdmchan); + return status; +} + +FT_DECLARE(ftdm_status_t) _ftdm_channel_reset(const char *file, const char *func, int line, ftdm_channel_t *ftdmchan) +{ + ftdm_assert_return(ftdmchan != NULL, FTDM_FAIL, "null channel"); + + ftdm_channel_lock(ftdmchan); + ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_RESET, 1); + ftdm_channel_unlock(ftdmchan); + return FTDM_SUCCESS; +} + FT_DECLARE(ftdm_status_t) _ftdm_channel_call_place(const char *file, const char *func, int line, ftdm_channel_t *ftdmchan) { ftdm_status_t status = FTDM_FAIL; @@ -2443,16 +2512,20 @@ FT_DECLARE(ftdm_status_t) _ftdm_channel_call_place(const char *file, const char ftdm_log(FTDM_LOG_ERROR, "outgoing_call method not implemented in this span!\n"); } + if (status == FTDM_SUCCESS) { + ftdm_set_flag(ftdmchan, FTDM_CHANNEL_CALL_STARTED); + ftdm_call_set_call_id(&ftdmchan->caller_data); + ftdm_wait_for_flag_cleared(ftdmchan, FTDM_CHANNEL_STATE_CHANGE, 100); + } + + ftdm_channel_unlock(ftdmchan); + #ifdef __WINDOWS__ UNREFERENCED_PARAMETER(file); UNREFERENCED_PARAMETER(func); UNREFERENCED_PARAMETER(line); #endif - ftdm_wait_for_flag_cleared(ftdmchan, FTDM_CHANNEL_STATE_CHANGE, 100); - - ftdm_channel_unlock(ftdmchan); - return status; } @@ -2460,9 +2533,18 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_set_sig_status(ftdm_channel_t *ftdmchan, { ftdm_assert_return(ftdmchan != NULL, FTDM_FAIL, "Null channel\n"); ftdm_assert_return(ftdmchan->span != NULL, FTDM_FAIL, "Null span\n"); - + + if (sigstatus == FTDM_SIG_STATE_DOWN) { + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_WARNING, "The user is not allowed to set the signaling status to DOWN, valid states are UP or SUSPENDED\n"); + return FTDM_FAIL; + } + if (ftdmchan->span->set_channel_sig_status) { - return ftdmchan->span->set_channel_sig_status(ftdmchan, sigstatus); + ftdm_status_t res; + ftdm_channel_lock(ftdmchan); + res = ftdmchan->span->set_channel_sig_status(ftdmchan, sigstatus); + ftdm_channel_unlock(ftdmchan); + return res; } else { ftdm_log(FTDM_LOG_ERROR, "set_channel_sig_status method not implemented!\n"); return FTDM_FAIL; @@ -2476,7 +2558,11 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_get_sig_status(ftdm_channel_t *ftdmchan, ftdm_assert_return(sigstatus != NULL, FTDM_FAIL, "Null sig status parameter\n"); if (ftdmchan->span->get_channel_sig_status) { - return ftdmchan->span->get_channel_sig_status(ftdmchan, sigstatus); + ftdm_status_t res; + ftdm_channel_lock(ftdmchan); + res = ftdmchan->span->get_channel_sig_status(ftdmchan, sigstatus); + ftdm_channel_unlock(ftdmchan); + return res; } else { /* don't log error here, it can be called just to test if its supported */ return FTDM_NOTIMPL; @@ -2487,6 +2573,11 @@ FT_DECLARE(ftdm_status_t) ftdm_span_set_sig_status(ftdm_span_t *span, ftdm_signa { ftdm_assert_return(span != NULL, FTDM_FAIL, "Null span\n"); + if (sigstatus == FTDM_SIG_STATE_DOWN) { + ftdm_log(FTDM_LOG_WARNING, "The user is not allowed to set the signaling status to DOWN, valid states are UP or SUSPENDED\n"); + return FTDM_FAIL; + } + if (span->set_span_sig_status) { return span->set_span_sig_status(span, sigstatus); } else { @@ -2507,15 +2598,13 @@ FT_DECLARE(ftdm_status_t) ftdm_span_get_sig_status(ftdm_span_t *span, ftdm_signa } } -static ftdm_status_t ftdm_channel_clear_vars(ftdm_channel_t *ftdmchan); -FT_DECLARE(ftdm_status_t) ftdm_channel_done(ftdm_channel_t *ftdmchan) +static ftdm_status_t ftdm_channel_done(ftdm_channel_t *ftdmchan) { ftdm_assert_return(ftdmchan != NULL, FTDM_FAIL, "Null channel can't be done!\n"); - ftdm_mutex_lock(ftdmchan->mutex); - - memset(&ftdmchan->caller_data, 0, sizeof(ftdmchan->caller_data)); - + ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_OPEN); + ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_DTMF_DETECT); + ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_SUPRESS_DTMF); ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_INUSE); ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND); ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_WINK); @@ -2547,7 +2636,7 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_done(ftdm_channel_t *ftdmchan) ftdm_channel_command(ftdmchan, FTDM_COMMAND_DISABLE_INPUT_DUMP, NULL); ftdm_channel_command(ftdmchan, FTDM_COMMAND_DISABLE_OUTPUT_DUMP, NULL); - if (FTDM_IS_VOICE_CHANNEL(ftdmchan)) { + if (FTDM_IS_VOICE_CHANNEL(ftdmchan) && ftdm_test_flag(ftdmchan, FTDM_CHANNEL_CALL_STARTED)) { ftdm_sigmsg_t sigmsg; memset(&sigmsg, 0, sizeof(sigmsg)); sigmsg.span_id = ftdmchan->span_id; @@ -2555,18 +2644,49 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_done(ftdm_channel_t *ftdmchan) sigmsg.channel = ftdmchan; sigmsg.event_id = FTDM_SIGEVENT_RELEASED; ftdm_span_send_signal(ftdmchan->span, &sigmsg); + ftdm_call_clear_call_id(&ftdmchan->caller_data); + ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_CALL_STARTED); } if (ftdmchan->txdrops || ftdmchan->rxdrops) { - ftdm_log_chan(ftdmchan, FTDM_LOG_WARNING, "channel dropped data: txdrops = %d, rxdrops = %d\n", + ftdm_log_chan(ftdmchan, FTDM_LOG_WARNING, "channel dropped data: txdrops = %d, rxdrops = %d\n", ftdmchan->txdrops, ftdmchan->rxdrops); } + + memset(&ftdmchan->caller_data, 0, sizeof(ftdmchan->caller_data)); + ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_HOLD); + + memset(ftdmchan->tokens, 0, sizeof(ftdmchan->tokens)); + ftdmchan->token_count = 0; + + ftdm_channel_flush_dtmf(ftdmchan); + + if (ftdmchan->gen_dtmf_buffer) { + ftdm_buffer_zero(ftdmchan->gen_dtmf_buffer); + } + + if (ftdmchan->digit_buffer) { + ftdm_buffer_zero(ftdmchan->digit_buffer); + } + + if (!ftdmchan->dtmf_on) { + ftdmchan->dtmf_on = FTDM_DEFAULT_DTMF_ON; + } + + if (!ftdmchan->dtmf_off) { + ftdmchan->dtmf_off = FTDM_DEFAULT_DTMF_OFF; + } + + memset(ftdmchan->dtmf_hangup_buf, '\0', ftdmchan->span->dtmf_hangup_len); + + if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_TRANSCODE)) { + ftdmchan->effective_codec = ftdmchan->native_codec; + ftdmchan->packet_len = ftdmchan->native_interval * (ftdmchan->effective_codec == FTDM_CODEC_SLIN ? 16 : 8); + ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_TRANSCODE); + } ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "channel done\n"); - - ftdm_mutex_unlock(ftdmchan->mutex); - return FTDM_SUCCESS; } @@ -2596,8 +2716,7 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_close(ftdm_channel_t **ftdmchan) if (ftdm_test_flag(check, FTDM_CHANNEL_OPEN)) { status = check->fio->close(check); if (status == FTDM_SUCCESS) { - ftdm_clear_flag(check, FTDM_CHANNEL_INUSE); - ftdm_channel_reset(check); + ftdm_channel_done(check); *ftdmchan = NULL; } } else { @@ -2661,7 +2780,8 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_command(ftdm_channel_t *ftdmchan, ftdm_co snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "%s", strerror(errno)); GOTO_STATUS(done, FTDM_FAIL); } - ftdm_set_flag_locked(ftdmchan, FTDM_CHANNEL_CALLERID_DETECT); + ftdm_set_flag(ftdmchan, FTDM_CHANNEL_CALLERID_DETECT); + GOTO_STATUS(done, FTDM_SUCCESS); } } break; @@ -2669,7 +2789,8 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_command(ftdm_channel_t *ftdmchan, ftdm_co { if (!ftdm_channel_test_feature(ftdmchan, FTDM_CHANNEL_FEATURE_CALLERID)) { ftdm_fsk_demod_destroy(&ftdmchan->fsk); - ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_CALLERID_DETECT); + ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_CALLERID_DETECT); + GOTO_STATUS(done, FTDM_SUCCESS); } } break; @@ -2680,7 +2801,8 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_command(ftdm_channel_t *ftdmchan, ftdm_co close(ftdmchan->fds[FTDM_READ_TRACE_INDEX]); ftdmchan->fds[FTDM_READ_TRACE_INDEX] = -1; } - if ((ftdmchan->fds[FTDM_READ_TRACE_INDEX] = open(path, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR)) > -1) { + if ((ftdmchan->fds[FTDM_READ_TRACE_INDEX] = open(path, O_WRONLY | O_CREAT | O_TRUNC + | FTDM_O_BINARY, S_IRUSR | S_IWUSR)) > -1) { ftdm_log(FTDM_LOG_DEBUG, "Tracing channel %u:%u input to [%s]\n", ftdmchan->span_id, ftdmchan->chan_id, path); GOTO_STATUS(done, FTDM_SUCCESS); } @@ -2696,7 +2818,8 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_command(ftdm_channel_t *ftdmchan, ftdm_co close(ftdmchan->fds[FTDM_WRITE_TRACE_INDEX]); ftdmchan->fds[FTDM_WRITE_TRACE_INDEX] = -1; } - if ((ftdmchan->fds[FTDM_WRITE_TRACE_INDEX] = open(path, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR)) > -1) { + if ((ftdmchan->fds[FTDM_WRITE_TRACE_INDEX] = open(path, O_WRONLY | O_CREAT | O_TRUNC + | FTDM_O_BINARY, S_IRUSR | S_IWUSR)) > -1) { ftdm_log(FTDM_LOG_DEBUG, "Tracing channel %u:%u output to [%s]\n", ftdmchan->span_id, ftdmchan->chan_id, path); GOTO_STATUS(done, FTDM_SUCCESS); } @@ -2764,10 +2887,10 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_command(ftdm_channel_t *ftdmchan, ftdm_co GOTO_STATUS(done, FTDM_FAIL); } if (start_chan_io_dump(ftdmchan, &ftdmchan->rxdump, size) != FTDM_SUCCESS) { - ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Failed to enable input dump of size %zd\n", size); + ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Failed to enable input dump of size %"FTDM_SIZE_FMT"\n", size); GOTO_STATUS(done, FTDM_FAIL); } - ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Enabled input dump with size %zd\n", size); + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Enabled input dump with size %"FTDM_SIZE_FMT"\n", size); GOTO_STATUS(done, FTDM_SUCCESS); } break; @@ -2779,7 +2902,8 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_command(ftdm_channel_t *ftdmchan, ftdm_co ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "No need to disable input dump\n"); GOTO_STATUS(done, FTDM_SUCCESS); } - ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Disabled input dump of size %zd\n", ftdmchan->rxdump.size); + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Disabled input dump of size %"FTDM_SIZE_FMT"\n", + ftdmchan->rxdump.size); stop_chan_io_dump(&ftdmchan->rxdump); GOTO_STATUS(done, FTDM_SUCCESS); } @@ -2797,7 +2921,7 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_command(ftdm_channel_t *ftdmchan, ftdm_co ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Failed to enable output dump of size %d\n", size); GOTO_STATUS(done, FTDM_FAIL); } - ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Enabled output dump with size %zd\n", size); + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Enabled output dump with size %"FTDM_SIZE_FMT"\n", size); GOTO_STATUS(done, FTDM_SUCCESS); } break; @@ -2809,7 +2933,7 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_command(ftdm_channel_t *ftdmchan, ftdm_co ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "No need to disable output dump\n"); GOTO_STATUS(done, FTDM_SUCCESS); } - ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Disabled output dump of size %zd\n", ftdmchan->rxdump.size); + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Disabled output dump of size %"FTDM_SIZE_FMT"\n", ftdmchan->rxdump.size); stop_chan_io_dump(&ftdmchan->txdump); GOTO_STATUS(done, FTDM_SUCCESS); } @@ -2821,6 +2945,10 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_command(ftdm_channel_t *ftdmchan, ftdm_co if (!obj) { GOTO_STATUS(done, FTDM_FAIL); } + if (!ftdmchan->rxdump.buffer) { + ftdm_log_chan(ftdmchan, FTDM_LOG_WARNING, "Not dumped input to file %p, input dump is not enabled\n", obj); + GOTO_STATUS(done, FTDM_FAIL); + } dump_chan_io_to_file(ftdmchan, &ftdmchan->rxdump, obj); ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Dumped input of size %d to file %p\n", ftdmchan->rxdump.size, obj); GOTO_STATUS(done, FTDM_SUCCESS); @@ -2833,8 +2961,12 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_command(ftdm_channel_t *ftdmchan, ftdm_co if (!obj) { GOTO_STATUS(done, FTDM_FAIL); } + if (!ftdmchan->txdump.buffer) { + ftdm_log_chan(ftdmchan, FTDM_LOG_WARNING, "Not dumped output to file %p, output dump is not enabled\n", obj); + GOTO_STATUS(done, FTDM_FAIL); + } dump_chan_io_to_file(ftdmchan, &ftdmchan->txdump, obj); - ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Dumped input of size %zd to file %p\n", ftdmchan->txdump.size, obj); + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Dumped input of size %"FTDM_SIZE_FMT" to file %p\n", ftdmchan->txdump.size, obj); GOTO_STATUS(done, FTDM_SUCCESS); } break; @@ -2921,7 +3053,7 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_command(ftdm_channel_t *ftdmchan, ftdm_co case FTDM_COMMAND_DISABLE_PROGRESS_DETECT: { if (!ftdm_channel_test_feature(ftdmchan, FTDM_CHANNEL_FEATURE_PROGRESS)) { - ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_PROGRESS_DETECT); + ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_PROGRESS_DETECT); ftdm_channel_clear_detected_tones(ftdmchan); ftdm_channel_clear_needed_tones(ftdmchan); GOTO_STATUS(done, FTDM_SUCCESS); @@ -2933,8 +3065,8 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_command(ftdm_channel_t *ftdmchan, ftdm_co /* if they don't have thier own, use ours */ if (!ftdm_channel_test_feature(ftdmchan, FTDM_CHANNEL_FEATURE_DTMF_DETECT)) { teletone_dtmf_detect_init (&ftdmchan->dtmf_detect, ftdmchan->rate); - ftdm_set_flag_locked(ftdmchan, FTDM_CHANNEL_DTMF_DETECT); - ftdm_set_flag_locked(ftdmchan, FTDM_CHANNEL_SUPRESS_DTMF); + ftdm_set_flag(ftdmchan, FTDM_CHANNEL_DTMF_DETECT); + ftdm_set_flag(ftdmchan, FTDM_CHANNEL_SUPRESS_DTMF); ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Enabled software DTMF detector\n"); GOTO_STATUS(done, FTDM_SUCCESS); } @@ -3333,7 +3465,7 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_queue_dtmf(ftdm_channel_t *ftdmchan, cons ftdmchan->span_id, ftdmchan->chan_id, currtime.tm_year-100, currtime.tm_mon+1, currtime.tm_mday, currtime.tm_hour, currtime.tm_min, currtime.tm_sec, ftdmchan->native_codec == FTDM_CODEC_ULAW ? "ulaw" : ftdmchan->native_codec == FTDM_CODEC_ALAW ? "alaw" : "sln"); - ftdmchan->dtmfdbg.file = fopen(dfile, "w"); + ftdmchan->dtmfdbg.file = fopen(dfile, "wb"); if (!ftdmchan->dtmfdbg.file) { ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "failed to open debug dtmf file %s\n", dfile); } else { @@ -3403,7 +3535,7 @@ static FIO_WRITE_FUNCTION(ftdm_raw_write) } if (ftdmchan->fds[FTDM_WRITE_TRACE_INDEX] > -1) { if ((write(ftdmchan->fds[FTDM_WRITE_TRACE_INDEX], data, dlen)) != dlen) { - ftdm_log(FTDM_LOG_WARNING, "Raw output trace failed to write all of the %zd bytes\n", dlen); + ftdm_log(FTDM_LOG_WARNING, "Raw output trace failed to write all of the %"FTDM_SIZE_FMT" bytes\n", dlen); } } write_chan_io_dump(&ftdmchan->txdump, data, dlen); @@ -3415,8 +3547,8 @@ static FIO_READ_FUNCTION(ftdm_raw_read) ftdm_status_t status = ftdmchan->fio->read(ftdmchan, data, datalen); if (status == FTDM_SUCCESS && ftdmchan->fds[FTDM_READ_TRACE_INDEX] > -1) { ftdm_size_t dlen = *datalen; - if ((ftdm_size_t)write(ftdmchan->fds[FTDM_READ_TRACE_INDEX], data, dlen) != dlen) { - ftdm_log(FTDM_LOG_WARNING, "Raw input trace failed to write all of the %zd bytes\n", dlen); + if ((ftdm_size_t)write(ftdmchan->fds[FTDM_READ_TRACE_INDEX], data, (int)dlen) != dlen) { + ftdm_log(FTDM_LOG_WARNING, "Raw input trace failed to write all of the %"FTDM_SIZE_FMT" bytes\n", dlen); } } @@ -3428,7 +3560,7 @@ static FIO_READ_FUNCTION(ftdm_raw_read) ftdm_size_t dlen = *datalen; ftdm_size_t rc = 0; - write_chan_io_dump(&ftdmchan->rxdump, data, dlen); + write_chan_io_dump(&ftdmchan->rxdump, data, (int)dlen); /* if dtmf debug is enabled and initialized, write there too */ if (ftdmchan->dtmfdbg.file) { @@ -3586,23 +3718,21 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_read(ftdm_channel_t *ftdmchan, void *data } status = ftdm_raw_read(ftdmchan, data, datalen); - if (status != FTDM_SUCCESS) { ftdm_log_chan_msg(ftdmchan, FTDM_LOG_WARNING, "raw I/O read filed\n"); + goto done; } - if (status == FTDM_SUCCESS) { - if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_USE_RX_GAIN) - && (ftdmchan->native_codec == FTDM_CODEC_ALAW || ftdmchan->native_codec == FTDM_CODEC_ULAW)) { - unsigned char *rdata = data; - for (i = 0; i < *datalen; i++) { - rdata[i] = ftdmchan->rxgain_table[rdata[i]]; - } + if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_USE_RX_GAIN) + && (ftdmchan->native_codec == FTDM_CODEC_ALAW || ftdmchan->native_codec == FTDM_CODEC_ULAW)) { + unsigned char *rdata = data; + for (i = 0; i < *datalen; i++) { + rdata[i] = ftdmchan->rxgain_table[rdata[i]]; } - handle_dtmf(ftdmchan, *datalen); } + handle_dtmf(ftdmchan, *datalen); - if (status == FTDM_SUCCESS && ftdm_test_flag(ftdmchan, FTDM_CHANNEL_TRANSCODE) && ftdmchan->effective_codec != ftdmchan->native_codec) { + if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_TRANSCODE) && ftdmchan->effective_codec != ftdmchan->native_codec) { if (ftdmchan->native_codec == FTDM_CODEC_ULAW && ftdmchan->effective_codec == FTDM_CODEC_SLIN) { codec_func = fio_ulaw2slin; } else if (ftdmchan->native_codec == FTDM_CODEC_ULAW && ftdmchan->effective_codec == FTDM_CODEC_ALAW) { @@ -3863,6 +3993,100 @@ done: return status; } +FT_DECLARE(void) ftdm_call_clear_data(ftdm_caller_data_t *caller_data) +{ + ftdm_call_clear_vars(caller_data); + memset(&caller_data->raw_data, 0, sizeof(caller_data->raw_data)); + caller_data->raw_data_len = 0; + return; +} + +FT_DECLARE(ftdm_status_t) ftdm_call_clear_vars(ftdm_caller_data_t *caller_data) +{ + if (caller_data->variables) { + hashtable_destroy(caller_data->variables); + } + caller_data->variables = NULL; + return FTDM_SUCCESS; +} + +FT_DECLARE(ftdm_status_t) ftdm_call_remove_var(ftdm_caller_data_t *caller_data, const char *var_name) +{ + if (caller_data->variables) { + hashtable_remove(caller_data->variables, (void *)var_name); + } + + return FTDM_SUCCESS; +} + + +FT_DECLARE(ftdm_status_t) ftdm_call_add_var(ftdm_caller_data_t *caller_data, const char *var_name, const char *value) +{ + char *t_name = 0, *t_val = 0; + + if (!var_name || !value) { + return FTDM_FAIL; + } + + if (!caller_data->variables) { + /* initialize on first use */ + caller_data->variables = create_hashtable(16, ftdm_hash_hashfromstring, ftdm_hash_equalkeys); + ftdm_assert_return(caller_data->variables, FTDM_FAIL, "Failed to create hash table\n"); + } + + t_name = ftdm_strdup(var_name); + t_val = ftdm_strdup(value); + hashtable_insert(caller_data->variables, t_name, t_val, HASHTABLE_FLAG_FREE_KEY | HASHTABLE_FLAG_FREE_VALUE); + return FTDM_SUCCESS; +} + +FT_DECLARE(const char *) ftdm_call_get_var(ftdm_caller_data_t *caller_data, const char *var_name) +{ + const char *var = NULL; + + if (!caller_data->variables || !var_name) { + return NULL; + } + + var = (const char *)hashtable_search(((struct hashtable*)caller_data->variables), (void *)var_name); + return var; +} + +FT_DECLARE(ftdm_iterator_t *) ftdm_call_get_var_iterator(const ftdm_caller_data_t *caller_data, ftdm_iterator_t *iter) +{ + ftdm_hash_iterator_t *hashiter = NULL; + hashiter = caller_data->variables == NULL ? NULL : hashtable_first(caller_data->variables); + + if (hashiter == NULL) { + return NULL; + } + + if (!(iter = get_iterator(FTDM_ITERATOR_VARS, iter))) { + return NULL; + } + iter->pvt.hashiter = hashiter; + return iter; +} + +FT_DECLARE(ftdm_status_t) ftdm_call_get_current_var(ftdm_iterator_t *iter, const char **var_name, const char **var_val) +{ + const void *key = NULL; + void *val = NULL; + + *var_name = NULL; + *var_val = NULL; + + ftdm_assert_return(iter && (iter->type == FTDM_ITERATOR_VARS) && iter->pvt.hashiter, FTDM_FAIL, "Cannot get variable from invalid iterator!\n"); + + hashtable_this(iter->pvt.hashiter, &key, NULL, &val); + + *var_name = key; + *var_val = val; + + return FTDM_SUCCESS; +} + + static ftdm_status_t ftdm_channel_clear_vars(ftdm_channel_t *ftdmchan) { ftdm_channel_lock(ftdmchan); @@ -3909,6 +4133,7 @@ done: return status; } + FT_DECLARE(const char *) ftdm_channel_get_var(ftdm_channel_t *ftdmchan, const char *var_name) { const char *var = NULL; @@ -4073,7 +4298,7 @@ static struct { ftdm_io_interface_t *pika_interface; } interfaces; -static void print_channels_by_flag(ftdm_stream_handle_t *stream, uint32_t flag, int not, int *count) +static void print_channels_by_flag(ftdm_stream_handle_t *stream, int32_t flagval, int not, int *count) { ftdm_hash_iterator_t *i = NULL; ftdm_span_t *span; @@ -4082,6 +4307,7 @@ static void print_channels_by_flag(ftdm_stream_handle_t *stream, uint32_t flag, ftdm_iterator_t *curr = NULL; const void *key = NULL; void *val = NULL; + uint32_t flag = (1 << flagval); *count = 0; @@ -4103,13 +4329,13 @@ static void print_channels_by_flag(ftdm_stream_handle_t *stream, uint32_t flag, stream->write_function(stream, "[s%dc%d][%d:%d] has not flag %d\n", fchan->span_id, fchan->chan_id, fchan->physical_span_id, fchan->physical_chan_id, - flag); + flagval); (*count)++; } else if (!not && ftdm_test_flag(fchan, flag)) { stream->write_function(stream, "[s%dc%d][%d:%d] has flag %d\n", fchan->span_id, fchan->chan_id, fchan->physical_span_id, fchan->physical_chan_id, - flag); + flagval); (*count)++; } } @@ -4219,7 +4445,7 @@ static char *handle_core_command(const char *cmd) } flagval = atoi(flag); print_channels_by_flag(&stream, flagval, not, &count); - stream.write_function(&stream, "\nTotal channels %s %s: %d\n", not ? "without flag" : "with flag", flagval, count); + stream.write_function(&stream, "\nTotal channels %s %d: %d\n", not ? "without flag" : "with flag", flagval, count); } else { stream.write_function(&stream, "invalid core command %s\n", argv[0]); } @@ -4561,7 +4787,7 @@ static ftdm_status_t load_config(void) len = strlen(val); if (len >= FTDM_MAX_NAME_STR_SZ) { len = FTDM_MAX_NAME_STR_SZ - 1; - ftdm_log(FTDM_LOG_WARNING, "Truncating group name %s to %zd length\n", val, len); + ftdm_log(FTDM_LOG_WARNING, "Truncating group name %s to %"FTDM_SIZE_FMT" length\n", val, len); } memcpy(chan_config.group_name, val, len); chan_config.group_name[len] = '\0'; @@ -5111,7 +5337,6 @@ static void ftdm_group_add(ftdm_group_t *group) ftdm_mutex_unlock(globals.group_mutex); } - FT_DECLARE(ftdm_status_t) ftdm_group_create(ftdm_group_t **group, const char *name) { ftdm_group_t *new_group = NULL; @@ -5141,15 +5366,22 @@ FT_DECLARE(ftdm_status_t) ftdm_group_create(ftdm_group_t **group, const char *na static ftdm_status_t ftdm_span_trigger_signal(const ftdm_span_t *span, ftdm_sigmsg_t *sigmsg) { - return span->signal_cb(sigmsg); + ftdm_status_t status = span->signal_cb(sigmsg); + if (sigmsg->channel) { + ftdm_call_clear_data(&(sigmsg->channel->caller_data)); + } + if (sigmsg->raw.autofree) { + ftdm_safe_free(sigmsg->raw.data); + sigmsg->raw.data = NULL; + sigmsg->raw.len = 0; + } + return status; } static ftdm_status_t ftdm_span_queue_signal(const ftdm_span_t *span, ftdm_sigmsg_t *sigmsg) { ftdm_sigmsg_t *new_sigmsg = NULL; - ftdm_assert_return((sigmsg->raw_data == NULL), FTDM_FAIL, "No raw data should be used with asynchronous notification\n"); - new_sigmsg = ftdm_calloc(1, sizeof(*sigmsg)); if (!new_sigmsg) { return FTDM_FAIL; @@ -5188,7 +5420,7 @@ static void execute_safety_hangup(void *data) FT_DECLARE(ftdm_status_t) ftdm_span_send_signal(ftdm_span_t *span, ftdm_sigmsg_t *sigmsg) { if (sigmsg->channel) { - ftdm_mutex_lock(sigmsg->channel->mutex); + ftdm_mutex_lock(sigmsg->channel->mutex); } /* some core things to do on special events */ @@ -5196,8 +5428,7 @@ FT_DECLARE(ftdm_status_t) ftdm_span_send_signal(ftdm_span_t *span, ftdm_sigmsg_t case FTDM_SIGEVENT_SIGSTATUS_CHANGED: { - ftdm_signaling_status_t sigstatus = ftdm_test_flag(span, FTDM_SPAN_USE_SIGNALS_QUEUE) ? sigmsg->sigstatus : *((ftdm_signaling_status_t*)(sigmsg->raw_data)); - if (sigstatus == FTDM_SIG_STATE_UP) { + if (sigmsg->ev_data.sigstatus.status == FTDM_SIG_STATE_UP) { ftdm_set_flag(sigmsg->channel, FTDM_CHANNEL_SIG_UP); } else { ftdm_clear_flag(sigmsg->channel, FTDM_CHANNEL_SIG_UP); @@ -5207,6 +5438,8 @@ FT_DECLARE(ftdm_status_t) ftdm_span_send_signal(ftdm_span_t *span, ftdm_sigmsg_t case FTDM_SIGEVENT_START: { + ftdm_set_flag(sigmsg->channel, FTDM_CHANNEL_CALL_STARTED); + ftdm_call_set_call_id(&sigmsg->channel->caller_data); ftdm_set_echocancel_call_begin(sigmsg->channel); if (sigmsg->channel->dtmfdbg.requested) { ftdm_channel_command(sigmsg->channel, FTDM_COMMAND_ENABLE_DEBUG_DTMF, NULL); @@ -5221,6 +5454,11 @@ FT_DECLARE(ftdm_status_t) ftdm_span_send_signal(ftdm_span_t *span, ftdm_sigmsg_t break; case FTDM_SIGEVENT_STOP: + if (!ftdm_test_flag(sigmsg->channel, FTDM_CHANNEL_CALL_STARTED)) { + /* this happens for FXS devices which blindly send SIGEVENT_STOP, we should fix it there ... */ + ftdm_log_chan_msg(sigmsg->channel, FTDM_LOG_DEBUG, "Ignoring SIGEVENT_STOP since user never knew about a call in this channel\n"); + goto done; + } if (ftdm_test_flag(sigmsg->channel, FTDM_CHANNEL_USER_HANGUP)) { ftdm_log_chan_msg(sigmsg->channel, FTDM_LOG_DEBUG, "Ignoring SIGEVENT_STOP since user already requested hangup\n"); goto done; @@ -5236,7 +5474,10 @@ FT_DECLARE(ftdm_status_t) ftdm_span_send_signal(ftdm_span_t *span, ftdm_sigmsg_t break; } - + + if (sigmsg->channel) { + sigmsg->call_id = sigmsg->channel->caller_data.call_id; + } /* if the signaling module uses a queue for signaling notifications, then enqueue it */ if (ftdm_test_flag(span, FTDM_SPAN_USE_SIGNALS_QUEUE)) { ftdm_span_queue_signal(span, sigmsg); @@ -5245,6 +5486,7 @@ FT_DECLARE(ftdm_status_t) ftdm_span_send_signal(ftdm_span_t *span, ftdm_sigmsg_t } done: + if (sigmsg->channel) { ftdm_mutex_unlock(sigmsg->channel->mutex); } @@ -5344,6 +5586,8 @@ FT_DECLARE(ftdm_status_t) ftdm_global_init(void) ftdm_mutex_create(&globals.mutex); ftdm_mutex_create(&globals.span_mutex); ftdm_mutex_create(&globals.group_mutex); + ftdm_mutex_create(&globals.call_id_mutex); + ftdm_sched_global_init(); if (ftdm_sched_create(&globals.timingsched, "freetdm-master") != FTDM_SUCCESS) { ftdm_log(FTDM_LOG_CRIT, "Failed to create master timing schedule context\n"); @@ -5353,6 +5597,7 @@ FT_DECLARE(ftdm_status_t) ftdm_global_init(void) ftdm_log(FTDM_LOG_CRIT, "Failed to run master timing schedule context\n"); return FTDM_FAIL; } + globals.running = 1; return FTDM_SUCCESS; } @@ -5456,6 +5701,7 @@ FT_DECLARE(ftdm_status_t) ftdm_global_destroy(void) ftdm_mutex_destroy(&globals.mutex); ftdm_mutex_destroy(&globals.span_mutex); ftdm_mutex_destroy(&globals.group_mutex); + ftdm_mutex_destroy(&globals.call_id_mutex); memset(&globals, 0, sizeof(globals)); return FTDM_SUCCESS; @@ -5778,12 +6024,34 @@ FT_DECLARE(char *) ftdm_strndup(const char *str, ftdm_size_t inlen) return new; } -FT_DECLARE(char *) ftdm_channel_get_history_str(const ftdm_channel_t *fchan) + +static void write_history_entry(const ftdm_channel_t *fchan, ftdm_stream_handle_t *stream, int i, ftdm_time_t *prevtime) { char func[255]; char line[255]; char states[255]; + const char *filename = NULL; + snprintf(states, sizeof(states), "%-5.15s => %-5.15s", ftdm_channel_state2str(fchan->history[i].last_state), ftdm_channel_state2str(fchan->history[i].state)); + snprintf(func, sizeof(func), "[%s]", fchan->history[i].func); + filename = strrchr(fchan->history[i].file, *FTDM_PATH_SEPARATOR); + if (!filename) { + filename = fchan->history[i].file; + } else { + filename++; + } + if (!(*prevtime)) { + *prevtime = fchan->history[i].time; + } + snprintf(line, sizeof(func), "[%s:%d]", filename, fchan->history[i].line); + stream->write_function(stream, "%-30.30s %-30.30s %-30.30s %lums\n", states, func, line, (fchan->history[i].time - *prevtime)); + *prevtime = fchan->history[i].time; +} + +FT_DECLARE(char *) ftdm_channel_get_history_str(const ftdm_channel_t *fchan) +{ uint8_t i = 0; + ftdm_time_t currtime = 0; + ftdm_time_t prevtime = 0; ftdm_stream_handle_t stream = { 0 }; FTDM_STANDARD_STREAM(stream); @@ -5792,28 +6060,76 @@ FT_DECLARE(char *) ftdm_channel_get_history_str(const ftdm_channel_t *fchan) return stream.data; } - stream.write_function(&stream, "%-30.30s %-30.30s %s", "-- States --", "-- Function --", "-- Location --\n"); + stream.write_function(&stream, "%-30.30s %-30.30s %-30.30s %s", + "-- States --", "-- Function --", "-- Location --", "-- Time Offset --\n"); for (i = fchan->hindex; i < ftdm_array_len(fchan->history); i++) { if (!fchan->history[i].file) { break; } - snprintf(states, sizeof(states), "%-5.15s => %-5.15s", ftdm_channel_state2str(fchan->history[i].last_state), ftdm_channel_state2str(fchan->history[i].state)); - snprintf(func, sizeof(func), "[%s]", fchan->history[i].func); - snprintf(line, sizeof(func), "[%s:%d]", fchan->history[i].file, fchan->history[i].line); - stream.write_function(&stream, "%-30.30s %-30.30s %s\n", states, func, line); + write_history_entry(fchan, &stream, i, &prevtime); } for (i = 0; i < fchan->hindex; i++) { - snprintf(states, sizeof(states), "%-5.15s => %-5.15s", ftdm_channel_state2str(fchan->history[i].last_state), ftdm_channel_state2str(fchan->history[i].state)); - snprintf(func, sizeof(func), "[%s]", fchan->history[i].func); - snprintf(line, sizeof(func), "[%s:%d]", fchan->history[i].file, fchan->history[i].line); - stream.write_function(&stream, "%-30.30s %-30.30s %s\n", states, func, line); + write_history_entry(fchan, &stream, i, &prevtime); } + currtime = ftdm_current_time_in_ms(); + + stream.write_function(&stream, "\nTime since last state change: %lums\n", (currtime - prevtime)); + return stream.data; } +static ftdm_status_t ftdm_call_set_call_id(ftdm_caller_data_t *caller_data) +{ + uint32_t current_call_id; + ftdm_assert_return(!caller_data->call_id, FTDM_FAIL, "Overwriting non-cleared call-id"); + + ftdm_mutex_lock(globals.call_id_mutex); + current_call_id = globals.last_call_id; + + do { + if (++current_call_id > MAX_CALLIDS) { + current_call_id = 1; + } + if (globals.call_ids[current_call_id] != NULL) { + continue; + } + } while (0); + + globals.last_call_id = current_call_id; + caller_data->call_id = current_call_id; + + globals.call_ids[current_call_id] = caller_data; + ftdm_mutex_unlock(globals.call_id_mutex); + return FTDM_SUCCESS; +} + +static ftdm_status_t ftdm_call_clear_call_id(ftdm_caller_data_t *caller_data) +{ + if (caller_data->call_id) { + ftdm_assert_return((caller_data->call_id <= MAX_CALLIDS), FTDM_FAIL, "Cannot clear call with invalid call-id\n"); + } else { + /* there might not be a call at all */ + return FTDM_SUCCESS; + } + + ftdm_mutex_lock(globals.call_id_mutex); + if (globals.call_ids[caller_data->call_id]) { + ftdm_log(FTDM_LOG_DEBUG, "Cleared call with id %u\n", caller_data->call_id); + caller_data->call_id = 0; + globals.call_ids[caller_data->call_id] = NULL; + } else { + ftdm_log(FTDM_LOG_CRIT, "call-id did not exist %u\n", caller_data->call_id); + } + ftdm_mutex_unlock(globals.call_id_mutex); + + return FTDM_SUCCESS; +} + + + /* For Emacs: * Local Variables: diff --git a/libs/freetdm/src/ftdm_m3ua.c b/libs/freetdm/src/ftdm_m3ua.c index 1a6fe362e7..8d3e00213a 100644 --- a/libs/freetdm/src/ftdm_m3ua.c +++ b/libs/freetdm/src/ftdm_m3ua.c @@ -156,7 +156,7 @@ static __inline__ void state_advance(ftdm_channel_t *ftdmchan) release_request_id((m3ua_request_id_t)ftdmchan->extra_id); ftdmchan->extra_id = 0; } - ftdm_channel_done(ftdmchan); + ftdm_channel_close(&ftdmchan); } break; case FTDM_CHANNEL_STATE_PROGRESS_MEDIA: diff --git a/libs/freetdm/src/ftmod/ftmod_analog/ftmod_analog.c b/libs/freetdm/src/ftmod/ftmod_analog/ftmod_analog.c index 95002e3e70..0acf70b18d 100644 --- a/libs/freetdm/src/ftmod/ftmod_analog/ftmod_analog.c +++ b/libs/freetdm/src/ftmod/ftmod_analog/ftmod_analog.c @@ -96,6 +96,10 @@ static FIO_CHANNEL_OUTGOING_CALL_FUNCTION(analog_fxs_outgoing_call) static FIO_CHANNEL_GET_SIG_STATUS_FUNCTION(analog_get_channel_sig_status) { + if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_IN_ALARM)) { + *status = FTDM_SIG_STATE_DOWN; + return FTDM_SUCCESS; + } *status = FTDM_SIG_STATE_UP; return FTDM_SUCCESS; } @@ -109,7 +113,25 @@ static FIO_CHANNEL_GET_SIG_STATUS_FUNCTION(analog_get_channel_sig_status) static FIO_SPAN_GET_SIG_STATUS_FUNCTION(analog_get_span_sig_status) { - *status = FTDM_SIG_STATE_UP; + ftdm_iterator_t *citer = NULL; + ftdm_iterator_t *chaniter = ftdm_span_get_chan_iterator(span, NULL); + if (!chaniter) { + ftdm_log(FTDM_LOG_CRIT, "Failed to allocate channel iterator for span %s!\n", span->name); + return FTDM_FAIL; + } + /* if ALL channels are in alarm, report DOWN, UP otherwise. */ + *status = FTDM_SIG_STATE_DOWN; + for (citer = chaniter; citer; citer = ftdm_iterator_next(citer)) { + ftdm_channel_t *fchan = ftdm_iterator_current(citer); + ftdm_channel_lock(fchan); + if (!ftdm_test_flag(fchan, FTDM_CHANNEL_IN_ALARM)) { + *status = FTDM_SIG_STATE_UP; + ftdm_channel_unlock(fchan); + break; + } + ftdm_channel_unlock(fchan); + } + ftdm_iterator_free(chaniter); return FTDM_SUCCESS; } @@ -491,9 +513,12 @@ static void *ftdm_analog_channel_run(ftdm_thread_t *me, void *obj) ftdm_channel_command(ftdmchan, FTDM_COMMAND_GENERATE_RING_OFF, NULL); } - if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OFFHOOK) && - (ftdmchan->last_state == FTDM_CHANNEL_STATE_RINGING || ftdmchan->last_state == FTDM_CHANNEL_STATE_DIALTONE - || ftdmchan->last_state >= FTDM_CHANNEL_STATE_RING)) { + if (ftdmchan->type == FTDM_CHAN_TYPE_FXS && + ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OFFHOOK) && + (ftdmchan->last_state == FTDM_CHANNEL_STATE_RINGING + || ftdmchan->last_state == FTDM_CHANNEL_STATE_DIALTONE + || ftdmchan->last_state == FTDM_CHANNEL_STATE_RING + || ftdmchan->last_state == FTDM_CHANNEL_STATE_UP)) { ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_BUSY); } else { ftdmchan->caller_data.hangup_cause = FTDM_CAUSE_NORMAL_CLEARING; @@ -716,7 +741,7 @@ static void *ftdm_analog_channel_run(ftdm_thread_t *me, void *obj) dtmf_offset = strlen(dtmf); last_digit = elapsed; sig.event_id = FTDM_SIGEVENT_COLLECTED_DIGIT; - sig.raw_data = dtmf; + ftdm_set_string(sig.ev_data.collected.digits, dtmf); if (ftdm_span_send_signal(ftdmchan->span, &sig) == FTDM_BREAK) { collecting = 0; } @@ -883,14 +908,14 @@ static __inline__ ftdm_status_t process_event(ftdm_span_t *span, ftdm_event_t *e { if (event->channel->type != FTDM_CHAN_TYPE_FXO) { ftdm_log_chan_msg(event->channel, FTDM_LOG_ERROR, "Cannot get a RING_START event on a non-fxo channel, please check your config.\n"); - ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_DOWN); + ftdm_set_state(event->channel, FTDM_CHANNEL_STATE_DOWN); goto end; } if (!event->channel->ring_count && (event->channel->state == FTDM_CHANNEL_STATE_DOWN && !ftdm_test_flag(event->channel, FTDM_CHANNEL_INTHREAD))) { if (ftdm_test_flag(analog_data, FTDM_ANALOG_CALLERID)) { - ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_GET_CALLERID); + ftdm_set_state(event->channel, FTDM_CHANNEL_STATE_GET_CALLERID); } else { - ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_RING); + ftdm_set_state(event->channel, FTDM_CHANNEL_STATE_RING); } event->channel->ring_count = 1; ftdm_mutex_unlock(event->channel->mutex); @@ -908,7 +933,12 @@ static __inline__ ftdm_status_t process_event(ftdm_span_t *span, ftdm_event_t *e } if (event->channel->state != FTDM_CHANNEL_STATE_DOWN) { - ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_DOWN); + if (event->channel->state == FTDM_CHANNEL_STATE_HANGUP && + ftdm_test_flag(event->channel, FTDM_CHANNEL_STATE_CHANGE)) { + ftdm_clear_flag(event->channel, FTDM_CHANNEL_STATE_CHANGE); + /* we do not need to process HANGUP since the device also hangup already */ + } + ftdm_set_state(event->channel, FTDM_CHANNEL_STATE_DOWN); } } @@ -916,16 +946,16 @@ static __inline__ ftdm_status_t process_event(ftdm_span_t *span, ftdm_event_t *e case FTDM_OOB_FLASH: { if (event->channel->state == FTDM_CHANNEL_STATE_CALLWAITING) { - ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_UP); - ftdm_clear_flag_locked(event->channel, FTDM_CHANNEL_STATE_CHANGE); - ftdm_clear_flag_locked(event->channel->span, FTDM_SPAN_STATE_CHANGE); + ftdm_set_state(event->channel, FTDM_CHANNEL_STATE_UP); + ftdm_clear_flag(event->channel, FTDM_CHANNEL_STATE_CHANGE); + ftdm_clear_flag(event->channel->span, FTDM_SPAN_STATE_CHANGE); event->channel->detected_tones[FTDM_TONEMAP_CALLWAITING_ACK] = 0; } ftdm_channel_rotate_tokens(event->channel); if (ftdm_test_flag(event->channel, FTDM_CHANNEL_HOLD) && event->channel->token_count != 1) { - ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_UP); + ftdm_set_state(event->channel, FTDM_CHANNEL_STATE_UP); } else { sig.event_id = FTDM_SIGEVENT_FLASH; ftdm_span_send_signal(span, &sig); @@ -939,12 +969,12 @@ static __inline__ ftdm_status_t process_event(ftdm_span_t *span, ftdm_event_t *e if (ftdm_test_flag(event->channel, FTDM_CHANNEL_RINGING)) { ftdm_channel_command(event->channel, FTDM_COMMAND_GENERATE_RING_OFF, NULL); } - ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_UP); + ftdm_set_state(event->channel, FTDM_CHANNEL_STATE_UP); } else { if(!analog_data->max_dialstr) { - ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_COLLECT); + ftdm_set_state(event->channel, FTDM_CHANNEL_STATE_COLLECT); } else { - ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_DIALTONE); + ftdm_set_state(event->channel, FTDM_CHANNEL_STATE_DIALTONE); } ftdm_mutex_unlock(event->channel->mutex); locked = 0; @@ -956,9 +986,24 @@ static __inline__ ftdm_status_t process_event(ftdm_span_t *span, ftdm_event_t *e ftdm_channel_command(event->channel, FTDM_COMMAND_ONHOOK, NULL); } } - ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_DOWN); + ftdm_set_state(event->channel, FTDM_CHANNEL_STATE_DOWN); } } + break; + case FTDM_OOB_ALARM_TRAP: + { + sig.event_id = FTDM_SIGEVENT_SIGSTATUS_CHANGED; + sig.ev_data.sigstatus.status = FTDM_SIG_STATE_DOWN; + ftdm_span_send_signal(span, &sig); + } + break; + case FTDM_OOB_ALARM_CLEAR: + { + sig.event_id = FTDM_SIGEVENT_SIGSTATUS_CHANGED; + sig.ev_data.sigstatus.status = FTDM_SIG_STATE_UP; + ftdm_span_send_signal(span, &sig); + } + break; default: { ftdm_log_chan(event->channel, FTDM_LOG_DEBUG, "Ignoring event [%s] in state [%s]\n", ftdm_oob_event2str(event->enum_id), ftdm_channel_state2str(event->channel->state)); 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 199bba43a3..843ac484a5 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 @@ -329,8 +329,8 @@ static void *ftdm_analog_em_channel_run(ftdm_thread_t *me, void *obj) { if (state_counter > 500) { if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OFFHOOK) && - (ftdmchan->last_state == FTDM_CHANNEL_STATE_RING || ftdmchan->last_state == FTDM_CHANNEL_STATE_DIALTONE - || ftdmchan->last_state >= FTDM_CHANNEL_STATE_IDLE)) { + (ftdmchan->last_state == FTDM_CHANNEL_STATE_RINGING || ftdmchan->last_state == FTDM_CHANNEL_STATE_DIALTONE + || ftdmchan->last_state == FTDM_CHANNEL_STATE_RING)) { ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_BUSY); } else { ftdmchan->caller_data.hangup_cause = FTDM_CAUSE_NORMAL_CLEARING; @@ -340,7 +340,7 @@ static void *ftdm_analog_em_channel_run(ftdm_thread_t *me, void *obj) } break; case FTDM_CHANNEL_STATE_UP: - case FTDM_CHANNEL_STATE_IDLE: + case FTDM_CHANNEL_STATE_RING: { ftdm_sleep(interval); continue; @@ -386,7 +386,7 @@ static void *ftdm_analog_em_channel_run(ftdm_thread_t *me, void *obj) ftdm_channel_use(ftdmchan); } break; - case FTDM_CHANNEL_STATE_IDLE: + case FTDM_CHANNEL_STATE_RING: { ftdm_channel_use(ftdmchan); @@ -421,7 +421,7 @@ static void *ftdm_analog_em_channel_run(ftdm_thread_t *me, void *obj) ftdm_channel_command(ftdmchan, FTDM_COMMAND_WINK, NULL); } break; - case FTDM_CHANNEL_STATE_RING: + case FTDM_CHANNEL_STATE_RINGING: { ftdm_buffer_zero(dt_buffer); teletone_run(&ts, ftdmchan->span->tone_map[FTDM_TONEMAP_RING]); @@ -467,7 +467,7 @@ static void *ftdm_analog_em_channel_run(ftdm_thread_t *me, void *obj) dtmf_offset = strlen(dtmf); last_digit = elapsed; sig.event_id = FTDM_SIGEVENT_COLLECTED_DIGIT; - sig.raw_data = dtmf; + ftdm_set_string(sig.ev_data.collected.digits, dtmf); if (ftdm_span_send_signal(ftdmchan->span, &sig) == FTDM_BREAK) { collecting = 0; } @@ -477,7 +477,7 @@ static void *ftdm_analog_em_channel_run(ftdm_thread_t *me, void *obj) if (last_digit && (!collecting || ((elapsed - last_digit > analog_data->digit_timeout) || strlen(dtmf) > analog_data->max_dialstr))) { ftdm_log(FTDM_LOG_DEBUG, "Number obtained [%s]\n", dtmf); - ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_IDLE); + ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_RING); last_digit = 0; collecting = 0; } diff --git a/libs/freetdm/src/ftmod/ftmod_isdn/ftmod_isdn.c b/libs/freetdm/src/ftmod/ftmod_isdn/ftmod_isdn.c index 6a8a4eb379..5b4ce7196a 100644 --- a/libs/freetdm/src/ftmod/ftmod_isdn/ftmod_isdn.c +++ b/libs/freetdm/src/ftmod/ftmod_isdn/ftmod_isdn.c @@ -1325,7 +1325,7 @@ static __inline__ void state_advance(ftdm_channel_t *ftdmchan) } Q931ReleaseCRV(&isdn_data->q931, gen->CRV); } - ftdm_channel_done(ftdmchan); + ftdm_channel_close(&ftdmchan); } break; case FTDM_CHANNEL_STATE_PROGRESS: diff --git a/libs/freetdm/src/ftmod/ftmod_libpri/ftmod_libpri.c b/libs/freetdm/src/ftmod/ftmod_libpri/ftmod_libpri.c index 68f0e9e5a4..1d3c76d2e2 100644 --- a/libs/freetdm/src/ftmod/ftmod_libpri/ftmod_libpri.c +++ b/libs/freetdm/src/ftmod/ftmod_libpri/ftmod_libpri.c @@ -515,23 +515,17 @@ static __inline__ void state_advance(ftdm_channel_t *chan) switch (ftdm_channel_get_state(chan)) { case FTDM_CHANNEL_STATE_DOWN: { + ftdm_channel_t *chtmp = chan; chan->call_data = NULL; - ftdm_channel_done(chan); - /* - * Close channel completely, BRI PTMP will thank us - */ - if (ftdm_test_flag(chan, FTDM_CHANNEL_OPEN)) { - ftdm_channel_t *chtmp = chan; - if (ftdm_channel_close(&chtmp) != FTDM_SUCCESS) { - ftdm_log(FTDM_LOG_WARNING, "-- Failed to close channel %d:%d\n", - ftdm_channel_get_span_id(chan), - ftdm_channel_get_id(chan)); - } else { - ftdm_log(FTDM_LOG_DEBUG, "-- Closed channel %d:%d\n", - ftdm_channel_get_span_id(chan), - ftdm_channel_get_id(chan)); - } + if (ftdm_channel_close(&chtmp) != FTDM_SUCCESS) { + ftdm_log(FTDM_LOG_WARNING, "-- Failed to close channel %d:%d\n", + ftdm_channel_get_span_id(chan), + ftdm_channel_get_id(chan)); + } else { + ftdm_log(FTDM_LOG_DEBUG, "-- Closed channel %d:%d\n", + ftdm_channel_get_span_id(chan), + ftdm_channel_get_id(chan)); } } break; @@ -1403,8 +1397,7 @@ static int on_dchan_up(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_ev sig.chan_id = ftdm_channel_get_id(chan); sig.channel = chan; sig.event_id = FTDM_SIGEVENT_SIGSTATUS_CHANGED; - sig.raw_data = &status; - + sig.ev_data.sigstatus.status = status; ftdm_span_send_signal(span, &sig); } } @@ -1440,7 +1433,7 @@ static int on_dchan_down(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_ sig.chan_id = ftdm_channel_get_id(chan); sig.channel = chan; sig.event_id = FTDM_SIGEVENT_SIGSTATUS_CHANGED; - sig.raw_data = &status; + sig.ev_data.sigstatus.status = status; ftdm_span_send_signal(span, &sig); } diff --git a/libs/freetdm/src/ftmod/ftmod_libpri/lpwrap_pri.c b/libs/freetdm/src/ftmod/ftmod_libpri/lpwrap_pri.c index de4fa2b232..bfb67e4c78 100644 --- a/libs/freetdm/src/ftmod/ftmod_libpri/lpwrap_pri.c +++ b/libs/freetdm/src/ftmod/ftmod_libpri/lpwrap_pri.c @@ -127,24 +127,24 @@ static int __pri_lpwrap_read(struct pri *pri, void *buf, int buflen) } else { ftdm_log(FTDM_LOG_CRIT, "span %d D-READ TIMEOUT\n", spri->span->span_id); } - - ftdm_clear_flag(spri, LPWRAP_PRI_READY); - return -1; + /* we cannot return -1, libpri seems to expect values >= 0 */ + return 0; } spri->errs = 0; res = (int)len; - memset(&((unsigned char*)buf)[res], 0, 2); - res += 2; - + if (res > 0) { + memset(&((unsigned char*)buf)[res], 0, 2); + res += 2; #ifdef IODEBUG - { - char bb[2048] = { 0 }; + { + char bb[2048] = { 0 }; - print_hex_bytes(buf, res - 2, bb, sizeof(bb)); - ftdm_log(FTDM_LOG_DEBUG, "READ %d\n", res - 2); - } + print_hex_bytes(buf, res - 2, bb, sizeof(bb)); + ftdm_log(FTDM_LOG_DEBUG, "READ %d\n", res - 2); + } #endif + } return res; } @@ -155,8 +155,8 @@ static int __pri_lpwrap_write(struct pri *pri, void *buf, int buflen) if (ftdm_channel_write(spri->dchan, buf, buflen, &len) != FTDM_SUCCESS) { ftdm_log(FTDM_LOG_CRIT, "span %d D-WRITE FAIL! [%s]\n", spri->span->span_id, spri->dchan->last_error); - ftdm_clear_flag(spri, LPWRAP_PRI_READY); - return -1; + /* we cannot return -1, libpri seems to expect values >= 0 */ + return 0; } #ifdef IODEBUG diff --git a/libs/freetdm/src/ftmod/ftmod_pritap/ftmod_pritap.c b/libs/freetdm/src/ftmod/ftmod_pritap/ftmod_pritap.c index 220a96515b..27fbe2139f 100644 --- a/libs/freetdm/src/ftmod/ftmod_pritap/ftmod_pritap.c +++ b/libs/freetdm/src/ftmod/ftmod_pritap/ftmod_pritap.c @@ -280,12 +280,12 @@ static __inline__ void state_advance(ftdm_channel_t *ftdmchan) switch (ftdmchan->state) { case FTDM_CHANNEL_STATE_DOWN: - { - ftdm_channel_done(ftdmchan); + { ftdmchan->call_data = NULL; + ftdm_channel_close(&ftdmchan); - ftdm_channel_done(peerchan); peerchan->call_data = NULL; + ftdm_channel_close(&peerchan); } break; diff --git a/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c b/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c index ab85d2b4d6..e3ae0cf4c5 100644 --- a/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c +++ b/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c @@ -29,6 +29,12 @@ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Contributors: + * + * Arnaldo Pereira + * Ricardo Barroetaveña + * */ #ifdef __linux__ @@ -44,16 +50,15 @@ #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 */ +/* when the user stops a span, we clear FTDM_R2_SPAN_STARTED, so that the signaling thread + * knows it must stop, and we wait for FTDM_R2_RUNNING to be clear, which tells us the + * signaling thread is done. */ /* FIXME: what about the calls that are already up-and-running? */ typedef enum { FTDM_R2_RUNNING = (1 << 0), + FTDM_R2_SPAN_STARTED = (1 << 1), } ftdm_r2_flag_t; /* private call information stored in ftdmchan->call_data void* ptr, @@ -250,7 +255,7 @@ static void ftdm_r2_set_chan_sig_status(ftdm_channel_t *ftdmchan, ftdm_signaling sig.span_id = ftdmchan->span_id; sig.channel = ftdmchan; sig.event_id = FTDM_SIGEVENT_SIGSTATUS_CHANGED; - sig.sigstatus = status; + sig.ev_data.sigstatus.status = status; if (ftdm_span_send_signal(ftdmchan->span, &sig) != FTDM_SUCCESS) { ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Failed to change channel status to %s\n", ftdm_signaling_status2str(status)); } @@ -372,11 +377,72 @@ static void ft_r2_answer_call(ftdm_channel_t *ftdmchan) R2CALL(ftdmchan)->answer_pending = 0; } +static __inline__ ftdm_calling_party_category_t ftdm_openr2_cpc_to_r2_ftdm_cpc(openr2_calling_party_category_t cpc) +{ + switch (cpc) { + case OR2_CALLING_PARTY_CATEGORY_UNKNOWN: + return FTDM_CPC_UNKNOWN; + + case OR2_CALLING_PARTY_CATEGORY_NATIONAL_SUBSCRIBER: + return FTDM_CPC_ORDINARY; + + case OR2_CALLING_PARTY_CATEGORY_NATIONAL_PRIORITY_SUBSCRIBER: + return FTDM_CPC_PRIORITY; + + case OR2_CALLING_PARTY_CATEGORY_INTERNATIONAL_SUBSCRIBER: + return FTDM_CPC_UNKNOWN; + + case OR2_CALLING_PARTY_CATEGORY_INTERNATIONAL_PRIORITY_SUBSCRIBER: + return FTDM_CPC_UNKNOWN; + + case OR2_CALLING_PARTY_CATEGORY_TEST_EQUIPMENT: + return FTDM_CPC_TEST; + + case OR2_CALLING_PARTY_CATEGORY_PAY_PHONE: + return FTDM_CPC_PAYPHONE; + + case OR2_CALLING_PARTY_CATEGORY_COLLECT_CALL: + return FTDM_CPC_OPERATOR; + } + return FTDM_CPC_INVALID; +} + +static __inline openr2_calling_party_category_t ftdm_r2_ftdm_cpc_to_openr2_cpc(ftdm_calling_party_category_t cpc) +{ + switch (cpc) { + case FTDM_CPC_UNKNOWN: + return OR2_CALLING_PARTY_CATEGORY_UNKNOWN; + + case FTDM_CPC_OPERATOR: + return OR2_CALLING_PARTY_CATEGORY_COLLECT_CALL; + + case FTDM_CPC_ORDINARY: + return OR2_CALLING_PARTY_CATEGORY_NATIONAL_SUBSCRIBER; + + case FTDM_CPC_PRIORITY: + return OR2_CALLING_PARTY_CATEGORY_NATIONAL_PRIORITY_SUBSCRIBER; + + case FTDM_CPC_DATA: + return OR2_CALLING_PARTY_CATEGORY_UNKNOWN; + + case FTDM_CPC_TEST: + return OR2_CALLING_PARTY_CATEGORY_TEST_EQUIPMENT; + + case FTDM_CPC_PAYPHONE: + return OR2_CALLING_PARTY_CATEGORY_PAY_PHONE; + + case FTDM_CPC_INVALID: + return OR2_CALLING_PARTY_CATEGORY_UNKNOWN; + } + return OR2_CALLING_PARTY_CATEGORY_UNKNOWN; +} + /* this function must be called with the chan mutex held! */ static FIO_CHANNEL_OUTGOING_CALL_FUNCTION(r2_outgoing_call) { openr2_call_status_t callstatus; ftdm_r2_data_t *r2data; + openr2_calling_party_category_t category = OR2_CALLING_PARTY_CATEGORY_NATIONAL_SUBSCRIBER; r2data = ftdmchan->span->signal_data; @@ -389,6 +455,12 @@ static FIO_CHANNEL_OUTGOING_CALL_FUNCTION(r2_outgoing_call) ft_r2_clean_call(ftdmchan->call_data); + if (ftdmchan->caller_data.cpc == FTDM_CPC_INVALID || ftdmchan->caller_data.cpc == FTDM_CPC_UNKNOWN) { + category = r2data->category; + } else { + category = ftdm_r2_ftdm_cpc_to_openr2_cpc(ftdmchan->caller_data.cpc); + } + /* start io dump */ if (r2data->mf_dump_size) { ftdm_channel_command(ftdmchan, FTDM_COMMAND_ENABLE_INPUT_DUMP, &r2data->mf_dump_size); @@ -396,9 +468,9 @@ static FIO_CHANNEL_OUTGOING_CALL_FUNCTION(r2_outgoing_call) } callstatus = openr2_chan_make_call(R2CALL(ftdmchan)->r2chan, - ftdmchan->caller_data.cid_num.digits, + ftdmchan->caller_data.pres == FTDM_PRES_ALLOWED ? ftdmchan->caller_data.cid_num.digits : NULL, ftdmchan->caller_data.dnis.digits, - r2data->category); + category); if (callstatus) { ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT, "Failed to make call in R2 channel, openr2_chan_make_call failed\n"); @@ -419,13 +491,14 @@ static FIO_CHANNEL_OUTGOING_CALL_FUNCTION(r2_outgoing_call) static ftdm_status_t ftdm_r2_start(ftdm_span_t *span) { ftdm_r2_data_t *r2_data = span->signal_data; - ftdm_set_flag(r2_data, FTDM_R2_RUNNING); + ftdm_set_flag(r2_data, FTDM_R2_SPAN_STARTED); 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; + ftdm_clear_flag(r2_data, FTDM_R2_SPAN_STARTED); 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); @@ -444,6 +517,95 @@ static FIO_CHANNEL_GET_SIG_STATUS_FUNCTION(ftdm_r2_get_channel_sig_status) return FTDM_SUCCESS; } +static FIO_CHANNEL_SET_SIG_STATUS_FUNCTION(ftdm_r2_set_channel_sig_status) +{ + openr2_chan_t *r2chan = R2CALL(ftdmchan)->r2chan; + openr2_cas_signal_t rxcas, txcas; + + /* get the current rx and tx cas bits */ + openr2_chan_get_cas(r2chan, &rxcas, &txcas); + + /* if we're already in the state the user asks us to be, we have nothing to do */ + if (status == FTDM_SIG_STATE_SUSPENDED && txcas == OR2_CAS_BLOCK) { + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Channel signaling status already in BLOCK state\n"); + return FTDM_SUCCESS; + } + if (status == FTDM_SIG_STATE_UP && txcas == OR2_CAS_IDLE) { + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Channel signaling status already in IDLE state\n"); + return FTDM_SUCCESS; + } + + /* set the signaling as requested and send SIGEVENT_SIGSTATUS_CHANGED, if applicable. + * see docs/sigstatus.txt for details */ + switch(status) { + case FTDM_SIG_STATE_SUSPENDED: + openr2_chan_set_blocked(r2chan); + if (rxcas == OR2_CAS_IDLE) { + ftdm_r2_set_chan_sig_status(ftdmchan, status); + } + break; + case FTDM_SIG_STATE_UP: + openr2_chan_set_idle(r2chan); + if (rxcas == OR2_CAS_IDLE) { + ftdm_r2_set_chan_sig_status(ftdmchan, status); + } + break; + default: + ftdm_log_chan(ftdmchan, FTDM_LOG_WARNING, "Cannot set signaling status to unknown value '%d'\n", status); + return FTDM_FAIL; + } + return FTDM_SUCCESS; +} + +static FIO_SPAN_GET_SIG_STATUS_FUNCTION(ftdm_r2_get_span_sig_status) +{ + ftdm_iterator_t *citer = NULL; + ftdm_iterator_t *chaniter = ftdm_span_get_chan_iterator(span, NULL); + if (!chaniter) { + ftdm_log(FTDM_LOG_CRIT, "Failed to allocate channel iterator for span %s!\n", span->name); + return FTDM_FAIL; + } + /* if ALL channels are non-idle, report SUSPENDED. UP otherwise. */ + *status = FTDM_SIG_STATE_SUSPENDED; + for (citer = chaniter; citer; citer = ftdm_iterator_next(citer)) { + ftdm_channel_t *fchan = ftdm_iterator_current(citer); + ftdm_channel_lock(fchan); + if (ftdm_test_flag(fchan, FTDM_CHANNEL_SIG_UP)) { + *status = FTDM_SIG_STATE_UP; + ftdm_channel_unlock(fchan); + break; + } + ftdm_channel_unlock(fchan); + } + ftdm_iterator_free(chaniter); + return FTDM_SUCCESS; +} + +static FIO_SPAN_SET_SIG_STATUS_FUNCTION(ftdm_r2_set_span_sig_status) +{ + ftdm_iterator_t *chaniter = NULL; + ftdm_iterator_t *citer = NULL; + + chaniter = ftdm_span_get_chan_iterator(span, NULL); + if (!chaniter) { + ftdm_log(FTDM_LOG_CRIT, "Failed to allocate channel iterator for span %s!\n", span->name); + return FTDM_FAIL; + } + /* iterate over all channels, setting them to the requested state */ + for (citer = chaniter; citer; citer = ftdm_iterator_next(citer)) { + ftdm_channel_t *fchan = ftdm_iterator_current(citer); + /* we set channel's state through ftdm_r2_set_channel_sig_status(), since it already takes + * care of notifying the user when appropriate */ + ftdm_channel_lock(fchan); + if ((ftdm_r2_set_channel_sig_status(fchan, status)) != FTDM_SUCCESS) { + ftdm_log_chan(fchan, FTDM_LOG_ERROR, "Failed to set signaling status to %s\n", ftdm_signaling_status2str(status)); + } + ftdm_channel_unlock(fchan); + } + ftdm_iterator_free(chaniter); + return FTDM_SUCCESS; +} + /* always called from the monitor thread */ static void ftdm_r2_on_call_init(openr2_chan_t *r2chan) { @@ -510,13 +672,21 @@ static void ftdm_r2_on_call_offered(openr2_chan_t *r2chan, const char *ani, cons ftdm_r2_data_t *r2data = ftdmchan->span->signal_data; ftdm_log_chan(ftdmchan, FTDM_LOG_NOTICE, "Call offered with ANI = %s, DNIS = %s, Category = (%d)\n", ani, dnis, category); - ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_RING); /* nothing went wrong during call setup, MF has ended, we can and must disable the MF dump */ if (r2data->mf_dump_size) { ftdm_channel_command(ftdmchan, FTDM_COMMAND_DISABLE_INPUT_DUMP, NULL); ftdm_channel_command(ftdmchan, FTDM_COMMAND_DISABLE_OUTPUT_DUMP, NULL); } + + /* check if this is a collect call and if we should accept it */ + if (!r2data->allow_collect_calls && category == OR2_CALLING_PARTY_CATEGORY_COLLECT_CALL) { + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_NOTICE, "Rejecting collect call\n"); + openr2_chan_disconnect_call(r2chan, OR2_CAUSE_COLLECT_CALL_REJECTED); + } else { + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_RING); + } + ftdmchan->caller_data.cpc = ftdm_openr2_cpc_to_r2_ftdm_cpc(category); } /* @@ -556,14 +726,14 @@ static void dump_mf(openr2_chan_t *r2chan) ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Dumping IO output in prefix %s\n", logname); snprintf(dfile, sizeof(dfile), logname ? "%s.s%dc%d.input.alaw" : "%s/s%dc%d.input.alaw", logname ? logname : r2data->logdir, ftdmchan->span_id, ftdmchan->chan_id); - f = fopen(dfile, "w"); + f = fopen(dfile, "wb"); ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Dumping IO input in file %s\n", dfile); ftdm_channel_command(ftdmchan, FTDM_COMMAND_DUMP_INPUT, f); fclose(f); snprintf(dfile, sizeof(dfile), logname ? "%s.s%dc%d.output.alaw" : "%s/s%dc%d.output.alaw", logname ? logname : r2data->logdir, ftdmchan->span_id, ftdmchan->chan_id); - f = fopen(dfile, "w"); + f = fopen(dfile, "wb"); ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Dumping IO output in file %s\n", dfile); ftdm_channel_command(ftdmchan, FTDM_COMMAND_DUMP_OUTPUT, f); fclose(f); @@ -573,6 +743,8 @@ static void dump_mf(openr2_chan_t *r2chan) 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_r2_data_t *r2data = ftdmchan->span->signal_data; + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_NOTICE, "Call accepted\n"); clear_accept_pending(ftdmchan); @@ -595,6 +767,11 @@ static void ftdm_r2_on_call_accepted(openr2_chan_t *r2chan, openr2_call_mode_t m return; } } else { + /* nothing went wrong during call setup, MF has ended, we can and must disable the MF dump */ + if (r2data->mf_dump_size) { + ftdm_channel_command(ftdmchan, FTDM_COMMAND_DISABLE_INPUT_DUMP, NULL); + ftdm_channel_command(ftdmchan, FTDM_COMMAND_DISABLE_OUTPUT_DUMP, NULL); + } ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_PROGRESS_MEDIA); } } @@ -653,7 +830,7 @@ static void ftdm_r2_on_call_read(openr2_chan_t *r2chan, const unsigned char *buf static void ftdm_r2_on_hardware_alarm(openr2_chan_t *r2chan, int alarm) { ftdm_channel_t *ftdmchan = openr2_chan_get_client_data(r2chan); - ftdm_log_chan(ftdmchan, FTDM_LOG_WARNING, "Alarm notification: %d\n", alarm); + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Alarm notification: %d\n", alarm); } static void ftdm_r2_on_os_error(openr2_chan_t *r2chan, int errorcode) @@ -895,7 +1072,7 @@ static int ftdm_r2_io_write(openr2_chan_t *r2chan, const void *buf, int size) if (FTDM_FAIL == status) { return -1; } - return outsize; + return (int)outsize; } static int ftdm_r2_io_read(openr2_chan_t *r2chan, const void *buf, int size) @@ -906,7 +1083,7 @@ static int ftdm_r2_io_read(openr2_chan_t *r2chan, const void *buf, int size) if (FTDM_FAIL == status) { return -1; } - return outsize; + return (int)outsize; } static int ftdm_r2_io_wait(openr2_chan_t *r2chan, int *flags, int block) @@ -988,6 +1165,10 @@ static int ftdm_r2_io_get_oob_event(openr2_chan_t *r2chan, openr2_oob_event_t *e return -1; } + if (fevent->e_type != FTDM_EVENT_OOB) { + return 0; + } + switch (fevent->enum_id) { case FTDM_OOB_CAS_BITS_CHANGE: { @@ -1396,13 +1577,14 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_r2_configure_span_signaling) span->sig_read = NULL; span->sig_write = NULL; - /* let the core set the states, we just read them */ - span->get_channel_sig_status = ftdm_r2_get_channel_sig_status; - span->signal_cb = sig_cb; span->signal_type = FTDM_SIGTYPE_R2; span->signal_data = r2data; span->outgoing_call = r2_outgoing_call; + span->get_span_sig_status = ftdm_r2_get_span_sig_status; + span->set_span_sig_status = ftdm_r2_set_span_sig_status; + span->get_channel_sig_status = ftdm_r2_get_channel_sig_status; + span->set_channel_sig_status = ftdm_r2_set_channel_sig_status; span->state_map = &r2_state_map; @@ -1593,6 +1775,13 @@ static int ftdm_r2_state_advance(ftdm_channel_t *ftdmchan) } break; + /* INDICATE_RINGING doesn't apply to MFC/R2. maybe we could generate a tone */ + case FTDM_CHANNEL_STATE_RINGING: + { + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "RINGING indicated, ignoring it as it doesn't apply to MFC/R2\n"); + } + break; + default: { ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Unhandled channel state change: %s\n", ftdm_channel_state2str(ftdmchan->state)); @@ -1639,9 +1828,13 @@ static void *ftdm_r2_run(ftdm_thread_t *me, void *obj) int index = 0; struct timeval start, end; ftdm_iterator_t *chaniter = NULL; + ftdm_iterator_t *citer = NULL; uint32_t txqueue_size = 4; short *poll_events = ftdm_malloc(sizeof(short) * span->chan_count); + /* as long as this thread is running, this flag is set */ + ftdm_set_flag(r2data, FTDM_R2_RUNNING); + #ifdef __linux__ r2data->monitor_thread_id = syscall(SYS_gettid); #endif @@ -1649,8 +1842,12 @@ static void *ftdm_r2_run(ftdm_thread_t *me, void *obj) ftdm_log(FTDM_LOG_DEBUG, "OpenR2 monitor thread %lu started.\n", r2data->monitor_thread_id); r2chan = NULL; chaniter = ftdm_span_get_chan_iterator(span, NULL); - for (i = 1; chaniter; chaniter = ftdm_iterator_next(chaniter), i++) { - ftdmchan = ftdm_iterator_current(chaniter); + if (!chaniter) { + ftdm_log(FTDM_LOG_CRIT, "Failed to allocate channel iterator for span %s!\n", span->name); + goto done; + } + for (i = 1, citer = chaniter; citer; citer = ftdm_iterator_next(citer), i++) { + ftdmchan = ftdm_iterator_current(citer); r2chan = R2CALL(ftdmchan)->r2chan; openr2_chan_set_span_id(r2chan, span->span_id); openr2_chan_set_idle(r2chan); @@ -1660,7 +1857,7 @@ static void *ftdm_r2_run(ftdm_thread_t *me, void *obj) memset(&start, 0, sizeof(start)); memset(&end, 0, sizeof(end)); - while (ftdm_running() && ftdm_test_flag(r2data, FTDM_R2_RUNNING)) { + while (ftdm_running() && ftdm_test_flag(r2data, FTDM_R2_SPAN_STARTED)) { res = gettimeofday(&end, NULL); if (res) { ftdm_log(FTDM_LOG_CRIT, "Failure gettimeofday [%s]\n", strerror(errno)); @@ -1685,24 +1882,24 @@ static void *ftdm_r2_run(ftdm_thread_t *me, void *obj) /* deliver the actual channel events to the user now without any channel locking */ ftdm_span_trigger_signals(span); -#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); - chaniter = ftdm_span_get_chan_iterator(span, chaniter); - for (i = 0; chaniter; chaniter = ftdm_iterator_next(chaniter), i++) { - ftdmchan = ftdm_iterator_current(chaniter); + citer = ftdm_span_get_chan_iterator(span, chaniter); + if (!citer) { + ftdm_log(FTDM_LOG_CRIT, "Failed to allocate channel iterator for span %s!\n", span->name); + goto done; + } + for (i = 0; citer; citer = ftdm_iterator_next(citer), i++) { + ftdmchan = ftdm_iterator_current(citer); r2chan = R2CALL(ftdmchan)->r2chan; - poll_events[i] = POLLPRI; + poll_events[i] = FTDM_EVENTS; if (openr2_chan_get_read_enabled(r2chan)) { - poll_events[i] |= POLLIN; + poll_events[i] |= FTDM_READ; } } - status = ftdm_span_poll_event(span, waitms, poll_events); -#else - status = ftdm_span_poll_event(span, waitms, NULL); -#endif /* run any span timers */ ftdm_sched_run(r2data->sched); @@ -1732,9 +1929,9 @@ static void *ftdm_r2_run(ftdm_thread_t *me, void *obj) /* this main loop takes care of MF and CAS signaling during call setup and tear down * for every single channel in the span, do not perform blocking operations here! */ - chaniter = ftdm_span_get_chan_iterator(span, chaniter); - for ( ; chaniter; chaniter = ftdm_iterator_next(chaniter)) { - ftdmchan = ftdm_iterator_current(chaniter); + citer = ftdm_span_get_chan_iterator(span, chaniter); + for ( ; citer; citer = ftdm_iterator_next(citer)) { + ftdmchan = ftdm_iterator_current(citer); ftdm_mutex_lock(ftdmchan->mutex); @@ -1761,10 +1958,11 @@ static void *ftdm_r2_run(ftdm_thread_t *me, void *obj) ftdm_mutex_unlock(ftdmchan->mutex); } } - - chaniter = ftdm_span_get_chan_iterator(span, chaniter); - for ( ; chaniter; chaniter = ftdm_iterator_next(chaniter)) { - ftdmchan = ftdm_iterator_current(chaniter); + +done: + citer = ftdm_span_get_chan_iterator(span, chaniter); + for ( ; citer; citer = ftdm_iterator_next(citer)) { + ftdmchan = ftdm_iterator_current(citer); r2chan = R2CALL(ftdmchan)->r2chan; openr2_chan_set_blocked(r2chan); } @@ -1821,6 +2019,14 @@ static void __inline__ unblock_channel(ftdm_channel_t *fchan, ftdm_stream_handle ftdm_mutex_unlock(fchan->mutex); } +#define FT_SYNTAX "USAGE:\n" \ +"--------------------------------------------------------------------------------\n" \ +"ftdm r2 status \n" \ +"ftdm r2 loopstats \n" \ +"ftdm r2 block|unblock []\n" \ +"ftdm r2 version\n" \ +"ftdm r2 variants\n" \ +"--------------------------------------------------------------------------------\n" static FIO_API_FUNCTION(ftdm_r2_api) { ftdm_span_t *span = NULL; @@ -1922,7 +2128,7 @@ static FIO_API_FUNCTION(ftdm_r2_api) "Max DNIS: %d\n" "ANI First: %s\n" "Immediate Accept: %s\n" - "Job Thread: %lu\n" + "Job Thread: %u\n" "Job Max ms: %d\n" "Job Loops: %lu\n", openr2_proto_get_variant_string(r2variant), @@ -2004,14 +2210,6 @@ static FIO_API_FUNCTION(ftdm_r2_api) } if (argc == 1) { - if (!strcasecmp(argv[0], "threads")) { - ftdm_mutex_lock(g_thread_count_mutex); - stream->write_function(stream, "%d R2 channel threads up\n", g_thread_count); - ftdm_mutex_unlock(g_thread_count_mutex); - stream->write_function(stream, "+OK.\n"); - goto done; - } - if (!strcasecmp(argv[0], "version")) { stream->write_function(stream, "OpenR2 version: %s, revision: %s\n", openr2_get_version(), openr2_get_revision()); stream->write_function(stream, "+OK.\n"); @@ -2037,7 +2235,7 @@ static FIO_API_FUNCTION(ftdm_r2_api) } } - stream->write_function(stream, "-ERR invalid command.\n"); + stream->write_function(stream, "%s", FT_SYNTAX); done: @@ -2066,7 +2264,6 @@ static FIO_SIG_LOAD_FUNCTION(ftdm_r2_init) if (!g_mod_data_hash) { return FTDM_FAIL; } - ftdm_mutex_create(&g_thread_count_mutex); return FTDM_SUCCESS; } @@ -2086,7 +2283,6 @@ static FIO_SIG_UNLOAD_FUNCTION(ftdm_r2_destroy) } } hashtable_destroy(g_mod_data_hash); - ftdm_mutex_destroy(&g_thread_count_mutex); return FTDM_SUCCESS; } 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 50a01cc0ec..97e242dacb 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 @@ -839,7 +839,7 @@ static void handle_call_released(ftdm_span_t *span, sangomabc_connection_t *mcon if ((ftdmchan = find_ftdmchan(span, event, 1))) { ftdm_log(FTDM_LOG_DEBUG, "Releasing completely chan s%dc%d\n", BOOST_EVENT_SPAN(mcon->sigmod, event), BOOST_EVENT_CHAN(mcon->sigmod, event)); - ftdm_channel_done(ftdmchan); + ftdm_channel_close(&ftdmchan); } else { ftdm_log(FTDM_LOG_CRIT, "Odd, We could not find chan: s%dc%d to release the call completely!!\n", BOOST_EVENT_SPAN(mcon->sigmod, event), BOOST_EVENT_CHAN(mcon->sigmod, event)); @@ -1105,8 +1105,9 @@ static void handle_call_loop_start(ftdm_span_t *span, sangomabc_connection_t *mc ftdm_set_state_r(ftdmchan, FTDM_CHANNEL_STATE_IN_LOOP, res); if (res != FTDM_SUCCESS) { + ftdm_channel_t *toclose = ftdmchan; ftdm_log(FTDM_LOG_CRIT, "yay, could not set the state of the channel to IN_LOOP, loop will fail\n"); - ftdm_channel_done(ftdmchan); + ftdm_channel_close(&toclose); return; } ftdm_log(FTDM_LOG_DEBUG, "%d:%d starting loop\n", ftdmchan->span_id, ftdmchan->chan_id); @@ -1426,11 +1427,12 @@ static __inline__ ftdm_status_t state_advance(ftdm_channel_t *ftdmchan) ftdmchan->sflags = 0; memset(ftdmchan->call_data, 0, sizeof(sangoma_boost_call_t)); if (sangoma_boost_data->sigmod && call_stopped_ack_sent) { - /* we dont want to call ftdm_channel_done just yet until call released is received */ + /* we dont want to call ftdm_channel_close just yet until call released is received */ ftdm_log(FTDM_LOG_DEBUG, "Waiting for call release confirmation before declaring chan %d:%d as available \n", ftdmchan->span_id, ftdmchan->chan_id); } else { - ftdm_channel_done(ftdmchan); + ftdm_channel_t *toclose = ftdmchan; + ftdm_channel_close(&toclose); } } break; @@ -2476,7 +2478,7 @@ static BOOST_SIG_STATUS_CB_FUNCTION(ftdm_boost_sig_status_change) sig.span_id = ftdmchan->span_id; sig.channel = ftdmchan; sig.event_id = FTDM_SIGEVENT_SIGSTATUS_CHANGED; - sig.raw_data = &status; + sig.ev_data.sigstatus.status = status; ftdm_span_send_signal(ftdmchan->span, &sig); return; } diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_boost/sangoma_boost_client.c b/libs/freetdm/src/ftmod/ftmod_sangoma_boost/sangoma_boost_client.c index 982dd4794d..6ddb74d253 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_boost/sangoma_boost_client.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_boost/sangoma_boost_client.c @@ -31,6 +31,8 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#define _GNU_SOURCE + #if HAVE_NETDB_H #include #endif 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 03b5a5fb1d..bb29b4f4a5 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 @@ -65,7 +65,13 @@ ftdm_state_map_t sangoma_isdn_state_map = { ZSD_INBOUND, ZSM_UNACCEPTABLE, {FTDM_ANY_STATE, FTDM_END}, - {FTDM_CHANNEL_STATE_RESTART, FTDM_CHANNEL_STATE_SUSPENDED, FTDM_END} + {FTDM_CHANNEL_STATE_RESET, FTDM_CHANNEL_STATE_RESTART, FTDM_END} + }, + { + ZSD_INBOUND, + ZSM_UNACCEPTABLE, + {FTDM_CHANNEL_STATE_RESET, FTDM_END}, + {FTDM_CHANNEL_STATE_DOWN, FTDM_END} }, { ZSD_INBOUND, @@ -170,7 +176,13 @@ ftdm_state_map_t sangoma_isdn_state_map = { ZSD_OUTBOUND, ZSM_UNACCEPTABLE, {FTDM_ANY_STATE, FTDM_END}, - {FTDM_CHANNEL_STATE_RESTART, FTDM_CHANNEL_STATE_SUSPENDED, FTDM_CHANNEL_STATE_TERMINATING, FTDM_END} + {FTDM_CHANNEL_STATE_RESET, FTDM_CHANNEL_STATE_RESTART, FTDM_CHANNEL_STATE_TERMINATING, FTDM_END} + }, + { + ZSD_OUTBOUND, + ZSM_UNACCEPTABLE, + {FTDM_CHANNEL_STATE_RESET, FTDM_END}, + {FTDM_CHANNEL_STATE_DOWN, FTDM_END} }, { ZSD_OUTBOUND, @@ -203,7 +215,7 @@ ftdm_state_map_t sangoma_isdn_state_map = { ZSM_UNACCEPTABLE, {FTDM_CHANNEL_STATE_DIALING, FTDM_END}, {FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_HANGUP, - FTDM_CHANNEL_STATE_PROCEED, FTDM_CHANNEL_STATE_PROGRESS, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_CHANNEL_STATE_UP, + FTDM_CHANNEL_STATE_PROCEED, FTDM_CHANNEL_STATE_RINGING, FTDM_CHANNEL_STATE_PROGRESS, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_CHANNEL_STATE_UP, FTDM_CHANNEL_STATE_DOWN, FTDM_END} }, { @@ -211,14 +223,20 @@ ftdm_state_map_t sangoma_isdn_state_map = { ZSM_UNACCEPTABLE, {FTDM_CHANNEL_STATE_PROCEED, FTDM_END}, {FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_HANGUP, - FTDM_CHANNEL_STATE_PROGRESS, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_CHANNEL_STATE_UP, FTDM_END}, - }, + FTDM_CHANNEL_STATE_RINGING, FTDM_CHANNEL_STATE_PROGRESS, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_CHANNEL_STATE_UP, FTDM_END}, + }, { ZSD_OUTBOUND, ZSM_UNACCEPTABLE, {FTDM_CHANNEL_STATE_PROGRESS, FTDM_END}, {FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_CHANNEL_STATE_UP, FTDM_END}, }, + { + ZSD_OUTBOUND, + ZSM_UNACCEPTABLE, + {FTDM_CHANNEL_STATE_RINGING, FTDM_END}, + {FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_CHANNEL_STATE_UP, FTDM_END}, + }, { ZSD_OUTBOUND, ZSM_UNACCEPTABLE, @@ -626,8 +644,11 @@ static void ftdm_sangoma_isdn_process_state_change(ftdm_channel_t *ftdmchan) case FTDM_CHANNEL_STATE_GET_CALLERID: { if (!sngisdn_test_flag(sngisdn_info, FLAG_SENT_PROCEED)) { + /* By default, we do not send a progress indicator in the proceed */ + ftdm_sngisdn_progind_t prog_ind = {SNGISDN_PROGIND_LOC_USER, SNGISDN_PROGIND_DESCR_INVALID}; + sngisdn_set_flag(sngisdn_info, FLAG_SENT_PROCEED); - sngisdn_snd_proceed(ftdmchan); + sngisdn_snd_proceed(ftdmchan, prog_ind); } /* Wait in this state until we get FACILITY msg */ } @@ -666,16 +687,28 @@ static void ftdm_sangoma_isdn_process_state_change(ftdm_channel_t *ftdmchan) ftdm_span_send_signal(ftdmchan->span, &sigev); } else { if (!sngisdn_test_flag(sngisdn_info, FLAG_SENT_PROCEED)) { + /* By default, we do not send a progress indicator in the proceed */ + ftdm_sngisdn_progind_t prog_ind = {SNGISDN_PROGIND_LOC_USER, SNGISDN_PROGIND_DESCR_INVALID}; + sngisdn_set_flag(sngisdn_info, FLAG_SENT_PROCEED); - sngisdn_snd_proceed(ftdmchan); + sngisdn_snd_proceed(ftdmchan, prog_ind); } } } break; case FTDM_CHANNEL_STATE_RINGING: { - ftdm_sngisdn_progind_t prog_ind = {SNGISDN_PROGIND_LOC_USER, SNGISDN_PROGIND_DESCR_NETE_ISDN}; - sngisdn_snd_alert(ftdmchan, prog_ind); + if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) { + /* OUTBOUND...so we were told by the line of this so notify the user */ + sigev.event_id = FTDM_SIGEVENT_RINGING; + ftdm_span_send_signal(ftdmchan->span, &sigev); + if (sngisdn_test_flag(sngisdn_info, FLAG_MEDIA_READY)) { + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_PROGRESS_MEDIA); + } + } else { + ftdm_sngisdn_progind_t prog_ind = {SNGISDN_PROGIND_LOC_USER, SNGISDN_PROGIND_DESCR_NETE_ISDN}; + sngisdn_snd_alert(ftdmchan, prog_ind); + } } break; case FTDM_CHANNEL_STATE_PROGRESS: @@ -686,12 +719,9 @@ static void ftdm_sangoma_isdn_process_state_change(ftdm_channel_t *ftdmchan) sigev.event_id = FTDM_SIGEVENT_PROGRESS; ftdm_span_send_signal(ftdmchan->span, &sigev); } else { - /* If we already sent a PROCEED before, do not send a PROGRESS as there is nothing to indicate to the remote switch */ - if (ftdmchan->last_state != FTDM_CHANNEL_STATE_PROCEED) { - /* Send a progress message, indicating: Call is not end-to-end ISDN, further call progress may be available */ - ftdm_sngisdn_progind_t prog_ind = {SNGISDN_PROGIND_LOC_USER, SNGISDN_PROGIND_DESCR_NETE_ISDN}; - sngisdn_snd_progress(ftdmchan, prog_ind); - } + /* Send a progress message, indicating: Call is not end-to-end ISDN, further call progress may be available */ + ftdm_sngisdn_progind_t prog_ind = {SNGISDN_PROGIND_LOC_USER, SNGISDN_PROGIND_DESCR_NETE_ISDN}; + sngisdn_snd_progress(ftdmchan, prog_ind); } } break; @@ -774,7 +804,7 @@ static void ftdm_sangoma_isdn_process_state_change(ftdm_channel_t *ftdmchan) sngisdn_snd_release(ftdmchan, 0); if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_SIG_UP)) { - sngisdn_set_avail_rate(ftdmchan->span, SNGISDN_AVAIL_DOWN); + sngisdn_set_span_avail_rate(ftdmchan->span, SNGISDN_AVAIL_DOWN); } } else { sngisdn_snd_disconnect(ftdmchan); @@ -832,6 +862,11 @@ static void ftdm_sangoma_isdn_process_state_change(ftdm_channel_t *ftdmchan) /* IMPLEMENT ME */ } break; + case FTDM_CHANNEL_STATE_RESET: + { + sngisdn_snd_restart(ftdmchan); + } + break; default: { ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "unsupported sngisdn_rcvd state %s\n", ftdm_channel_state2str(ftdmchan->state)); @@ -851,6 +886,22 @@ static void ftdm_sangoma_isdn_process_state_change(ftdm_channel_t *ftdmchan) return; } +static FIO_CHANNEL_SEND_MSG_FUNCTION(ftdm_sangoma_isdn_send_msg) +{ + ftdm_status_t status = FTDM_FAIL; + + switch (sigmsg->event_id) { + case FTDM_SIGEVENT_FACILITY: + sngisdn_snd_fac_req(ftdmchan); + break; + default: + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_WARNING, "Unsupported signalling msg requested\n"); + status = FTDM_BREAK; + } + ftdm_call_clear_data(&ftdmchan->caller_data); + return status; +} + static FIO_CHANNEL_OUTGOING_CALL_FUNCTION(ftdm_sangoma_isdn_outgoing_call) { sngisdn_chan_data_t *sngisdn_info = ftdmchan->call_data; @@ -925,7 +976,8 @@ static FIO_SPAN_SET_SIG_STATUS_FUNCTION(ftdm_sangoma_isdn_set_span_sig_status) } static ftdm_status_t ftdm_sangoma_isdn_start(ftdm_span_t *span) -{ +{ + sngisdn_span_data_t *signal_data = span->signal_data; ftdm_log(FTDM_LOG_INFO,"Starting span %s:%u.\n",span->name,span->span_id); if (sngisdn_stack_start(span) != FTDM_SUCCESS) { ftdm_log(FTDM_LOG_CRIT, "Failed to start span %s\n", span->name); @@ -935,6 +987,14 @@ static ftdm_status_t ftdm_sangoma_isdn_start(ftdm_span_t *span) ftdm_clear_flag(span, FTDM_SPAN_STOP_THREAD); ftdm_clear_flag(span, FTDM_SPAN_IN_THREAD); + if (signal_data->raw_trace_q921 == SNGISDN_OPT_TRUE) { + sngisdn_activate_trace(span, SNGISDN_TRACE_Q921); + } + + if (signal_data->raw_trace_q931 == SNGISDN_OPT_TRUE) { + sngisdn_activate_trace(span, SNGISDN_TRACE_Q931); + } + /*start the span monitor thread*/ if (ftdm_thread_create_detached(ftdm_sangoma_isdn_run, span) != FTDM_SUCCESS) { ftdm_log(FTDM_LOG_CRIT,"Failed to start Sangoma ISDN Span Monitor Thread!\n"); @@ -1030,6 +1090,7 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_sangoma_isdn_span_config) span->stop = ftdm_sangoma_isdn_stop; span->signal_type = FTDM_SIGTYPE_ISDN; span->outgoing_call = ftdm_sangoma_isdn_outgoing_call; + span->send_msg = ftdm_sangoma_isdn_send_msg; span->channel_request = NULL; span->signal_cb = sig_cb; span->get_channel_sig_status = ftdm_sangoma_isdn_get_chan_sig_status; @@ -1040,11 +1101,12 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_sangoma_isdn_span_config) ftdm_set_flag(span, FTDM_SPAN_USE_CHAN_QUEUE); ftdm_set_flag(span, FTDM_SPAN_USE_SIGNALS_QUEUE); ftdm_set_flag(span, FTDM_SPAN_USE_PROCEED_STATE); + ftdm_set_flag(span, FTDM_SPAN_USE_SKIP_STATES); if (span->trunk_type == FTDM_TRUNK_BRI_PTMP || span->trunk_type == FTDM_TRUNK_BRI) { - sngisdn_set_avail_rate(span, SNGISDN_AVAIL_PWR_SAVING); + sngisdn_set_span_avail_rate(span, SNGISDN_AVAIL_PWR_SAVING); } /* Initialize scheduling context */ @@ -1139,6 +1201,7 @@ static FIO_API_FUNCTION(ftdm_sangoma_isdn_api) goto done; } + /* TODO: Move functions to table + function pointers */ if (!strcasecmp(argv[0], "trace")) { char *trace_opt; @@ -1156,6 +1219,7 @@ static FIO_API_FUNCTION(ftdm_sangoma_isdn_api) stream->write_function(stream, "-ERR failed to find span by name %s\n", argv[2]); goto done; } + if (!strcasecmp(trace_opt, "q921")) { sngisdn_activate_trace(span, SNGISDN_TRACE_Q921); } else if (!strcasecmp(trace_opt, "q931")) { @@ -1164,7 +1228,7 @@ static FIO_API_FUNCTION(ftdm_sangoma_isdn_api) sngisdn_activate_trace(span, SNGISDN_TRACE_DISABLE); } else { stream->write_function(stream, "-ERR invalid trace option \n"); - } + } } if (!strcasecmp(argv[0], "l1_stats")) { ftdm_span_t *span; @@ -1182,7 +1246,7 @@ static FIO_API_FUNCTION(ftdm_sangoma_isdn_api) } sngisdn_print_phy_stats(stream, span); } - + if (!strcasecmp(argv[0], "show_spans")) { ftdm_span_t *span = NULL; if (argc == 2) { 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 b9ab3395ae..6a440e4f66 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 @@ -101,9 +101,11 @@ typedef enum { FLAG_GLARE = (1 << 6), FLAG_DELAYED_REL = (1 << 7), FLAG_SENT_PROCEED = (1 << 8), - FLAG_SEND_DISC = (1 << 9), + FLAG_SEND_DISC = (1 << 9), /* Used for BRI only, flag is set after we request line CONNECTED */ - FLAG_ACTIVATING = (1 << 10), + FLAG_ACTIVATING = (1 << 10), + /* Used when we receive an ALERT msg + inband tones ready */ + FLAG_MEDIA_READY = (1 << 11), } sngisdn_flag_t; @@ -259,6 +261,8 @@ typedef struct sngisdn_span_data { int8_t facility_timeout; uint8_t num_local_numbers; uint8_t ignore_cause_value; + uint8_t raw_trace_q931; + uint8_t raw_trace_q921; uint8_t timer_t3; uint8_t restart_opt; char* local_numbers[SNGISDN_NUM_LOCAL_NUMBERS]; @@ -352,8 +356,11 @@ void clear_call_glare_data(sngisdn_chan_data_t *sngisdn_info); ftdm_status_t get_ftdmchan_by_suInstId(int16_t cc_id, uint32_t suInstId, sngisdn_chan_data_t **sngisdn_data); ftdm_status_t get_ftdmchan_by_spInstId(int16_t cc_id, uint32_t spInstId, sngisdn_chan_data_t **sngisdn_data); +ftdm_status_t sngisdn_set_span_avail_rate(ftdm_span_t *span, sngisdn_avail_t avail); +ftdm_status_t sngisdn_set_chan_avail_rate(ftdm_channel_t *chan, sngisdn_avail_t avail); +void sngisdn_set_span_sig_status(ftdm_span_t *ftdmspan, ftdm_signaling_status_t status); +void sngisdn_set_chan_sig_status(ftdm_channel_t *ftdmchan, ftdm_signaling_status_t status); -ftdm_status_t sngisdn_set_avail_rate(ftdm_span_t *span, sngisdn_avail_t avail); ftdm_status_t sngisdn_activate_trace(ftdm_span_t *span, sngisdn_tracetype_t trace_opt); @@ -363,7 +370,7 @@ void stack_pst_init(Pst *pst); /* Outbound Call Control functions */ void sngisdn_snd_setup(ftdm_channel_t *ftdmchan); void sngisdn_snd_setup_ack(ftdm_channel_t *ftdmchan); -void sngisdn_snd_proceed(ftdm_channel_t *ftdmchan); +void sngisdn_snd_proceed(ftdm_channel_t *ftdmchan, ftdm_sngisdn_progind_t prog_ind); void sngisdn_snd_progress(ftdm_channel_t *ftdmchan, ftdm_sngisdn_progind_t prog_ind); void sngisdn_snd_alert(ftdm_channel_t *ftdmchan, ftdm_sngisdn_progind_t prog_ind); void sngisdn_snd_connect(ftdm_channel_t *ftdmchan); @@ -374,6 +381,7 @@ void sngisdn_snd_con_complete(ftdm_channel_t *ftdmchan); void sngisdn_snd_fac_req(ftdm_channel_t *ftdmchan); void sngisdn_snd_info_req(ftdm_channel_t *ftdmchan); void sngisdn_snd_status_enq(ftdm_channel_t *ftdmchan); +void sngisdn_snd_restart(ftdm_channel_t *ftdmchan); void sngisdn_snd_data(ftdm_channel_t *dchan, uint8_t *data, ftdm_size_t len); void sngisdn_snd_event(ftdm_channel_t *dchan, ftdm_oob_event_t event); @@ -421,8 +429,11 @@ void sngisdn_process_rst_ind (sngisdn_event_data_t *sngisdn_event); void sngisdn_rcv_phy_ind(SuId suId, Reason reason); void sngisdn_rcv_q921_ind(BdMngmt *status); -void sngisdn_trace_q921(char* str, uint8_t* data, uint32_t data_len); -void sngisdn_trace_q931(char* str, uint8_t* data, uint32_t data_len); +void sngisdn_trace_interpreted_q921(sngisdn_span_data_t *signal_data, ftdm_trace_dir_t dir, uint8_t *data, uint32_t data_len); +void sngisdn_trace_interpreted_q931(sngisdn_span_data_t *signal_data, ftdm_trace_dir_t dir, uint8_t *data, uint32_t data_len); +void sngisdn_trace_raw_q921(sngisdn_span_data_t *signal_data, ftdm_trace_dir_t dir, uint8_t *data, uint32_t data_len); +void sngisdn_trace_raw_q931(sngisdn_span_data_t *signal_data, ftdm_trace_dir_t dir, uint8_t *data, uint32_t data_len); + void get_memory_info(void); ftdm_status_t sng_isdn_activate_trace(ftdm_span_t *span, sngisdn_tracetype_t trace_opt); @@ -436,6 +447,7 @@ void sngisdn_rcv_sng_log(uint8_t level, char *fmt,...); void sngisdn_rcv_sng_assert(char *message); ftdm_status_t get_calling_num(ftdm_channel_t *ftdmchan, CgPtyNmb *cgPtyNmb); +ftdm_status_t get_calling_num2(ftdm_channel_t *ftdmchan, CgPtyNmb *cgPtyNmb); ftdm_status_t get_called_num(ftdm_channel_t *ftdmchan, CdPtyNmb *cdPtyNmb); ftdm_status_t get_redir_num(ftdm_channel_t *ftdmchan, RedirNmb *redirNmb); ftdm_status_t get_calling_name_from_display(ftdm_channel_t *ftdmchan, Display *display); @@ -443,16 +455,20 @@ ftdm_status_t get_calling_name_from_usr_usr(ftdm_channel_t *ftdmchan, UsrUsr *us ftdm_status_t get_calling_subaddr(ftdm_channel_t *ftdmchan, CgPtySad *cgPtySad); ftdm_status_t get_prog_ind_ie(ftdm_channel_t *ftdmchan, ProgInd *progInd); ftdm_status_t get_facility_ie(ftdm_channel_t *ftdmchan, FacilityStr *facilityStr); -ftdm_status_t get_facility_ie_str(ftdm_channel_t *ftdmchan, uint8_t *data, ftdm_size_t data_len); +ftdm_status_t get_facility_ie_str(ftdm_channel_t *ftdmchan, uint8_t *data, uint8_t data_len); ftdm_status_t set_calling_num(ftdm_channel_t *ftdmchan, CgPtyNmb *cgPtyNmb); +ftdm_status_t set_calling_num2(ftdm_channel_t *ftdmchan, CgPtyNmb *cgPtyNmb); ftdm_status_t set_called_num(ftdm_channel_t *ftdmchan, CdPtyNmb *cdPtyNmb); ftdm_status_t set_redir_num(ftdm_channel_t *ftdmchan, RedirNmb *redirNmb); ftdm_status_t set_calling_name(ftdm_channel_t *ftdmchan, ConEvnt *conEvnt); ftdm_status_t set_calling_subaddr(ftdm_channel_t *ftdmchan, CgPtySad *cgPtySad); ftdm_status_t set_prog_ind_ie(ftdm_channel_t *ftdmchan, ProgInd *progInd, ftdm_sngisdn_progind_t prog_ind); +ftdm_status_t set_bear_cap_ie(ftdm_channel_t *ftdmchan, BearCap *bearCap); +ftdm_status_t set_chan_id_ie(ftdm_channel_t *ftdmchan, ChanId *chanId); +ftdm_status_t set_restart_ind_ie(ftdm_channel_t *ftdmchan, RstInd *rstInd); ftdm_status_t set_facility_ie(ftdm_channel_t *ftdmchan, FacilityStr *facilityStr); -ftdm_status_t set_facility_ie_str(ftdm_channel_t *ftdmchan, uint8_t *data, ftdm_size_t *data_len); +ftdm_status_t set_facility_ie_str(ftdm_channel_t *ftdmchan, uint8_t *data, uint8_t *data_len); uint8_t sngisdn_get_infoTranCap_from_stack(ftdm_bearer_cap_t bearer_capability); @@ -480,7 +496,6 @@ static __inline__ void sngisdn_set_flag(sngisdn_chan_data_t *sngisdn_info, sngis void handle_sng_log(uint8_t level, char *fmt,...); -void sngisdn_set_span_sig_status(ftdm_span_t *ftdmspan, ftdm_signaling_status_t status); void sngisdn_delayed_setup(void* p_sngisdn_info); void sngisdn_delayed_release(void* p_sngisdn_info); void sngisdn_delayed_connect(void* p_sngisdn_info); diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_cfg.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_cfg.c index cce10cc1dd..c979000223 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_cfg.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_cfg.c @@ -296,6 +296,10 @@ ftdm_status_t ftmod_isdn_parse_cfg(ftdm_conf_parameter_t *ftdm_parameters, ftdm_ parse_yesno(var, val, &signal_data->facility_ie_decode); } else if (!strcasecmp(var, "ignore-cause-value")) { parse_yesno(var, val, &signal_data->ignore_cause_value); + } else if (!strcasecmp(var, "q931-raw-trace")) { + parse_yesno(var, val, &signal_data->raw_trace_q931); + } else if (!strcasecmp(var, "q921-raw-trace")) { + parse_yesno(var, val, &signal_data->raw_trace_q921); } else { ftdm_log(FTDM_LOG_WARNING, "Ignoring unknown parameter %s\n", ftdm_parameters[paramindex].var); } diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_cntrl.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_cntrl.c index 5060cb6bba..668b63006c 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_cntrl.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_cntrl.c @@ -47,7 +47,7 @@ void sngisdn_set_chan_sig_status(ftdm_channel_t *ftdmchan, ftdm_signaling_status sig.span_id = ftdmchan->span_id; sig.channel = ftdmchan; sig.event_id = FTDM_SIGEVENT_SIGSTATUS_CHANGED; - sig.sigstatus = status; + sig.ev_data.sigstatus.status = status; ftdm_span_send_signal(ftdmchan->span, &sig); return; } 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 086354a993..7e9e360c6d 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_hndl.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_hndl.c @@ -33,7 +33,8 @@ */ #include "ftmod_sangoma_isdn.h" -ftdm_status_t sngisdn_cause_val_requires_disconnect(ftdm_channel_t *ftdmchan, CauseDgn *causeDgn); +static ftdm_status_t sngisdn_cause_val_requires_disconnect(ftdm_channel_t *ftdmchan, CauseDgn *causeDgn); +static void sngisdn_process_restart_confirm(ftdm_channel_t *ftdmchan); /* Remote side transmit a SETUP */ void sngisdn_process_con_ind (sngisdn_event_data_t *sngisdn_event) @@ -123,12 +124,9 @@ void sngisdn_process_con_ind (sngisdn_event_data_t *sngisdn_event) break; } -#if 0 - /* Export ftdmchan variables here if we need to */ - ftdm_channel_add_var(ftdmchan, "isdn_specific_var", "1"); -#endif /* Fill in call information */ get_calling_num(ftdmchan, &conEvnt->cgPtyNmb); + get_calling_num2(ftdmchan, &conEvnt->cgPtyNmb2); get_called_num(ftdmchan, &conEvnt->cdPtyNmb); get_redir_num(ftdmchan, &conEvnt->redirNmb); get_calling_subaddr(ftdmchan, &conEvnt->cgPtySad); @@ -235,6 +233,9 @@ void sngisdn_process_con_ind (sngisdn_event_data_t *sngisdn_event) ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING); } break; + case FTDM_CHANNEL_STATE_RESET: + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Processing SETUP but channel in RESET state, ignoring\n"); + break; default: ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "Processing SETUP in an invalid state (%s)\n", ftdm_channel_state2str(ftdmchan->state)); break; @@ -277,6 +278,7 @@ void sngisdn_process_con_cfm (sngisdn_event_data_t *sngisdn_event) if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) { switch(ftdmchan->state) { case FTDM_CHANNEL_STATE_PROCEED: + case FTDM_CHANNEL_STATE_RINGING: case FTDM_CHANNEL_STATE_PROGRESS: case FTDM_CHANNEL_STATE_PROGRESS_MEDIA: case FTDM_CHANNEL_STATE_DIALING: @@ -288,6 +290,9 @@ void sngisdn_process_con_cfm (sngisdn_event_data_t *sngisdn_event) case FTDM_CHANNEL_STATE_HANGUP: /* Race condition, we just hung up the call - ignore this message */ break; + case FTDM_CHANNEL_STATE_RESET: + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Processing SETUP but channel in RESET state, ignoring\n"); + break; default: ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "Processing CONNECT/CONNECT ACK in an invalid state (%s)\n", ftdm_channel_state2str(ftdmchan->state)); @@ -304,6 +309,9 @@ void sngisdn_process_con_cfm (sngisdn_event_data_t *sngisdn_event) case FTDM_CHANNEL_STATE_HANGUP_COMPLETE: /* Race condition, We just hung up an incoming call right after we sent a CONNECT - ignore this message */ break; + case FTDM_CHANNEL_STATE_RESET: + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Processing SETUP but channel in RESET state, ignoring\n"); + break; default: ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "Processing CONNECT/CONNECT ACK in an invalid state (%s)\n", ftdm_channel_state2str(ftdmchan->state)); @@ -357,27 +365,47 @@ void sngisdn_process_cnst_ind (sngisdn_event_data_t *sngisdn_event) ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING); goto sngisdn_process_cnst_ind_end; } - + switch(ftdmchan->state) { case FTDM_CHANNEL_STATE_DIALING: case FTDM_CHANNEL_STATE_PROCEED: - if (cnStEvnt->progInd.eh.pres && cnStEvnt->progInd.progDesc.val == IN_PD_IBAVAIL) { - ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_PROGRESS_MEDIA); - } else if (evntType == MI_CALLPROC) { - ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_PROCEED); - } else { - ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_PROGRESS); - } - break; case FTDM_CHANNEL_STATE_PROGRESS: + case FTDM_CHANNEL_STATE_RINGING: if (cnStEvnt->progInd.eh.pres && cnStEvnt->progInd.progDesc.val == IN_PD_IBAVAIL) { - ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_PROGRESS_MEDIA); + sngisdn_set_flag(sngisdn_info, FLAG_MEDIA_READY); + } + switch (evntType) { + case MI_CALLPROC: + if (ftdmchan->state == FTDM_CHANNEL_STATE_DIALING) { + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_PROCEED); + } + break; + case MI_ALERTING: + if (ftdmchan->state == FTDM_CHANNEL_STATE_PROCEED) { + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_RINGING); + } + break; + case MI_PROGRESS: + if (sngisdn_test_flag(sngisdn_info, FLAG_MEDIA_READY)) { + + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_PROGRESS_MEDIA); + } else if (ftdmchan->state != FTDM_CHANNEL_STATE_PROGRESS) { + + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_PROGRESS); + } + break; + default: + /* We should never reach this section !*/ + ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "Don't know how to handle this event %d\n", evntType); } break; case FTDM_CHANNEL_STATE_PROGRESS_MEDIA: /* We are already in progress media, we can't go to any higher state except up */ /* Do nothing */ break; + case FTDM_CHANNEL_STATE_RESET: + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Processing SETUP but channel in RESET state, ignoring\n"); + break; default: ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "Processing ALERT/PROCEED/PROGRESS in an invalid state (%s)\n", ftdm_channel_state2str(ftdmchan->state)); @@ -410,12 +438,16 @@ void sngisdn_process_cnst_ind (sngisdn_event_data_t *sngisdn_event) } break; case FTDM_CHANNEL_STATE_RING: + case FTDM_CHANNEL_STATE_RINGING: case FTDM_CHANNEL_STATE_PROCEED: case FTDM_CHANNEL_STATE_PROGRESS: case FTDM_CHANNEL_STATE_PROGRESS_MEDIA: case FTDM_CHANNEL_STATE_UP: ftdm_log_chan(ftdmchan, FTDM_LOG_WARNING, "Receiving more digits %s, but we already proceeded with call\n", cnStEvnt->cdPtyNmb.nmbDigits.val); break; + case FTDM_CHANNEL_STATE_RESET: + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Processing SETUP but channel in RESET state, ignoring\n"); + break; default: ftdm_log_chan(ftdmchan, FTDM_LOG_WARNING, "\n", suId, suInstId, spInstId); break; @@ -450,6 +482,7 @@ void sngisdn_process_disc_ind (sngisdn_event_data_t *sngisdn_event) ftdm_assert(!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE), "State change flag pending\n"); switch (ftdmchan->state) { case FTDM_CHANNEL_STATE_RING: + case FTDM_CHANNEL_STATE_RINGING: case FTDM_CHANNEL_STATE_DIALING: case FTDM_CHANNEL_STATE_PROCEED: case FTDM_CHANNEL_STATE_PROGRESS: @@ -478,6 +511,9 @@ void sngisdn_process_disc_ind (sngisdn_event_data_t *sngisdn_event) /* This is a race condition. We just sent a DISCONNECT, on this channel */ /* Do nothing */ break; + case FTDM_CHANNEL_STATE_RESET: + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Processing SETUP but channel in RESET state, ignoring\n"); + break; default: ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "Received DISCONNECT in an invalid state (%s)\n", ftdm_channel_state2str(ftdmchan->state)); @@ -532,7 +568,7 @@ void sngisdn_process_rel_ind (sngisdn_event_data_t *sngisdn_event) case FTDM_CHANNEL_STATE_DIALING: /* Remote side rejected our SETUP message on outbound call */ if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_SIG_UP)) { - sngisdn_set_avail_rate(ftdmchan->span, SNGISDN_AVAIL_DOWN); + sngisdn_set_span_avail_rate(ftdmchan->span, SNGISDN_AVAIL_DOWN); } /* fall-through */ case FTDM_CHANNEL_STATE_PROCEED: @@ -540,6 +576,7 @@ void sngisdn_process_rel_ind (sngisdn_event_data_t *sngisdn_event) case FTDM_CHANNEL_STATE_PROGRESS_MEDIA: case FTDM_CHANNEL_STATE_UP: case FTDM_CHANNEL_STATE_RING: + case FTDM_CHANNEL_STATE_RINGING: /* If we previously had a glare on this channel, this RELEASE could be for the previous call. Confirm whether call_data has not changed while we were waiting for ftdmchan->mutex by comparing suInstId's */ @@ -581,6 +618,9 @@ void sngisdn_process_rel_ind (sngisdn_event_data_t *sngisdn_event) /* set abort flag so that we do not transmit another release complete on this channel once FS core is done */ } break; + case FTDM_CHANNEL_STATE_RESET: + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Processing SETUP but channel in RESET state, ignoring\n"); + break; default: ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "Received RELEASE in an invalid state (%s)\n", ftdm_channel_state2str(ftdmchan->state)); @@ -757,14 +797,14 @@ void sngisdn_process_fac_ind (sngisdn_event_data_t *sngisdn_event) { ftdm_sigmsg_t sigev; if (facEvnt->facElmt.facStr.pres) { - get_facility_ie_str(ftdmchan, &facEvnt->facElmt.facStr.val[2], facEvnt->facElmt.facStr.len); + get_facility_ie_str(ftdmchan, &facEvnt->facElmt.facStr.val[2], facEvnt->facElmt.facStr.len-2); } 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_MSG; + sigev.event_id = FTDM_SIGEVENT_FACILITY; ftdm_span_send_signal(ftdmchan->span, &sigev); } break; @@ -884,6 +924,7 @@ void sngisdn_process_sta_cfm (sngisdn_event_data_t *sngisdn_event) break; case FTDM_CHANNEL_STATE_PROCEED: case FTDM_CHANNEL_STATE_PROGRESS: + case FTDM_CHANNEL_STATE_RINGING: case FTDM_CHANNEL_STATE_PROGRESS_MEDIA: ftdm_log_chan_msg(ftdmchan, FTDM_LOG_WARNING, "Remote switch expecting OVERLAP receive, but we are already PROCEEDING\n"); sngisdn_snd_disconnect(ftdmchan); @@ -902,6 +943,7 @@ void sngisdn_process_sta_cfm (sngisdn_event_data_t *sngisdn_event) switch (ftdmchan->state) { case FTDM_CHANNEL_STATE_PROCEED: case FTDM_CHANNEL_STATE_PROGRESS: + case FTDM_CHANNEL_STATE_RINGING: /* T310 timer has expired */ ftdmchan->caller_data.hangup_cause = staEvnt->causeDgn[0].causeVal.val; ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "T310 Timer expired, hanging up call\n"); @@ -938,6 +980,7 @@ void sngisdn_process_sta_cfm (sngisdn_event_data_t *sngisdn_event) break; case 9: /* Remote switch is in "Incoming call proceeding" state */ switch (ftdmchan->state) { + case FTDM_CHANNEL_STATE_RINGING: case FTDM_CHANNEL_STATE_PROGRESS: case FTDM_CHANNEL_STATE_PROGRESS_MEDIA: case FTDM_CHANNEL_STATE_GET_CALLERID: @@ -1047,18 +1090,91 @@ void sngisdn_process_srv_cfm (sngisdn_event_data_t *sngisdn_event) return; } +static void sngisdn_process_restart_confirm(ftdm_channel_t *ftdmchan) +{ + switch (ftdmchan->state) { + case FTDM_CHANNEL_STATE_RESET: + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DOWN); + break; + case FTDM_CHANNEL_STATE_DOWN: + /* Do nothing */ + break; + default: + ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "Received RESTART CFM in an invalid state (%s)\n", + ftdm_channel_state2str(ftdmchan->state)); + } + + return; +} + + void sngisdn_process_rst_cfm (sngisdn_event_data_t *sngisdn_event) { 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;*/ + uint8_t chan_no = 0; + Rst *rstEvnt = &sngisdn_event->event.rstEvnt; + sngisdn_span_data_t *signal_data = g_sngisdn_data.dchans[dChan].spans[1]; + if (!signal_data) { + ftdm_log(FTDM_LOG_CRIT, "Received RESTART on unconfigured span (suId:%d)\n", suId); + return; + } + + if (!rstEvnt->rstInd.eh.pres || !rstEvnt->rstInd.rstClass.pres) { + ftdm_log(FTDM_LOG_DEBUG, "Receved RESTART, but Restart Indicator IE not present\n"); + return; + } + + switch(rstEvnt->rstInd.rstClass.val) { + case IN_CL_INDCHAN: /* Indicated b-channel */ + if (rstEvnt->chanId.eh.pres) { + if (rstEvnt->chanId.intType.val == IN_IT_BASIC) { + if (rstEvnt->chanId.infoChanSel.pres == PRSNT_NODEF) { + chan_no = rstEvnt->chanId.infoChanSel.val; + } + } else if (rstEvnt->chanId.intType.val == IN_IT_OTHER) { + if (rstEvnt->chanId.chanNmbSlotMap.pres == PRSNT_NODEF) { + chan_no = rstEvnt->chanId.chanNmbSlotMap.val[0]; + } + } + } + if (!chan_no) { + ftdm_log(FTDM_LOG_CRIT, "Failed to determine channel from RESTART\n"); + return; + } + break; + case IN_CL_SNGINT: /* Single interface */ + case IN_CL_ALLINT: /* All interfaces */ + /* In case restart class indicates all interfaces, we will duplicate + this event on each span associated to this d-channel in sngisdn_rcv_rst_cfm, + so treat it as a single interface anyway */ + break; + default: + ftdm_log(FTDM_LOG_CRIT, "Invalid restart indicator class:%d\n", rstEvnt->rstInd.rstClass.val); + return; + } + + if (chan_no) { /* For a single channel */ + if (chan_no > ftdm_span_get_chan_count(signal_data->ftdm_span)) { + ftdm_log(FTDM_LOG_CRIT, "Received RESTART on invalid channel:%d\n", chan_no); + } else { + ftdm_channel_t *ftdmchan = ftdm_span_get_channel(signal_data->ftdm_span, chan_no); + sngisdn_process_restart_confirm(ftdmchan); + } + } else { /* for all channels */ + ftdm_iterator_t *chaniter = NULL; + ftdm_iterator_t *curr = NULL; + + chaniter = ftdm_span_get_chan_iterator(signal_data->ftdm_span, NULL); + for (curr = chaniter; curr; curr = ftdm_iterator_next(curr)) { + sngisdn_process_restart_confirm((ftdm_channel_t*)ftdm_iterator_current(curr)); + } + ftdm_iterator_free(chaniter); + } + ftdm_log(FTDM_LOG_DEBUG, "Processing RESTART CFM (suId:%u dChan:%d ces:%d type:%d)\n", suId, dChan, ces, evntType); ISDN_FUNC_TRACE_EXIT(__FUNCTION__); return; @@ -1087,7 +1203,7 @@ void sngisdn_process_rst_ind (sngisdn_event_data_t *sngisdn_event) return; } -ftdm_status_t sngisdn_cause_val_requires_disconnect(ftdm_channel_t *ftdmchan, CauseDgn *causeDgn) +static ftdm_status_t sngisdn_cause_val_requires_disconnect(ftdm_channel_t *ftdmchan, CauseDgn *causeDgn) { sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) ftdmchan->span->signal_data; diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_out.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_out.c index 38bbdb6968..bb04f887ab 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_out.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_out.c @@ -51,72 +51,6 @@ void sngisdn_snd_setup(ftdm_channel_t *ftdmchan) ftdm_mutex_unlock(g_sngisdn_data.ccs[signal_data->cc_id].mutex); memset(&conEvnt, 0, sizeof(conEvnt)); - - conEvnt.bearCap[0].eh.pres = PRSNT_NODEF; - conEvnt.bearCap[0].infoTranCap.pres = PRSNT_NODEF; - conEvnt.bearCap[0].infoTranCap.val = sngisdn_get_infoTranCap_from_user(ftdmchan->caller_data.bearer_capability); - - conEvnt.bearCap[0].codeStand0.pres = PRSNT_NODEF; - conEvnt.bearCap[0].codeStand0.val = IN_CSTD_CCITT; - conEvnt.bearCap[0].infoTranRate0.pres = PRSNT_NODEF; - conEvnt.bearCap[0].infoTranRate0.val = IN_ITR_64KBIT; - conEvnt.bearCap[0].tranMode.pres = PRSNT_NODEF; - conEvnt.bearCap[0].tranMode.val = IN_TM_CIRCUIT; - - conEvnt.chanId.eh.pres = PRSNT_NODEF; - conEvnt.chanId.prefExc.pres = PRSNT_NODEF; - conEvnt.chanId.prefExc.val = IN_PE_EXCLSVE; - conEvnt.chanId.dChanInd.pres = PRSNT_NODEF; - conEvnt.chanId.dChanInd.val = IN_DSI_NOTDCHAN; - conEvnt.chanId.intIdentPres.pres = PRSNT_NODEF; - conEvnt.chanId.intIdentPres.val = IN_IIP_IMPLICIT; - conEvnt.chanId.intIdent.pres = NOTPRSNT; - - if (ftdmchan->span->trunk_type == FTDM_TRUNK_BRI || - ftdmchan->span->trunk_type == FTDM_TRUNK_BRI_PTMP) { - /* Trillium stack rejests lyr1Ident on BRI, but Netbricks always sends it. - Check with Trillium if this ever causes calls to fail in the field */ - - /* BRI only params */ - conEvnt.chanId.intType.pres = PRSNT_NODEF; - conEvnt.chanId.intType.val = IN_IT_BASIC; - conEvnt.chanId.infoChanSel.pres = PRSNT_NODEF; - conEvnt.chanId.infoChanSel.val = ftdmchan->physical_chan_id; - } else { - /* PRI only params */ - conEvnt.bearCap[0].usrInfoLyr1Prot.pres = PRSNT_NODEF; - conEvnt.bearCap[0].usrInfoLyr1Prot.val = sngisdn_get_usrInfoLyr1Prot_from_user(ftdmchan->caller_data.bearer_layer1); - - if (signal_data->switchtype == SNGISDN_SWITCH_EUROISDN && - conEvnt.bearCap[0].usrInfoLyr1Prot.val == IN_UIL1_G711ULAW) { - - /* We are bridging a call from T1 */ - conEvnt.bearCap[0].usrInfoLyr1Prot.val = IN_UIL1_G711ALAW; - - } else if (conEvnt.bearCap[0].usrInfoLyr1Prot.val == IN_UIL1_G711ALAW) { - - /* We are bridging a call from E1 */ - conEvnt.bearCap[0].usrInfoLyr1Prot.val = IN_UIL1_G711ULAW; - } - - conEvnt.bearCap[0].lyr1Ident.pres = PRSNT_NODEF; - conEvnt.bearCap[0].lyr1Ident.val = IN_L1_IDENT; - - conEvnt.chanId.intType.pres = PRSNT_NODEF; - conEvnt.chanId.intType.val = IN_IT_OTHER; - conEvnt.chanId.infoChanSel.pres = PRSNT_NODEF; - conEvnt.chanId.infoChanSel.val = IN_ICS_B1CHAN; - conEvnt.chanId.chanMapType.pres = PRSNT_NODEF; - conEvnt.chanId.chanMapType.val = IN_CMT_BCHAN; - conEvnt.chanId.nmbMap.pres = PRSNT_NODEF; - conEvnt.chanId.nmbMap.val = IN_NM_CHNNMB; - conEvnt.chanId.codeStand1.pres = PRSNT_NODEF; - conEvnt.chanId.codeStand1.val = IN_CSTD_CCITT; - conEvnt.chanId.chanNmbSlotMap.pres = PRSNT_NODEF; - conEvnt.chanId.chanNmbSlotMap.len = 1; - conEvnt.chanId.chanNmbSlotMap.val[0] = ftdmchan->physical_chan_id; - } - if (signal_data->switchtype == SNGISDN_SWITCH_EUROISDN) { conEvnt.sndCmplt.eh.pres = PRSNT_NODEF; } @@ -126,8 +60,11 @@ void sngisdn_snd_setup(ftdm_channel_t *ftdmchan) } ftdm_log_chan(sngisdn_info->ftdmchan, FTDM_LOG_INFO, "Outgoing call: Called No:[%s] Calling No:[%s]\n", ftdmchan->caller_data.dnis.digits, ftdmchan->caller_data.cid_num.digits); + set_chan_id_ie(ftdmchan, &conEvnt.chanId); + set_bear_cap_ie(ftdmchan, &conEvnt.bearCap[0]); set_called_num(ftdmchan, &conEvnt.cdPtyNmb); set_calling_num(ftdmchan, &conEvnt.cgPtyNmb); + set_calling_num2(ftdmchan, &conEvnt.cgPtyNmb2); set_calling_subaddr(ftdmchan, &conEvnt.cgPtySad); set_redir_num(ftdmchan, &conEvnt.redirNmb); set_calling_name(ftdmchan, &conEvnt); @@ -160,38 +97,7 @@ void sngisdn_snd_setup_ack(ftdm_channel_t *ftdmchan) memset(&cnStEvnt, 0, sizeof(cnStEvnt)); - cnStEvnt.chanId.eh.pres = PRSNT_NODEF; - cnStEvnt.chanId.prefExc.pres = PRSNT_NODEF; - cnStEvnt.chanId.prefExc.val = IN_PE_EXCLSVE; - cnStEvnt.chanId.dChanInd.pres = PRSNT_NODEF; - cnStEvnt.chanId.dChanInd.val = IN_DSI_NOTDCHAN; - cnStEvnt.chanId.intIdentPres.pres = PRSNT_NODEF; - cnStEvnt.chanId.intIdentPres.val = IN_IIP_IMPLICIT; - - if (ftdmchan->span->trunk_type == FTDM_TRUNK_BRI || - ftdmchan->span->trunk_type == FTDM_TRUNK_BRI_PTMP) { - - /* BRI only params */ - cnStEvnt.chanId.intType.pres = PRSNT_NODEF; - cnStEvnt.chanId.intType.val = IN_IT_BASIC; - cnStEvnt.chanId.infoChanSel.pres = PRSNT_NODEF; - cnStEvnt.chanId.infoChanSel.val = ftdmchan->physical_chan_id; - } else { - cnStEvnt.chanId.intType.pres = PRSNT_NODEF; - cnStEvnt.chanId.intType.val = IN_IT_OTHER; - cnStEvnt.chanId.infoChanSel.pres = PRSNT_NODEF; - cnStEvnt.chanId.infoChanSel.val = IN_ICS_B1CHAN; - cnStEvnt.chanId.chanMapType.pres = PRSNT_NODEF; - cnStEvnt.chanId.chanMapType.val = IN_CMT_BCHAN; - cnStEvnt.chanId.nmbMap.pres = PRSNT_NODEF; - cnStEvnt.chanId.nmbMap.val = IN_NM_CHNNMB; - cnStEvnt.chanId.codeStand1.pres = PRSNT_NODEF; - cnStEvnt.chanId.codeStand1.val = IN_CSTD_CCITT; - cnStEvnt.chanId.chanNmbSlotMap.pres = PRSNT_NODEF; - cnStEvnt.chanId.chanNmbSlotMap.len = 1; - cnStEvnt.chanId.chanNmbSlotMap.val[0] = ftdmchan->physical_chan_id; - } ftdm_log_chan(ftdmchan, FTDM_LOG_INFO, "Sending SETUP ACK (suId:%d suInstId:%u spInstId:%u dchan:%d ces:%d)\n", signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId, signal_data->dchan_id, sngisdn_info->ces); @@ -220,38 +126,7 @@ void sngisdn_snd_con_complete(ftdm_channel_t *ftdmchan) memset(&cnStEvnt, 0, sizeof(cnStEvnt)); - cnStEvnt.chanId.eh.pres = PRSNT_NODEF; - cnStEvnt.chanId.prefExc.pres = PRSNT_NODEF; - cnStEvnt.chanId.prefExc.val = IN_PE_EXCLSVE; - cnStEvnt.chanId.dChanInd.pres = PRSNT_NODEF; - cnStEvnt.chanId.dChanInd.val = IN_DSI_NOTDCHAN; - cnStEvnt.chanId.intIdentPres.pres = PRSNT_NODEF; - cnStEvnt.chanId.intIdentPres.val = IN_IIP_IMPLICIT; - - if (ftdmchan->span->trunk_type == FTDM_TRUNK_BRI || - ftdmchan->span->trunk_type == FTDM_TRUNK_BRI_PTMP) { - - /* BRI only params */ - cnStEvnt.chanId.intType.pres = PRSNT_NODEF; - cnStEvnt.chanId.intType.val = IN_IT_BASIC; - cnStEvnt.chanId.infoChanSel.pres = PRSNT_NODEF; - cnStEvnt.chanId.infoChanSel.val = ftdmchan->physical_chan_id; - } else { - cnStEvnt.chanId.intType.pres = PRSNT_NODEF; - cnStEvnt.chanId.intType.val = IN_IT_OTHER; - cnStEvnt.chanId.infoChanSel.pres = PRSNT_NODEF; - cnStEvnt.chanId.infoChanSel.val = IN_ICS_B1CHAN; - cnStEvnt.chanId.chanMapType.pres = PRSNT_NODEF; - cnStEvnt.chanId.chanMapType.val = IN_CMT_BCHAN; - cnStEvnt.chanId.nmbMap.pres = PRSNT_NODEF; - cnStEvnt.chanId.nmbMap.val = IN_NM_CHNNMB; - cnStEvnt.chanId.codeStand1.pres = PRSNT_NODEF; - cnStEvnt.chanId.codeStand1.val = IN_CSTD_CCITT; - cnStEvnt.chanId.chanNmbSlotMap.pres = PRSNT_NODEF; - cnStEvnt.chanId.chanNmbSlotMap.len = 1; - cnStEvnt.chanId.chanNmbSlotMap.val[0] = ftdmchan->physical_chan_id; - } - + set_chan_id_ie(ftdmchan, &cnStEvnt.chanId); ftdm_log_chan(ftdmchan, FTDM_LOG_INFO, "Sending CONNECT COMPL (suId:%d suInstId:%u spInstId:%u dchan:%d ces:%d)\n", signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId, signal_data->dchan_id, sngisdn_info->ces); @@ -262,10 +137,9 @@ void sngisdn_snd_con_complete(ftdm_channel_t *ftdmchan) } -void sngisdn_snd_proceed(ftdm_channel_t *ftdmchan) +void sngisdn_snd_proceed(ftdm_channel_t *ftdmchan, ftdm_sngisdn_progind_t prog_ind) { CnStEvnt cnStEvnt; - sngisdn_chan_data_t *sngisdn_info = (sngisdn_chan_data_t*) ftdmchan->call_data; sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) ftdmchan->span->signal_data; @@ -277,40 +151,12 @@ void sngisdn_snd_proceed(ftdm_channel_t *ftdmchan) } memset(&cnStEvnt, 0, sizeof(cnStEvnt)); - - cnStEvnt.chanId.eh.pres = PRSNT_NODEF; - cnStEvnt.chanId.prefExc.pres = PRSNT_NODEF; - cnStEvnt.chanId.prefExc.val = IN_PE_EXCLSVE; - cnStEvnt.chanId.dChanInd.pres = PRSNT_NODEF; - cnStEvnt.chanId.dChanInd.val = IN_DSI_NOTDCHAN; - cnStEvnt.chanId.intIdentPres.pres = PRSNT_NODEF; - cnStEvnt.chanId.intIdentPres.val = IN_IIP_IMPLICIT; - - if (ftdmchan->span->trunk_type == FTDM_TRUNK_BRI || - ftdmchan->span->trunk_type == FTDM_TRUNK_BRI_PTMP) { - - /* BRI only params */ - cnStEvnt.chanId.intType.pres = PRSNT_NODEF; - cnStEvnt.chanId.intType.val = IN_IT_BASIC; - cnStEvnt.chanId.infoChanSel.pres = PRSNT_NODEF; - cnStEvnt.chanId.infoChanSel.val = ftdmchan->physical_chan_id; - } else { - cnStEvnt.chanId.intType.pres = PRSNT_NODEF; - cnStEvnt.chanId.intType.val = IN_IT_OTHER; - cnStEvnt.chanId.infoChanSel.pres = PRSNT_NODEF; - cnStEvnt.chanId.infoChanSel.val = IN_ICS_B1CHAN; - cnStEvnt.chanId.chanMapType.pres = PRSNT_NODEF; - cnStEvnt.chanId.chanMapType.val = IN_CMT_BCHAN; - cnStEvnt.chanId.nmbMap.pres = PRSNT_NODEF; - cnStEvnt.chanId.nmbMap.val = IN_NM_CHNNMB; - cnStEvnt.chanId.codeStand1.pres = PRSNT_NODEF; - cnStEvnt.chanId.codeStand1.val = IN_CSTD_CCITT; - cnStEvnt.chanId.chanNmbSlotMap.pres = PRSNT_NODEF; - cnStEvnt.chanId.chanNmbSlotMap.len = 1; - cnStEvnt.chanId.chanNmbSlotMap.val[0] = ftdmchan->physical_chan_id; - } + set_chan_id_ie(ftdmchan, &cnStEvnt.chanId); + set_prog_ind_ie(ftdmchan, &cnStEvnt.progInd, prog_ind); set_facility_ie(ftdmchan, &cnStEvnt.facilityStr); + + ftdm_call_clear_data(&ftdmchan->caller_data); ftdm_log_chan(ftdmchan, FTDM_LOG_INFO, "Sending PROCEED (suId:%d suInstId:%u spInstId:%u dchan:%d ces:%d)\n", signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId, signal_data->dchan_id, sngisdn_info->ces); @@ -343,6 +189,7 @@ void sngisdn_snd_progress(ftdm_channel_t *ftdmchan, ftdm_sngisdn_progind_t prog_ memset(&cnStEvnt, 0, sizeof(cnStEvnt)); set_prog_ind_ie(ftdmchan, &cnStEvnt.progInd, prog_ind); set_facility_ie(ftdmchan, &cnStEvnt.facilityStr); + ftdm_call_clear_data(&ftdmchan->caller_data); ftdm_log_chan(ftdmchan, FTDM_LOG_INFO, "Sending PROGRESS (suId:%d suInstId:%u spInstId:%u dchan:%d ces:%d)\n", signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId, signal_data->dchan_id, sngisdn_info->ces); if(sng_isdn_con_status(signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId,&cnStEvnt, MI_PROGRESS, signal_data->dchan_id, sngisdn_info->ces)) { @@ -369,6 +216,7 @@ void sngisdn_snd_alert(ftdm_channel_t *ftdmchan, ftdm_sngisdn_progind_t prog_ind set_prog_ind_ie(ftdmchan, &cnStEvnt.progInd, prog_ind); set_facility_ie(ftdmchan, &cnStEvnt.facilityStr); + ftdm_call_clear_data(&ftdmchan->caller_data); ftdm_log_chan(ftdmchan, FTDM_LOG_INFO, "Sending ALERT (suId:%d suInstId:%u spInstId:%u dchan:%d ces:%d)\n", signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId, signal_data->dchan_id, sngisdn_info->ces); @@ -393,41 +241,11 @@ void sngisdn_snd_connect(ftdm_channel_t *ftdmchan) } memset(&cnStEvnt, 0, sizeof(cnStEvnt)); - - cnStEvnt.chanId.eh.pres = PRSNT_NODEF; - cnStEvnt.chanId.prefExc.pres = PRSNT_NODEF; - cnStEvnt.chanId.prefExc.val = IN_PE_EXCLSVE; - cnStEvnt.chanId.dChanInd.pres = PRSNT_NODEF; - cnStEvnt.chanId.dChanInd.val = IN_DSI_NOTDCHAN; - cnStEvnt.chanId.intIdentPres.pres = PRSNT_NODEF; - cnStEvnt.chanId.intIdentPres.val = IN_IIP_IMPLICIT; - if (ftdmchan->span->trunk_type == FTDM_TRUNK_BRI || - ftdmchan->span->trunk_type == FTDM_TRUNK_BRI_PTMP) { - - /* BRI only params */ - cnStEvnt.chanId.intType.pres = PRSNT_NODEF; - cnStEvnt.chanId.intType.val = IN_IT_BASIC; - cnStEvnt.chanId.infoChanSel.pres = PRSNT_NODEF; - cnStEvnt.chanId.infoChanSel.val = ftdmchan->physical_chan_id; - } else { - cnStEvnt.chanId.intType.pres = PRSNT_NODEF; - cnStEvnt.chanId.intType.val = IN_IT_OTHER; - cnStEvnt.chanId.infoChanSel.pres = PRSNT_NODEF; - cnStEvnt.chanId.infoChanSel.val = IN_ICS_B1CHAN; - cnStEvnt.chanId.chanMapType.pres = PRSNT_NODEF; - cnStEvnt.chanId.chanMapType.val = IN_CMT_BCHAN; - cnStEvnt.chanId.nmbMap.pres = PRSNT_NODEF; - cnStEvnt.chanId.nmbMap.val = IN_NM_CHNNMB; - cnStEvnt.chanId.codeStand1.pres = PRSNT_NODEF; - cnStEvnt.chanId.codeStand1.val = IN_CSTD_CCITT; - cnStEvnt.chanId.chanNmbSlotMap.pres = PRSNT_NODEF; - cnStEvnt.chanId.chanNmbSlotMap.len = 1; - cnStEvnt.chanId.chanNmbSlotMap.val[0] = ftdmchan->physical_chan_id; - } - + set_chan_id_ie(ftdmchan, &cnStEvnt.chanId); set_prog_ind_ie(ftdmchan, &cnStEvnt.progInd, prog_ind); set_facility_ie(ftdmchan, &cnStEvnt.facilityStr); + ftdm_call_clear_data(&ftdmchan->caller_data); ftdm_log_chan(ftdmchan, FTDM_LOG_INFO, "Sending CONNECT (suId:%d suInstId:%u spInstId:%u dchan:%d ces:%d)\n", signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId, signal_data->dchan_id, sngisdn_info->ces); if (sng_isdn_con_response(signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId, &cnStEvnt, signal_data->dchan_id, sngisdn_info->ces)) { @@ -450,10 +268,17 @@ void sngisdn_snd_fac_req(ftdm_channel_t *ftdmchan) memset(&facEvnt, 0, sizeof(facEvnt)); - set_facility_ie_str(ftdmchan, &facEvnt.facElmt.facStr.val[2], (ftdm_size_t*)&facEvnt.facElmt.facStr.len); + if (set_facility_ie_str(ftdmchan, &facEvnt.facElmt.facStr.val[2], (uint8_t*)&facEvnt.facElmt.facStr.len) != FTDM_SUCCESS) { + /* No point in sending a FACILITY message if there is no Facility IE to transmit */ + return; + } + ftdm_call_clear_data(&ftdmchan->caller_data); + facEvnt.facElmt.eh.pres = PRSNT_NODEF; + facEvnt.facElmt.facStr.pres = PRSNT_NODEF; facEvnt.facElmt.facStr.val[0] = 0x1C; - facEvnt.facElmt.facStr.val[1] = facEvnt.facElmt.facStr.len; + facEvnt.facElmt.facStr.val[1] = (uint8_t)facEvnt.facElmt.facStr.len; + facEvnt.facElmt.facStr.len +=2; /* Need to include the size of identifier + len */ ftdm_log_chan(ftdmchan, FTDM_LOG_INFO, "Sending FACILITY (suId:%d suInstId:%u spInstId:%u dchan:%d ces:%d)\n", signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId, signal_data->dchan_id, sngisdn_info->ces); @@ -481,6 +306,8 @@ void sngisdn_snd_info_req(ftdm_channel_t *ftdmchan) //ftdm_log_chan_msg(ftdmchan, FTDM_LOG_INFO, "Sending INFO REQ\n"); + ftdm_call_clear_data(&ftdmchan->caller_data); + ftdm_log_chan(ftdmchan, FTDM_LOG_INFO, "Sending INFO REQ (suId:%d dchan:%d ces:%d)\n", signal_data->cc_id, signal_data->dchan_id, sngisdn_info->ces); if (sng_isdn_con_status(signal_data->cc_id, 0, 0, &cnStEvnt, MI_INFO, signal_data->dchan_id, sngisdn_info->ces)) { @@ -501,6 +328,8 @@ void sngisdn_snd_status_enq(ftdm_channel_t *ftdmchan) memset(&staEvnt, 0, sizeof(StaEvnt)); + ftdm_call_clear_data(&ftdmchan->caller_data); + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Sending Status ENQ on suId:%d suInstId:%u spInstId:%d dchan:%d ces:%d\n", signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId, signal_data->dchan_id, sngisdn_info->ces); if (sng_isdn_status_request(signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId, &staEvnt, MI_STATENQ)) { ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT, "stack refused Status ENQ request\n"); @@ -539,6 +368,7 @@ void sngisdn_snd_disconnect(ftdm_channel_t *ftdmchan) discEvnt.causeDgn[0].dgnVal.pres = NOTPRSNT; set_facility_ie(ftdmchan, &discEvnt.facilityStr); + ftdm_call_clear_data(&ftdmchan->caller_data); ftdm_log_chan(ftdmchan, FTDM_LOG_INFO, "Sending DISCONNECT (suId:%d suInstId:%u spInstId:%u)\n", signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId); if (sng_isdn_disc_request(signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId, &discEvnt)) { @@ -546,6 +376,7 @@ void sngisdn_snd_disconnect(ftdm_channel_t *ftdmchan) } return; } + void sngisdn_snd_release(ftdm_channel_t *ftdmchan, uint8_t glare) { RelEvnt relEvnt; @@ -585,6 +416,7 @@ void sngisdn_snd_release(ftdm_channel_t *ftdmchan, uint8_t glare) } set_facility_ie(ftdmchan, &relEvnt.facilityStr); + ftdm_call_clear_data(&ftdmchan->caller_data); ftdm_log_chan(ftdmchan, FTDM_LOG_INFO, "Sending RELEASE/RELEASE COMPLETE (suId:%d suInstId:%u spInstId:%u)\n", signal_data->cc_id, suInstId, spInstId); @@ -600,6 +432,24 @@ void sngisdn_snd_release(ftdm_channel_t *ftdmchan, uint8_t glare) return; } +void sngisdn_snd_restart(ftdm_channel_t *ftdmchan) +{ + Rst rstEvnt; + sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) ftdmchan->span->signal_data; + + memset(&rstEvnt, 0, sizeof(rstEvnt)); + + set_chan_id_ie(ftdmchan, &rstEvnt.chanId); + set_restart_ind_ie(ftdmchan, &rstEvnt.rstInd); + + ftdm_log_chan(ftdmchan, FTDM_LOG_INFO, "Sending RESTART (suId:%d dchan:%d ces:%d)\n", signal_data->cc_id, signal_data->dchan_id, CES_MNGMNT); + + if (sng_isdn_restart_request(signal_data->cc_id, &rstEvnt, signal_data->dchan_id, CES_MNGMNT, IN_SND_RST)) { + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT, "stack refused RESTART request\n"); + } + return; +} + /* We received an incoming frame on the d-channel, send data to the stack */ void sngisdn_snd_data(ftdm_channel_t *dchan, uint8_t *data, ftdm_size_t len) 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 af180d1f7c..3afdaa599e 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 @@ -34,9 +34,6 @@ #include "ftmod_sangoma_isdn.h" -#define MAX_DECODE_STR_LEN 2000 - - void sngisdn_rcv_con_ind (int16_t suId, uint32_t suInstId, uint32_t spInstId, ConEvnt *conEvnt, int16_t dChan, uint8_t ces) { uint8_t bchan_no = 0; @@ -630,8 +627,9 @@ void sngisdn_rcv_rst_cfm (int16_t suId, Rst *rstEvnt, int16_t dChan, uint8_t ces 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 */ for(i=1; i<=g_sngisdn_data.dchans[dChan].num_spans; i++) { signal_data = g_sngisdn_data.dchans[dChan].spans[i]; @@ -725,14 +723,25 @@ void sngisdn_rcv_q931_ind(InMngmt *status) ftdmspan = signal_data->ftdm_span; if (status->t.usta.alarm.event == LCM_EVENT_UP) { + uint32_t chan_no = status->t.usta.evntParm[2]; ftdm_log(FTDM_LOG_INFO, "[SNGISDN Q931] s%d: %s: %s(%d): %s(%d)\n", status->t.usta.suId, DECODE_LCM_CATEGORY(status->t.usta.alarm.category), DECODE_LCM_EVENT(status->t.usta.alarm.event), status->t.usta.alarm.event, DECODE_LCM_CAUSE(status->t.usta.alarm.cause), status->t.usta.alarm.cause); - - sngisdn_set_span_sig_status(ftdmspan, FTDM_SIG_STATE_UP); - sngisdn_set_avail_rate(ftdmspan, SNGISDN_AVAIL_UP); + + if (chan_no) { + ftdm_channel_t *ftdmchan = ftdm_span_get_channel(ftdmspan, chan_no); + if (ftdmchan) { + sngisdn_set_chan_sig_status(ftdmchan, FTDM_SIG_STATE_UP); + sngisdn_set_chan_avail_rate(ftdmchan, SNGISDN_AVAIL_UP); + } else { + ftdm_log(FTDM_LOG_CRIT, "stack alarm event on invalid channel :%d\n", chan_no); + } + } else { + sngisdn_set_span_sig_status(ftdmspan, FTDM_SIG_STATE_UP); + sngisdn_set_span_avail_rate(ftdmspan, SNGISDN_AVAIL_UP); + } } else { ftdm_log(FTDM_LOG_WARNING, "[SNGISDN Q931] s%d: %s: %s(%d): %s(%d)\n", status->t.usta.suId, @@ -741,7 +750,7 @@ void sngisdn_rcv_q931_ind(InMngmt *status) DECODE_LCM_CAUSE(status->t.usta.alarm.cause), status->t.usta.alarm.cause); sngisdn_set_span_sig_status(ftdmspan, FTDM_SIG_STATE_DOWN); - sngisdn_set_avail_rate(ftdmspan, SNGISDN_AVAIL_PWR_SAVING); + sngisdn_set_span_avail_rate(ftdmspan, SNGISDN_AVAIL_PWR_SAVING); } } break; @@ -765,9 +774,6 @@ void sngisdn_rcv_cc_ind(CcMngmt *status) return; } -#define Q931_TRC_EVENT(event) (event == TL3PKTTX)?"TX": \ - (event == TL3PKTRX)?"RX":"UNKNOWN" - void sngisdn_rcv_q931_trace(InMngmt *trc, Buffer *mBuf) { MsgLen mlen; @@ -776,13 +782,20 @@ void sngisdn_rcv_q931_trace(InMngmt *trc, Buffer *mBuf) Buffer *tmp; Data *cptr; uint8_t data; + ftdm_trace_dir_t dir; uint8_t tdata[1000]; - char *data_str = ftdm_calloc(1,MAX_DECODE_STR_LEN); /* TODO Find a proper size */ - + sngisdn_span_data_t *signal_data = g_sngisdn_data.spans[trc->t.trc.suId]; + ftdm_assert(mBuf != NULLP, "Received a Q931 trace with no buffer"); mlen = ((SsMsgInfo*)(mBuf->b_rptr))->len; - - if (mlen != 0) { + + if (trc->t.trc.evnt == TL3PKTTX) { + dir = FTDM_TRACE_OUTGOING; + } else { + dir = FTDM_TRACE_INCOMING; + } + + if (mlen) { tmp = mBuf->b_cont; cptr = tmp->b_rptr; data = *cptr++; @@ -797,41 +810,40 @@ void sngisdn_rcv_q931_trace(InMngmt *trc, Buffer *mBuf) } data = *cptr++; } - - sngisdn_trace_q931(data_str, tdata, mlen); - ftdm_log(FTDM_LOG_INFO, "[SNGISDN Q931] s%d FRAME %s:%s\n", trc->t.trc.suId, Q931_TRC_EVENT(trc->t.trc.evnt), data_str); + if (signal_data->raw_trace_q931 == SNGISDN_OPT_TRUE) { + sngisdn_trace_raw_q931(signal_data, dir, tdata, mlen); + } else { + sngisdn_trace_interpreted_q931(signal_data, dir, tdata, mlen); + } } - - ftdm_safe_free(data_str); - /* We do not need to free mBuf in this case because stack does it */ - /* SPutMsg(mBuf); */ return; } -#define Q921_TRC_EVENT(event) (event == TL2FRMRX)?"RX": \ - (event == TL2FRMTX)?"TX": \ - (event == TL2TMR)?"TMR EXPIRED":"UNKNOWN" - void sngisdn_rcv_q921_trace(BdMngmt *trc, Buffer *mBuf) { MsgLen mlen; + Buffer *tmp; MsgLen i; int16_t j; - Buffer *tmp; Data *cptr; uint8_t data; - uint8_t tdata[16]; - char *data_str = ftdm_calloc(1,200); /* TODO Find a proper size */ - + ftdm_trace_dir_t dir; + uint8_t tdata[1000]; + sngisdn_span_data_t *signal_data = g_sngisdn_data.spans[trc->t.trc.lnkNmb]; if (trc->t.trc.evnt == TL2TMR) { - goto end_of_trace; + return; } + if (trc->t.trc.evnt == TL2FRMTX) { + dir = FTDM_TRACE_OUTGOING; + } else { + dir = FTDM_TRACE_INCOMING; + } + ftdm_assert(mBuf != NULLP, "Received a Q921 trace with no buffer"); mlen = ((SsMsgInfo*)(mBuf->b_rptr))->len; - if (mlen != 0) { tmp = mBuf->b_cont; cptr = tmp->b_rptr; @@ -853,12 +865,12 @@ void sngisdn_rcv_q921_trace(BdMngmt *trc, Buffer *mBuf) } } - sngisdn_trace_q921(data_str, tdata, mlen); - ftdm_log(FTDM_LOG_INFO, "[SNGISDN Q921] s%d FRAME %s:%s\n", trc->t.trc.lnkNmb, Q921_TRC_EVENT(trc->t.trc.evnt), data_str); + if (signal_data->raw_trace_q921 == SNGISDN_OPT_TRUE) { + sngisdn_trace_raw_q921(signal_data, dir, tdata, mlen); + } else { + sngisdn_trace_interpreted_q921(signal_data, dir, tdata, mlen); + } } -end_of_trace: - ftdm_safe_free(data_str); - SPutMsg(mBuf); return; } 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 fae25c9ad6..28768a1f09 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 @@ -136,19 +136,25 @@ ftdm_status_t get_ftdmchan_by_spInstId(int16_t cc_id, uint32_t spInstId, sngisdn return FTDM_SUCCESS; } -ftdm_status_t sngisdn_set_avail_rate(ftdm_span_t *span, sngisdn_avail_t avail) +ftdm_status_t sngisdn_set_chan_avail_rate(ftdm_channel_t *chan, sngisdn_avail_t avail) { - if (span->trunk_type == FTDM_TRUNK_BRI || - span->trunk_type == FTDM_TRUNK_BRI_PTMP) { + if (FTDM_SPAN_IS_BRI(chan->span)) { + ftdm_log_chan(chan, FTDM_LOG_DEBUG, "Setting availability rate to:%d\n", avail); + chan->availability_rate = avail; + } + return FTDM_SUCCESS; +} +ftdm_status_t sngisdn_set_span_avail_rate(ftdm_span_t *span, sngisdn_avail_t avail) +{ + if (FTDM_SPAN_IS_BRI(span)) { ftdm_iterator_t *chaniter = NULL; ftdm_iterator_t *curr = NULL; - chaniter = ftdm_span_get_chan_iterator(span, NULL); for (curr = chaniter; curr; curr = ftdm_iterator_next(curr)) { ftdm_log_chan(((ftdm_channel_t*)ftdm_iterator_current(curr)), FTDM_LOG_DEBUG, "Setting availability rate to:%d\n", avail); - ((ftdm_channel_t*)ftdm_iterator_current(curr))->availability_rate = avail; + sngisdn_set_chan_avail_rate(((ftdm_channel_t*)ftdm_iterator_current(curr)), avail); } ftdm_iterator_free(chaniter); } @@ -185,6 +191,39 @@ ftdm_status_t get_calling_num(ftdm_channel_t *ftdmchan, CgPtyNmb *cgPtyNmb) return FTDM_SUCCESS; } +ftdm_status_t get_calling_num2(ftdm_channel_t *ftdmchan, CgPtyNmb *cgPtyNmb) +{ + ftdm_caller_data_t *caller_data = &ftdmchan->caller_data; + if (cgPtyNmb->eh.pres != PRSNT_NODEF) { + return FTDM_FAIL; + } + + if (cgPtyNmb->screenInd.pres == PRSNT_NODEF) { + ftdm_call_add_var(caller_data, "isdn.cg_pty2.screen_ind", ftdm_screening2str(cgPtyNmb->screenInd.val)); + } + + if (cgPtyNmb->presInd0.pres == PRSNT_NODEF) { + ftdm_call_add_var(caller_data, "isdn.cg_pty2.presentation_ind", ftdm_presentation2str(cgPtyNmb->presInd0.val)); + } + + if (cgPtyNmb->nmbPlanId.pres == PRSNT_NODEF) { + ftdm_call_add_var(caller_data, "isdn.cg_pty2.npi", ftdm_npi2str(cgPtyNmb->nmbPlanId.val)); + } + + if (cgPtyNmb->typeNmb1.pres == PRSNT_NODEF) { + ftdm_call_add_var(caller_data, "isdn.cg_pty2.ton", ftdm_ton2str(cgPtyNmb->typeNmb1.val)); + } + + if (cgPtyNmb->nmbDigits.pres == PRSNT_NODEF) { + char digits_string [32]; + memcpy(digits_string, (const char*)cgPtyNmb->nmbDigits.val, cgPtyNmb->nmbDigits.len); + digits_string[cgPtyNmb->nmbDigits.len] = '\0'; + ftdm_call_add_var(caller_data, "isdn.cg_pty2.digits", digits_string); + } + memcpy(&caller_data->ani, &caller_data->cid_num, sizeof(caller_data->ani)); + return FTDM_SUCCESS; +} + ftdm_status_t get_called_num(ftdm_channel_t *ftdmchan, CdPtyNmb *cdPtyNmb) { ftdm_caller_data_t *caller_data = &ftdmchan->caller_data; @@ -278,7 +317,7 @@ ftdm_status_t get_calling_subaddr(ftdm_channel_t *ftdmchan, CgPtySad *cgPtySad) memcpy(subaddress, (char*)cgPtySad->sadInfo.val, cgPtySad->sadInfo.len); subaddress[cgPtySad->sadInfo.len] = '\0'; - ftdm_channel_add_var(ftdmchan, "isdn.calling_subaddr", subaddress); + ftdm_call_add_var(&ftdmchan->caller_data, "isdn.calling_subaddr", subaddress); return FTDM_SUCCESS; } @@ -291,17 +330,16 @@ ftdm_status_t get_facility_ie(ftdm_channel_t *ftdmchan, FacilityStr *facilityStr return get_facility_ie_str(ftdmchan, facilityStr->facilityStr.val, facilityStr->facilityStr.len); } -ftdm_status_t get_facility_ie_str(ftdm_channel_t *ftdmchan, uint8_t *data, ftdm_size_t data_len) +ftdm_status_t get_facility_ie_str(ftdm_channel_t *ftdmchan, uint8_t *data, uint8_t data_len) { ftdm_caller_data_t *caller_data = &ftdmchan->caller_data; sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) ftdmchan->span->signal_data; if (signal_data->facility_ie_decode == SNGISDN_OPT_FALSE) { - if (data_len > sizeof(caller_data->raw_data)-2) { - ftdm_log(FTDM_LOG_CRIT, "Length of Facility IE exceeds maximum length\n"); - return FTDM_FAIL; - } - + /* size of facilityStr->facilityStr.len is a uint8_t so no need to check + for overflow here as facilityStr->facilityStr.len will always be smaller + than sizeof(caller_data->raw_data) */ + memset(caller_data->raw_data, 0, sizeof(caller_data->raw_data)); /* Always include Facility IE identifier + len so this can be used as a sanity check by the user */ caller_data->raw_data[0] = SNGISDN_Q931_FACILITY_IE_ID; @@ -348,7 +386,7 @@ ftdm_status_t get_prog_ind_ie(ftdm_channel_t *ftdmchan, ProgInd *progInd) val = SNGISDN_PROGIND_DESCR_INVALID; break; } - ftdm_channel_add_var(ftdmchan, "isdn.prog_ind.descr", ftdm_sngisdn_progind_descr2str(val)); + ftdm_call_add_var(&ftdmchan->caller_data, "isdn.prog_ind.descr", ftdm_sngisdn_progind_descr2str(val)); } if (progInd->location.pres) { @@ -379,7 +417,7 @@ ftdm_status_t get_prog_ind_ie(ftdm_channel_t *ftdmchan, ProgInd *progInd) val = SNGISDN_PROGIND_LOC_INVALID; break; } - ftdm_channel_add_var(ftdmchan, "isdn.prog_ind.loc", ftdm_sngisdn_progind_loc2str(val)); + ftdm_call_add_var(&ftdmchan->caller_data, "isdn.prog_ind.loc", ftdm_sngisdn_progind_loc2str(val)); } return FTDM_SUCCESS; } @@ -423,6 +461,89 @@ ftdm_status_t set_calling_num(ftdm_channel_t *ftdmchan, CgPtyNmb *cgPtyNmb) return FTDM_SUCCESS; } +ftdm_status_t set_calling_num2(ftdm_channel_t *ftdmchan, CgPtyNmb *cgPtyNmb) +{ + const char* string = NULL; + uint8_t len,val; + ftdm_caller_data_t *caller_data = &ftdmchan->caller_data; + + string = ftdm_call_get_var(caller_data, "isdn.cg_pty2.digits"); + if ((string == NULL) || !(*string)) { + return FTDM_FAIL; + } + + cgPtyNmb->eh.pres = PRSNT_NODEF; + + len = strlen(string); + cgPtyNmb->nmbDigits.len = len; + + cgPtyNmb->nmbDigits.pres = PRSNT_NODEF; + memcpy(cgPtyNmb->nmbDigits.val, string, len); + + /* Screening Indicator */ + cgPtyNmb->screenInd.pres = PRSNT_NODEF; + + val = FTDM_SCREENING_INVALID; + string = ftdm_call_get_var(caller_data, "isdn.cg_pty2.screening_ind"); + if ((string != NULL) && (*string)) { + val = ftdm_str2ftdm_screening(string); + } + + /* isdn.cg_pty2.screen_ind does not exist or we could not parse its value */ + if (val == FTDM_SCREENING_INVALID) { + /* default to caller data screening ind */ + cgPtyNmb->screenInd.val = caller_data->screen; + } else { + cgPtyNmb->screenInd.val = val; + } + + /* Presentation Indicator */ + cgPtyNmb->presInd0.pres = PRSNT_NODEF; + + val = FTDM_PRES_INVALID; + string = ftdm_call_get_var(caller_data, "isdn.cg_pty2.presentation_ind"); + if ((string != NULL) && (*string)) { + val = ftdm_str2ftdm_presentation(string); + } + + if (val == FTDM_PRES_INVALID) { + cgPtyNmb->presInd0.val = caller_data->pres; + } else { + cgPtyNmb->presInd0.val = val; + } + + /* Numbering Plan Indicator */ + cgPtyNmb->nmbPlanId.pres = PRSNT_NODEF; + + val = FTDM_NPI_INVALID; + string = ftdm_call_get_var(caller_data, "isdn.cg_pty2.npi"); + if ((string != NULL) && (*string)) { + val = ftdm_str2ftdm_npi(string); + } + + if (val == FTDM_NPI_INVALID) { + cgPtyNmb->nmbPlanId.val = caller_data->cid_num.plan; + } else { + cgPtyNmb->nmbPlanId.val = val; + } + + cgPtyNmb->typeNmb1.pres = PRSNT_NODEF; + + /* Type of Number */ + val = FTDM_TON_INVALID; + string = ftdm_call_get_var(caller_data, "isdn.cg_pty2.ton"); + if ((string != NULL) && (*string)) { + val = ftdm_str2ftdm_ton(string); + } + + if (val == FTDM_TON_INVALID) { + cgPtyNmb->typeNmb1.val = caller_data->cid_num.type; + } else { + cgPtyNmb->typeNmb1.val = val; + } + return FTDM_SUCCESS; +} + ftdm_status_t set_called_num(ftdm_channel_t *ftdmchan, CdPtyNmb *cdPtyNmb) { ftdm_caller_data_t *caller_data = &ftdmchan->caller_data; @@ -544,7 +665,7 @@ ftdm_status_t set_calling_name(ftdm_channel_t *ftdmchan, ConEvnt *conEvnt) ftdm_status_t set_calling_subaddr(ftdm_channel_t *ftdmchan, CgPtySad *cgPtySad) { const char* clg_subaddr = NULL; - clg_subaddr = ftdm_channel_get_var(ftdmchan, "isdn.calling_subaddr"); + clg_subaddr = ftdm_call_get_var(&ftdmchan->caller_data, "isdn.calling_subaddr"); if ((clg_subaddr != NULL) && (*clg_subaddr)) { unsigned len = strlen (clg_subaddr); cgPtySad->eh.pres = PRSNT_NODEF; @@ -561,11 +682,10 @@ ftdm_status_t set_calling_subaddr(ftdm_channel_t *ftdmchan, CgPtySad *cgPtySad) return FTDM_SUCCESS; } - ftdm_status_t set_facility_ie(ftdm_channel_t *ftdmchan, FacilityStr *facilityStr) { ftdm_status_t status; - status = set_facility_ie_str(ftdmchan, facilityStr->facilityStr.val, (ftdm_size_t*)&facilityStr->facilityStr.len); + status = set_facility_ie_str(ftdmchan, facilityStr->facilityStr.val, (uint8_t*)&(facilityStr->facilityStr.len)); if (status == FTDM_SUCCESS) { facilityStr->eh.pres = PRSNT_NODEF; facilityStr->facilityStr.pres = PRSNT_NODEF; @@ -573,13 +693,15 @@ ftdm_status_t set_facility_ie(ftdm_channel_t *ftdmchan, FacilityStr *facilityStr return status; } -ftdm_status_t set_facility_ie_str(ftdm_channel_t *ftdmchan, uint8_t *data, ftdm_size_t *data_len) +ftdm_status_t set_facility_ie_str(ftdm_channel_t *ftdmchan, uint8_t *data, uint8_t *data_len) { + int len; ftdm_caller_data_t *caller_data = &ftdmchan->caller_data; if (caller_data->raw_data_len > 0 && caller_data->raw_data[0] == SNGISDN_Q931_FACILITY_IE_ID) { - *data_len = caller_data->raw_data[1]; - memcpy(data, &caller_data->raw_data[2], *data_len); + len = caller_data->raw_data[1]; + memcpy(data, &caller_data->raw_data[2], len); + *data_len = len; return FTDM_SUCCESS; } return FTDM_FAIL; @@ -591,7 +713,7 @@ ftdm_status_t set_prog_ind_ie(ftdm_channel_t *ftdmchan, ProgInd *progInd, ftdm_s int descr = prog_ind.descr; int loc = prog_ind.loc; - str = ftdm_channel_get_var(ftdmchan, "isdn.prog_ind.descr"); + str = ftdm_call_get_var(&ftdmchan->caller_data, "isdn.prog_ind.descr"); if (str && *str) { /* User wants to override progress indicator */ descr = ftdm_str2ftdm_sngisdn_progind_descr(str); @@ -602,8 +724,8 @@ ftdm_status_t set_prog_ind_ie(ftdm_channel_t *ftdmchan, ProgInd *progInd, ftdm_s return FTDM_SUCCESS; } - str = ftdm_channel_get_var(ftdmchan, "isdn.prog_ind.loc"); - if (str && *str) { + str = ftdm_call_get_var(&ftdmchan->caller_data, "isdn.prog_ind.loc"); + if (str && *str) { loc = ftdm_str2ftdm_sngisdn_progind_loc(str); } if (loc == SNGISDN_PROGIND_LOC_INVALID) { @@ -672,6 +794,93 @@ ftdm_status_t set_prog_ind_ie(ftdm_channel_t *ftdmchan, ProgInd *progInd, ftdm_s return FTDM_SUCCESS; } +ftdm_status_t set_chan_id_ie(ftdm_channel_t *ftdmchan, ChanId *chanId) +{ + if (!ftdmchan) { + return FTDM_SUCCESS; + } + chanId->eh.pres = PRSNT_NODEF; + chanId->prefExc.pres = PRSNT_NODEF; + chanId->prefExc.val = IN_PE_EXCLSVE; + chanId->dChanInd.pres = PRSNT_NODEF; + chanId->dChanInd.val = IN_DSI_NOTDCHAN; + chanId->intIdentPres.pres = PRSNT_NODEF; + chanId->intIdentPres.val = IN_IIP_IMPLICIT; + + if (ftdmchan->span->trunk_type == FTDM_TRUNK_BRI || + ftdmchan->span->trunk_type == FTDM_TRUNK_BRI_PTMP) { + + /* BRI only params */ + chanId->intType.pres = PRSNT_NODEF; + chanId->intType.val = IN_IT_BASIC; + chanId->infoChanSel.pres = PRSNT_NODEF; + chanId->infoChanSel.val = ftdmchan->physical_chan_id; + } else { + chanId->intType.pres = PRSNT_NODEF; + chanId->intType.val = IN_IT_OTHER; + chanId->infoChanSel.pres = PRSNT_NODEF; + chanId->infoChanSel.val = IN_ICS_B1CHAN; + chanId->chanMapType.pres = PRSNT_NODEF; + chanId->chanMapType.val = IN_CMT_BCHAN; + chanId->nmbMap.pres = PRSNT_NODEF; + chanId->nmbMap.val = IN_NM_CHNNMB; + chanId->codeStand1.pres = PRSNT_NODEF; + chanId->codeStand1.val = IN_CSTD_CCITT; + chanId->chanNmbSlotMap.pres = PRSNT_NODEF; + chanId->chanNmbSlotMap.len = 1; + chanId->chanNmbSlotMap.val[0] = ftdmchan->physical_chan_id; + } + return FTDM_SUCCESS; +} + +ftdm_status_t set_bear_cap_ie(ftdm_channel_t *ftdmchan, BearCap *bearCap) +{ + sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) ftdmchan->span->signal_data; + + bearCap->eh.pres = PRSNT_NODEF; + bearCap->infoTranCap.pres = PRSNT_NODEF; + bearCap->infoTranCap.val = sngisdn_get_infoTranCap_from_user(ftdmchan->caller_data.bearer_capability); + + bearCap->codeStand0.pres = PRSNT_NODEF; + bearCap->codeStand0.val = IN_CSTD_CCITT; + bearCap->infoTranRate0.pres = PRSNT_NODEF; + bearCap->infoTranRate0.val = IN_ITR_64KBIT; + bearCap->tranMode.pres = PRSNT_NODEF; + bearCap->tranMode.val = IN_TM_CIRCUIT; + + if (!FTDM_SPAN_IS_BRI(ftdmchan->span)) { + /* Trillium stack rejests lyr1Ident on BRI, but Netbricks always sends it. + Check with Trillium if this ever causes calls to fail in the field */ + + /* PRI only params */ + bearCap->usrInfoLyr1Prot.pres = PRSNT_NODEF; + bearCap->usrInfoLyr1Prot.val = sngisdn_get_usrInfoLyr1Prot_from_user(ftdmchan->caller_data.bearer_layer1); + + if (signal_data->switchtype == SNGISDN_SWITCH_EUROISDN && + bearCap->usrInfoLyr1Prot.val == IN_UIL1_G711ULAW) { + + /* We are bridging a call from T1 */ + bearCap->usrInfoLyr1Prot.val = IN_UIL1_G711ALAW; + + } else if (bearCap->usrInfoLyr1Prot.val == IN_UIL1_G711ALAW) { + + /* We are bridging a call from E1 */ + bearCap->usrInfoLyr1Prot.val = IN_UIL1_G711ULAW; + } + + bearCap->lyr1Ident.pres = PRSNT_NODEF; + bearCap->lyr1Ident.val = IN_L1_IDENT; + } + return FTDM_SUCCESS; +} + +ftdm_status_t set_restart_ind_ie(ftdm_channel_t *ftdmchan, RstInd *rstInd) +{ + rstInd->eh.pres = PRSNT_NODEF; + rstInd->rstClass.pres = PRSNT_NODEF; + rstInd->rstClass.val = IN_CL_INDCHAN; + return FTDM_SUCCESS; +} void sngisdn_t3_timeout(void* p_sngisdn_info) { 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 e5167164b3..8c421b0691 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 @@ -36,14 +36,15 @@ #include "ftmod_sangoma_isdn_trace.h" #define OCTET(x) (ieData[x-1] & 0xFF) +#define MAX_DECODE_STR_LEN 2000 void print_hex_dump(char* str, uint32_t *str_len, uint8_t* data, uint32_t index_start, uint32_t index_end); -void sngisdn_trace_q921(char* str, uint8_t* data, uint32_t data_len); -void sngisdn_trace_q931(char* str, uint8_t* data, uint32_t data_len); uint32_t sngisdn_decode_ie(char *str, uint32_t *str_len, uint8_t current_codeset, uint8_t *data, uint16_t index_start); uint8_t get_bits(uint8_t octet, uint8_t bitLo, uint8_t bitHi); char* get_code_2_str(int code, struct code2str *pCodeTable); +void sngisdn_decode_q921(char* str, uint8_t* data, uint32_t data_len); +void sngisdn_decode_q931(char* str, uint8_t* data, uint32_t data_len); char* get_code_2_str(int code, struct code2str *pCodeTable) { @@ -97,7 +98,43 @@ uint8_t get_bits(uint8_t octet, uint8_t bitLo, uint8_t bitHi) return 0; } -void sngisdn_trace_q921(char* str, uint8_t* data, uint32_t data_len) +void sngisdn_trace_interpreted_q921(sngisdn_span_data_t *signal_data, ftdm_trace_dir_t dir, uint8_t *data, uint32_t data_len) +{ + char *data_str = ftdm_calloc(1,200); /* TODO Find a proper size */ + sngisdn_decode_q921(data_str, data, data_len); + ftdm_log(FTDM_LOG_INFO, "[SNGISDN Q921] s%d FRAME %s:%s\n", signal_data->ftdm_span->name, ftdm_trace_dir2str(dir), data_str); + ftdm_safe_free(data_str); +} + +void sngisdn_trace_raw_q921(sngisdn_span_data_t *signal_data, ftdm_trace_dir_t dir, uint8_t *data, uint32_t data_len) +{ + uint8_t *raw_data; + ftdm_sigmsg_t sigev; + + memset(&sigev, 0, sizeof(sigev)); + + sigev.span_id = signal_data->ftdm_span->span_id; + sigev.chan_id = signal_data->dchan->chan_id; + sigev.channel = signal_data->dchan; + sigev.event_id = FTDM_SIGEVENT_TRACE_RAW; + + sigev.ev_data.logevent.dir = dir; + sigev.ev_data.logevent.level = 2; + + /* TODO: Map trace to call ID here */ + sigev.call_id = 0; + + raw_data = ftdm_malloc(data_len); + ftdm_assert(raw_data, "Failed to malloc"); + + memcpy(raw_data, data, data_len); + sigev.raw.data = raw_data; + sigev.raw.len = data_len; + sigev.raw.autofree = 1; + ftdm_span_send_signal(signal_data->ftdm_span, &sigev); +} + +void sngisdn_decode_q921(char* str, uint8_t* data, uint32_t data_len) { int str_len; uint32_t i; @@ -169,7 +206,43 @@ void sngisdn_trace_q921(char* str, uint8_t* data, uint32_t data_len) return; } -void sngisdn_trace_q931(char* str, uint8_t* data, uint32_t data_len) + +void sngisdn_trace_interpreted_q931(sngisdn_span_data_t *signal_data, ftdm_trace_dir_t dir, uint8_t *data, uint32_t data_len) +{ + char *data_str = ftdm_calloc(1,MAX_DECODE_STR_LEN); /* TODO Find a proper size */ + sngisdn_decode_q931(data_str, data, data_len); + ftdm_log(FTDM_LOG_INFO, "[SNGISDN Q931] %s FRAME %s:%s\n", signal_data->ftdm_span->name, ftdm_trace_dir2str(dir), data_str); + ftdm_safe_free(data_str); +} + +void sngisdn_trace_raw_q931(sngisdn_span_data_t *signal_data, ftdm_trace_dir_t dir, uint8_t *data, uint32_t data_len) +{ + uint8_t *raw_data; + ftdm_sigmsg_t sigev; + + memset(&sigev, 0, sizeof(sigev)); + + sigev.span_id = signal_data->ftdm_span->span_id; + sigev.chan_id = signal_data->dchan->chan_id; + sigev.channel = signal_data->dchan; + sigev.event_id = FTDM_SIGEVENT_TRACE_RAW; + + sigev.ev_data.logevent.dir = dir; + sigev.ev_data.logevent.level = 3; + + /* TODO: Map trace to call ID here */ + + raw_data = ftdm_malloc(data_len); + ftdm_assert(raw_data, "Failed to malloc"); + + memcpy(raw_data, data, data_len); + sigev.raw.data = raw_data; + sigev.raw.len = data_len; + sigev.raw.autofree = 1; + ftdm_span_send_signal(signal_data->ftdm_span, &sigev); +} + +void sngisdn_decode_q931(char* str, uint8_t* data, uint32_t data_len) { uint32_t str_len; uint8_t prot_disc, callRefFlag; diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c index 34cca80140..dc2d24f42a 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c @@ -1589,7 +1589,7 @@ static ftdm_status_t handle_tx_cgb(ftdm_stream_handle_t *stream, int span, int c sigev.span_id = ftdmchan->span_id; sigev.channel = ftdmchan; sigev.event_id = FTDM_SIGEVENT_SIGSTATUS_CHANGED; - sigev.sigstatus = FTDM_SIG_STATE_DOWN; + sigev.ev_data.sigstatus.status = FTDM_SIG_STATE_DOWN; ftdm_span_send_signal(ftdmchan->span, &sigev); /* if this is the first channel in the range */ @@ -1689,7 +1689,7 @@ static ftdm_status_t handle_tx_cgu(ftdm_stream_handle_t *stream, int span, int c sigev.span_id = ftdmchan->span_id; sigev.channel = ftdmchan; sigev.event_id = FTDM_SIGEVENT_SIGSTATUS_CHANGED; - sigev.sigstatus = FTDM_SIG_STATE_UP; + sigev.ev_data.sigstatus.status = FTDM_SIG_STATE_UP; ftdm_span_send_signal(ftdmchan->span, &sigev); /* if this is the first channel in the range */ 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 72e4bacf52..dcfb7f79e0 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 @@ -211,10 +211,10 @@ ftdm_status_t handle_con_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circ /* add any special variables for the dialplan */ sprintf(nadi, "%d", siConEvnt->cgPtyNum.natAddrInd.val); - ftdm_channel_add_var(ftdmchan, "ss7_clg_nadi", nadi); + ftdm_call_add_var(&ftdmchan->caller_data, "ss7_clg_nadi", nadi); sprintf(nadi, "%d", siConEvnt->cdPtyNum.natAddrInd.val); - ftdm_channel_add_var(ftdmchan, "ss7_cld_nadi", nadi); + ftdm_call_add_var(&ftdmchan->caller_data, "ss7_cld_nadi", nadi); /* check if a COT test is requested */ @@ -2004,7 +2004,7 @@ ftdm_status_t handle_cgb_req(uint32_t suInstId, uint32_t spInstId, uint32_t circ /* bring the sig status down */ sigev.event_id = FTDM_SIGEVENT_SIGSTATUS_CHANGED; - sigev.sigstatus = FTDM_SIG_STATE_DOWN; + sigev.ev_data.sigstatus.status = FTDM_SIG_STATE_DOWN; ftdm_span_send_signal(ftdmchan->span, &sigev); /* unlock the channel again before we exit */ @@ -2135,7 +2135,7 @@ ftdm_status_t handle_cgu_req(uint32_t suInstId, uint32_t spInstId, uint32_t circ /* bring the sig status down */ sigev.event_id = FTDM_SIGEVENT_SIGSTATUS_CHANGED; - sigev.sigstatus = FTDM_SIG_STATE_UP; + sigev.ev_data.sigstatus.status = FTDM_SIG_STATE_UP; ftdm_span_send_signal(ftdmchan->span, &sigev); /* unlock the channel again before we exit */ 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 304e9d6ce3..05a325b913 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 @@ -502,6 +502,8 @@ void ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) /**************************************************************************/ case FTDM_CHANNEL_STATE_COLLECT: /* IAM received but wating on digits */ + isup_intf = &g_ftdm_sngss7_data.cfg.isupIntf[sngss7_info->circuit->infId]; + if (ftdmchan->last_state == FTDM_CHANNEL_STATE_SUSPENDED) { SS7_DEBUG("re-entering state from processing block/unblock request ... do nothing\n"); break; @@ -521,8 +523,8 @@ void ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) /*now go to the RING state */ ftdm_set_state_locked (ftdmchan, FTDM_CHANNEL_STATE_RING); - } else if (i >= g_ftdm_sngss7_data.min_digits) { - SS7_DEBUG_CHAN(ftdmchan, "Received %d digits (min digits = %d)\n", i, g_ftdm_sngss7_data.min_digits); + } else if (i >= isup_intf->min_digits) { + SS7_DEBUG_CHAN(ftdmchan, "Received %d digits (min digits = %d)\n", i, isup_intf->min_digits); /*now go to the RING state */ ftdm_set_state_locked (ftdmchan, FTDM_CHANNEL_STATE_RING); @@ -532,7 +534,7 @@ void ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) 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, + isup_intf->min_digits, ftdmchan->caller_data.dnis.digits); /* start ISUP t35 */ @@ -839,7 +841,7 @@ void ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) SS7_DEBUG_CHAN(ftdmchan,"All reset flags cleared %s\n", ""); /* all flags are down so we can bring up the sig status */ sigev.event_id = FTDM_SIGEVENT_SIGSTATUS_CHANGED; - sigev.sigstatus = FTDM_SIG_STATE_UP; + sigev.ev_data.sigstatus.status = FTDM_SIG_STATE_UP; ftdm_span_send_signal (ftdmchan->span, &sigev); } /* if (!ftdm_test_flag (ftdmchan, FTDM_CHANNEL_SIG_UP)) */ } /* if !blocked */ @@ -947,7 +949,7 @@ void ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) /* if the sig_status is up...bring it down */ if (ftdm_test_flag (ftdmchan, FTDM_CHANNEL_SIG_UP)) { sigev.event_id = FTDM_SIGEVENT_SIGSTATUS_CHANGED; - sigev.sigstatus = FTDM_SIG_STATE_DOWN; + sigev.ev_data.sigstatus.status = FTDM_SIG_STATE_DOWN; ftdm_span_send_signal (ftdmchan->span, &sigev); } @@ -1031,7 +1033,7 @@ void ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) /* bring the sig status back up */ sigev.event_id = FTDM_SIGEVENT_SIGSTATUS_CHANGED; - sigev.sigstatus = FTDM_SIG_STATE_UP; + sigev.ev_data.sigstatus.status = FTDM_SIG_STATE_UP; ftdm_span_send_signal(ftdmchan->span, &sigev); } @@ -1044,7 +1046,7 @@ void ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) /* bring the sig status down */ sigev.event_id = FTDM_SIGEVENT_SIGSTATUS_CHANGED; - sigev.sigstatus = FTDM_SIG_STATE_DOWN; + sigev.ev_data.sigstatus.status = FTDM_SIG_STATE_DOWN; ftdm_span_send_signal(ftdmchan->span, &sigev); /* go back to the last state */ @@ -1056,7 +1058,7 @@ void ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) /* bring the sig status down */ sigev.event_id = FTDM_SIGEVENT_SIGSTATUS_CHANGED; - sigev.sigstatus = FTDM_SIG_STATE_DOWN; + sigev.ev_data.sigstatus.status = FTDM_SIG_STATE_DOWN; ftdm_span_send_signal(ftdmchan->span, &sigev); /* send a BLA */ @@ -1074,7 +1076,7 @@ void ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) /* bring the sig status up */ sigev.event_id = FTDM_SIGEVENT_SIGSTATUS_CHANGED; - sigev.sigstatus = FTDM_SIG_STATE_UP; + sigev.ev_data.sigstatus.status = FTDM_SIG_STATE_UP; ftdm_span_send_signal(ftdmchan->span, &sigev); /* send a uba */ @@ -1090,7 +1092,7 @@ void ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) /* bring the sig status down */ sigev.event_id = FTDM_SIGEVENT_SIGSTATUS_CHANGED; - sigev.sigstatus = FTDM_SIG_STATE_DOWN; + sigev.ev_data.sigstatus.status = FTDM_SIG_STATE_DOWN; ftdm_span_send_signal(ftdmchan->span, &sigev); /* send a blo */ @@ -1108,7 +1110,7 @@ void ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) /* bring the sig status up */ sigev.event_id = FTDM_SIGEVENT_SIGSTATUS_CHANGED; - sigev.sigstatus = FTDM_SIG_STATE_UP; + sigev.ev_data.sigstatus.status = FTDM_SIG_STATE_UP; ftdm_span_send_signal(ftdmchan->span, &sigev); /* send a ubl */ @@ -1147,7 +1149,7 @@ void ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) /* bring the channel signaling status to down */ sigev.event_id = FTDM_SIGEVENT_SIGSTATUS_CHANGED; - sigev.sigstatus = FTDM_SIG_STATE_DOWN; + sigev.ev_data.sigstatus.status = FTDM_SIG_STATE_DOWN; ftdm_span_send_signal (ftdmchan->span, &sigev); /* remove any reset flags */ @@ -1520,9 +1522,6 @@ static FIO_SIG_LOAD_FUNCTION(ftdm_sangoma_ss7_init) /* initalize the global gen_config flag */ g_ftdm_sngss7_data.gen_config = 0; - /* min. number of digitis to wait for */ - g_ftdm_sngss7_data.min_digits = 7; - /* function trace initizalation */ g_ftdm_sngss7_data.function_trace = 1; g_ftdm_sngss7_data.function_trace_level = 7; 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 378b50e0ad..fe4b6f45c4 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 @@ -50,7 +50,7 @@ /******************************************************************************/ /* DEFINES ********************************************************************/ -#define MAX_NAME_LEN 10 +#define MAX_NAME_LEN 25 #define MAX_PATH 255 #define MAX_CIC_LENGTH 5 @@ -224,6 +224,7 @@ typedef struct sng_isup_intf { uint32_t isap; uint32_t clg_nadi; uint32_t cld_nadi; + uint32_t min_digits; uint16_t t4; uint32_t t10; uint32_t t11; @@ -326,7 +327,6 @@ typedef struct sng_ss7_cfg { typedef struct ftdm_sngss7_data { sng_ss7_cfg_t cfg; int gen_config; - int min_digits; int function_trace; int function_trace_level; int message_trace; 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 008265b9a4..ec8d7df12a 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 @@ -187,7 +187,7 @@ void ft_to_sngss7_iam (ftdm_channel_t * ftdmchan) copy_cgPtyNum_to_sngss7 (&ftdmchan->caller_data, &iam.cgPtyNum); /* check if the user would like a custom NADI value for the calling Pty Num */ - clg_nadi = ftdm_channel_get_var(ftdmchan, "ss7_clg_nadi"); + clg_nadi = ftdm_call_get_var(&ftdmchan->caller_data, "ss7_clg_nadi"); if ((clg_nadi != NULL) && (*clg_nadi)) { SS7_DEBUG_CHAN(ftdmchan,"Found user supplied Calling NADI value \"%s\"\n", clg_nadi); iam.cgPtyNum.natAddrInd.val = atoi(clg_nadi); @@ -196,7 +196,7 @@ void ft_to_sngss7_iam (ftdm_channel_t * ftdmchan) SS7_DEBUG_CHAN(ftdmchan,"No user supplied NADI value found for CLG, using \"%d\"\n", iam.cgPtyNum.natAddrInd.val); } - cld_nadi = ftdm_channel_get_var(ftdmchan, "ss7_cld_nadi"); + cld_nadi = ftdm_call_get_var(&ftdmchan->caller_data, "ss7_cld_nadi"); if ((cld_nadi != NULL) && (*cld_nadi)) { SS7_DEBUG_CHAN(ftdmchan,"Found user supplied Called NADI value \"%s\"\n", cld_nadi); iam.cdPtyNum.natAddrInd.val = atoi(cld_nadi); @@ -206,7 +206,7 @@ void ft_to_sngss7_iam (ftdm_channel_t * ftdmchan) } /* check if the user would like us to send a clg_sub-address */ - clg_subAddr = ftdm_channel_get_var(ftdmchan, "ss7_clg_subaddr"); + clg_subAddr = ftdm_call_get_var(&ftdmchan->caller_data, "ss7_clg_subaddr"); if ((clg_subAddr != NULL) && (*clg_subAddr)) { SS7_DEBUG_CHAN(ftdmchan,"Found user supplied Calling Sub-Address value \"%s\"\n", clg_subAddr); @@ -245,7 +245,7 @@ void ft_to_sngss7_iam (ftdm_channel_t * ftdmchan) } /* check if the user would like us to send a cld_sub-address */ - cld_subAddr = ftdm_channel_get_var(ftdmchan, "ss7_cld_subaddr"); + cld_subAddr = ftdm_call_get_var(&ftdmchan->caller_data, "ss7_cld_subaddr"); if ((cld_subAddr != NULL) && (*cld_subAddr)) { SS7_DEBUG_CHAN(ftdmchan,"Found user supplied Called Sub-Address value \"%s\"\n", cld_subAddr); @@ -298,7 +298,8 @@ void ft_to_sngss7_iam (ftdm_channel_t * ftdmchan) iam.cgPtyNum.natAddrInd.val, ftdmchan->caller_data.dnis.digits, iam.cdPtyNum.natAddrInd.val); - + + ftdm_call_clear_vars(&ftdmchan->caller_data); SS7_FUNC_TRACE_EXIT (__FUNCTION__); return; } @@ -379,7 +380,7 @@ void ft_to_sngss7_acm (ftdm_channel_t * ftdmchan) ADDRCMPLT); SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx ACM\n", sngss7_info->circuit->cic); - + ftdm_call_clear_vars(&ftdmchan->caller_data); SS7_FUNC_TRACE_EXIT (__FUNCTION__); return; } @@ -403,7 +404,7 @@ void ft_to_sngss7_anm (ftdm_channel_t * ftdmchan) 5); SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx ANM\n", sngss7_info->circuit->cic); - + ftdm_call_clear_vars(&ftdmchan->caller_data); SS7_FUNC_TRACE_EXIT (__FUNCTION__); return; } @@ -438,7 +439,7 @@ void ft_to_sngss7_rel (ftdm_channel_t * ftdmchan) SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx REL cause=%d \n", sngss7_info->circuit->cic, ftdmchan->caller_data.hangup_cause ); - + ftdm_call_clear_vars(&ftdmchan->caller_data); SS7_FUNC_TRACE_EXIT (__FUNCTION__); return; } @@ -461,7 +462,7 @@ void ft_to_sngss7_rlc (ftdm_channel_t * ftdmchan) &rlc); SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx RLC\n", sngss7_info->circuit->cic); - + ftdm_call_clear_vars(&ftdmchan->caller_data); SS7_FUNC_TRACE_EXIT (__FUNCTION__); return; } @@ -482,7 +483,7 @@ void ft_to_sngss7_rsc (ftdm_channel_t * ftdmchan) NULL); SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx RSC\n", sngss7_info->circuit->cic); - + ftdm_call_clear_vars(&ftdmchan->caller_data); SS7_FUNC_TRACE_EXIT (__FUNCTION__); return; } @@ -503,7 +504,7 @@ void ft_to_sngss7_rsca (ftdm_channel_t * ftdmchan) NULL); SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx RSC-RLC\n", sngss7_info->circuit->cic); - + ftdm_call_clear_vars(&ftdmchan->caller_data); SS7_FUNC_TRACE_EXIT (__FUNCTION__); return; } @@ -524,7 +525,7 @@ void ft_to_sngss7_blo (ftdm_channel_t * ftdmchan) NULL); SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx BLO\n", sngss7_info->circuit->cic); - + ftdm_call_clear_vars(&ftdmchan->caller_data); SS7_FUNC_TRACE_EXIT (__FUNCTION__); return; } @@ -545,7 +546,7 @@ void ft_to_sngss7_bla (ftdm_channel_t * ftdmchan) NULL); SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx BLA\n", sngss7_info->circuit->cic); - + ftdm_call_clear_vars(&ftdmchan->caller_data); SS7_FUNC_TRACE_EXIT (__FUNCTION__); return; } @@ -567,7 +568,7 @@ ft_to_sngss7_ubl (ftdm_channel_t * ftdmchan) NULL); SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx UBL\n", sngss7_info->circuit->cic); - + ftdm_call_clear_vars(&ftdmchan->caller_data); SS7_FUNC_TRACE_EXIT (__FUNCTION__); return; } @@ -588,7 +589,7 @@ void ft_to_sngss7_uba (ftdm_channel_t * ftdmchan) NULL); SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx UBA\n", sngss7_info->circuit->cic); - + ftdm_call_clear_vars(&ftdmchan->caller_data); SS7_FUNC_TRACE_EXIT (__FUNCTION__); return; } @@ -609,7 +610,7 @@ void ft_to_sngss7_lpa (ftdm_channel_t * ftdmchan) NULL); SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx LPA\n", sngss7_info->circuit->cic); - + ftdm_call_clear_vars(&ftdmchan->caller_data); SS7_FUNC_TRACE_EXIT (__FUNCTION__); return; } @@ -654,6 +655,7 @@ void ft_to_sngss7_gra (ftdm_channel_t * ftdmchan) sngss7_info->circuit->cic, (sngss7_info->circuit->cic + sngss7_span->rx_grs.range)); + ftdm_call_clear_vars(&ftdmchan->caller_data); SS7_FUNC_TRACE_EXIT (__FUNCTION__); return; } @@ -686,7 +688,8 @@ void ft_to_sngss7_grs (ftdm_channel_t * ftdmchan) sngss7_info->circuit->cic, sngss7_info->circuit->cic, (sngss7_info->circuit->cic + sngss7_span->tx_grs.range)); - + + ftdm_call_clear_vars(&ftdmchan->caller_data); SS7_FUNC_TRACE_EXIT (__FUNCTION__); return; } @@ -735,7 +738,7 @@ void ft_to_sngss7_cgba(ftdm_channel_t * ftdmchan) /* clean out the saved data */ memset(&sngss7_span->rx_cgb, 0x0, sizeof(sngss7_group_data_t)); - + ftdm_call_clear_vars(&ftdmchan->caller_data); SS7_FUNC_TRACE_EXIT (__FUNCTION__); return; } @@ -785,6 +788,7 @@ void ft_to_sngss7_cgua(ftdm_channel_t * ftdmchan) /* clean out the saved data */ memset(&sngss7_span->rx_cgu, 0x0, sizeof(sngss7_group_data_t)); + ftdm_call_clear_vars(&ftdmchan->caller_data); SS7_FUNC_TRACE_EXIT (__FUNCTION__); return; } @@ -835,6 +839,7 @@ void ft_to_sngss7_cgb(ftdm_channel_t * ftdmchan) /* clean out the saved data */ memset(&sngss7_span->tx_cgb, 0x0, sizeof(sngss7_group_data_t)); + ftdm_call_clear_vars(&ftdmchan->caller_data); SS7_FUNC_TRACE_EXIT (__FUNCTION__); return; } @@ -885,6 +890,7 @@ void ft_to_sngss7_cgu(ftdm_channel_t * ftdmchan) /* clean out the saved data */ memset(&sngss7_span->tx_cgu, 0x0, sizeof(sngss7_group_data_t)); + ftdm_call_clear_vars(&ftdmchan->caller_data); SS7_FUNC_TRACE_EXIT (__FUNCTION__); return; } 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 4a9c863b12..d4fd1ca9b3 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 @@ -142,7 +142,7 @@ int ftmod_ss7_parse_xml(ftdm_conf_parameter_t *ftdm_parameters, ftdm_span_t *spa if (!strcasecmp(var, "ch_map")) { /**********************************************************************/ - strcpy(isupCkt.ch_map, val); + strncpy(isupCkt.ch_map, val, MAX_CIC_MAP_LENGTH-1); SS7_DEBUG("\tFound channel map \"%s\"\n", isupCkt.ch_map); /**********************************************************************/ } else if (!strcasecmp(var, "typeCntrl")) { @@ -393,7 +393,7 @@ static int ftmod_ss7_parse_mtp_linkset(ftdm_conf_node_t *mtp_linkset) for (i = 0; i < num_parms; i++) { /**********************************************************************/ if (!strcasecmp(parm->var, "name")) { - strcpy((char *)mtpLinkSet.name, parm->val); + strncpy((char *)mtpLinkSet.name, parm->val, MAX_NAME_LEN-1); SS7_DEBUG("\tFound an \"mtp_linkset\" named = %s\n", mtpLinkSet.name); /**********************************************************************/ } else if (!strcasecmp(parm->var, "apc")) { @@ -508,7 +508,7 @@ static int ftmod_ss7_parse_mtp_link(ftdm_conf_node_t *mtp_link, sng_mtp_link_t * /* try to match the parameter to what we expect */ /**********************************************************************/ if (!strcasecmp(parm->var, "name")) { - strcpy((char *)mtpLink->name, parm->val); + strncpy((char *)mtpLink->name, parm->val, MAX_NAME_LEN-1); SS7_DEBUG("\tFound an \"mtp_link\" named = %s\n", mtpLink->name); /**********************************************************************/ } else if (!strcasecmp(parm->var, "span")) { @@ -827,7 +827,7 @@ static int ftmod_ss7_parse_mtp_route(ftdm_conf_node_t *mtp_route) /* try to match the parameter to what we expect */ /**********************************************************************/ if (!strcasecmp(parm->var, "name")) { - strcpy((char *)mtpRoute.name, parm->val); + strncpy((char *)mtpRoute.name, parm->val, MAX_NAME_LEN-1); SS7_DEBUG("\tFound an \"mtp_route\" named = %s\n", mtpRoute.name); /**********************************************************************/ } else if (!strcasecmp(parm->var, "dpc")) { @@ -999,7 +999,7 @@ static int ftmod_ss7_parse_isup_interface(ftdm_conf_node_t *isup_interface) /* try to match the parameter to what we expect */ /**********************************************************************/ if (!strcasecmp(parm->var, "name")) { - strcpy((char *)sng_isup.name, parm->val); + strncpy((char *)sng_isup.name, parm->val, MAX_NAME_LEN-1); SS7_DEBUG("\tFound an \"isup_interface\" named = %s\n", sng_isup.name); /**********************************************************************/ } else if (!strcasecmp(parm->var, "spc")) { @@ -1047,6 +1047,11 @@ static int ftmod_ss7_parse_isup_interface(ftdm_conf_node_t *isup_interface) SS7_DEBUG("\tFound MTP3 Route = %s\n", parm->val); } /**********************************************************************/ + } else if (!strcasecmp(parm->var, "min_digits")) { + sng_isup.min_digits = atoi(parm->val); + + SS7_DEBUG("\tFound min_digits = %d\n", sng_isup.min_digits); + /**********************************************************************/ } else if (!strcasecmp(parm->var, "ssf")) { if (!strcasecmp(parm->val, "nat")) { sng_isup.ssf = SSF_NAT; @@ -1067,8 +1072,8 @@ static int ftmod_ss7_parse_isup_interface(ftdm_conf_node_t *isup_interface) /**********************************************************************/ } else if (!strcasecmp(parm->var, "license")) { /**********************************************************************/ - strcpy(g_ftdm_sngss7_data.cfg.license, parm->val); - strcpy(g_ftdm_sngss7_data.cfg.signature, parm->val); + strncpy(g_ftdm_sngss7_data.cfg.license, parm->val, MAX_PATH-1); + strncpy(g_ftdm_sngss7_data.cfg.signature, parm->val, MAX_PATH-1); strcat(g_ftdm_sngss7_data.cfg.signature, ".sig"); SS7_DEBUG("\tFound license file = %s\n", g_ftdm_sngss7_data.cfg.license); SS7_DEBUG("\tFound signature file = %s\n", g_ftdm_sngss7_data.cfg.signature); @@ -1304,6 +1309,13 @@ static int ftmod_ss7_parse_isup_interface(ftdm_conf_node_t *isup_interface) sng_isup.clg_nadi = 0x03; } + /* check if the user requested min_digits value */ + if (sng_isup.min_digits == 0) { + /* default to 7 */ + sng_isup.min_digits = 7; + } + + /* trickle down the SPC to all sub entities */ linkSetId = g_ftdm_sngss7_data.cfg.mtpRoute[sng_isup.mtpRouteId].linkSetId; @@ -1359,7 +1371,7 @@ static int ftmod_ss7_fill_in_mtpLink(sng_mtp_link_t *mtpLink) } /* fill in the information */ - strcpy((char *)g_ftdm_sngss7_data.cfg.mtpLink[i].name, (char *)mtpLink->name); + strncpy((char *)g_ftdm_sngss7_data.cfg.mtpLink[i].name, (char *)mtpLink->name, MAX_NAME_LEN-1); g_ftdm_sngss7_data.cfg.mtpLink[i].id = mtpLink->id; @@ -1521,7 +1533,7 @@ static int ftmod_ss7_fill_in_mtpLinkSet(sng_link_set_t *mtpLinkSet) { int i = mtpLinkSet->id; - strcpy((char *)g_ftdm_sngss7_data.cfg.mtpLinkSet[i].name, (char *)mtpLinkSet->name); + strncpy((char *)g_ftdm_sngss7_data.cfg.mtpLinkSet[i].name, (char *)mtpLinkSet->name, MAX_NAME_LEN-1); g_ftdm_sngss7_data.cfg.mtpLinkSet[i].id = mtpLinkSet->id; g_ftdm_sngss7_data.cfg.mtpLinkSet[i].apc = mtpLinkSet->apc; @@ -1559,7 +1571,7 @@ static int ftmod_ss7_fill_in_mtp3_route(sng_route_t *mtp3_route) SS7_DEBUG("found existing mtp3_route, id is = %d\n", mtp3_route->id); } - strcpy((char *)g_ftdm_sngss7_data.cfg.mtpRoute[i].name, (char *)mtp3_route->name); + strncpy((char *)g_ftdm_sngss7_data.cfg.mtpRoute[i].name, (char *)mtp3_route->name, MAX_NAME_LEN-1); g_ftdm_sngss7_data.cfg.mtpRoute[i].id = mtp3_route->id; g_ftdm_sngss7_data.cfg.mtpRoute[i].dpc = mtp3_route->dpc; @@ -1693,7 +1705,7 @@ static int ftmod_ss7_fill_in_isup_interface(sng_isup_inf_t *sng_isup) SS7_DEBUG("found existing isup interface, id is = %d\n", sng_isup->id); } - strcpy((char *)g_ftdm_sngss7_data.cfg.isupIntf[i].name, (char *)sng_isup->name); + strncpy((char *)g_ftdm_sngss7_data.cfg.isupIntf[i].name, (char *)sng_isup->name, MAX_NAME_LEN-1); g_ftdm_sngss7_data.cfg.isupIntf[i].id = sng_isup->id; g_ftdm_sngss7_data.cfg.isupIntf[i].mtpRouteId = sng_isup->mtpRouteId; @@ -1705,6 +1717,7 @@ static int ftmod_ss7_fill_in_isup_interface(sng_isup_inf_t *sng_isup) g_ftdm_sngss7_data.cfg.isupIntf[i].isap = sng_isup->isap; g_ftdm_sngss7_data.cfg.isupIntf[i].cld_nadi = sng_isup->cld_nadi; g_ftdm_sngss7_data.cfg.isupIntf[i].clg_nadi = sng_isup->clg_nadi; + g_ftdm_sngss7_data.cfg.isupIntf[i].min_digits = sng_isup->min_digits; g_ftdm_sngss7_data.cfg.isupIntf[i].options = sng_isup->options; if (sng_isup->t4 != 0) { g_ftdm_sngss7_data.cfg.isupIntf[i].t4 = sng_isup->t4; @@ -1976,7 +1989,7 @@ static int ftmod_ss7_fill_in_self_route(int spc, int linkType, int switchType, i return FTDM_FAIL; } - strcpy((char *)g_ftdm_sngss7_data.cfg.mtpRoute[0].name, "self-route"); + strncpy((char *)g_ftdm_sngss7_data.cfg.mtpRoute[0].name, "self-route", MAX_NAME_LEN-1); g_ftdm_sngss7_data.cfg.mtpRoute[0].id = 0; g_ftdm_sngss7_data.cfg.mtpRoute[0].dpc = spc; @@ -2230,7 +2243,7 @@ static int ftmod_ss7_next_timeslot(char *ch_map, sng_timeslot_t *timeslot) int lower; int upper; char tmp[5]; /*KONRAD FIX ME*/ - char new_ch_map[MAX_CIC_LENGTH]; + char new_ch_map[MAX_CIC_MAP_LENGTH]; memset(&tmp[0], '\0', sizeof(tmp)); memset(&new_ch_map[0], '\0', sizeof(new_ch_map)); @@ -2337,7 +2350,9 @@ static int ftmod_ss7_next_timeslot(char *ch_map, sng_timeslot_t *timeslot) /* the the rest of ch_map to new_ch_map */ strncat(new_ch_map, &ch_map[x], strlen(&ch_map[x])); + /* set the new cic map to ch_map*/ + memset(ch_map, '\0', sizeof(ch_map)); strcpy(ch_map, new_ch_map); } else if (ch_map[x] == ',') { @@ -2345,16 +2360,21 @@ static int ftmod_ss7_next_timeslot(char *ch_map, sng_timeslot_t *timeslot) x++; /* copy the rest of the list to new_ch_map */ + memset(new_ch_map, '\0', sizeof(new_ch_map)); strcpy(new_ch_map, &ch_map[x]); /* copy the new_ch_map over the old one */ + memset(ch_map, '\0', sizeof(ch_map)); strcpy(ch_map, new_ch_map); } else if (ch_map[x] == '\0') { + /* we're at the end of the string...copy the rest of the list to new_ch_map */ + memset(new_ch_map, '\0', sizeof(new_ch_map)); strcpy(new_ch_map, &ch_map[x]); /* set the new cic map to ch_map*/ + memset(ch_map, '\0', sizeof(ch_map)); strcpy(ch_map, new_ch_map); } else { /* nothing to do */ diff --git a/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c b/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c index 1c0baa731f..2db4326847 100644 --- a/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c +++ b/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c @@ -811,13 +811,14 @@ static void wanpipe_write_stats(ftdm_channel_t *ftdmchan, wp_tdm_api_tx_hdr_t *t ftdm_clear_flag(&(ftdmchan->iostats.tx), FTDM_IOSTATS_ERROR_QUEUE_FULL); } - if (ftdmchan->iostats.tx.idle_packets < tx_stats->wp_api_tx_hdr_number_of_frames_in_queue) { - ftdmchan->iostats.tx.idle_packets = tx_stats->wp_api_tx_hdr_tx_idle_packets; + if (ftdmchan->iostats.tx.idle_packets < tx_stats->wp_api_tx_hdr_tx_idle_packets) { /* HDLC channels do not always transmit, so its ok for drivers to fill with idle * also do not report idle warning when we just started transmitting */ if (ftdmchan->iostats.tx.packets && FTDM_IS_VOICE_CHANNEL(ftdmchan)) { - ftdm_log_chan(ftdmchan, FTDM_LOG_WARNING, "Tx idle: %d\n", ftdmchan->iostats.tx.idle_packets); + ftdm_log_chan(ftdmchan, FTDM_LOG_WARNING, "Tx idle changed from %d to %d\n", + ftdmchan->iostats.tx.idle_packets, tx_stats->wp_api_tx_hdr_tx_idle_packets); } + ftdmchan->iostats.tx.idle_packets = tx_stats->wp_api_tx_hdr_tx_idle_packets; } if (!ftdmchan->iostats.tx.packets) { @@ -941,7 +942,6 @@ static FIO_WRITE_FUNCTION(wanpipe_write) { int bsent = 0; int err = 0; - ftdm_time_t ms = 0; wp_tdm_api_tx_hdr_t hdrframe; /* Do we even need the headerframe here? on windows, we don't even pass it to the driver */ @@ -1051,16 +1051,34 @@ FIO_SPAN_POLL_EVENT_FUNCTION(wanpipe_poll_event) for(i = 1; i <= span->chan_count; i++) { ftdm_channel_t *ftdmchan = span->channels[i]; + uint32_t chan_events = 0; + + /* translate events from ftdm to libsnagoma. if the user don't specify which events to poll the + * channel for, we just use SANG_WAIT_OBJ_HAS_EVENTS */ + if (poll_events) { + if (poll_events[j] & FTDM_READ) { + chan_events = SANG_WAIT_OBJ_HAS_INPUT; + } + if (poll_events[j] & FTDM_WRITE) { + chan_events |= SANG_WAIT_OBJ_HAS_OUTPUT; + } + if (poll_events[j] & FTDM_EVENTS) { + chan_events |= SANG_WAIT_OBJ_HAS_EVENTS; + } + } else { + chan_events = SANG_WAIT_OBJ_HAS_EVENTS; + } + #ifdef LIBSANGOMA_VERSION if (!ftdmchan->io_data) { continue; /* should never happen but happens when shutting down */ } pfds[j] = ftdmchan->io_data; - inflags[j] = poll_events ? poll_events[j] : POLLPRI; + inflags[j] = chan_events; #else memset(&pfds[j], 0, sizeof(pfds[j])); pfds[j].fd = span->channels[i]->sockfd; - pfds[j].events = poll_events ? poll_events[j] : POLLPRI; + pfds[j].events = chan_events; #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! */ diff --git a/libs/freetdm/src/ftmod/ftmod_zt/ftmod_zt.c b/libs/freetdm/src/ftmod/ftmod_zt/ftmod_zt.c index e1d664092a..25f9b291ed 100644 --- a/libs/freetdm/src/ftmod/ftmod_zt/ftmod_zt.c +++ b/libs/freetdm/src/ftmod/ftmod_zt/ftmod_zt.c @@ -31,10 +31,14 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - #include "private/ftdm_core.h" #include "ftmod_zt.h" +/* used by dahdi to indicate there is no data available, but events to read */ +#ifndef ELAST +#define ELAST 500 +#endif + /** * \brief Zaptel globals */ @@ -48,42 +52,48 @@ static struct { float txgain; } zt_globals; +#if defined(__FreeBSD__) +typedef unsigned long ioctlcmd; +#else +typedef int ioctlcmd; +#endif + /** * \brief General IOCTL codes */ struct ioctl_codes { - int GET_BLOCKSIZE; - int SET_BLOCKSIZE; - int FLUSH; - int SYNC; - int GET_PARAMS; - int SET_PARAMS; - int HOOK; - int GETEVENT; - int IOMUX; - int SPANSTAT; - int MAINT; - int GETCONF; - int SETCONF; - int CONFLINK; - int CONFDIAG; - int GETGAINS; - int SETGAINS; - int SPANCONFIG; - int CHANCONFIG; - int SET_BUFINFO; - int GET_BUFINFO; - int AUDIOMODE; - int ECHOCANCEL; - int HDLCRAWMODE; - int HDLCFCSMODE; - int SPECIFY; - int SETLAW; - int SETLINEAR; - int GETCONFMUTE; - int ECHOTRAIN; - int SETTXBITS; - int GETRXBITS; + ioctlcmd GET_BLOCKSIZE; + ioctlcmd SET_BLOCKSIZE; + ioctlcmd FLUSH; + ioctlcmd SYNC; + ioctlcmd GET_PARAMS; + ioctlcmd SET_PARAMS; + ioctlcmd HOOK; + ioctlcmd GETEVENT; + ioctlcmd IOMUX; + ioctlcmd SPANSTAT; + ioctlcmd MAINT; + ioctlcmd GETCONF; + ioctlcmd SETCONF; + ioctlcmd CONFLINK; + ioctlcmd CONFDIAG; + ioctlcmd GETGAINS; + ioctlcmd SETGAINS; + ioctlcmd SPANCONFIG; + ioctlcmd CHANCONFIG; + ioctlcmd SET_BUFINFO; + ioctlcmd GET_BUFINFO; + ioctlcmd AUDIOMODE; + ioctlcmd ECHOCANCEL; + ioctlcmd HDLCRAWMODE; + ioctlcmd HDLCFCSMODE; + ioctlcmd SPECIFY; + ioctlcmd SETLAW; + ioctlcmd SETLINEAR; + ioctlcmd GETCONFMUTE; + ioctlcmd ECHOTRAIN; + ioctlcmd SETTXBITS; + ioctlcmd GETRXBITS; }; /** @@ -1183,7 +1193,6 @@ FIO_SPAN_NEXT_EVENT_FUNCTION(zt_next_event) } return FTDM_FAIL; - } /** @@ -1202,12 +1211,19 @@ static FIO_READ_FUNCTION(zt_read) if ((r = read(ftdmchan->sockfd, data, *datalen)) > 0) { break; } - ftdm_sleep(10); - if (r == 0) { - errs--; + else if (r == 0) { + ftdm_sleep(10); + if (errs) errs--; + } + else { + if (errno == EAGAIN || errno == EINTR) + continue; + if (errno == ELAST) + break; + + ftdm_log(FTDM_LOG_ERROR, "read failed: %s\n", strerror(errno)); } } - if (r > 0) { *datalen = r; if (ftdmchan->type == FTDM_CHAN_TYPE_DQ921) { @@ -1215,7 +1231,9 @@ static FIO_READ_FUNCTION(zt_read) } return FTDM_SUCCESS; } - + else if (errno == ELAST) { + return FTDM_SUCCESS; + } return r == 0 ? FTDM_TIMEOUT : FTDM_FAIL; } @@ -1236,6 +1254,7 @@ static FIO_WRITE_FUNCTION(zt_write) bytes += 2; } +tryagain: w = write(ftdmchan->sockfd, data, bytes); if (w >= 0) { @@ -1243,6 +1262,17 @@ static FIO_WRITE_FUNCTION(zt_write) return FTDM_SUCCESS; } + if (errno == ELAST) { + zt_event_t zt_event_id = 0; + if (ioctl(ftdmchan->sockfd, codes.GETEVENT, &zt_event_id) == -1) { + ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Failed retrieving event after ELAST on write: %s\n", strerror(errno)); + return FTDM_FAIL; + } + /* we should enqueue this event somewhere so it can be retrieved by the user, for now, dropping it to see what it is! */ + ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Dropping event %d to be able to write data\n", zt_event_id); + goto tryagain; + } + return FTDM_FAIL; } diff --git a/libs/freetdm/src/include/freetdm.h b/libs/freetdm/src/include/freetdm.h index 41e7f50ed8..79e873390e 100644 --- a/libs/freetdm/src/include/freetdm.h +++ b/libs/freetdm/src/include/freetdm.h @@ -144,7 +144,9 @@ typedef enum { /*! \brief Hunting direction (when hunting for free channels) */ typedef enum { FTDM_TOP_DOWN, - FTDM_BOTTOM_UP + FTDM_BOTTOM_UP, + FTDM_RR_DOWN, + FTDM_RR_UP, } ftdm_direction_t; /*! \brief I/O channel type */ @@ -265,13 +267,32 @@ typedef enum { #define USER_LAYER1_PROT_STRINGS "V.110", "u-law", "a-law", "Invalid" FTDM_STR2ENUM_P(ftdm_str2ftdm_usr_layer1_prot, ftdm_user_layer1_prot2str, ftdm_user_layer1_prot_t) +/*! Calling Party Category */ +typedef enum { + FTDM_CPC_UNKNOWN, + FTDM_CPC_OPERATOR, + FTDM_CPC_ORDINARY, + FTDM_CPC_PRIORITY, + FTDM_CPC_DATA, + FTDM_CPC_TEST, + FTDM_CPC_PAYPHONE, + FTDM_CPC_INVALID +} ftdm_calling_party_category_t; +#define CALLING_PARTY_CATEGORY_STRINGS "unknown", "operator", "ordinary", "priority", "data-call", "test-call", "payphone", "invalid" +FTDM_STR2ENUM_P(ftdm_str2ftdm_calling_party_category, ftdm_calling_party_category2str, ftdm_calling_party_category_t) + +/*! \brief Digit limit used in DNIS/ANI */ +#define FTDM_DIGITS_LIMIT 25 + /*! \brief Number abstraction */ typedef struct { - char digits[25]; + char digits[FTDM_DIGITS_LIMIT]; uint8_t type; uint8_t plan; } ftdm_number_t; +typedef void * ftdm_variable_container_t; + /*! \brief Caller information */ typedef struct ftdm_caller_data { char cid_date[8]; /*!< Caller ID date */ @@ -280,18 +301,25 @@ typedef struct ftdm_caller_data { ftdm_number_t ani; /*!< ANI (Automatic Number Identification) */ ftdm_number_t dnis; /*!< DNIS (Dialed Number Identification Service) */ ftdm_number_t rdnis; /*!< RDNIS (Redirected Dialed Number Identification Service) */ - char aniII[25]; /*! ANI II */ + char aniII[FTDM_DIGITS_LIMIT]; /*! ANI II */ uint8_t screen; /*!< Screening */ uint8_t pres; /*!< Presentation*/ - char collected[25]; /*!< Collected digits so far */ + char collected[FTDM_DIGITS_LIMIT]; /*!< Collected digits so far */ int hangup_cause; /*!< Hangup cause */ char raw_data[1024]; /*!< Protocol specific raw caller data */ - uint32_t raw_data_len; /* !< Raw data length */ + uint32_t raw_data_len; /*!< Raw data length */ /* these 2 are undocumented right now, only used by boost: */ /* bearer capability */ ftdm_bearer_cap_t bearer_capability; /* user information layer 1 protocol */ ftdm_user_layer1_prot_t bearer_layer1; + ftdm_calling_party_category_t cpc; /*!< Calling party category */ + ftdm_variable_container_t variables; /*!< Variables attached to this call */ + /* We need call_id inside caller_data for the user to be able to retrieve + * the call_id when ftdm_channel_call_place is called. This is the only time + * that the user can use caller_data.call_id to obtain the call_id. The user + * should use the call_id from sigmsg otherwise */ + uint32_t call_id; /*!< Unique call ID for this call */ } ftdm_caller_data_t; /*! \brief Tone type */ @@ -306,7 +334,8 @@ typedef enum { FTDM_SIGEVENT_RELEASED, /*!< Channel is completely released and available */ FTDM_SIGEVENT_UP, /*!< Outgoing call has been answered */ FTDM_SIGEVENT_FLASH, /*!< Flash event (typically on-hook/off-hook for analog devices) */ - FTDM_SIGEVENT_PROCEED, /*!< Outgoing call got a response */ + FTDM_SIGEVENT_PROCEED, /*!< Outgoing call got a response */ + FTDM_SIGEVENT_RINGING, /*!< Remote side is in ringing state */ FTDM_SIGEVENT_PROGRESS, /*!< Outgoing call is making progress */ FTDM_SIGEVENT_PROGRESS_MEDIA, /*!< Outgoing call is making progress and there is media available */ FTDM_SIGEVENT_ALARM_TRAP, /*!< Hardware alarm ON */ @@ -316,12 +345,14 @@ typedef enum { FTDM_SIGEVENT_RESTART, /*!< Restart has been requested. Typically you hangup your call resources here */ FTDM_SIGEVENT_SIGSTATUS_CHANGED, /*!< Signaling protocol status changed (ie: D-chan up), see new status in raw_data ftdm_sigmsg_t member */ FTDM_SIGEVENT_COLLISION, /*!< Outgoing call was dropped because an incoming call arrived at the same time */ - FTDM_SIGEVENT_MSG, /*!< We received an in-call msg */ - FTDM_SIGEVENT_INVALID + FTDM_SIGEVENT_FACILITY, /*!< In call facility event */ + FTDM_SIGEVENT_TRACE, /*! 0 if availability is supported + * \retval -1 if availability is not supported + */ +FT_DECLARE(int) ftdm_channel_get_availability(ftdm_channel_t *ftdmchan); + /*! \brief Answer call */ #define ftdm_channel_call_answer(ftdmchan) _ftdm_channel_call_answer(__FILE__, __FUNCTION__, __LINE__, (ftdmchan)) @@ -672,6 +752,12 @@ FT_DECLARE(ftdm_status_t) _ftdm_channel_call_place(const char *file, const char /*! \brief Indicate a new condition in an incoming call recording the source code point where it was called (see ftdm_channel_call_indicate for an easy to use macro) */ FT_DECLARE(ftdm_status_t) _ftdm_channel_call_indicate(const char *file, const char *func, int line, ftdm_channel_t *ftdmchan, ftdm_channel_indication_t indication); +/*! \brief Send a message on a call */ +#define ftdm_channel_call_send_msg(ftdmchan, sigmsg) _ftdm_channel_call_send_msg(__FILE__, __FUNCTION__, __LINE__, (ftdmchan), (sigmsg)) + +/*! \brief Send a signal on a call recording the source code point where it was called (see ftdm_channel_call_send_msg for an easy to use macro) */ +FT_DECLARE(ftdm_status_t) _ftdm_channel_call_send_msg(const char *file, const char *func, int line, ftdm_channel_t *ftdmchan, ftdm_sigmsg_t *sigmsg); + /*! \brief Hangup the call without cause */ #define ftdm_channel_call_hangup(ftdmchan) _ftdm_channel_call_hangup(__FILE__, __FUNCTION__, __LINE__, (ftdmchan)) @@ -684,6 +770,14 @@ FT_DECLARE(ftdm_status_t) _ftdm_channel_call_hangup(const char *file, const char /*! \brief Hangup the call with cause recording the source code point where it was called (see ftdm_channel_call_hangup_with_cause for an easy to use macro) */ FT_DECLARE(ftdm_status_t) _ftdm_channel_call_hangup_with_cause(const char *file, const char *func, int line, ftdm_channel_t *ftdmchan, ftdm_call_cause_t); +/*! \brief Reset the channel */ +#define ftdm_channel_reset(ftdmchan) _ftdm_channel_reset(__FILE__, __FUNCTION__, __LINE__, (ftdmchan)) + +/*! \brief Reset the channel (see _ftdm_channel_reset for an easy to use macro) + * \note if there was a call on this channel, call will be cleared without any notifications to the user + */ +FT_DECLARE(ftdm_status_t) _ftdm_channel_reset(const char *file, const char *func, int line, ftdm_channel_t *ftdmchan); + /*! \brief Put a call on hold (if supported by the signaling stack) */ #define ftdm_channel_call_hold(ftdmchan) _ftdm_channel_call_hold(__FILE__, __FUNCTION__, __LINE__, (ftdmchan)) @@ -723,6 +817,7 @@ FT_DECLARE(ftdm_status_t) ftdm_span_set_sig_status(ftdm_span_t *span, ftdm_signa /*! \brief Get span signaling status (ie: whether protocol layer is up or down) */ FT_DECLARE(ftdm_status_t) ftdm_span_get_sig_status(ftdm_span_t *span, ftdm_signaling_status_t *status); + /*! * \brief Set user private data in the channel * @@ -1128,6 +1223,45 @@ FT_DECLARE(ftdm_iterator_t *) ftdm_iterator_next(ftdm_iterator_t *iter); */ FT_DECLARE(ftdm_status_t) ftdm_iterator_free(ftdm_iterator_t *iter); +/*! \brief Add a custom variable to the call + * \note This variables may be used by signaling modules to override signaling parameters + * \todo Document which signaling variables are available + * */ +FT_DECLARE(ftdm_status_t) ftdm_call_add_var(ftdm_caller_data_t *caller_data, const char *var_name, const char *value); + +/*! \brief Get a custom variable from the call. + * \note The variable pointer returned is only valid during the callback receiving SIGEVENT. */ +FT_DECLARE(const char *) ftdm_call_get_var(ftdm_caller_data_t *caller_data, const char *var_name); + +/*! \brief Get an iterator to iterate over the channel variables + * \param caller_data The signal msg structure containing the variables + * \param iter Optional iterator. You can reuse an old iterator (not previously freed) to avoid the extra allocation of a new iterator. + * \note The iterator pointer returned is only valid while the signal message and it'll be destroyed when the signal message is processed. + * This iterator is completely non-thread safe, if you are adding variables or removing variables while iterating + * results are unpredictable + */ +FT_DECLARE(ftdm_iterator_t *) ftdm_call_get_var_iterator(const ftdm_caller_data_t *caller_data, ftdm_iterator_t *iter); + +/*! \brief Get variable name and value for the current iterator position */ +FT_DECLARE(ftdm_status_t) ftdm_call_get_current_var(ftdm_iterator_t *iter, const char **var_name, const char **var_val); + +/*! \brief Clear all variables attached to the call + * \note Variables are cleared at the end of each call back, so it is not necessary for the user to call this function. + * \todo Document which signaling variables are available + * */ +FT_DECLARE(ftdm_status_t) ftdm_call_clear_vars(ftdm_caller_data_t *caller_data); + +/*! \brief Remove a variable attached to the call + * \note Removes a variable that was attached to the call. + * \todo Document which call variables are available + * */ +FT_DECLARE(ftdm_status_t) ftdm_call_remove_var(ftdm_caller_data_t *caller_data, const char *var_name); + +/*! \brief Clears all the temporary data attached to this call + * \note Clears caller_data->variables and caller_data->raw_data. + * */ +FT_DECLARE(void) ftdm_call_clear_data(ftdm_caller_data_t *caller_data); + /*! \brief Get the span pointer associated to the channel */ FT_DECLARE(ftdm_span_t *) ftdm_channel_get_span(const ftdm_channel_t *ftdmchan); diff --git a/libs/freetdm/src/include/ftdm_call_utils.h b/libs/freetdm/src/include/ftdm_call_utils.h index 835a5c6cdc..2418273343 100644 --- a/libs/freetdm/src/include/ftdm_call_utils.h +++ b/libs/freetdm/src/include/ftdm_call_utils.h @@ -30,6 +30,12 @@ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Contributors: + * + * Moises Silva + * Ricardo Barroetaveña + * */ #ifndef __FTDM_CALL_UTILS_H__ @@ -114,5 +120,16 @@ FT_DECLARE(ftdm_status_t) ftdm_set_presentation_ind(const char *string, uint8_t */ FT_DECLARE(ftdm_status_t) ftdm_is_number(const char *number); +/*! + * \brief Set the Calling Party Category from an enum + * + * \param cpc_string string value + * \param target the target to set value to + * + * \retval FTDM_SUCCESS success + * \retval FTDM_FAIL failure + */ +FT_DECLARE(ftdm_status_t) ftdm_set_calling_party_category(const char *string, uint8_t *target); + #endif /* __FTDM_CALL_UTILS_H__ */ diff --git a/libs/freetdm/src/include/ftdm_declare.h b/libs/freetdm/src/include/ftdm_declare.h index 4aba703f28..bfec448253 100644 --- a/libs/freetdm/src/include/ftdm_declare.h +++ b/libs/freetdm/src/include/ftdm_declare.h @@ -158,12 +158,16 @@ typedef __int64 int64_t; typedef __int32 int32_t; typedef __int16 int16_t; typedef __int8 int8_t; +#define FTDM_O_BINARY O_BINARY +#define FTDM_SIZE_FMT "Id" #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_O_BINARY 0 +#define FTDM_SIZE_FMT "zd" #define FTDM_INVALID_SOCKET -1 typedef int ftdm_socket_t; #include diff --git a/libs/freetdm/src/include/ftdm_os.h b/libs/freetdm/src/include/ftdm_os.h index 5026bb7236..f3ebee9ea2 100644 --- a/libs/freetdm/src/include/ftdm_os.h +++ b/libs/freetdm/src/include/ftdm_os.h @@ -39,9 +39,12 @@ extern "C" { #endif +#if defined(__linux__) && !defined(__USE_BSD) +#define __USE_BSD +#endif + #include "ftdm_declare.h" #include "ftdm_threadmutex.h" - #include #ifndef __WINDOWS__ diff --git a/libs/freetdm/src/include/private/ftdm_core.h b/libs/freetdm/src/include/private/ftdm_core.h index a1e1c02439..606a89fc77 100644 --- a/libs/freetdm/src/include/private/ftdm_core.h +++ b/libs/freetdm/src/include/private/ftdm_core.h @@ -411,7 +411,7 @@ struct ftdm_channel { uint32_t extra_id; ftdm_chan_type_t type; ftdm_socket_t sockfd; - uint32_t flags; + uint64_t flags; uint32_t pflags; uint32_t sflags; ftdm_alarm_flag_t alarm_flags; @@ -493,6 +493,7 @@ struct ftdm_span { ftdm_trunk_type_t trunk_type; ftdm_analog_start_type_t start_type; ftdm_signal_type_t signal_type; + uint32_t last_used_index; /* Private signaling data. Do not touch unless you are a signaling module */ void *signal_data; fio_signal_cb_t signal_cb; @@ -503,6 +504,7 @@ struct ftdm_span { teletone_multi_tone_t tone_finder[FTDM_TONEMAP_INVALID+1]; ftdm_channel_t *channels[FTDM_MAX_CHANNELS_SPAN+1]; fio_channel_outgoing_call_t outgoing_call; + fio_channel_send_msg_t send_msg; fio_channel_set_sig_status_t set_channel_sig_status; fio_channel_get_sig_status_t get_channel_sig_status; fio_span_set_sig_status_t set_span_sig_status; @@ -598,7 +600,6 @@ FT_DECLARE(void) ftdm_channel_rotate_tokens(ftdm_channel_t *ftdmchan); FT_DECLARE(int) ftdm_load_module(const char *name); FT_DECLARE(int) ftdm_load_module_assume(const char *name); FT_DECLARE(int) ftdm_vasprintf(char **ret, const char *fmt, va_list ap); -FT_DECLARE(ftdm_status_t) ftdm_channel_done(ftdm_channel_t *ftdmchan); FT_DECLARE(ftdm_status_t) ftdm_span_close_all(void); FT_DECLARE(ftdm_status_t) ftdm_channel_open_chan(ftdm_channel_t *ftdmchan); diff --git a/libs/freetdm/src/include/private/ftdm_types.h b/libs/freetdm/src/include/private/ftdm_types.h index df747021b2..b7c6d4a6f3 100644 --- a/libs/freetdm/src/include/private/ftdm_types.h +++ b/libs/freetdm/src/include/private/ftdm_types.h @@ -184,6 +184,9 @@ typedef enum { FTDM_SPAN_USE_SIGNALS_QUEUE = (1 << 10), /* If this flag is set, channel will be moved to proceed state when calls goes to routing */ FTDM_SPAN_USE_PROCEED_STATE = (1 << 11), + /* If this flag is set, the signalling module supports jumping directly to state up, without + going through PROGRESS/PROGRESS_MEDIA */ + FTDM_SPAN_USE_SKIP_STATES = (1 << 12), } ftdm_span_flag_t; /*! \brief Channel supported features */ @@ -225,60 +228,50 @@ typedef enum { FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_HANGUP_COMPLETE, FTDM_CHANNEL_STATE_IN_LOOP, + FTDM_CHANNEL_STATE_RESET, FTDM_CHANNEL_STATE_INVALID } ftdm_channel_state_t; #define CHANNEL_STATE_STRINGS "DOWN", "HOLD", "SUSPENDED", "DIALTONE", "COLLECT", \ "RING", "RINGING", "BUSY", "ATTN", "GENRING", "DIALING", "GET_CALLERID", "CALLWAITING", \ "RESTART", "PROCEED", "PROGRESS", "PROGRESS_MEDIA", "UP", "IDLE", "TERMINATING", "CANCEL", \ - "HANGUP", "HANGUP_COMPLETE", "IN_LOOP", "INVALID" + "HANGUP", "HANGUP_COMPLETE", "IN_LOOP", "RESET", "INVALID" FTDM_STR2ENUM_P(ftdm_str2ftdm_channel_state, ftdm_channel_state2str, ftdm_channel_state_t) -typedef enum { - FTDM_CHANNEL_CONFIGURED = (1 << 0), - FTDM_CHANNEL_READY = (1 << 1), - FTDM_CHANNEL_OPEN = (1 << 2), - FTDM_CHANNEL_DTMF_DETECT = (1 << 3), - FTDM_CHANNEL_SUPRESS_DTMF = (1 << 4), - FTDM_CHANNEL_TRANSCODE = (1 << 5), - FTDM_CHANNEL_BUFFER = (1 << 6), - FTDM_CHANNEL_EVENT = (1 << 7), - FTDM_CHANNEL_INTHREAD = (1 << 8), - FTDM_CHANNEL_WINK = (1 << 9), - FTDM_CHANNEL_FLASH = (1 << 10), - FTDM_CHANNEL_STATE_CHANGE = (1 << 11), - FTDM_CHANNEL_HOLD = (1 << 12), - FTDM_CHANNEL_INUSE = (1 << 13), - FTDM_CHANNEL_OFFHOOK = (1 << 14), - FTDM_CHANNEL_RINGING = (1 << 15), - FTDM_CHANNEL_PROGRESS_DETECT = (1 << 16), - FTDM_CHANNEL_CALLERID_DETECT = (1 << 17), - FTDM_CHANNEL_OUTBOUND = (1 << 18), - FTDM_CHANNEL_SUSPENDED = (1 << 19), - FTDM_CHANNEL_3WAY = (1 << 20), - FTDM_CHANNEL_PROGRESS = (1 << 21), - FTDM_CHANNEL_MEDIA = (1 << 22), - FTDM_CHANNEL_ANSWERED = (1 << 23), - FTDM_CHANNEL_MUTE = (1 << 24), - FTDM_CHANNEL_USE_RX_GAIN = (1 << 25), - FTDM_CHANNEL_USE_TX_GAIN = (1 << 26), - FTDM_CHANNEL_IN_ALARM = (1 << 27), - FTDM_CHANNEL_SIG_UP = (1 << 28), - FTDM_CHANNEL_USER_HANGUP = (1 << 29), - FTDM_CHANNEL_RX_DISABLED = (1 << 30), - FTDM_CHANNEL_TX_DISABLED = (1 << 31), - /* ok, when we reach 32, we need to move to uint64_t all the flag stuff */ -} ftdm_channel_flag_t; -#if defined(__cplusplus) && defined(WIN32) - // fix C2676 -__inline__ ftdm_channel_flag_t operator|=(ftdm_channel_flag_t a, int32_t b) { - a = (ftdm_channel_flag_t)(a | b); - return a; -} -__inline__ ftdm_channel_flag_t operator&=(ftdm_channel_flag_t a, int32_t b) { - a = (ftdm_channel_flag_t)(a & b); - return a; -} -#endif +/*!< Channel flags. This used to be an enum but we reached the 32bit limit for enums, is safer this way */ +#define FTDM_CHANNEL_CONFIGURED (1ULL << 0) +#define FTDM_CHANNEL_READY (1ULL << 1) +#define FTDM_CHANNEL_OPEN (1ULL << 2) +#define FTDM_CHANNEL_DTMF_DETECT (1ULL << 3) +#define FTDM_CHANNEL_SUPRESS_DTMF (1ULL << 4) +#define FTDM_CHANNEL_TRANSCODE (1ULL << 5) +#define FTDM_CHANNEL_BUFFER (1ULL << 6) +#define FTDM_CHANNEL_EVENT (1ULL << 7) +#define FTDM_CHANNEL_INTHREAD (1ULL << 8) +#define FTDM_CHANNEL_WINK (1ULL << 9) +#define FTDM_CHANNEL_FLASH (1ULL << 10) +#define FTDM_CHANNEL_STATE_CHANGE (1ULL << 11) +#define FTDM_CHANNEL_HOLD (1ULL << 12) +#define FTDM_CHANNEL_INUSE (1ULL << 13) +#define FTDM_CHANNEL_OFFHOOK (1ULL << 14) +#define FTDM_CHANNEL_RINGING (1ULL << 15) +#define FTDM_CHANNEL_PROGRESS_DETECT (1ULL << 16) +#define FTDM_CHANNEL_CALLERID_DETECT (1ULL << 17) +#define FTDM_CHANNEL_OUTBOUND (1ULL << 18) +#define FTDM_CHANNEL_SUSPENDED (1ULL << 19) +#define FTDM_CHANNEL_3WAY (1ULL << 20) +#define FTDM_CHANNEL_PROGRESS (1ULL << 21) +#define FTDM_CHANNEL_MEDIA (1ULL << 22) +#define FTDM_CHANNEL_ANSWERED (1ULL << 23) +#define FTDM_CHANNEL_MUTE (1ULL << 24) +#define FTDM_CHANNEL_USE_RX_GAIN (1ULL << 25) +#define FTDM_CHANNEL_USE_TX_GAIN (1ULL << 26) +#define FTDM_CHANNEL_IN_ALARM (1ULL << 27) +#define FTDM_CHANNEL_SIG_UP (1ULL << 28) +#define FTDM_CHANNEL_USER_HANGUP (1ULL << 29) +#define FTDM_CHANNEL_RX_DISABLED (1ULL << 30) +#define FTDM_CHANNEL_TX_DISABLED (1ULL << 31) +/*!< The user knows about a call in this channel */ +#define FTDM_CHANNEL_CALL_STARTED (1ULL << 32) typedef enum { ZSM_NONE, diff --git a/libs/freetdm/src/testsangomaboost.c b/libs/freetdm/src/testsangomaboost.c index 84ff287830..b007fc186b 100644 --- a/libs/freetdm/src/testsangomaboost.c +++ b/libs/freetdm/src/testsangomaboost.c @@ -48,12 +48,7 @@ #include #include #include -#ifdef __linux__ -#ifndef __USE_BSD -#define __USE_BSD -#endif -#include -#endif + #include "freetdm.h" diff --git a/libs/openzap/mod_openzap/mod_openzap.c b/libs/openzap/mod_openzap/mod_openzap.c index 8425372ef5..6a75dc85ff 100644 --- a/libs/openzap/mod_openzap/mod_openzap.c +++ b/libs/openzap/mod_openzap/mod_openzap.c @@ -821,7 +821,7 @@ static switch_status_t channel_receive_message_cas(switch_core_session_t *sessio switch (msg->message_id) { case SWITCH_MESSAGE_INDICATE_RINGING: { - if (switch_channel_test_flag(channel, CF_OUTBOUND)) { + if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) { zap_set_flag_locked(tech_pvt->zchan, ZAP_CHANNEL_PROGRESS); } else { zap_set_state_locked_wait(tech_pvt->zchan, ZAP_CHANNEL_STATE_PROGRESS); @@ -830,7 +830,7 @@ static switch_status_t channel_receive_message_cas(switch_core_session_t *sessio break; case SWITCH_MESSAGE_INDICATE_PROGRESS: { - if (switch_channel_test_flag(channel, CF_OUTBOUND)) { + if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) { zap_set_flag_locked(tech_pvt->zchan, ZAP_CHANNEL_PROGRESS); zap_set_flag_locked(tech_pvt->zchan, ZAP_CHANNEL_MEDIA); } else { @@ -841,7 +841,7 @@ static switch_status_t channel_receive_message_cas(switch_core_session_t *sessio break; case SWITCH_MESSAGE_INDICATE_ANSWER: { - if (switch_channel_test_flag(channel, CF_OUTBOUND)) { + if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) { zap_set_flag_locked(tech_pvt->zchan, ZAP_CHANNEL_ANSWERED); } else { /* lets make the ozmod_r2 module life easier by moving thru each @@ -888,7 +888,7 @@ static switch_status_t channel_receive_message_b(switch_core_session_t *session, switch (msg->message_id) { case SWITCH_MESSAGE_INDICATE_RINGING: { - if (switch_channel_test_flag(channel, CF_OUTBOUND)) { + if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) { zap_set_flag(tech_pvt->zchan, ZAP_CHANNEL_PROGRESS); } else { zap_set_state_wait(tech_pvt->zchan, ZAP_CHANNEL_STATE_PROGRESS); @@ -897,7 +897,7 @@ static switch_status_t channel_receive_message_b(switch_core_session_t *session, break; case SWITCH_MESSAGE_INDICATE_PROGRESS: { - if (switch_channel_test_flag(channel, CF_OUTBOUND)) { + if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) { zap_set_flag(tech_pvt->zchan, ZAP_CHANNEL_PROGRESS); zap_set_flag(tech_pvt->zchan, ZAP_CHANNEL_MEDIA); } else { @@ -914,7 +914,7 @@ static switch_status_t channel_receive_message_b(switch_core_session_t *session, break; case SWITCH_MESSAGE_INDICATE_ANSWER: { - if (switch_channel_test_flag(channel, CF_OUTBOUND)) { + if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) { zap_set_flag(tech_pvt->zchan, ZAP_CHANNEL_ANSWERED); } else { /* Don't skip messages in the ISDN call setup @@ -957,7 +957,7 @@ static switch_status_t channel_receive_message_fxo(switch_core_session_t *sessio switch (msg->message_id) { case SWITCH_MESSAGE_INDICATE_PROGRESS: case SWITCH_MESSAGE_INDICATE_ANSWER: - if (switch_channel_test_flag(channel, CF_OUTBOUND)) { + if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) { zap_set_flag_locked(tech_pvt->zchan, ZAP_CHANNEL_ANSWERED); zap_set_flag_locked(tech_pvt->zchan, ZAP_CHANNEL_PROGRESS); zap_set_flag_locked(tech_pvt->zchan, ZAP_CHANNEL_MEDIA); @@ -991,7 +991,7 @@ static switch_status_t channel_receive_message_fxs(switch_core_session_t *sessio switch (msg->message_id) { case SWITCH_MESSAGE_INDICATE_PROGRESS: case SWITCH_MESSAGE_INDICATE_ANSWER: - if (!switch_channel_test_flag(channel, CF_OUTBOUND)) { + if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_INBOUND) { zap_set_flag_locked(tech_pvt->zchan, ZAP_CHANNEL_ANSWERED); zap_set_flag_locked(tech_pvt->zchan, ZAP_CHANNEL_PROGRESS); zap_set_flag_locked(tech_pvt->zchan, ZAP_CHANNEL_MEDIA); @@ -1000,7 +1000,7 @@ static switch_status_t channel_receive_message_fxs(switch_core_session_t *sessio } break; case SWITCH_MESSAGE_INDICATE_RINGING: - if (!switch_channel_test_flag(channel, CF_OUTBOUND)) { + if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_INBOUND) { if (!switch_channel_test_flag(channel, CF_ANSWERED) && !switch_channel_test_flag(channel, CF_EARLY_MEDIA) && @@ -1052,7 +1052,7 @@ static switch_status_t channel_receive_message(switch_core_session_t *session, s switch (msg->message_id) { case SWITCH_MESSAGE_INDICATE_PROGRESS: case SWITCH_MESSAGE_INDICATE_ANSWER: - if (!switch_channel_test_flag(channel, CF_OUTBOUND)) { + if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_INBOUND) { if ((var = switch_channel_get_variable(channel, "openzap_pre_buffer_size"))) { int tmp = atoi(var); if (tmp > -1) { @@ -1327,7 +1327,6 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi tech_pvt->caller_profile = caller_profile; - switch_channel_set_flag(channel, CF_OUTBOUND); switch_channel_set_state(channel, CS_INIT); if (zap_channel_add_token(zchan, switch_core_session_get_uuid(*new_session), zchan->token_count) != ZAP_SUCCESS) { switch_core_session_destroy(new_session); @@ -1678,7 +1677,9 @@ static ZIO_SIGNAL_CB_FUNCTION(on_fxs_signal) switch_clear_flag_locked(tech_pvt, TFLAG_HOLD); } - if (channel_a && channel_b && !switch_channel_test_flag(channel_a, CF_OUTBOUND) && !switch_channel_test_flag(channel_b, CF_OUTBOUND)) { + if (channel_a && channel_b && switch_channel_direction(channel_a) == SWITCH_CALL_DIRECTION_INBOUND && + switch_channel_direction(channel_b) == SWITCH_CALL_DIRECTION_INBOUND) { + cause = SWITCH_CAUSE_ATTENDED_TRANSFER; if (br_a_uuid && br_b_uuid) { switch_ivr_uuid_bridge(br_a_uuid, br_b_uuid); diff --git a/libs/spandsp/src/spandsp.h.in b/libs/spandsp/src/spandsp.h.in index 9167c1c2cc..eaed548c97 100644 --- a/libs/spandsp/src/spandsp.h.in +++ b/libs/spandsp/src/spandsp.h.in @@ -39,8 +39,9 @@ #include #include @INSERT_MATH_HEADER@ +#if !defined(SPANDSP_NO_TIFF) #include - +#endif #include #include #include diff --git a/libs/stfu/stfu.c b/libs/stfu/stfu.c index 0422cd2081..b7df8ea870 100644 --- a/libs/stfu/stfu.c +++ b/libs/stfu/stfu.c @@ -27,58 +27,162 @@ */ #include "stfu.h" +//#define DB_JB 1 + +#ifndef UINT_MAX +# define UINT_MAX 4294967295U +#endif + +#ifndef UINT16_MAX +# define UINT16_MAX 65535 +#endif + #ifdef _MSC_VER /* warning C4706: assignment within conditional expression*/ #pragma warning(disable: 4706) +/* warning C4996: 'strdup': The POSIX name for this item is deprecated. Instead, use the ISO C++ conformant name: _strdup. See online help for details. */ +#pragma warning(disable:4996) #endif +#define least1(_z) (_z ? _z : 1) + +static int stfu_log_level = 7; + struct stfu_queue { struct stfu_frame *array; struct stfu_frame int_frame; + uint32_t real_array_size; uint32_t array_size; uint32_t array_len; uint32_t wr_len; + uint32_t last_index; + int32_t last_jitter; }; typedef struct stfu_queue stfu_queue_t; struct stfu_instance { struct stfu_queue a_queue; struct stfu_queue b_queue; + struct stfu_queue c_queue; struct stfu_queue *in_queue; struct stfu_queue *out_queue; + struct stfu_queue *old_queue; struct stfu_frame *last_frame; uint32_t cur_ts; uint32_t last_wr_ts; uint32_t last_rd_ts; - uint32_t interval; + uint32_t samples_per_packet; + uint32_t samples_per_second; uint32_t miss_count; uint32_t max_plc; + uint32_t qlen; + uint32_t max_qlen; + uint32_t orig_qlen; + uint32_t packet_count; + uint32_t consecutive_good_count; + uint32_t consecutive_bad_count; + uint32_t period_good_count; + uint32_t period_bad_count; + uint32_t period_packet_in_count; + uint32_t period_packet_out_count; + uint32_t period_missing_count; + + uint32_t period_need_range; + uint32_t period_need_range_avg; + uint32_t period_clean_count; + + uint32_t session_clean_count; + uint32_t session_missing_count; + + uint32_t session_packet_in_count; + uint32_t session_packet_out_count; + + uint32_t sync_out; + uint32_t sync_in; + + + int32_t ts_diff; + int32_t last_ts_diff; + int32_t same_ts; + + uint32_t period_time; + uint32_t decrement_time; + + uint32_t plc_len; + uint32_t plc_pt; + uint32_t diff; + uint32_t diff_total; + uint8_t ready; + uint8_t debug; + + char *name; + stfu_n_call_me_t callback; + void *udata; }; +static void stfu_n_reset_counters(stfu_instance_t *i); +static void null_logger(const char *file, const char *func, int line, int level, const char *fmt, ...); +static void default_logger(const char *file, const char *func, int line, int level, const char *fmt, ...); + +stfu_logger_t stfu_log = null_logger; + +void stfu_global_set_logger(stfu_logger_t logger) +{ + if (logger) { + stfu_log = logger; + } else { + stfu_log = null_logger; + } +} + +void stfu_global_set_default_logger(int level) +{ + if (level < 0 || level > 7) { + level = 7; + } + + stfu_log = default_logger; + stfu_log_level = level; +} + + static stfu_status_t stfu_n_resize_aqueue(stfu_queue_t *queue, uint32_t qlen) { unsigned char *m; - if (qlen <= queue->array_size) { - return STFU_IT_FAILED;; + if (qlen <= queue->real_array_size) { + queue->array_size = qlen; + if (queue->array_len > qlen) { + queue->array_len = qlen; + } + } else { + m = realloc(queue->array, qlen * sizeof(struct stfu_frame)); + assert(m); + memset(m + queue->array_size * sizeof(struct stfu_frame), 0, (qlen * sizeof(struct stfu_frame)) - (queue->array_size * sizeof(struct stfu_frame))); + queue->array = (struct stfu_frame *) m; + queue->real_array_size = queue->array_size = qlen; } - m = realloc(queue->array, qlen * sizeof(struct stfu_frame)); - assert(m); - memset(m + queue->array_size, 0, qlen * sizeof(struct stfu_frame) - queue->array_size); - queue->array = (struct stfu_frame *) m; - queue->array_size = qlen; return STFU_IT_WORKED; } static void stfu_n_init_aqueue(stfu_queue_t *queue, uint32_t qlen) { + queue->array = calloc(qlen, sizeof(struct stfu_frame)); assert(queue->array != NULL); memset(queue->array, 0, sizeof(struct stfu_frame) * qlen); - queue->array_size = qlen; + queue->real_array_size = queue->array_size = qlen; queue->int_frame.plc = 1; + memset(queue->int_frame.data, 255, sizeof(queue->int_frame.data)); +} + + +void stfu_n_call_me(stfu_instance_t *i, stfu_n_call_me_t callback, void *udata) +{ + i->callback = callback; + i->udata = udata; } void stfu_n_destroy(stfu_instance_t **i) @@ -88,33 +192,66 @@ void stfu_n_destroy(stfu_instance_t **i) if (i && *i) { ii = *i; *i = NULL; + if (ii->name) free(ii->name); free(ii->a_queue.array); free(ii->b_queue.array); + free(ii->c_queue.array); free(ii); } } +void stfu_n_debug(stfu_instance_t *i, const char *name) +{ + if (i->name) free(i->name); + + if (name) { + i->name = strdup(name); + i->debug = 1; + } else { + i->name = strdup("none"); + i->debug = 0; + } +} + void stfu_n_report(stfu_instance_t *i, stfu_report_t *r) { assert(i); - r->in_len = i->in_queue->array_len; - r->in_size = i->in_queue->array_size; - r->out_len = i->out_queue->array_len; - r->out_size = i->out_queue->array_size; + r->qlen = i->qlen; + r->packet_in_count = i->period_packet_in_count; + r->clean_count = i->period_clean_count; + r->consecutive_good_count = i->consecutive_good_count; + r->consecutive_bad_count = i->consecutive_bad_count; } stfu_status_t stfu_n_resize(stfu_instance_t *i, uint32_t qlen) { stfu_status_t s; + if (i->qlen == i->max_qlen) { + return STFU_IT_FAILED; + } + + if (i->max_qlen && qlen > i->max_qlen) { + if (i->qlen < i->max_qlen) { + qlen = i->max_qlen; + } else { + return STFU_IT_FAILED; + } + } + if ((s = stfu_n_resize_aqueue(&i->a_queue, qlen)) == STFU_IT_WORKED) { s = stfu_n_resize_aqueue(&i->b_queue, qlen); + s = stfu_n_resize_aqueue(&i->c_queue, qlen); + + i->qlen = qlen; + i->max_plc = 5; + i->last_frame = NULL; } return s; } -stfu_instance_t *stfu_n_init(uint32_t qlen, uint32_t max_plc) +stfu_instance_t *stfu_n_init(uint32_t qlen, uint32_t max_qlen, uint32_t samples_per_packet, uint32_t samples_per_second) { struct stfu_instance *i; @@ -123,116 +260,259 @@ stfu_instance_t *stfu_n_init(uint32_t qlen, uint32_t max_plc) return NULL; } memset(i, 0, sizeof(*i)); + + i->qlen = qlen; + i->max_qlen = max_qlen; + i->orig_qlen = qlen; + i->samples_per_packet = samples_per_packet; + stfu_n_init_aqueue(&i->a_queue, qlen); stfu_n_init_aqueue(&i->b_queue, qlen); + stfu_n_init_aqueue(&i->c_queue, qlen); + i->in_queue = &i->a_queue; i->out_queue = &i->b_queue; + i->old_queue = &i->c_queue; + i->name = strdup("none"); + + i->max_plc = i->qlen / 2; - if (max_plc) { - i->max_plc = max_plc; - } else { - i->max_plc = qlen / 2; - } + i->samples_per_second = samples_per_second ? samples_per_second : 8000; + + i->period_time = ((i->samples_per_second * 20) / i->samples_per_packet); + i->decrement_time = ((i->samples_per_second * 15) / i->samples_per_packet); return i; } +static void stfu_n_reset_counters(stfu_instance_t *i) +{ + if (stfu_log != null_logger && i->debug) { + stfu_log(STFU_LOG_EMERG, "%s COUNTER RESET........\n", i->name); + } + + if (i->callback) { + i->callback(i, i->udata); + } + + i->consecutive_good_count = 0; + i->consecutive_bad_count = 0; + i->period_good_count = 0; + i->period_clean_count = 0; + i->period_bad_count = 0; + i->period_packet_in_count = 0; + i->period_packet_out_count = 0; + i->period_missing_count = 0; + + i->period_need_range = 0; + i->period_need_range_avg = 0; + + i->diff = 0; + i->diff_total = 0; + +} + void stfu_n_reset(stfu_instance_t *i) { + if (stfu_log != null_logger && i->debug) { + stfu_log(STFU_LOG_EMERG, "%s RESET\n", i->name); + } + + i->ready = 0; i->in_queue = &i->a_queue; i->out_queue = &i->b_queue; + i->old_queue = &i->c_queue; + i->in_queue->array_len = 0; i->out_queue->array_len = 0; i->out_queue->wr_len = 0; i->last_frame = NULL; - i->miss_count = 0; + i->in_queue->last_jitter = 0; + i->out_queue->last_jitter = 0; + + + stfu_n_reset_counters(i); + stfu_n_sync(i, 1); + + i->cur_ts = 0; i->last_wr_ts = 0; - i->miss_count = 0; - i->interval = 0; + i->last_rd_ts = 0; + i->miss_count = 0; + i->packet_count = 0; + + } -static int32_t stfu_n_measure_interval(stfu_queue_t *queue) +stfu_status_t stfu_n_sync(stfu_instance_t *i, uint32_t packets) { - uint32_t index; - int32_t d, most = 0, last = 0, this, track[STFU_MAX_TRACK] = {0}; - for(index = 0; index < queue->array_len; index++) { - this = queue->array[index].ts; - if (last) { + if (packets > i->qlen) { + stfu_n_reset(i); + } else { + i->sync_out = packets; + i->sync_in = packets; + } - if ((d = this - last) > 0 && d / 10 < STFU_MAX_TRACK) { - track[(d/10)]++; - } - } - - last = this; - } - - for(index = 0; index < STFU_MAX_TRACK; index++) { - if (track[index] > track[most]) { - most = index; - } - } - - return most * 10; + return STFU_IT_WORKED; } -static int16_t stfu_n_process(stfu_instance_t *i, stfu_queue_t *queue) -{ - if (!i->interval && !(i->interval = stfu_n_measure_interval(queue))) { - return -1; - } - return 0; +static void stfu_n_swap(stfu_instance_t *i) +{ + stfu_queue_t *last_in = i->in_queue, *last_out = i->out_queue, *last_old = i->old_queue; + + i->ready = 1; + + i->in_queue = last_out; + i->out_queue = last_old; + i->old_queue = last_in; + + i->in_queue->array_len = 0; + i->out_queue->wr_len = 0; + i->last_frame = NULL; + i->miss_count = 0; + i->in_queue->last_index = 0; + i->out_queue->last_index = 0; + i->out_queue->last_jitter = 0; } stfu_status_t stfu_n_add_data(stfu_instance_t *i, uint32_t ts, uint32_t pt, void *data, size_t datalen, int last) { - uint32_t index; + uint32_t index = 0; stfu_frame_t *frame; size_t cplen = 0; + int good_ts = 0; + + if (!i->samples_per_packet && ts && i->last_rd_ts) { + i->ts_diff = ts - i->last_rd_ts; + + if (i->last_ts_diff == i->ts_diff) { + if (++i->same_ts == 5) { + i->samples_per_packet = i->ts_diff; + } + } else { + i->same_ts = 0; + } + + i->last_ts_diff = i->ts_diff; + + if (!i->samples_per_packet) { + i->last_rd_ts = ts; + return STFU_IT_FAILED; + } + } + + if (i->sync_in) { + good_ts = 1; + i->sync_in = 0; + } else { + + if ((ts && ts == i->last_rd_ts + i->samples_per_packet) || (i->last_rd_ts > 4294900000 && ts < 5000)) { + good_ts = 1; + } + + if (i->last_wr_ts) { + if ((ts <= i->last_wr_ts && (i->last_wr_ts != UINT_MAX || ts == i->last_wr_ts))) { + if (stfu_log != null_logger && i->debug) { + stfu_log(STFU_LOG_EMERG, "%s TOO LATE !!! %u \n\n\n", i->name, ts); + } + if (i->in_queue->array_len < i->in_queue->array_size) { + i->in_queue->array_len++; + } + return STFU_ITS_TOO_LATE; + } + } + } + + if (good_ts) { + i->period_clean_count++; + i->session_clean_count++; + } + + i->period_packet_in_count++; + i->session_packet_in_count++; + + i->period_need_range_avg = i->period_need_range / least1(i->period_missing_count); + + if (i->period_missing_count > i->qlen * 2) { + if (stfu_log != null_logger && i->debug) { + stfu_log(STFU_LOG_EMERG, "%s resize %u %u\n", i->name, i->qlen, i->qlen + 1); + } + stfu_n_resize(i, i->qlen + 1); + stfu_n_reset_counters(i); + } else { + if (i->qlen > i->orig_qlen && (i->consecutive_good_count > i->decrement_time || i->period_clean_count > i->decrement_time)) { + stfu_n_resize(i, i->qlen - 1); + stfu_n_reset_counters(i); + stfu_n_sync(i, i->qlen); + } + } + + + i->diff = 0; + + if (i->last_wr_ts) { + if (ts < 1000 && i->last_wr_ts > (UINT_MAX - 1000)) { + i->diff = abs(((UINT_MAX - i->last_wr_ts) + ts) / i->samples_per_packet); + } else if (ts) { + i->diff = abs(i->last_wr_ts - ts) / i->samples_per_packet; + } + } + + i->diff_total += i->diff; + + if ((i->period_packet_in_count > i->period_time)) { + uint32_t avg; + + avg = i->diff_total / least1(i->period_packet_in_count); + + i->period_packet_in_count = 0; + + if (i->period_missing_count == 0 && i->qlen > i->orig_qlen) { + stfu_n_resize(i, i->qlen - 1); + stfu_n_sync(i, i->qlen); + } + + stfu_n_reset_counters(i); + } + + + + + if (stfu_log != null_logger && i->debug) { + stfu_log(STFU_LOG_EMERG, "%s %u i=%u/%u - g:%u/%u c:%u/%u b:%u - %u:%u - %u %d %u %u %d %d\n", i->name, + i->qlen, i->period_packet_in_count, i->period_time, i->consecutive_good_count, + i->decrement_time, i->period_clean_count, i->decrement_time, i->consecutive_bad_count, + ts, ts / i->samples_per_packet, + i->period_missing_count, i->period_need_range_avg, + i->last_wr_ts, ts, i->diff, i->diff_total / least1(i->period_packet_in_count)); + } if (last || i->in_queue->array_len == i->in_queue->array_size) { - stfu_queue_t *other_queue; - - if (i->out_queue->wr_len < i->out_queue->array_len) { - return STFU_IT_FAILED; - } - - other_queue = i->in_queue; - i->in_queue = i->out_queue; - i->out_queue = other_queue; - - i->in_queue->array_len = 0; - i->out_queue->wr_len = 0; - i->last_frame = NULL; - i->miss_count = 0; - - if (stfu_n_process(i, i->out_queue) < 0) { - if (i->in_queue->array_len == i->in_queue->array_size && i->out_queue->array_len == i->out_queue->array_size) { - stfu_n_resize(i, i->out_queue->array_size * 2); - } - //return STFU_IT_FAILED; - } - for(index = 0; index < i->out_queue->array_len; index++) { - i->out_queue->array[index].was_read = 0; - } - } + stfu_n_swap(i); + } if (last) { return STFU_IM_DONE; } - index = i->in_queue->array_len++; + index = i->in_queue->array_len++; + assert(index < i->in_queue->array_size); frame = &i->in_queue->array[index]; + if (i->in_queue->array_len == i->in_queue->array_size) { + stfu_n_swap(i); + } + if ((cplen = datalen) > sizeof(frame->data)) { cplen = sizeof(frame->data); } i->last_rd_ts = ts; + i->packet_count++; memcpy(frame->data, data, cplen); + frame->pt = pt; frame->ts = ts; frame->dlen = cplen; @@ -241,23 +521,51 @@ 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) +static int stfu_n_find_any_frame(stfu_instance_t *in, stfu_queue_t *queue, stfu_frame_t **r_frame) { 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++) { + for(i = 0; i < queue->real_array_size; i++) { + frame = &queue->array[i]; + if (!frame->was_read) { + *r_frame = frame; + queue->last_index = i; + frame->was_read = 1; + in->period_packet_out_count++; + in->session_packet_out_count++; + return 1; + } + } + + return 0; +} + + +static int stfu_n_find_frame(stfu_instance_t *in, stfu_queue_t *queue, uint32_t ts, stfu_frame_t **r_frame) +{ + uint32_t i = 0; + stfu_frame_t *frame = NULL; + + if (r_frame) { + *r_frame = NULL; + } + + for(i = 0; i < queue->array_size; i++) { frame = &queue->array[i]; if (frame->ts == ts) { - *r_frame = frame; - *index = i; - frame->was_read = 1; + if (r_frame) { + *r_frame = frame; + queue->last_index = i; + frame->was_read = 1; + in->period_packet_out_count++; + in->session_packet_out_count++; + } return 1; } } @@ -267,47 +575,300 @@ static int stfu_n_find_frame(stfu_queue_t *queue, uint32_t ts, stfu_frame_t **r_ stfu_frame_t *stfu_n_read_a_frame(stfu_instance_t *i) { - uint32_t index; stfu_frame_t *rframe = NULL; - - if (((i->out_queue->wr_len == i->out_queue->array_len) || !i->out_queue->array_len)) { - return NULL; - } + int found = 0; - if (i->cur_ts == 0) { - i->cur_ts = i->out_queue->array[0].ts; - } else { - i->cur_ts += i->interval; + if (!i->samples_per_packet) { + return NULL; } + if (!i->ready) { + if (stfu_log != null_logger && i->debug) { + stfu_log(STFU_LOG_EMERG, "%s XXXSKIP\n", i->name); + } + return NULL; + } - if (stfu_n_find_frame(i->out_queue, i->cur_ts, &rframe, &index) || stfu_n_find_frame(i->in_queue, i->cur_ts, &rframe, &index)) { + + if (i->cur_ts == 0 && i->last_wr_ts < 1000) { + uint32_t x = 0; + for (x = 0; x < i->out_queue->array_len; x++) { + if (!i->out_queue->array[x].was_read) { + i->cur_ts = i->out_queue->array[x].ts; + break; + } + if (i->cur_ts == 0) { + if (stfu_log != null_logger && i->debug) { + stfu_log(STFU_LOG_EMERG, "%s XXXPUNT\n", i->name); + return NULL; + } + } + } + } else { + i->cur_ts = i->cur_ts + i->samples_per_packet; + } + + found = stfu_n_find_frame(i, i->out_queue, i->cur_ts, &rframe); + + if (found) { + if (i->out_queue->array_len) { + i->out_queue->array_len--; + } + } else { + found = stfu_n_find_frame(i, i->in_queue, i->cur_ts, &rframe); + + if (!found) { + found = stfu_n_find_frame(i, i->old_queue, i->cur_ts, &rframe); + } + } + + if (i->sync_out) { + if (!found) { + if ((found = stfu_n_find_any_frame(i, i->out_queue, &rframe))) { + i->cur_ts = rframe->ts; + } + + if (stfu_log != null_logger && i->debug) { + stfu_log(STFU_LOG_EMERG, "%s SYNC %u %u:%u\n", i->name, i->sync_out, i->cur_ts, i->cur_ts / i->samples_per_packet); + } + + } + i->sync_out = 0; + } + + if (!i->cur_ts) { + if (stfu_log != null_logger && i->debug) { + stfu_log(STFU_LOG_EMERG, "%s NO TS\n", i->name); + } + return NULL; + } + + + if (!found && i->samples_per_packet) { + uint32_t y; + stfu_frame_t *frame = NULL; + + int32_t delay = i->last_rd_ts - i->cur_ts; + uint32_t need = abs(i->last_rd_ts - i->cur_ts) / i->samples_per_packet; + + + i->period_missing_count++; + i->session_missing_count++; + i->period_need_range += need; + + if (stfu_log != null_logger && i->debug) { + stfu_log(STFU_LOG_EMERG, "%s MISSING %u:%u %u %u %d %u %d\n", i->name, + i->cur_ts, i->cur_ts / i->samples_per_packet, i->packet_count, i->last_rd_ts, delay, i->qlen, need); + } + + if (i->packet_count > i->orig_qlen * 100 && delay > 0 && need > i->qlen && need < (i->qlen + 5)) { + i->packet_count = 0; + } + + if (stfu_log != null_logger && i->debug) { + stfu_log(STFU_LOG_EMERG, "%s ", i->name); + for(y = 0; y < i->out_queue->array_size; y++) { + if ((y % 5) == 0) stfu_log(STFU_LOG_EMERG, "\n%s ", i->name); + frame = &i->out_queue->array[y]; + stfu_log(STFU_LOG_EMERG, "%u:%u\t", frame->ts, frame->ts / i->samples_per_packet); + } + stfu_log(STFU_LOG_EMERG, "\n%s ", i->name); + + + for(y = 0; y < i->in_queue->array_size; y++) { + if ((y % 5) == 0) stfu_log(STFU_LOG_EMERG, "\n%s ", i->name); + frame = &i->in_queue->array[y]; + stfu_log(STFU_LOG_EMERG, "%u:%u\t", frame->ts, frame->ts / i->samples_per_packet); + } + stfu_log(STFU_LOG_EMERG, "\n%s\n\n\n", i->name); + + } + + if (delay < 0) { + stfu_n_reset(i); + return NULL; + } + } + + if (stfu_log != null_logger && i->debug) { + if (found) { + stfu_log(STFU_LOG_EMERG, "%s O: %u:%u %u\n", i->name, rframe->ts, rframe->ts / i->samples_per_packet, rframe->plc); + } + } + + if (found) { + i->consecutive_good_count++; + i->period_good_count++; + i->consecutive_bad_count = 0; + } else { + i->consecutive_bad_count++; + i->period_bad_count++; + i->consecutive_good_count = 0; + } + + if (found) { i->last_frame = rframe; - i->out_queue->wr_len++; - i->last_wr_ts = rframe->ts; - i->miss_count = 0; + i->out_queue->wr_len++; + i->last_wr_ts = rframe->ts; + + i->miss_count = 0; + if (rframe->dlen) { + i->plc_len = rframe->dlen; + } + + i->plc_pt = rframe->pt; + } else { i->last_wr_ts = i->cur_ts; 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->dlen = i->plc_len; + rframe->pt = i->plc_pt; + rframe->ts = i->cur_ts; + i->miss_count++; + + if (stfu_log != null_logger && i->debug) { + stfu_log(STFU_LOG_EMERG, "%s PLC %d %d %ld %u:%u\n", i->name, + i->miss_count, rframe->plc, rframe->dlen, rframe->ts, rframe->ts / i->samples_per_packet); } - rframe->ts = i->cur_ts; - - if (++i->miss_count > i->max_plc) { - i->out_queue->wr_len = i->out_queue->array_size; - i->cur_ts = 0; + if (i->miss_count > i->max_plc) { + stfu_n_reset(i); rframe = NULL; } } - return rframe; + return rframe; } +#ifdef WIN32 +#ifndef vsnprintf +#define vsnprintf _vsnprintf +#endif +#endif + + +int vasprintf(char **ret, const char *format, va_list ap); + +int stfu_vasprintf(char **ret, const char *fmt, va_list ap) +{ +#if !defined(WIN32) && !defined(__sun) + return vasprintf(ret, fmt, ap); +#else + char *buf; + int len; + size_t buflen; + va_list ap2; + char *tmp = NULL; + +#ifdef _MSC_VER +#if _MSC_VER >= 1500 + /* hack for incorrect assumption in msvc header files for code analysis */ + __analysis_assume(tmp); +#endif + ap2 = ap; +#else + va_copy(ap2, ap); +#endif + + len = vsnprintf(tmp, 0, fmt, ap2); + + if (len > 0 && (buf = malloc((buflen = (size_t) (len + 1)))) != NULL) { + len = vsnprintf(buf, buflen, fmt, ap); + *ret = buf; + } else { + *ret = NULL; + len = -1; + } + + va_end(ap2); + return len; +#endif +} + + + + +int stfu_snprintf(char *buffer, size_t count, const char *fmt, ...) +{ + va_list ap; + int ret; + + va_start(ap, fmt); + ret = vsnprintf(buffer, count-1, fmt, ap); + if (ret < 0) + buffer[count-1] = '\0'; + va_end(ap); + return ret; +} + +static void null_logger(const char *file, const char *func, int line, int level, const char *fmt, ...) +{ + if (file && func && line && level && fmt) { + return; + } + return; +} + + + +static const char *LEVEL_NAMES[] = { + "EMERG", + "ALERT", + "CRIT", + "ERROR", + "WARNING", + "NOTICE", + "INFO", + "DEBUG", + NULL +}; + +static const char *cut_path(const char *in) +{ + const char *p, *ret = in; + char delims[] = "/\\"; + char *i; + + for (i = delims; *i; i++) { + p = in; + while ((p = strchr(p, *i)) != 0) { + ret = ++p; + } + } + return ret; +} + + +static void default_logger(const char *file, const char *func, int line, int level, const char *fmt, ...) +{ + const char *fp; + char *data; + va_list ap; + int ret; + + if (level < 0 || level > 7) { + level = 7; + } + if (level > stfu_log_level) { + return; + } + + fp = cut_path(file); + + va_start(ap, fmt); + + ret = stfu_vasprintf(&data, fmt, ap); + + if (ret != -1) { + fprintf(stderr, "[%s] %s:%d %s() %s", LEVEL_NAMES[level], file, line, func, data); + free(data); + } + + va_end(ap); + +} + + /* For Emacs: * Local Variables: * mode:c diff --git a/libs/stfu/stfu.h b/libs/stfu/stfu.h index 900db6f9ac..ad769c62e2 100644 --- a/libs/stfu/stfu.h +++ b/libs/stfu/stfu.h @@ -38,6 +38,8 @@ extern "C" { #include #include #include +#include + #ifdef _MSC_VER #ifndef uint32_t @@ -62,6 +64,85 @@ typedef unsigned long in_addr_t; #endif #include + + +#ifdef WIN32 +#include +#include +typedef SOCKET stfu_socket_t; +typedef unsigned __int64 uint64_t; +typedef unsigned __int32 uint32_t; +typedef unsigned __int16 uint16_t; +typedef unsigned __int8 uint8_t; +typedef __int64 int64_t; +typedef __int32 int32_t; +typedef __int16 int16_t; +typedef __int8 int8_t; +typedef intptr_t stfu_ssize_t; +typedef int stfu_filehandle_t; +#define STFU_SOCK_INVALID INVALID_SOCKET +#define strerror_r(num, buf, size) strerror_s(buf, size, num) +#if defined(STFU_DECLARE_STATIC) +#define STFU_DECLARE(type) type __stdcall +#define STFU_DECLARE_NONSTD(type) type __cdecl +#define STFU_DECLARE_DATA +#elif defined(STFU_EXPORTS) +#define STFU_DECLARE(type) __declspec(dllexport) type __stdcall +#define STFU_DECLARE_NONSTD(type) __declspec(dllexport) type __cdecl +#define STFU_DECLARE_DATA __declspec(dllexport) +#else +#define STFU_DECLARE(type) __declspec(dllimport) type __stdcall +#define STFU_DECLARE_NONSTD(type) __declspec(dllimport) type __cdecl +#define STFU_DECLARE_DATA __declspec(dllimport) +#endif +#else +#define STFU_DECLARE(type) type +#define STFU_DECLARE_NONSTD(type) type +#define STFU_DECLARE_DATA +#include +#include +#include +#include +#include +#include +#include +#define STFU_SOCK_INVALID -1 +typedef int stfu_socket_t; +typedef ssize_t stfu_ssize_t; +typedef int stfu_filehandle_t; +#endif + + +#define STFU_PRE __FILE__, __FUNCTION__, __LINE__ +#define STFU_LOG_LEVEL_DEBUG 7 +#define STFU_LOG_LEVEL_INFO 6 +#define STFU_LOG_LEVEL_NOTICE 5 +#define STFU_LOG_LEVEL_WARNING 4 +#define STFU_LOG_LEVEL_ERROR 3 +#define STFU_LOG_LEVEL_CRIT 2 +#define STFU_LOG_LEVEL_ALERT 1 +#define STFU_LOG_LEVEL_EMERG 0 + +#define STFU_LOG_DEBUG STFU_PRE, STFU_LOG_LEVEL_DEBUG +#define STFU_LOG_INFO STFU_PRE, STFU_LOG_LEVEL_INFO +#define STFU_LOG_NOTICE STFU_PRE, STFU_LOG_LEVEL_NOTICE +#define STFU_LOG_WARNING STFU_PRE, STFU_LOG_LEVEL_WARNING +#define STFU_LOG_ERROR STFU_PRE, STFU_LOG_LEVEL_ERROR +#define STFU_LOG_CRIT STFU_PRE, STFU_LOG_LEVEL_CRIT +#define STFU_LOG_ALERT STFU_PRE, STFU_LOG_LEVEL_ALERT +#define STFU_LOG_EMERG STFU_PRE, STFU_LOG_LEVEL_EMERG +typedef void (*stfu_logger_t)(const char *file, const char *func, int line, int level, const char *fmt, ...); + + +int stfu_vasprintf(char **ret, const char *fmt, va_list ap); + +extern stfu_logger_t stfu_log; + +/*! Sets the logger for libstfu. Default is the null_logger */ +void stfu_global_set_logger(stfu_logger_t logger); +/*! Sets the default log level for libstfu */ +void stfu_global_set_default_logger(int level); + #define STFU_DATALEN 16384 #define STFU_QLEN 300 #define STFU_MAX_TRACK 256 @@ -69,7 +150,8 @@ typedef unsigned long in_addr_t; typedef enum { STFU_IT_FAILED, STFU_IT_WORKED, - STFU_IM_DONE + STFU_IM_DONE, + STFU_ITS_TOO_LATE } stfu_status_t; struct stfu_frame { @@ -86,21 +168,25 @@ struct stfu_instance; typedef struct stfu_instance stfu_instance_t; typedef struct { - uint32_t in_len; - uint32_t in_size; - uint32_t out_len; - uint32_t out_size; - + uint32_t qlen; + uint32_t packet_in_count; + uint32_t clean_count; + uint32_t consecutive_good_count; + uint32_t consecutive_bad_count; } stfu_report_t; +typedef void (*stfu_n_call_me_t)(stfu_instance_t *i, void *); 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, uint32_t max_plc); +stfu_instance_t *stfu_n_init(uint32_t qlen, uint32_t max_qlen, uint32_t samples_per_packet, uint32_t samples_per_second); 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); void stfu_n_reset(stfu_instance_t *i); +stfu_status_t stfu_n_sync(stfu_instance_t *i, uint32_t packets); +void stfu_n_call_me(stfu_instance_t *i, stfu_n_call_me_t callback, void *udata); +void stfu_n_debug(stfu_instance_t *i, const char *name); #define stfu_im_done(i) stfu_n_add_data(i, 0, NULL, 0, 1) #define stfu_n_eat(i,t,p,d,l) stfu_n_add_data(i, t, p, d, l, 0) diff --git a/src/include/private/switch_core_pvt.h b/src/include/private/switch_core_pvt.h index 13410a00ae..422d5f2930 100644 --- a/src/include/private/switch_core_pvt.h +++ b/src/include/private/switch_core_pvt.h @@ -31,7 +31,8 @@ * this file does not exist!!!! * */ - +#define SPANDSP_NO_TIFF 1 +#include "spandsp.h" #include "switch_profile.h" #ifndef WIN32 @@ -169,6 +170,7 @@ struct switch_core_session { switch_log_level_t loglevel; uint32_t soft_lock; switch_ivr_dmachine_t *dmachine; + plc_state_t *plc; }; struct switch_media_bug { diff --git a/src/include/switch_apr.h b/src/include/switch_apr.h index dc81d1a522..d89a13bb30 100644 --- a/src/include/switch_apr.h +++ b/src/include/switch_apr.h @@ -1110,6 +1110,8 @@ SWITCH_DECLARE(int) switch_sockaddr_equal(const switch_sockaddr_t *sa1, const sw SWITCH_DECLARE(switch_status_t) switch_sockaddr_info_get(switch_sockaddr_t ** sa, const char *hostname, int32_t family, switch_port_t port, int32_t flags, switch_memory_pool_t *pool); +SWITCH_DECLARE(switch_status_t) switch_sockaddr_create(switch_sockaddr_t **sa, switch_memory_pool_t *pool); + /** * Send data over a network. * @param sock The socket to send the data over. diff --git a/src/include/switch_channel.h b/src/include/switch_channel.h index d6bce5e8bf..e726554d81 100644 --- a/src/include/switch_channel.h +++ b/src/include/switch_channel.h @@ -312,6 +312,8 @@ SWITCH_DECLARE(switch_status_t) switch_channel_caller_extension_masquerade(switc */ SWITCH_DECLARE(void) switch_channel_set_caller_extension(switch_channel_t *channel, switch_caller_extension_t *caller_extension); +SWITCH_DECLARE(void) switch_channel_sort_cid(switch_channel_t *channel, switch_bool_t in); + /*! \brief Retrieve caller extension from a given channel \param channel channel to retrieve extension from diff --git a/src/include/switch_rtp.h b/src/include/switch_rtp.h index 7269a2b8d9..c48a40e6d1 100644 --- a/src/include/switch_rtp.h +++ b/src/include/switch_rtp.h @@ -229,7 +229,14 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_activate_rtcp(switch_rtp_t *rtp_sessi \param queue_frames the number of frames to delay \return SWITCH_STATUS_SUCCESS */ -SWITCH_DECLARE(switch_status_t) switch_rtp_activate_jitter_buffer(switch_rtp_t *rtp_session, uint32_t queue_frames); +SWITCH_DECLARE(switch_status_t) switch_rtp_activate_jitter_buffer(switch_rtp_t *rtp_session, + uint32_t queue_frames, + uint32_t max_queue_frames, + uint32_t samples_per_packet, uint32_t samples_per_second); + +SWITCH_DECLARE(switch_status_t) switch_rtp_debug_jitter_buffer(switch_rtp_t *rtp_session, const char *name); + +SWITCH_DECLARE(switch_status_t) switch_rtp_deactivate_jitter_buffer(switch_rtp_t *rtp_session); /*! \brief Set an RTP Flag diff --git a/src/include/switch_types.h b/src/include/switch_types.h index c01638089f..e04f437eb3 100644 --- a/src/include/switch_types.h +++ b/src/include/switch_types.h @@ -790,6 +790,7 @@ typedef enum { SWITCH_MESSAGE_INDICATE_T38_DESCRIPTION, SWITCH_MESSAGE_INDICATE_UDPTL_MODE, SWITCH_MESSAGE_INDICATE_CLEAR_PROGRESS, + SWITCH_MESSAGE_INDICATE_JITTER_BUFFER, SWITCH_MESSAGE_INVALID } switch_core_session_message_types_t; @@ -1093,6 +1094,8 @@ typedef enum { CF_PASSTHRU_PTIME_MISMATCH, CF_BRIDGE_NOWRITE, CF_RECOVERED, + CF_JITTERBUFFER, + CF_DIALPLAN, /* WARNING: DO NOT ADD ANY FLAGS BELOW THIS LINE */ CF_FLAG_MAX } switch_channel_flag_t; diff --git a/src/mod/applications/mod_commands/mod_commands.c b/src/mod/applications/mod_commands/mod_commands.c index c7edfd5420..dba86e3103 100644 --- a/src/mod/applications/mod_commands/mod_commands.c +++ b/src/mod/applications/mod_commands/mod_commands.c @@ -2491,24 +2491,101 @@ SWITCH_STANDARD_API(uuid_display_function) #define SIMPLIFY_SYNTAX "" SWITCH_STANDARD_API(uuid_simplify_function) { + char *mydata = NULL, *argv[2] = { 0 }; + int argc = 0; + switch_status_t status = SWITCH_STATUS_FALSE; if (zstr(cmd)) { - stream->write_function(stream, "-USAGE: %s\n", SIMPLIFY_SYNTAX); - } else { + goto error; + } + + mydata = strdup(cmd); + switch_assert(mydata); + + argc = switch_separate_string(mydata, ' ', argv, (sizeof(argv) / sizeof(argv[0]))); + + if (argc < 1) { + goto error; + } + if (argv[0]) { switch_core_session_message_t msg = { 0 }; switch_core_session_t *lsession = NULL; msg.message_id = SWITCH_MESSAGE_INDICATE_SIMPLIFY; - msg.string_arg = cmd; + msg.string_arg = argv[0]; msg.from = __FILE__; - if ((lsession = switch_core_session_locate(cmd))) { + if ((lsession = switch_core_session_locate(argv[0]))) { status = switch_core_session_receive_message(lsession, &msg); switch_core_session_rwunlock(lsession); } + goto ok; + } else { + goto error; } + error: + stream->write_function(stream, "-USAGE: %s\n", SIMPLIFY_SYNTAX); + switch_safe_free(mydata); + return SWITCH_STATUS_SUCCESS; + ok: + switch_safe_free(mydata); + + if (status == SWITCH_STATUS_SUCCESS) { + stream->write_function(stream, "+OK Success\n"); + } else { + stream->write_function(stream, "-ERR Operation Failed\n"); + } + + return SWITCH_STATUS_SUCCESS; +} + + +#define JITTERBUFFER_SYNTAX " [0|[:]]" +SWITCH_STANDARD_API(uuid_jitterbuffer_function) +{ + char *mydata = NULL, *argv[2] = { 0 }; + int argc = 0; + + switch_status_t status = SWITCH_STATUS_FALSE; + + if (zstr(cmd)) { + goto error; + } + + mydata = strdup(cmd); + switch_assert(mydata); + + argc = switch_separate_string(mydata, ' ', argv, (sizeof(argv) / sizeof(argv[0]))); + + if (argc < 2) { + goto error; + } + if (argv[1]) { + switch_core_session_message_t msg = { 0 }; + switch_core_session_t *lsession = NULL; + + msg.message_id = SWITCH_MESSAGE_INDICATE_JITTER_BUFFER; + msg.string_arg = argv[1]; + msg.from = __FILE__; + + if ((lsession = switch_core_session_locate(argv[0]))) { + status = switch_core_session_receive_message(lsession, &msg); + switch_core_session_rwunlock(lsession); + } + goto ok; + } else { + goto error; + } + + error: + stream->write_function(stream, "-USAGE: %s\n", JITTERBUFFER_SYNTAX); + switch_safe_free(mydata); + return SWITCH_STATUS_SUCCESS; + ok: + switch_safe_free(mydata); + if (status == SWITCH_STATUS_SUCCESS) { stream->write_function(stream, "+OK Success\n"); } else { @@ -4255,21 +4332,33 @@ SWITCH_STANDARD_API(strftime_tz_api_function) char *format = NULL; const char *tz_name = NULL; char date[80] = ""; + char *mycmd = NULL, *p; + switch_time_t when = 0; - if (!zstr(cmd)) { - format = strchr(cmd, ' '); - tz_name = cmd; - if (format) { + if (cmd) mycmd = strdup(cmd); + + if (!zstr(mycmd)) { + tz_name = mycmd; + + if ((format = strchr(mycmd, ' '))) { *format++ = '\0'; } + + if ((p = strchr(format, '|'))) { + *p++ = '\0'; + when = atol(format); + format = p; + } } - if (switch_strftime_tz(tz_name, format, date, sizeof(date), 0) == SWITCH_STATUS_SUCCESS) { /* The lookup of the zone may fail. */ + if (switch_strftime_tz(tz_name, format, date, sizeof(date), when * 1000000) == SWITCH_STATUS_SUCCESS) { /* The lookup of the zone may fail. */ stream->write_function(stream, "%s", date); } else { stream->write_function(stream, "-ERR Invalid Timezone\n"); } + switch_safe_free(mycmd); + return SWITCH_STATUS_SUCCESS; } @@ -4692,7 +4781,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_commands_load) SWITCH_ADD_API(commands_api_interface, "show", "Show", show_function, SHOW_SYNTAX); SWITCH_ADD_API(commands_api_interface, "sql_escape", "Escape a string to prevent sql injection", sql_escape, SQL_ESCAPE_SYNTAX); SWITCH_ADD_API(commands_api_interface, "status", "status", status_function, ""); - SWITCH_ADD_API(commands_api_interface, "strftime_tz", "strftime_tz", strftime_tz_api_function, " [format string]"); + SWITCH_ADD_API(commands_api_interface, "strftime_tz", "strftime_tz", strftime_tz_api_function, " [|][format string]"); SWITCH_ADD_API(commands_api_interface, "stun", "stun", stun_function, "[:port]"); SWITCH_ADD_API(commands_api_interface, "system", "Execute a system command", system_function, SYSTEM_SYNTAX); SWITCH_ADD_API(commands_api_interface, "time_test", "time_test", time_test_function, " [count]"); @@ -4735,6 +4824,8 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_commands_load) SWITCH_ADD_API(commands_api_interface, "uuid_transfer", "Transfer a session", transfer_function, TRANSFER_SYNTAX); SWITCH_ADD_API(commands_api_interface, "uuid_dual_transfer", "Transfer a session and its partner", dual_transfer_function, DUAL_TRANSFER_SYNTAX); SWITCH_ADD_API(commands_api_interface, "uuid_simplify", "Try to cut out of a call path / attended xfer", uuid_simplify_function, SIMPLIFY_SYNTAX); + SWITCH_ADD_API(commands_api_interface, "uuid_jitterbuffer", "Try to cut out of a call path / attended xfer", + uuid_jitterbuffer_function, JITTERBUFFER_SYNTAX); SWITCH_ADD_API(commands_api_interface, "xml_locate", "find some xml", xml_locate_function, "[root |
]"); SWITCH_ADD_API(commands_api_interface, "xml_wrap", "Wrap another api command in xml", xml_wrap_api_function, " "); switch_console_set_complete("add alias add"); @@ -4831,6 +4922,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_commands_load) switch_console_set_complete("add uuid_flush_dtmf ::console::list_uuid"); switch_console_set_complete("add uuid_getvar ::console::list_uuid"); switch_console_set_complete("add uuid_hold ::console::list_uuid"); + switch_console_set_complete("add uuid_jitterbuffer ::console::list_uuid"); switch_console_set_complete("add uuid_kill ::console::list_uuid"); switch_console_set_complete("add uuid_limit_release ::console::list_uuid"); switch_console_set_complete("add uuid_loglevel ::console::list_uuid console"); @@ -4853,6 +4945,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_commands_load) switch_console_set_complete("add uuid_session_heartbeat ::console::list_uuid"); switch_console_set_complete("add uuid_setvar_multi ::console::list_uuid"); switch_console_set_complete("add uuid_setvar ::console::list_uuid"); + switch_console_set_complete("add uuid_simplify ::console::list_uuid"); switch_console_set_complete("add uuid_transfer ::console::list_uuid"); switch_console_set_complete("add uuid_dual_transfer ::console::list_uuid"); switch_console_set_complete("add version"); diff --git a/src/mod/applications/mod_conference/mod_conference.c b/src/mod/applications/mod_conference/mod_conference.c index 4cbb052994..53ce82b4cb 100644 --- a/src/mod/applications/mod_conference/mod_conference.c +++ b/src/mod/applications/mod_conference/mod_conference.c @@ -2456,7 +2456,7 @@ static void conference_loop_output(conference_member_t *member) switch_event_destroy(&event); } - if (switch_channel_test_flag(channel, CF_OUTBOUND)) { + if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) { /* test to see if outbound channel has answered */ if (switch_channel_test_flag(channel, CF_ANSWERED) && !switch_test_flag(member->conference, CFLAG_ANSWERED)) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(member->session), SWITCH_LOG_DEBUG, @@ -2599,7 +2599,7 @@ static void conference_loop_output(conference_member_t *member) switch_channel_cause2str(switch_channel_get_cause(channel))); /* if it's an outbound channel, store the release cause in the conference struct, we might need it */ - if (switch_channel_test_flag(channel, CF_OUTBOUND)) { + if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) { member->conference->bridge_hangup_cause = switch_channel_get_cause(channel); } @@ -4366,6 +4366,8 @@ static switch_status_t conf_api_sub_transfer(conference_obj_t *conference, switc } } + switch_channel_set_variable(channel, "last_transfered_conference", argv[2]); + unlock_member(member); stream->write_function(stream, "OK Member '%d' sent to conference %s.\n", member->id, argv[2]); @@ -5374,6 +5376,14 @@ SWITCH_STANDARD_APP(conference_function) } #endif + if (switch_channel_test_flag(channel, CF_RECOVERED)) { + const char *check = switch_channel_get_variable(channel, "last_transfered_conference"); + + if (!zstr(check)) { + conf_name = (char *) check; + } + } + switch_event_create(¶ms, SWITCH_EVENT_COMMAND); switch_assert(params); switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "conf_name", conf_name); @@ -5436,7 +5446,7 @@ SWITCH_STANDARD_APP(conference_function) launch_conference_thread(conference); } else { - int enforce_security = !switch_channel_test_flag(channel, CF_OUTBOUND); + int enforce_security = switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_INBOUND; const char *pvar = switch_channel_get_variable(channel, "conference_enforce_security"); if (pvar) { @@ -5645,7 +5655,7 @@ SWITCH_STANDARD_APP(conference_function) } else { /* if we're not using "bridge:" set the conference answered flag */ /* and this isn't an outbound channel, answer the call */ - if (!switch_channel_test_flag(channel, CF_OUTBOUND)) + if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_INBOUND) switch_set_flag(conference, CFLAG_ANSWERED); } diff --git a/src/mod/applications/mod_dptools/mod_dptools.c b/src/mod/applications/mod_dptools/mod_dptools.c index 4fd6a676ea..e508486380 100755 --- a/src/mod/applications/mod_dptools/mod_dptools.c +++ b/src/mod/applications/mod_dptools/mod_dptools.c @@ -269,7 +269,7 @@ SWITCH_STANDARD_APP(bind_digit_action_function) } -#define DETECT_SPEECH_SYNTAX " [] OR grammar [] OR pause OR resume" +#define DETECT_SPEECH_SYNTAX " [] OR grammar [] OR nogrammar OR pause OR resume OR stop OR param " SWITCH_STANDARD_APP(detect_speech_function) { char *argv[4]; @@ -957,6 +957,17 @@ SWITCH_STANDARD_APP(redirect_function) switch_core_session_receive_message(session, &msg); } +SWITCH_STANDARD_APP(jitterbuffer_function) +{ + switch_core_session_message_t msg = { 0 }; + + /* Tell the channel to change the jitter buffer */ + msg.from = __FILE__; + msg.string_arg = data; + msg.message_id = SWITCH_MESSAGE_INDICATE_JITTER_BUFFER; + switch_core_session_receive_message(session, &msg); +} + SWITCH_STANDARD_APP(display_function) { switch_core_session_message_t msg = { 0 }; @@ -1303,13 +1314,22 @@ SWITCH_STANDARD_API(strftime_api_function) char date[80] = ""; switch_time_t thetime; char *p; - if (!zstr(cmd) && (p = strchr(cmd, '|'))) { - thetime = switch_time_make(atoi(cmd), 0); + char *mycmd = NULL; + + if (!zstr(cmd)) { + mycmd = strdup(cmd); + } + + if (!zstr(mycmd) && (p = strchr(cmd, '|'))) { + *p++ = '\0'; + + thetime = switch_time_make(atol(cmd), 0); cmd = p + 1; } else { thetime = switch_micro_time_now(); } switch_time_exp_lt(&tm, thetime); + if (zstr(cmd)) { switch_strftime_nocheck(date, &retsize, sizeof(date), "%Y-%m-%d %T", &tm); } else { @@ -3513,6 +3533,8 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_dptools_load) SWITCH_ADD_APP(app_interface, "ivr", "Run an ivr menu", "Run an ivr menu.", ivr_application_function, "", SAF_NONE); SWITCH_ADD_APP(app_interface, "redirect", "Send session redirect", "Send a redirect message to a session.", redirect_function, "", SAF_SUPPORT_NOMEDIA); + SWITCH_ADD_APP(app_interface, "jitterbuffer", "Send session jitterbuffer", "Send a jitterbuffer message to a session.", + jitterbuffer_function, "", SAF_SUPPORT_NOMEDIA); SWITCH_ADD_APP(app_interface, "send_display", "Send session a new display", "Send session a new display.", display_function, "", SAF_SUPPORT_NOMEDIA); SWITCH_ADD_APP(app_interface, "respond", "Send session respond", "Send a respond message to a session.", respond_function, "", diff --git a/src/mod/applications/mod_fifo/mod_fifo.c b/src/mod/applications/mod_fifo/mod_fifo.c index 3943ac6ea6..9d9896956e 100644 --- a/src/mod/applications/mod_fifo/mod_fifo.c +++ b/src/mod/applications/mod_fifo/mod_fifo.c @@ -291,6 +291,7 @@ static switch_status_t fifo_queue_popfly(fifo_queue_t *queue, const char *uuid) struct fifo_node { char *name; switch_mutex_t *mutex; + switch_mutex_t *update_mutex; fifo_queue_t *fifo_list[MAX_PRI]; switch_hash_t *consumer_hash; int outbound_priority; @@ -801,6 +802,7 @@ static fifo_node_t *create_node(const char *name, uint32_t importance, switch_mu switch_core_hash_init(&node->consumer_hash, node->pool); switch_thread_rwlock_create(&node->rwlock, node->pool); switch_mutex_init(&node->mutex, SWITCH_MUTEX_NESTED, node->pool); + switch_mutex_init(&node->update_mutex, SWITCH_MUTEX_NESTED, node->pool); cbt.buf = outbound_count; cbt.len = sizeof(outbound_count); sql = switch_mprintf("select count(*) from fifo_outbound where fifo_name = '%q'", name); @@ -1193,10 +1195,10 @@ static void *SWITCH_THREAD_FUNC ringall_thread_run(switch_thread_t *thread, void if (node) { - switch_thread_rwlock_wrlock(node->rwlock); + switch_mutex_lock(node->update_mutex); node->busy = 0; node->ring_consumer_count = 1; - switch_thread_rwlock_unlock(node->rwlock); + switch_mutex_unlock(node->update_mutex); } else { goto end; } @@ -1437,10 +1439,10 @@ static void *SWITCH_THREAD_FUNC ringall_thread_run(switch_thread_t *thread, void cbh->ready = 1; if (node) { - switch_thread_rwlock_wrlock(node->rwlock); + switch_mutex_lock(node->update_mutex); node->ring_consumer_count = 0; node->busy = 0; - switch_thread_rwlock_unlock(node->rwlock); + switch_mutex_unlock(node->update_mutex); } @@ -1501,10 +1503,10 @@ static void *SWITCH_THREAD_FUNC o_thread_run(switch_thread_t *thread, void *obj) switch_mutex_unlock(globals.mutex); if (node) { - switch_thread_rwlock_wrlock(node->rwlock); + switch_mutex_lock(node->update_mutex); node->ring_consumer_count++; node->busy = 0; - switch_thread_rwlock_unlock(node->rwlock); + switch_mutex_unlock(node->update_mutex); } switch_event_create(&ovars, SWITCH_EVENT_REQUEST_PARAMS); @@ -1601,12 +1603,12 @@ static void *SWITCH_THREAD_FUNC o_thread_run(switch_thread_t *thread, void *obj) switch_event_destroy(&ovars); if (node) { - switch_thread_rwlock_wrlock(node->rwlock); + switch_mutex_lock(node->update_mutex); if (node->ring_consumer_count-- < 0) { node->ring_consumer_count = 0; } node->busy = 0; - switch_thread_rwlock_unlock(node->rwlock); + switch_mutex_unlock(node->update_mutex); } switch_core_destroy_memory_pool(&h->pool); @@ -1754,9 +1756,35 @@ static void *SWITCH_THREAD_FUNC node_thread_run(switch_thread_t *thread, void *o if (globals.debug) switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Trying priority: %d\n", cur_priority); + restart: + for (hi = switch_hash_first(NULL, globals.fifo_hash); hi; hi = switch_hash_next(hi)) { switch_hash_this(hi, &var, NULL, &val); if ((node = (fifo_node_t *) val)) { + + if (node->ready == FIFO_DELAY_DESTROY) { + int doit = 0; + + switch_mutex_lock(node->update_mutex); + doit = node->consumer_count == 0 && node_caller_count(node) == 0; + switch_mutex_unlock(node->update_mutex); + + if (doit) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "%s removed.\n", node->name); + switch_core_hash_delete(globals.fifo_hash, node->name); + + node->ready = 0; + switch_mutex_lock(node->mutex); + switch_core_hash_destroy(&node->consumer_hash); + switch_mutex_unlock(node->mutex); + switch_mutex_unlock(node->update_mutex); + switch_core_destroy_memory_pool(&node->pool); + goto restart; + } + + } + + if (node->outbound_priority == 0) node->outbound_priority = 5; if (node->has_outbound && node->ready && !node->busy && node->outbound_priority == cur_priority) { ppl_waiting = node_caller_count(node); @@ -2219,6 +2247,7 @@ SWITCH_STANDARD_APP(fifo_function) if (!(node = switch_core_hash_find(globals.fifo_hash, nlist[i]))) { node = create_node(nlist[i], importance, globals.sql_mutex); node->ready = 1; + switch_thread_rwlock_rdlock(node->rwlock); } node_list[node_count++] = node; } @@ -2306,7 +2335,7 @@ SWITCH_STANDARD_APP(fifo_function) switch_channel_answer(channel); - switch_thread_rwlock_wrlock(node->rwlock); + switch_mutex_lock(node->update_mutex); if ((pri = switch_channel_get_variable(channel, "fifo_priority"))) { p = atoi(pri); @@ -2344,7 +2373,7 @@ SWITCH_STANDARD_APP(fifo_function) switch_channel_set_variable(channel, "fifo_priority", tmp); } - switch_thread_rwlock_unlock(node->rwlock); + switch_mutex_unlock(node->update_mutex); ts = switch_micro_time_now(); switch_time_exp_lt(&tm, ts); @@ -2450,9 +2479,9 @@ SWITCH_STANDARD_APP(fifo_function) } switch_mutex_lock(globals.mutex); - switch_thread_rwlock_wrlock(node->rwlock); + switch_mutex_lock(node->update_mutex); node_remove_uuid(node, uuid); - switch_thread_rwlock_unlock(node->rwlock); + switch_mutex_unlock(node->update_mutex); send_presence(node); check_cancel(node); switch_mutex_unlock(globals.mutex); @@ -2682,9 +2711,9 @@ SWITCH_STANDARD_APP(fifo_function) } if (pop && !node_caller_count(node)) { - switch_thread_rwlock_wrlock(node->rwlock); + switch_mutex_lock(node->update_mutex); node->start_waiting = 0; - switch_thread_rwlock_unlock(node->rwlock); + switch_mutex_unlock(node->update_mutex); } } @@ -3074,21 +3103,9 @@ SWITCH_STANDARD_APP(fifo_function) done: - switch_mutex_lock(globals.mutex); - if (node && node->ready == FIFO_DELAY_DESTROY && node->consumer_count == 0 && node_caller_count(node) == 0) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_NOTICE, "%s removed.\n", node->name); - switch_core_hash_delete(globals.fifo_hash, node->name); - switch_thread_rwlock_wrlock(node->rwlock); - node->ready = 0; - switch_mutex_lock(node->mutex); - switch_core_hash_destroy(&node->consumer_hash); - switch_mutex_unlock(node->mutex); + if (node) { switch_thread_rwlock_unlock(node->rwlock); - switch_core_destroy_memory_pool(&node->pool); - } - switch_mutex_unlock(globals.mutex); - switch_channel_clear_app_flag_key(FIFO_APP_KEY, channel, FIFO_APP_BRIDGE_TAG); @@ -3699,9 +3716,9 @@ SWITCH_STANDARD_API(fifo_api_function) switch_hash_this(hi, &var, NULL, &val); node = (fifo_node_t *) val; len = node_caller_count(node); - switch_thread_rwlock_wrlock(node->rwlock); + switch_mutex_lock(node->update_mutex); stream->write_function(stream, "%s:%d:%d:%d\n", (char *) var, node->consumer_count, node_caller_count(node), len); - switch_thread_rwlock_unlock(node->rwlock); + switch_mutex_unlock(node->update_mutex); x++; } @@ -3710,9 +3727,9 @@ SWITCH_STANDARD_API(fifo_api_function) } } else if ((node = switch_core_hash_find(globals.fifo_hash, argv[1]))) { len = node_caller_count(node); - switch_thread_rwlock_wrlock(node->rwlock); + switch_mutex_lock(node->update_mutex); stream->write_function(stream, "%s:%d:%d:%d\n", argv[1], node->consumer_count, node_caller_count(node), len); - switch_thread_rwlock_unlock(node->rwlock); + switch_mutex_unlock(node->update_mutex); } else { stream->write_function(stream, "none\n"); } @@ -3722,9 +3739,9 @@ SWITCH_STANDARD_API(fifo_api_function) switch_hash_this(hi, &var, NULL, &val); node = (fifo_node_t *) val; len = node_caller_count(node); - switch_thread_rwlock_wrlock(node->rwlock); + switch_mutex_lock(node->update_mutex); stream->write_function(stream, "%s:%d\n", (char *) var, node->has_outbound); - switch_thread_rwlock_unlock(node->rwlock); + switch_mutex_unlock(node->update_mutex); x++; } @@ -3733,9 +3750,9 @@ SWITCH_STANDARD_API(fifo_api_function) } } else if ((node = switch_core_hash_find(globals.fifo_hash, argv[1]))) { len = node_caller_count(node); - switch_thread_rwlock_wrlock(node->rwlock); + switch_mutex_lock(node->update_mutex); stream->write_function(stream, "%s:%d\n", argv[1], node->has_outbound); - switch_thread_rwlock_unlock(node->rwlock); + switch_mutex_unlock(node->update_mutex); } else { stream->write_function(stream, "none\n"); } @@ -4108,7 +4125,7 @@ static switch_status_t load_config(int reload, int del_all) node->ready = FIFO_DELAY_DESTROY; } else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "%s removed.\n", node->name); - switch_thread_rwlock_wrlock(node->rwlock); + switch_mutex_lock(node->update_mutex); for (x = 0; x < MAX_PRI; x++) { while (fifo_queue_pop(node->fifo_list[x], &pop, 2) == SWITCH_STATUS_SUCCESS) { switch_event_destroy(&pop); @@ -4117,7 +4134,7 @@ static switch_status_t load_config(int reload, int del_all) switch_core_hash_delete(globals.fifo_hash, node->name); switch_core_hash_destroy(&node->consumer_hash); - switch_thread_rwlock_unlock(node->rwlock); + switch_mutex_unlock(node->update_mutex); switch_core_destroy_memory_pool(&node->pool); goto top; } @@ -4393,7 +4410,7 @@ SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_fifo_shutdown) switch_hash_this(hi, NULL, NULL, &val); node = (fifo_node_t *) val; - switch_thread_rwlock_wrlock(node->rwlock); + switch_mutex_lock(node->update_mutex); switch_mutex_lock(node->mutex); for (x = 0; x < MAX_PRI; x++) { while (fifo_queue_pop(node->fifo_list[x], &pop, 2) == SWITCH_STATUS_SUCCESS) { @@ -4403,7 +4420,7 @@ SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_fifo_shutdown) switch_mutex_unlock(node->mutex); switch_core_hash_delete(globals.fifo_hash, node->name); switch_core_hash_destroy(&node->consumer_hash); - switch_thread_rwlock_unlock(node->rwlock); + switch_mutex_unlock(node->update_mutex); switch_core_destroy_memory_pool(&node->pool); } diff --git a/src/mod/applications/mod_spy/mod_spy.c b/src/mod/applications/mod_spy/mod_spy.c index 5093ad8f22..cb8981d264 100644 --- a/src/mod/applications/mod_spy/mod_spy.c +++ b/src/mod/applications/mod_spy/mod_spy.c @@ -131,7 +131,6 @@ SWITCH_STANDARD_API(dump_hash) static switch_status_t process_event(switch_event_t *event) { switch_core_session_t *session = NULL; - switch_channel_t *channel; char *username[3] = { 0 }; char *domain[3] = { 0 }; char key[512]; @@ -172,18 +171,19 @@ static switch_status_t process_event(switch_event_t *event) return SWITCH_STATUS_FALSE; } - session = switch_core_session_locate(uuid); - channel = switch_core_session_get_channel(session); + if ((session = switch_core_session_locate(uuid))) { + switch_channel_t *channel = switch_core_session_get_channel(session); - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "UserSpy retrieved uuid %s for key %s, activating eavesdrop \n", uuid, key); - my_uuid = switch_event_get_header(event, "Unique-ID"); + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "UserSpy retrieved uuid %s for key %s, activating eavesdrop \n", uuid, key); + my_uuid = switch_event_get_header(event, "Unique-ID"); - switch_channel_set_variable(channel, "spy_uuid", my_uuid); + switch_channel_set_variable(channel, "spy_uuid", my_uuid); - switch_channel_set_state(channel, CS_EXCHANGE_MEDIA); - switch_channel_set_flag(channel, CF_BREAK); + switch_channel_set_state(channel, CS_EXCHANGE_MEDIA); + switch_channel_set_flag(channel, CF_BREAK); - switch_core_session_rwunlock(session); + switch_core_session_rwunlock(session); + } return SWITCH_STATUS_SUCCESS; } diff --git a/src/mod/endpoints/mod_gsmopen/mod_gsmopen.cpp b/src/mod/endpoints/mod_gsmopen/mod_gsmopen.cpp index 7e20b7c25e..13e433557d 100644 --- a/src/mod/endpoints/mod_gsmopen/mod_gsmopen.cpp +++ b/src/mod/endpoints/mod_gsmopen/mod_gsmopen.cpp @@ -1324,7 +1324,6 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi caller_profile = tech_pvt->caller_profile; caller_profile->destination_number = rdest; - switch_channel_set_flag(channel, CF_OUTBOUND); switch_set_flag(tech_pvt, TFLAG_OUTBOUND); switch_channel_set_state(channel, CS_INIT); gsmopen_call(tech_pvt, rdest, 30); diff --git a/src/mod/endpoints/mod_h323/mod_h323.cpp b/src/mod/endpoints/mod_h323/mod_h323.cpp index 74fb6ae11a..3d79917434 100644 --- a/src/mod/endpoints/mod_h323/mod_h323.cpp +++ b/src/mod/endpoints/mod_h323/mod_h323.cpp @@ -725,7 +725,6 @@ FSH323Connection::FSH323Connection(FSH323EndPoint& endpoint, H323Transport* tran name += outbound_profile->destination_number; switch_channel_set_name(m_fsChannel, name); - switch_channel_set_flag(m_fsChannel, CF_OUTBOUND); switch_channel_set_state(m_fsChannel, CS_INIT); } @@ -1508,7 +1507,7 @@ switch_status_t FSH323Connection::receive_message(switch_core_session_message_t break; } case SWITCH_MESSAGE_INDICATE_ANSWER: { - if (switch_channel_test_flag(channel, CF_OUTBOUND)) { + if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) { return SWITCH_STATUS_FALSE; } AnsweringCall(H323Connection::AnswerCallNow); diff --git a/src/mod/endpoints/mod_khomp/src/khomp_pvt.cpp b/src/mod/endpoints/mod_khomp/src/khomp_pvt.cpp index 3abbe3ecfb..1b126eb277 100644 --- a/src/mod/endpoints/mod_khomp/src/khomp_pvt.cpp +++ b/src/mod/endpoints/mod_khomp/src/khomp_pvt.cpp @@ -868,7 +868,6 @@ switch_status_t Board::KhompPvt::justStart(switch_caller_profile_t *profile) _caller_profile = switch_caller_profile_clone(_session, profile); switch_channel_set_caller_profile(channel, _caller_profile); - switch_channel_set_flag(channel, CF_OUTBOUND); switch_channel_set_state(channel, CS_INIT); } else diff --git a/src/mod/endpoints/mod_opal/mod_opal.cpp b/src/mod/endpoints/mod_opal/mod_opal.cpp index 8935bbb06d..0760588019 100644 --- a/src/mod/endpoints/mod_opal/mod_opal.cpp +++ b/src/mod/endpoints/mod_opal/mod_opal.cpp @@ -580,7 +580,6 @@ FSConnection::FSConnection(OpalCall & call, FSEndPoint & endpoint, void* userDat name += outbound_profile->destination_number; switch_channel_set_name(m_fsChannel, name); - switch_channel_set_flag(m_fsChannel, CF_OUTBOUND); switch_channel_set_state(m_fsChannel, CS_INIT); } } @@ -966,7 +965,7 @@ switch_status_t FSConnection::receive_message(switch_core_session_message_t *msg It would only happen if someone called switch_channel_answer() instead of switch_channel_mark_answered() on an outbound call. it should not do anything if someone does it by accident somewhere hense this in both cases: - if (switch_channel_test_flag(channel, CF_OUTBOUND)) { + if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) { return SWITCH_STATUS_FALSE; } @@ -1025,7 +1024,7 @@ switch_status_t FSConnection::receive_message(switch_core_session_message_t *msg { int fixed = 0; - if (switch_channel_test_flag(channel, CF_OUTBOUND)) { + if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) { return SWITCH_STATUS_FALSE; } diff --git a/src/mod/endpoints/mod_skinny/Net/Skinny/Protocol.pm b/src/mod/endpoints/mod_skinny/Net/Skinny/Protocol.pm index 90de304817..94708881e3 100644 --- a/src/mod/endpoints/mod_skinny/Net/Skinny/Protocol.pm +++ b/src/mod/endpoints/mod_skinny/Net/Skinny/Protocol.pm @@ -48,7 +48,7 @@ sub _find { my ($name, $value) = ($1,hex($2)); $sub{$name} = sub () { $value }; $const{$name} = $value; - } elsif(/^\s*struct\s+([a-z_]+)\s*\{\s*$/) { + } elsif(/^\s*struct\s+PACKED\s+([a-z_]+)\s*\{\s*$/) { my $struct_name = $1; $struct{$struct_name} = []; while(<$fh>) { diff --git a/src/mod/endpoints/mod_skinny/mod_skinny.c b/src/mod/endpoints/mod_skinny/mod_skinny.c index 2df8937647..5320ca52d1 100644 --- a/src/mod/endpoints/mod_skinny/mod_skinny.c +++ b/src/mod/endpoints/mod_skinny/mod_skinny.c @@ -1080,8 +1080,6 @@ switch_call_cause_t channel_outgoing_channel(switch_core_session_t *session, swi switch_channel_set_caller_profile(nchannel, caller_profile); tech_pvt->caller_profile = caller_profile; - switch_channel_set_flag(nchannel, CF_OUTBOUND); - if ((sql = switch_mprintf( "INSERT INTO skinny_active_lines " "(device_name, device_instance, line_instance, channel_uuid, call_id, call_state) " diff --git a/src/mod/endpoints/mod_skinny/mod_skinny.h b/src/mod/endpoints/mod_skinny/mod_skinny.h index b5cc96b7ae..20d68faba5 100644 --- a/src/mod/endpoints/mod_skinny/mod_skinny.h +++ b/src/mod/endpoints/mod_skinny/mod_skinny.h @@ -42,6 +42,7 @@ #define SKINNY_EVENT_UNREGISTER "skinny::unregister" #define SKINNY_EVENT_EXPIRE "skinny::expire" #define SKINNY_EVENT_ALARM "skinny::alarm" +#define SKINNY_EVENT_XML_ALARM "skinny::xml_alarm" #define SKINNY_EVENT_CALL_STATE "skinny::call_state" #define SKINNY_EVENT_USER_TO_DEVICE "skinny::user_to_device" #define SKINNY_EVENT_DEVICE_TO_USER "skinny::device_to_user" diff --git a/src/mod/endpoints/mod_skinny/skinny_protocol.h b/src/mod/endpoints/mod_skinny/skinny_protocol.h index d85a190ba8..20e7d7f92f 100644 --- a/src/mod/endpoints/mod_skinny/skinny_protocol.h +++ b/src/mod/endpoints/mod_skinny/skinny_protocol.h @@ -547,12 +547,15 @@ struct PACKED service_url_stat_res_message { #define USER_TO_DEVICE_DATA_VERSION1_MESSAGE 0x013F /* See struct PACKED extended_data_message */ +/* XMLAlarmMessage */ +#define XML_ALARM_MESSAGE 0x015A + /*****************************************************************************/ /* SKINNY MESSAGE */ /*****************************************************************************/ #define SKINNY_MESSAGE_FIELD_SIZE 4 /* 4-bytes field */ #define SKINNY_MESSAGE_HEADERSIZE 12 /* three 4-bytes fields */ -#define SKINNY_MESSAGE_MAXSIZE 1000 +#define SKINNY_MESSAGE_MAXSIZE 2048 union skinny_data { /* no data for KEEP_ALIVE_MESSAGE */ @@ -624,8 +627,7 @@ union skinny_data { struct extended_data_message extended_data; uint16_t as_uint16; - char as_char; - void *raw; + char as_char[1]; }; /* diff --git a/src/mod/endpoints/mod_skinny/skinny_server.c b/src/mod/endpoints/mod_skinny/skinny_server.c index cfafea6f01..5874be4c6c 100644 --- a/src/mod/endpoints/mod_skinny/skinny_server.c +++ b/src/mod/endpoints/mod_skinny/skinny_server.c @@ -343,7 +343,7 @@ switch_status_t skinny_session_send_call_info(switch_core_session_t *session, li zstr((called_party_number = switch_channel_get_variable(channel, "destination_number")))) { called_party_number = "0000000000"; } - if (switch_channel_test_flag(channel, CF_OUTBOUND)) { + if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) { call_type = SKINNY_INBOUND_CALL; } else { call_type = SKINNY_OUTBOUND_CALL; @@ -1674,7 +1674,7 @@ switch_status_t skinny_handle_open_receive_channel_ack_message(listener_t *liste ); switch_set_flag_locked(tech_pvt, TFLAG_IO); - if (switch_channel_test_flag(channel, CF_OUTBOUND)) { + if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) { switch_channel_mark_answered(channel); } if (switch_channel_test_flag(channel, CF_HOLD)) { @@ -1963,6 +1963,26 @@ switch_status_t skinny_handle_extended_data_message(listener_t *listener, skinny return SWITCH_STATUS_SUCCESS; } +switch_status_t skinny_handle_xml_alarm(listener_t *listener, skinny_message_t *request) +{ + switch_event_t *event = NULL; + char *tmp = NULL; + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, + "Received XML alarm.\n"); + /* skinny::xml_alarm event */ + skinny_device_event(listener, &event, SWITCH_EVENT_CUSTOM, SKINNY_EVENT_XML_ALARM); + /* Ensure that the body is null-terminated */ + tmp = malloc(request->length - 4 + 1); + memcpy(tmp, request->data.as_char, request->length - 4); + tmp[request->length - 4] = '\0'; + switch_event_add_body(event, "%s", tmp); + switch_safe_free(tmp); + switch_event_fire(&event); + + return SWITCH_STATUS_SUCCESS; +} + switch_status_t skinny_handle_request(listener_t *listener, skinny_message_t *request) { if (listener->profile->debug >= 10 || request->type != KEEP_ALIVE_MESSAGE) { @@ -1970,7 +1990,7 @@ switch_status_t skinny_handle_request(listener_t *listener, skinny_message_t *re "Received %s (type=%x,length=%d) from %s:%d.\n", skinny_message_type2str(request->type), request->type, request->length, listener->device_name, listener->device_instance); } - if(zstr(listener->device_name) && request->type != REGISTER_MESSAGE && request->type != ALARM_MESSAGE) { + if(zstr(listener->device_name) && request->type != REGISTER_MESSAGE && request->type != ALARM_MESSAGE && request->type != XML_ALARM_MESSAGE) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Device should send a register message first.\n"); return SWITCH_STATUS_FALSE; @@ -2032,6 +2052,8 @@ switch_status_t skinny_handle_request(listener_t *listener, skinny_message_t *re return skinny_handle_extended_data_message(listener, request); case DEVICE_TO_USER_DATA_RESPONSE_VERSION1_MESSAGE: return skinny_handle_extended_data_message(listener, request); + case XML_ALARM_MESSAGE: + return skinny_handle_xml_alarm(listener, request); default: switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Unhandled request %s (type=%x,length=%d).\n", skinny_message_type2str(request->type), request->type, request->length); diff --git a/src/mod/endpoints/mod_skinny/skinny_tables.c b/src/mod/endpoints/mod_skinny/skinny_tables.c index 0a27ad76c4..053b350b46 100644 --- a/src/mod/endpoints/mod_skinny/skinny_tables.c +++ b/src/mod/endpoints/mod_skinny/skinny_tables.c @@ -99,6 +99,7 @@ struct skinny_table SKINNY_MESSAGE_TYPES[] = { {"DisplayPriNotifyMessage", DISPLAY_PRI_NOTIFY_MESSAGE}, {"ServiceUrlStatMessage", SERVICE_URL_STAT_RES_MESSAGE}, {"UserToDeviceDataVersion1Message", USER_TO_DEVICE_DATA_VERSION1_MESSAGE}, + {"XMLAlarmMessage", XML_ALARM_MESSAGE}, {NULL, 0} }; SKINNY_DECLARE_ID2STR(skinny_message_type2str, SKINNY_MESSAGE_TYPES, "UnknownMessage") diff --git a/src/mod/endpoints/mod_skinny/skinny_tables.h b/src/mod/endpoints/mod_skinny/skinny_tables.h index 14962b8b78..c119e1f141 100644 --- a/src/mod/endpoints/mod_skinny/skinny_tables.h +++ b/src/mod/endpoints/mod_skinny/skinny_tables.h @@ -87,7 +87,7 @@ uint32_t func(const char *str)\ } -extern struct skinny_table SKINNY_MESSAGE_TYPES[65]; +extern struct skinny_table SKINNY_MESSAGE_TYPES[66]; const char *skinny_message_type2str(uint32_t id); uint32_t skinny_str2message_type(const char *str); #define SKINNY_PUSH_MESSAGE_TYPES SKINNY_DECLARE_PUSH_MATCH(SKINNY_MESSAGE_TYPES) diff --git a/src/mod/endpoints/mod_skypopen/mod_skypopen.c b/src/mod/endpoints/mod_skypopen/mod_skypopen.c index 1263e5f81a..56188a4188 100644 --- a/src/mod/endpoints/mod_skypopen/mod_skypopen.c +++ b/src/mod/endpoints/mod_skypopen/mod_skypopen.c @@ -526,6 +526,10 @@ static switch_status_t channel_on_destroy(switch_core_session_t *session) switch_core_timer_destroy(&tech_pvt->timer_read); } + if (tech_pvt->timer_read_srv.timer_interface && tech_pvt->timer_read_srv.timer_interface->timer_next) { + switch_core_timer_destroy(&tech_pvt->timer_read_srv); + } + if (tech_pvt->timer_write.timer_interface && tech_pvt->timer_write.timer_interface->timer_next) { switch_core_timer_destroy(&tech_pvt->timer_write); } @@ -1121,6 +1125,9 @@ static switch_status_t channel_receive_message(switch_core_session_t *session, s if (tech_pvt->timer_read.timer_interface && tech_pvt->timer_read.timer_interface->timer_next) { switch_core_timer_sync(&tech_pvt->timer_read); } + if (tech_pvt->timer_read_srv.timer_interface && tech_pvt->timer_read_srv.timer_interface->timer_next) { + switch_core_timer_sync(&tech_pvt->timer_read_srv); + } switch_mutex_unlock(tech_pvt->mutex_audio_srv); } @@ -1146,6 +1153,9 @@ static switch_status_t channel_receive_message(switch_core_session_t *session, s if (tech_pvt->timer_read.timer_interface && tech_pvt->timer_read.timer_interface->timer_next) { switch_core_timer_sync(&tech_pvt->timer_read); } + if (tech_pvt->timer_read_srv.timer_interface && tech_pvt->timer_read_srv.timer_interface->timer_next) { + switch_core_timer_sync(&tech_pvt->timer_read_srv); + } switch_mutex_unlock(tech_pvt->mutex_audio_srv); } @@ -1168,6 +1178,9 @@ static switch_status_t channel_receive_message(switch_core_session_t *session, s if (tech_pvt->timer_read.timer_interface && tech_pvt->timer_read.timer_interface->timer_next) { switch_core_timer_sync(&tech_pvt->timer_read); } + if (tech_pvt->timer_read_srv.timer_interface && tech_pvt->timer_read_srv.timer_interface->timer_next) { + switch_core_timer_sync(&tech_pvt->timer_read_srv); + } switch_mutex_unlock(tech_pvt->mutex_audio_srv); } @@ -1351,7 +1364,6 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi caller_profile = tech_pvt->caller_profile; caller_profile->destination_number = rdest; - switch_channel_set_flag(channel, CF_OUTBOUND); switch_mutex_lock(tech_pvt->flag_mutex); switch_set_flag(tech_pvt, TFLAG_OUTBOUND); switch_mutex_unlock(tech_pvt->flag_mutex); @@ -2168,6 +2180,13 @@ int start_audio_threads(private_t *tech_pvt) switch_core_timer_sync(&tech_pvt->timer_read); + if (switch_core_timer_init(&tech_pvt->timer_read_srv, "soft", MS_SKYPOPEN, SAMPLES_PER_FRAME, skypopen_module_pool) != SWITCH_STATUS_SUCCESS) { + ERRORA("setup timer failed\n", SKYPOPEN_P_LOG); + return SWITCH_STATUS_FALSE; + } + + switch_core_timer_sync(&tech_pvt->timer_read_srv); + if (switch_core_timer_init(&tech_pvt->timer_write, "soft", MS_SKYPOPEN, SAMPLES_PER_FRAME, skypopen_module_pool) != SWITCH_STATUS_SUCCESS) { ERRORA("setup timer failed\n", SKYPOPEN_P_LOG); return SWITCH_STATUS_FALSE; diff --git a/src/mod/endpoints/mod_skypopen/oss/Makefile b/src/mod/endpoints/mod_skypopen/oss/Makefile new file mode 100644 index 0000000000..8df20f68c5 --- /dev/null +++ b/src/mod/endpoints/mod_skypopen/oss/Makefile @@ -0,0 +1,43 @@ +# Comment/uncomment the following line to disable/enable debugging +#DEBUG = y +#LDDINC=/usr/src/linux-headers-2.6.32-26-server/include + +# Add your debugging flag (or not) to CFLAGS +ifeq ($(DEBUG),y) + DEBFLAGS = -O -g -DSKYPOPEN_DEBUG # "-O" is needed to expand inlines +else + DEBFLAGS = -O2 -Wall +endif + +EXTRA_CFLAGS += $(DEBFLAGS) +EXTRA_CFLAGS += -I$(LDDINC) + +ifneq ($(KERNELRELEASE),) +# call from kernel build system + +skypopen-objs := main.o + +obj-m := skypopen.o + +else + +KERNELDIR ?= /lib/modules/$(shell uname -r)/build +PWD := $(shell pwd) + +modules: + $(MAKE) -C $(KERNELDIR) M=$(PWD) LDDINC=$(PWD)/../include modules + +endif + + + +clean: + rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions + +depend .depend dep: + $(CC) $(EXTRA_CFLAGS) -M *.c > .depend + + +ifeq (.depend,$(wildcard .depend)) +include .depend +endif diff --git a/src/mod/endpoints/mod_skypopen/oss/main.c b/src/mod/endpoints/mod_skypopen/oss/main.c new file mode 100644 index 0000000000..a96e38d68a --- /dev/null +++ b/src/mod/endpoints/mod_skypopen/oss/main.c @@ -0,0 +1,470 @@ +/* + * main.c -- the bare skypopen char module + * + * Copyright (C) 2010 Giovanni Maruzzelli + * Copyright (C) 2001 Alessandro Rubini and Jonathan Corbet + * Copyright (C) 2001 O'Reilly & Associates + * + * The source code in this file can be freely used, adapted, + * and redistributed in source or binary form, so long as an + * acknowledgment appears in derived source files. The citation + * should list that the code comes from the book "Linux Device + * Drivers" by Alessandro Rubini and Jonathan Corbet, published + * by O'Reilly & Associates. No warranty is attached; + * we cannot take responsibility for errors or fitness for use. + * + */ + +#include +#include +#include + +#include /* printk() */ +#include /* kmalloc() */ +#include /* everything... */ +#include /* error codes */ +#include /* size_t */ +#include +#include /* O_ACCMODE */ +#include +#include + +#include /* cli(), *_flags */ +#include /* copy_*_user */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "skypopen.h" /* local definitions */ + +/* + * Our parameters which can be set at load time. + */ + +int skypopen_major = SKYPOPEN_MAJOR; +int skypopen_minor = 3; +int skypopen_nr_devs = SKYPOPEN_NR_DEVS; /* number of bare skypopen devices */ + +module_param(skypopen_major, int, S_IRUGO); +module_param(skypopen_minor, int, S_IRUGO); +module_param(skypopen_nr_devs, int, S_IRUGO); + +MODULE_AUTHOR("Original: Alessandro Rubini, Jonathan Corbet. Modified by: Giovanni Maruzzelli for FreeSWITCH skypopen"); +MODULE_LICENSE("Dual BSD/GPL"); + +static struct skypopen_dev *skypopen_devices; /* allocated in skypopen_init_module */ + +static int unload = 0; +#ifdef CENTOS +#define HRTIMER_MODE_REL HRTIMER_REL +#endif// CENTOS + +#ifndef WANT_HRTIMER +void my_timer_callback_inq( unsigned long data ) +{ + struct skypopen_dev *dev = (void *)data; + + wake_up_interruptible(&dev->inq); + mod_timer( &dev->timer_inq, jiffies + msecs_to_jiffies(SKYPOPEN_SLEEP) ); + +} + +void my_timer_callback_outq( unsigned long data ) +{ + struct skypopen_dev *dev = (void *)data; + + wake_up_interruptible(&dev->outq); + mod_timer( &dev->timer_outq, jiffies + msecs_to_jiffies(SKYPOPEN_SLEEP) ); +} +#else// WANT_HRTIMER + +#ifndef CENTOS +static enum hrtimer_restart my_hrtimer_callback_inq( struct hrtimer *timer_inq ) +{ + struct skypopen_dev *dev = container_of(timer_inq, struct skypopen_dev, timer_inq); + ktime_t now; + + if(unload) + return HRTIMER_NORESTART; + + now = ktime_get(); + hrtimer_forward(&dev->timer_inq, now, ktime_set(0, SKYPOPEN_SLEEP * 1000000)); + wake_up_interruptible(&dev->inq); + + return HRTIMER_RESTART; +} +static enum hrtimer_restart my_hrtimer_callback_outq( struct hrtimer *timer_outq ) +{ + struct skypopen_dev *dev = container_of(timer_outq, struct skypopen_dev, timer_outq); + ktime_t now; + + if(unload) + return HRTIMER_NORESTART; + + now = ktime_get(); + hrtimer_forward(&dev->timer_outq, now, ktime_set(0, SKYPOPEN_SLEEP * 1000000)); + wake_up_interruptible(&dev->outq); + + return HRTIMER_RESTART; +} +#else// CENTOS +static int my_hrtimer_callback_inq( struct hrtimer *timer_inq ) +{ + struct skypopen_dev *dev = container_of(timer_inq, struct skypopen_dev, timer_inq); + + if(unload) + return HRTIMER_NORESTART; + + hrtimer_forward(&dev->timer_inq, timer_inq->expires, ktime_set(0, SKYPOPEN_SLEEP * 1000000)); + wake_up_interruptible(&dev->inq); + + return HRTIMER_RESTART; +} +static int my_hrtimer_callback_outq( struct hrtimer *timer_outq ) +{ + struct skypopen_dev *dev = container_of(timer_outq, struct skypopen_dev, timer_outq); + + if(unload) + return HRTIMER_NORESTART; + + hrtimer_forward(&dev->timer_outq, timer_outq->expires, ktime_set(0, SKYPOPEN_SLEEP * 1000000)); + wake_up_interruptible(&dev->outq); + + return HRTIMER_RESTART; +} +#endif// CENTOS +#endif// WANT_HRTIMER + +/* The clone-specific data structure includes a key field */ + +struct skypopen_listitem { + struct skypopen_dev device; + dev_t key; + struct list_head list; + +}; + +/* The list of devices, and a lock to protect it */ +static LIST_HEAD(skypopen_c_list); +static spinlock_t skypopen_c_lock = SPIN_LOCK_UNLOCKED; + +/* Look for a device or create one if missing */ +static struct skypopen_dev *skypopen_c_lookfor_device(dev_t key) +{ + struct skypopen_listitem *lptr; +#ifdef WANT_HRTIMER +#if 0 + ktime_t ktime_inq; + ktime_t ktime_outq; +#endif //0 +#endif// WANT_HRTIMER + + list_for_each_entry(lptr, &skypopen_c_list, list) { + if (lptr->key == key) + return &(lptr->device); + } + + /* not found */ + lptr = kmalloc(sizeof(struct skypopen_listitem), GFP_KERNEL); + if (!lptr) + return NULL; + + /* initialize the device */ + memset(lptr, 0, sizeof(struct skypopen_listitem)); + lptr->key = key; + + init_waitqueue_head(&lptr->device.inq); + init_waitqueue_head(&lptr->device.outq); +#ifndef WANT_HRTIMER + setup_timer( &lptr->device.timer_inq, my_timer_callback_inq, (long int)lptr ); + setup_timer( &lptr->device.timer_outq, my_timer_callback_outq, (long int)lptr ); + printk( "Starting skypopen OSS driver read timer (%dms) skype client:(%d)\n", SKYPOPEN_SLEEP, current->tgid ); + mod_timer( &lptr->device.timer_inq, jiffies + msecs_to_jiffies(SKYPOPEN_SLEEP) ); + printk( "Starting skypopen OSS driver write timer (%dms) skype client:(%d)\n", SKYPOPEN_SLEEP, current->tgid ); + mod_timer( &lptr->device.timer_outq, jiffies + msecs_to_jiffies(SKYPOPEN_SLEEP) ); +#else// WANT_HRTIMER +#if 0 + ktime_inq = ktime_set( 0, SKYPOPEN_SLEEP * 1000000); + hrtimer_init( &lptr->device.timer_inq, CLOCK_MONOTONIC, HRTIMER_MODE_REL ); + lptr->device.timer_inq.function = &my_hrtimer_callback_inq; + hrtimer_start( &lptr->device.timer_inq, ktime_inq, HRTIMER_MODE_REL ); + + ktime_outq = ktime_set( 0, SKYPOPEN_SLEEP * 1000000); + hrtimer_init( &lptr->device.timer_outq, CLOCK_MONOTONIC, HRTIMER_MODE_REL ); + lptr->device.timer_outq.function = &my_hrtimer_callback_outq; + hrtimer_start( &lptr->device.timer_outq, ktime_outq, HRTIMER_MODE_REL ); +#endif + +#endif// WANT_HRTIMER + + /* place it in the list */ + list_add(&lptr->list, &skypopen_c_list); + + return &(lptr->device); +} + +/* + * Open and close + */ +static int skypopen_c_open(struct inode *inode, struct file *filp) +{ + struct skypopen_dev *dev; + dev_t key; + + key = current->tgid; + + /* look for a skypopenc device in the list */ + spin_lock(&skypopen_c_lock); + dev = skypopen_c_lookfor_device(key); + spin_unlock(&skypopen_c_lock); + + if (!dev) + return -ENOMEM; + + /* then, everything else is copied from the bare skypopen device */ + filp->private_data = dev; + return 0; /* success */ +} + +static int skypopen_c_release(struct inode *inode, struct file *filp) +{ + /* + * Nothing to do, because the device is persistent. + * A `real' cloned device should be freed on last close + */ + return 0; +} + + + +/*************************************************************/ + +static ssize_t skypopen_read(struct file *filp, char __user *buf, size_t count, + loff_t *f_pos) +{ + DEFINE_WAIT(wait); + struct skypopen_dev *dev = filp->private_data; + + if(unload) + return -1; + +#ifdef WANT_HRTIMER +#if 1 + if(dev->timer_inq_started == 0){ + ktime_t ktime_inq; + + ktime_inq = ktime_set( 0, SKYPOPEN_SLEEP * 1000000); + hrtimer_init( &dev->timer_inq, CLOCK_MONOTONIC, HRTIMER_MODE_REL ); + dev->timer_inq.function = &my_hrtimer_callback_inq; + hrtimer_start( &dev->timer_inq, ktime_inq, HRTIMER_MODE_REL ); + dev->timer_inq_started = 1; + } +#endif +#endif// WANT_HRTIMER + + + //printk("READ\n"); + prepare_to_wait(&dev->inq, &wait, TASK_INTERRUPTIBLE); + schedule(); + finish_wait(&dev->inq, &wait); + return count; + +} + +static ssize_t skypopen_write(struct file *filp, const char __user *buf, size_t count, + loff_t *f_pos) +{ + DEFINE_WAIT(wait); + struct skypopen_dev *dev = filp->private_data; + + if(unload) + return -1; + +#ifdef WANT_HRTIMER +#if 1 + if(dev->timer_outq_started == 0){ + ktime_t ktime_outq; + + ktime_outq = ktime_set( 0, SKYPOPEN_SLEEP * 1000000); + hrtimer_init( &dev->timer_outq, CLOCK_MONOTONIC, HRTIMER_MODE_REL ); + dev->timer_outq.function = &my_hrtimer_callback_outq; + hrtimer_start( &dev->timer_outq, ktime_outq, HRTIMER_MODE_REL ); + dev->timer_outq_started = 1; + } +#endif +#endif// WANT_HRTIMER + + + //printk("WRITE\n"); + prepare_to_wait(&dev->outq, &wait, TASK_INTERRUPTIBLE); + schedule(); + finish_wait(&dev->outq, &wait); + return count; + +} +/* + * The ioctl() implementation + */ + +static int skypopen_ioctl(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + void __user *argp = (void __user *)arg; + int __user *p = argp; + + switch (cmd) { + case OSS_GETVERSION: + return put_user(SOUND_VERSION, p); + case SNDCTL_DSP_GETBLKSIZE: + return put_user(SKYPOPEN_BLK, p); + case SNDCTL_DSP_GETFMTS: + return put_user(28731, p); + + default: + return 0; + } + +} + +struct file_operations skypopen_fops = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .read = skypopen_read, + .write = skypopen_write, + .ioctl = skypopen_ioctl, + .open = skypopen_c_open, + .release = skypopen_c_release, +}; + +/* + * Finally, the module stuff + */ + +/* + * The cleanup function is used to handle initialization failures as well. + * Thefore, it must be careful to work correctly even if some of the items + * have not been initialized + */ + +void skypopen_cleanup_module(void) +{ + int i; + int ret; + struct skypopen_listitem *lptr, *next; + dev_t devno = MKDEV(skypopen_major, skypopen_minor); + + + unload = 1; + + msleep(100); + + /* Get rid of our char dev entries */ + if (skypopen_devices) { + for (i = 0; i < skypopen_nr_devs; i++) { + cdev_del(&skypopen_devices[i].cdev); + } + kfree(skypopen_devices); + } + + /* And all the cloned devices */ + list_for_each_entry_safe(lptr, next, &skypopen_c_list, list) { +#ifndef WANT_HRTIMER + ret= del_timer( &lptr->device.timer_inq ); + printk( "Stopped skypopen OSS driver read timer\n"); + ret= del_timer( &lptr->device.timer_outq ); + printk( "Stopped skypopen OSS driver write timer\n"); +#else// WANT_HRTIMER + if(lptr->device.timer_inq_started){ + ret = hrtimer_cancel( &lptr->device.timer_inq ); + printk( "Stopped skypopen OSS driver read HRtimer\n"); + } + if(lptr->device.timer_outq_started){ + ret = hrtimer_cancel( &lptr->device.timer_outq ); + printk( "Stopped skypopen OSS driver write HRtimer\n"); + } + +#endif// WANT_HRTIMER + list_del(&lptr->list); + kfree(lptr); + } + /* cleanup_module is never called if registering failed */ + unregister_chrdev_region(devno, skypopen_nr_devs); + printk("skypopen OSS driver unloaded\n"); + +} + + +/* + * Set up the char_dev structure for this device. + */ +static void skypopen_setup_cdev(struct skypopen_dev *dev, int index) +{ + int err, devno = MKDEV(skypopen_major, skypopen_minor + index); + + cdev_init(&dev->cdev, &skypopen_fops); + dev->cdev.owner = THIS_MODULE; + dev->cdev.ops = &skypopen_fops; + err = cdev_add (&dev->cdev, devno, 1); + /* Fail gracefully if need be */ + if (err) + printk(KERN_NOTICE "Error %d adding skypopen%d", err, index); +} + + + +int skypopen_init_module(void) +{ + int result, i; + dev_t dev = 0; + + printk("skypopen OSS driver loading (www.freeswitch.org)\n"); + /* + * Get a range of minor numbers to work with, asking for a dynamic + * major unless directed otherwise at load time. + */ + if (skypopen_major) { + dev = MKDEV(skypopen_major, skypopen_minor); + result = register_chrdev_region(dev, skypopen_nr_devs, "dsp"); + } else { + result = alloc_chrdev_region(&dev, skypopen_minor, skypopen_nr_devs, + "dsp"); + skypopen_major = MAJOR(dev); + } + if (result < 0) { + printk(KERN_WARNING "skypopen OSS driver: can't get major %d\n", skypopen_major); + return result; + } + + /* + * allocate the devices -- we can't have them static, as the number + * can be specified at load time + */ + skypopen_devices = kmalloc(skypopen_nr_devs * sizeof(struct skypopen_dev), GFP_KERNEL); + if (!skypopen_devices) { + result = -ENOMEM; + goto fail; /* Make this more graceful */ + } + memset(skypopen_devices, 0, skypopen_nr_devs * sizeof(struct skypopen_dev)); + + /* Initialize each device. */ + for (i = 0; i < skypopen_nr_devs; i++) { + skypopen_setup_cdev(&skypopen_devices[i], i); + } + + /* At this point call the init function for any friend device */ + dev = MKDEV(skypopen_major, skypopen_minor + skypopen_nr_devs); + return 0; /* succeed */ + +fail: + skypopen_cleanup_module(); + return result; +} + +module_init(skypopen_init_module); +module_exit(skypopen_cleanup_module); diff --git a/src/mod/endpoints/mod_skypopen/oss/skypopen.h b/src/mod/endpoints/mod_skypopen/oss/skypopen.h new file mode 100644 index 0000000000..2324e448cb --- /dev/null +++ b/src/mod/endpoints/mod_skypopen/oss/skypopen.h @@ -0,0 +1,71 @@ +/* + * skypopen.h -- definitions for the char module + * + * Copyright (C) 2001 Alessandro Rubini and Jonathan Corbet + * Copyright (C) 2001 O'Reilly & Associates + * + * The source code in this file can be freely used, adapted, + * and redistributed in source or binary form, so long as an + * acknowledgment appears in derived source files. The citation + * should list that the code comes from the book "Linux Device + * Drivers" by Alessandro Rubini and Jonathan Corbet, published + * by O'Reilly & Associates. No warranty is attached; + * we cannot take responsibility for errors or fitness for use. + * + * $Id: skypopen.h,v 1.15 2004/11/04 17:51:18 rubini Exp $ + */ + +#ifndef _SKYPOPEN_H_ +#define _SKYPOPEN_H_ + +#include /* needed for the _IOW etc stuff used later */ + +#define SKYPOPEN_BLK 960 +#define SKYPOPEN_SLEEP 10 + +#define CENTOS + +#ifndef SKYPOPEN_MAJOR +#define SKYPOPEN_MAJOR 14 /* dynamic major by default */ +#endif + +#ifndef SKYPOPEN_NR_DEVS +#define SKYPOPEN_NR_DEVS 1 /* skypopen0 through skypopen3 */ +#endif + +#define WANT_HRTIMER +struct skypopen_dev { + struct cdev cdev; /* Char device structure */ + wait_queue_head_t inq; /* read and write queues */ + wait_queue_head_t outq; /* read and write queues */ +#ifndef WANT_HRTIMER + struct timer_list timer_inq; + struct timer_list timer_outq; +#else// WANT_HRTIMER + struct hrtimer timer_inq; + struct hrtimer timer_outq; +#endif// WANT_HRTIMER + int timer_inq_started; + int timer_outq_started; +}; + + +/* + * The different configurable parameters + */ +extern int skypopen_major; /* main.c */ +extern int skypopen_nr_devs; + + +/* + * Prototypes for shared functions + */ + +//ssize_t skypopen_read(struct file *filp, char __user *buf, size_t count, + //loff_t *f_pos); +//ssize_t skypopen_write(struct file *filp, const char __user *buf, size_t count, + //loff_t *f_pos); +//int skypopen_ioctl(struct inode *inode, struct file *filp, + //unsigned int cmd, unsigned long arg); + +#endif /* _SKYPOPEN_H_ */ diff --git a/src/mod/endpoints/mod_skypopen/skypopen.h b/src/mod/endpoints/mod_skypopen/skypopen.h index 4ff2b012c6..2f1c8e48e9 100644 --- a/src/mod/endpoints/mod_skypopen/skypopen.h +++ b/src/mod/endpoints/mod_skypopen/skypopen.h @@ -76,8 +76,8 @@ #define SAMPLERATE_SKYPOPEN 16000 #define MS_SKYPOPEN 20 -#define SAMPLES_PER_FRAME SAMPLERATE_SKYPOPEN/(1000/MS_SKYPOPEN) -#define BYTES_PER_FRAME SAMPLES_PER_FRAME * sizeof(short) +#define SAMPLES_PER_FRAME (SAMPLERATE_SKYPOPEN/(1000/MS_SKYPOPEN)) +#define BYTES_PER_FRAME (SAMPLES_PER_FRAME * sizeof(short)) #ifdef SKYPOPEN_C_VER #ifdef MODSKYPOPEN_C_VER @@ -341,6 +341,7 @@ struct private_object { chat_t chats[MAX_CHATS]; uint32_t report_incoming_chatmessages; switch_timer_t timer_read; + switch_timer_t timer_read_srv; switch_timer_t timer_write; int begin_to_write; int begin_to_read; diff --git a/src/mod/endpoints/mod_skypopen/skypopen_protocol.c b/src/mod/endpoints/mod_skypopen/skypopen_protocol.c index ef06bfac1e..391a23caaf 100644 --- a/src/mod/endpoints/mod_skypopen/skypopen_protocol.c +++ b/src/mod/endpoints/mod_skypopen/skypopen_protocol.c @@ -547,6 +547,9 @@ int skypopen_signaling_read(private_t *tech_pvt) if (tech_pvt->timer_read.timer_interface && tech_pvt->timer_read.timer_interface->timer_next) { switch_core_timer_sync(&tech_pvt->timer_read); } + if (tech_pvt->timer_read_srv.timer_interface && tech_pvt->timer_read_srv.timer_interface->timer_next) { + switch_core_timer_sync(&tech_pvt->timer_read_srv); + } switch_mutex_unlock(tech_pvt->mutex_audio_srv); } @@ -878,7 +881,7 @@ void *skypopen_do_tcp_srv_thread_func(void *obj) || tech_pvt->skype_callflow == CALLFLOW_STATUS_REMOTEHOLD || tech_pvt->skype_callflow == SKYPOPEN_STATE_UP)) { unsigned int fdselect; - int rt; + int rt=1; fd_set fs; struct timeval to; int nospace; @@ -891,7 +894,10 @@ void *skypopen_do_tcp_srv_thread_func(void *obj) to.tv_usec = MS_SKYPOPEN * 1000 * 3; to.tv_sec = 0; - rt = select(fdselect + 1, &fs, NULL, NULL, &to); + if (tech_pvt->timer_read_srv.timer_interface && tech_pvt->timer_read_srv.timer_interface->timer_next) { + switch_core_timer_next(&tech_pvt->timer_read_srv); + } + //rt = select(fdselect + 1, &fs, NULL, NULL, &to); if (rt > 0) { if (tech_pvt->skype_callflow != CALLFLOW_STATUS_REMOTEHOLD) { diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.c b/src/mod/endpoints/mod_sofia/mod_sofia.c index 74c4c0897e..8aa37b95be 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.c +++ b/src/mod/endpoints/mod_sofia/mod_sofia.c @@ -508,7 +508,7 @@ switch_status_t sofia_on_hangup(switch_core_session_t *session) TAG_IF(!zstr(bye_headers), SIPTAG_HEADER_STR(bye_headers)), TAG_END()); } } else { - if (switch_channel_test_flag(channel, CF_OUTBOUND)) { + if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Sending CANCEL to %s\n", switch_channel_get_name(channel)); if (!tech_pvt->got_bye) { switch_channel_set_variable(channel, "sip_hangup_disposition", "send_cancel"); @@ -573,7 +573,7 @@ static switch_status_t sofia_answer_channel(switch_core_session_t *session) char *sticky = NULL; const char *call_info = switch_channel_get_variable(channel, "presence_call_info_full"); - if (sofia_test_flag(tech_pvt, TFLAG_ANS) || switch_channel_test_flag(channel, CF_OUTBOUND)) { + if (sofia_test_flag(tech_pvt, TFLAG_ANS) || switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) { return SWITCH_STATUS_SUCCESS; } @@ -653,7 +653,7 @@ static switch_status_t sofia_answer_channel(switch_core_session_t *session) switch_channel_clear_flag(channel, CF_PROXY_MODE); } - if (!switch_channel_test_flag(tech_pvt->channel, CF_OUTBOUND)) { + if (switch_channel_direction(tech_pvt->channel) == SWITCH_CALL_DIRECTION_INBOUND) { const char *r_sdp = switch_channel_get_variable(channel, SWITCH_R_SDP_VARIABLE); tech_pvt->num_codecs = 0; sofia_glue_tech_prepare_codecs(tech_pvt); @@ -723,7 +723,7 @@ static switch_status_t sofia_answer_channel(switch_core_session_t *session) TAG_IF(sticky, NUTAG_PROXY(tech_pvt->record_route)), TAG_IF(cid, SIPTAG_HEADER_STR(cid)), NUTAG_SESSION_TIMER(session_timeout), - TAG_IF(session_timeout, NUTAG_SESSION_REFRESHER(nua_remote_refresher)), + NUTAG_SESSION_REFRESHER(session_timeout ? nua_local_refresher : nua_no_refresher), SIPTAG_CONTACT_STR(tech_pvt->reply_contact), SIPTAG_CALL_INFO_STR(switch_channel_get_variable(tech_pvt->channel, SOFIA_SIP_HEADER_PREFIX "call_info")), SOATAG_USER_SDP_STR(tech_pvt->local_sdp_str), @@ -739,7 +739,7 @@ static switch_status_t sofia_answer_channel(switch_core_session_t *session) TAG_IF(sticky, NUTAG_PROXY(tech_pvt->record_route)), TAG_IF(cid, SIPTAG_HEADER_STR(cid)), NUTAG_SESSION_TIMER(session_timeout), - TAG_IF(session_timeout, NUTAG_SESSION_REFRESHER(nua_remote_refresher)), + NUTAG_SESSION_REFRESHER(session_timeout ? nua_local_refresher : nua_no_refresher), SIPTAG_CONTACT_STR(tech_pvt->reply_contact), SIPTAG_CALL_INFO_STR(switch_channel_get_variable(tech_pvt->channel, SOFIA_SIP_HEADER_PREFIX "call_info")), SIPTAG_CONTENT_TYPE_STR("application/sdp"), @@ -906,7 +906,7 @@ static switch_status_t sofia_read_frame(switch_core_session_t *session, switch_f tech_pvt->read_frame.flags = SFF_NONE; status = switch_rtp_zerocopy_read_frame(tech_pvt->rtp_session, &tech_pvt->read_frame, flags); - + if (status != SWITCH_STATUS_SUCCESS && status != SWITCH_STATUS_BREAK) { if (status == SWITCH_STATUS_TIMEOUT) { @@ -1084,7 +1084,7 @@ static switch_status_t sofia_read_frame(switch_core_session_t *session, switch_f tech_pvt->last_ts = 0; /* inform them of the codec they are actually sending */ - +#if 0 if (++tech_pvt->codec_reinvites > 2) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Ok, some devices *cough* X-lite *cough*\n" @@ -1093,7 +1093,10 @@ static switch_status_t sofia_read_frame(switch_core_session_t *session, switch_f } else { sofia_glue_do_invite(session); } +#endif + *frame = &silence_frame; + return SWITCH_STATUS_SUCCESS; } } @@ -1332,6 +1335,60 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi } } break; + case SWITCH_MESSAGE_INDICATE_JITTER_BUFFER: + { + if (switch_rtp_ready(tech_pvt->rtp_session)) { + int len, maxlen = 0, qlen = 0, maxqlen = 50; + + if (msg->string_arg) { + char *p; + const char *s; + + if (!strncasecmp(msg->string_arg, "debug:", 6)) { + s = msg->string_arg + 6; + if (s && !strcmp(s, "off")) { + s = NULL; + } + switch_rtp_debug_jitter_buffer(tech_pvt->rtp_session, s); + goto end; + } + + + if ((len = atoi(msg->string_arg))) { + qlen = len / (tech_pvt->read_impl.microseconds_per_packet / 1000); + } + + if (qlen) { + if ((p = strchr(msg->string_arg, ':'))) { + p++; + maxlen = atol(p); + } + } + + + if (maxlen) { + maxqlen = maxlen / (tech_pvt->read_impl.microseconds_per_packet / 1000); + } + } + + if (qlen) { + if (switch_rtp_activate_jitter_buffer(tech_pvt->rtp_session, qlen, maxqlen, + tech_pvt->read_impl.samples_per_packet, + tech_pvt->read_impl.samples_per_second) == SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), + SWITCH_LOG_DEBUG, "Setting Jitterbuffer to %dms (%d frames) (%d max frames)\n", len, qlen, maxqlen); + switch_channel_set_flag(tech_pvt->channel, CF_JITTERBUFFER); + } else { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), + SWITCH_LOG_WARNING, "Error Setting Jitterbuffer to %dms (%d frames)\n", len, qlen); + } + + } else { + switch_rtp_deactivate_jitter_buffer(tech_pvt->rtp_session); + } + } + } + break; case SWITCH_MESSAGE_INDICATE_DEBUG_AUDIO: { if (switch_rtp_ready(tech_pvt->rtp_session) && !zstr(msg->string_array_arg[0]) && !zstr(msg->string_array_arg[1])) { @@ -1629,7 +1686,7 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi sofia_glue_tech_set_local_sdp(tech_pvt, NULL, SWITCH_FALSE); if (!(switch_channel_test_flag(channel, CF_ANSWERED) || switch_channel_test_flag(channel, CF_EARLY_MEDIA))) { - if (!switch_channel_test_flag(tech_pvt->channel, CF_OUTBOUND)) { + if (switch_channel_direction(tech_pvt->channel) == SWITCH_CALL_DIRECTION_INBOUND) { const char *r_sdp = switch_channel_get_variable(channel, SWITCH_R_SDP_VARIABLE); tech_pvt->num_codecs = 0; @@ -2144,7 +2201,7 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi } else { if (sofia_test_flag(tech_pvt, TFLAG_LATE_NEGOTIATION) || !tech_pvt->iananame) { sofia_clear_flag_locked(tech_pvt, TFLAG_LATE_NEGOTIATION); - if (!switch_channel_test_flag(tech_pvt->channel, CF_OUTBOUND)) { + if (switch_channel_direction(tech_pvt->channel) == SWITCH_CALL_DIRECTION_INBOUND) { const char *r_sdp = switch_channel_get_variable(channel, SWITCH_R_SDP_VARIABLE); tech_pvt->num_codecs = 0; diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.h b/src/mod/endpoints/mod_sofia/mod_sofia.h index 6970a7ab05..61d165753c 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.h +++ b/src/mod/endpoints/mod_sofia/mod_sofia.h @@ -225,6 +225,7 @@ typedef enum { PFLAG_DEL_SUBS_ON_REG, PFLAG_IGNORE_183NOSDP, PFLAG_PRESENCE_PROBE_ON_REGISTER, + PFLAG_NO_CONNECTION_REUSE, /* No new flags below this line */ PFLAG_MAX } PFLAGS; diff --git a/src/mod/endpoints/mod_sofia/sofia.c b/src/mod/endpoints/mod_sofia/sofia.c index 2e13b544d0..94eab68858 100644 --- a/src/mod/endpoints/mod_sofia/sofia.c +++ b/src/mod/endpoints/mod_sofia/sofia.c @@ -357,7 +357,7 @@ void sofia_handle_sip_i_notify(switch_core_session_t *session, int status, goto error; } - if (!switch_channel_test_flag(channel, CF_OUTBOUND)) { + if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_INBOUND) { switch_channel_answer(channel); switch_channel_set_variable(channel, "auto_answer_destination", switch_channel_get_variable(channel, "destination_number")); switch_ivr_session_transfer(session, "auto_answer", NULL, NULL); @@ -1486,6 +1486,8 @@ void *SWITCH_THREAD_FUNC sofia_profile_thread_run(switch_thread_t *thread, void TAG_IF(profile->timer_t2, NTATAG_SIP_T2(profile->timer_t2)), TAG_IF(profile->timer_t4, NTATAG_SIP_T4(profile->timer_t4)), SIPTAG_ACCEPT_STR("application/sdp, multipart/mixed"), + TAG_IF(sofia_test_pflag(profile, PFLAG_NO_CONNECTION_REUSE), + TPTAG_REUSE(0)), TAG_END()); /* Last tag should always finish the sequence */ if (!profile->nua) { @@ -1715,16 +1717,9 @@ void launch_sofia_profile_thread(sofia_profile_t *profile) static void logger(void *logarg, char const *fmt, va_list ap) { - /* gcc 4.4 gets mad at us for testing if (ap) so let's try to work around it....*/ - void *ap_ptr = (void *) (intptr_t) ap; - if (!fmt) return; - if (ap_ptr) { - switch_log_vprintf(SWITCH_CHANNEL_LOG_CLEAN, mod_sofia_globals.tracelevel, fmt, ap); - } else { - switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, mod_sofia_globals.tracelevel, "%s", fmt); - } + switch_log_vprintf(SWITCH_CHANNEL_LOG_CLEAN, mod_sofia_globals.tracelevel, fmt, ap); } static su_log_t *sofia_get_logger(const char *name) @@ -3673,6 +3668,13 @@ switch_status_t config_sofia(int reload, char *profile_name) } else { profile->timer_t4 = 4000; } + } else if (!strcasecmp(var, "reuse-connections")) { + switch_bool_t value = switch_true(val); + if (!value) { + sofia_set_pflag(profile, PFLAG_NO_CONNECTION_REUSE); + } else { + sofia_clear_pflag(profile, PFLAG_NO_CONNECTION_REUSE); + } } } @@ -4112,7 +4114,7 @@ static void sofia_handle_sip_r_invite(switch_core_session_t *session, int status } - if (channel && sip && (status == 300 || status == 301 || status == 302 || status == 305) && switch_channel_test_flag(channel, CF_OUTBOUND)) { + if (channel && sip && (status == 300 || status == 301 || status == 302 || status == 305) && switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) { sip_contact_t *p_contact = sip->sip_contact; int i = 0; char var_name[80]; @@ -4643,7 +4645,7 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status, status = 183; } - if (channel && (status == 180 || status == 183) && switch_channel_test_flag(channel, CF_OUTBOUND)) { + if (channel && (status == 180 || status == 183) && switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) { const char *val; if ((val = switch_channel_get_variable(channel, "sip_auto_answer")) && switch_true(val)) { nua_notify(nh, NUTAG_NEWSUB(1), NUTAG_SUBSTATE(nua_substate_active), SIPTAG_EVENT_STR("talk"), TAG_END()); @@ -4690,7 +4692,7 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status, if (r_sdp) { if (switch_channel_test_flag(channel, CF_PROXY_MODE) || switch_channel_test_flag(channel, CF_PROXY_MEDIA)) { - if (switch_channel_test_flag(channel, CF_PROXY_MEDIA) && !switch_channel_test_flag(tech_pvt->channel, CF_OUTBOUND)) { + if (switch_channel_test_flag(channel, CF_PROXY_MEDIA) && switch_channel_direction(tech_pvt->channel) == SWITCH_CALL_DIRECTION_INBOUND) { switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "PROXY MEDIA"); } sofia_set_flag_locked(tech_pvt, TFLAG_EARLY_MEDIA); @@ -4713,7 +4715,7 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status, } goto done; } else { - if (sofia_test_flag(tech_pvt, TFLAG_LATE_NEGOTIATION) && !switch_channel_test_flag(tech_pvt->channel, CF_OUTBOUND)) { + if (sofia_test_flag(tech_pvt, TFLAG_LATE_NEGOTIATION) && switch_channel_direction(tech_pvt->channel) == SWITCH_CALL_DIRECTION_INBOUND) { switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "DELAYED NEGOTIATION"); } else { if (sofia_glue_tech_media(tech_pvt, (char *) r_sdp) != SWITCH_STATUS_SUCCESS) { @@ -4908,7 +4910,7 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status, sofia_glue_tech_set_local_sdp(tech_pvt, NULL, SWITCH_FALSE); if (!switch_channel_media_ready(channel)) { - if (!switch_channel_test_flag(tech_pvt->channel, CF_OUTBOUND)) { + if (switch_channel_direction(tech_pvt->channel) == SWITCH_CALL_DIRECTION_INBOUND) { //const char *r_sdp = switch_channel_get_variable(channel, SWITCH_R_SDP_VARIABLE); tech_pvt->num_codecs = 0; @@ -6253,7 +6255,8 @@ void sofia_handle_sip_i_invite(nua_t *nua, sofia_profile_t *profile, nua_handle_ if (!is_nat && profile->nat_acl_count) { uint32_t x = 0; - int ok = 1; + int contact_private_ip = 1; + int network_private_ip = 0; char *last_acl = NULL; const char *contact_host = NULL; @@ -6262,14 +6265,37 @@ void sofia_handle_sip_i_invite(nua_t *nua, sofia_profile_t *profile, nua_handle_ } if (!zstr(contact_host)) { + /* NAT mode double check logic and examples. + + Example 1: the contact_host is 192.168.1.100 and the network_ip is also 192.168.1.100 the end point + is most likely behind nat with us so we need to veto that decision to turn on nat processing. + + Example 2: the contact_host is 192.168.1.100 and the network_ip is 192.0.2.100 which is a public internet ip + the remote endpoint is likely behind a remote nat traversing the public internet. + + This secondary check is here to double check the conclusion of nat settigs to ensure we don't set net + in cases where we don't really need to be doing this. + + Why would you want to do this? Well if your FreeSWITCH is behind nat and you want to talk to endpoints behind + remote NAT over the public internet in addition to endpoints behind nat with you. This simplifies that process. + + */ + for (x = 0; x < profile->nat_acl_count; x++) { last_acl = profile->nat_acl[x]; - if (!(ok = switch_check_network_list_ip(contact_host, last_acl))) { + if ((contact_private_ip = switch_check_network_list_ip(contact_host, last_acl))) { break; } } + if (contact_private_ip) { + for (x = 0; x < profile->nat_acl_count; x++) { + if ((network_private_ip = switch_check_network_list_ip(network_ip, profile->nat_acl[x]))) { + break; + } + } + } - if (ok) { + if (contact_private_ip && !network_private_ip) { is_nat = last_acl; } } diff --git a/src/mod/endpoints/mod_sofia/sofia_glue.c b/src/mod/endpoints/mod_sofia/sofia_glue.c index 6416778ab0..029f60ad33 100644 --- a/src/mod/endpoints/mod_sofia/sofia_glue.c +++ b/src/mod/endpoints/mod_sofia/sofia_glue.c @@ -2342,7 +2342,7 @@ switch_status_t sofia_glue_do_invite(switch_core_session_t *session) nua_invite(tech_pvt->nh, NUTAG_AUTOANSWER(0), NUTAG_SESSION_TIMER(session_timeout), - TAG_IF(session_timeout, NUTAG_SESSION_REFRESHER(nua_remote_refresher)), + NUTAG_SESSION_REFRESHER(session_timeout ? nua_local_refresher : nua_no_refresher), TAG_IF(sofia_test_flag(tech_pvt, TFLAG_RECOVERED), NUTAG_INVITE_TIMER(UINT_MAX)), TAG_IF(invite_full_from, SIPTAG_FROM_STR(invite_full_from)), TAG_IF(invite_full_to, SIPTAG_TO_STR(invite_full_to)), @@ -2669,7 +2669,8 @@ switch_status_t sofia_glue_tech_set_codec(private_object_t *tech_pvt, int force) tech_pvt->rm_encoding, tech_pvt->codec_ms, tech_pvt->rm_rate); - + + switch_yield(tech_pvt->read_impl.microseconds_per_packet); switch_core_session_lock_codec_write(tech_pvt->session); switch_core_session_lock_codec_read(tech_pvt->session); resetting = 1; @@ -3153,18 +3154,37 @@ switch_status_t sofia_glue_activate_rtp(private_object_t *tech_pvt, switch_rtp_f if ((val = switch_channel_get_variable(tech_pvt->channel, "jitterbuffer_msec"))) { int len = atoi(val); + int maxlen = 0; + char *p; - if (len < 100 || len > 1000) { + if ((p = strchr(val, ':'))) { + p++; + maxlen = atoi(p); + } + + if (len < 20 || len > 10000) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_ERROR, - "Invalid Jitterbuffer spec [%d] must be between 100 and 1000\n", len); + "Invalid Jitterbuffer spec [%d] must be between 20 and 10000\n", len); } else { - int qlen; - + int qlen, maxqlen = 50; + qlen = len / (tech_pvt->read_impl.microseconds_per_packet / 1000); - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Setting Jitterbuffer to %dms (%d frames)\n", len, - qlen); - switch_rtp_activate_jitter_buffer(tech_pvt->rtp_session, qlen); + if (maxlen) { + maxqlen = maxlen / (tech_pvt->read_impl.microseconds_per_packet / 1000); + } + + if (switch_rtp_activate_jitter_buffer(tech_pvt->rtp_session, qlen, maxqlen, + tech_pvt->read_impl.samples_per_packet, + tech_pvt->read_impl.samples_per_second) == SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), + SWITCH_LOG_DEBUG, "Setting Jitterbuffer to %dms (%d frames)\n", len, qlen); + switch_channel_set_flag(tech_pvt->channel, CF_JITTERBUFFER); + } else { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), + SWITCH_LOG_WARNING, "Error Setting Jitterbuffer to %dms (%d frames)\n", len, qlen); + } + } } @@ -4668,8 +4688,8 @@ void sofia_glue_pass_sdp(private_object_t *tech_pvt, char *sdp) switch_channel_set_variable(other_channel, SWITCH_B_SDP_VARIABLE, sdp); if (!sofia_test_flag(tech_pvt, TFLAG_CHANGE_MEDIA) && !sofia_test_flag(tech_pvt, TFLAG_RECOVERING) && - (switch_channel_test_flag(other_channel, CF_OUTBOUND) && - switch_channel_test_flag(tech_pvt->channel, CF_OUTBOUND) && switch_channel_test_flag(tech_pvt->channel, CF_PROXY_MODE))) { + (switch_channel_direction(other_channel) == SWITCH_CALL_DIRECTION_OUTBOUND && + switch_channel_direction(tech_pvt->channel) == SWITCH_CALL_DIRECTION_OUTBOUND && switch_channel_test_flag(tech_pvt->channel, CF_PROXY_MODE))) { switch_ivr_nomedia(val, SMF_FORCE); sofia_set_flag_locked(tech_pvt, TFLAG_CHANGE_MEDIA); } @@ -5041,9 +5061,20 @@ static int recover_callback(void *pArg, int argc, char **argv, char **columnName const char *port = switch_channel_get_variable(channel, SWITCH_LOCAL_MEDIA_PORT_VARIABLE); const char *r_ip = switch_channel_get_variable(channel, SWITCH_REMOTE_MEDIA_IP_VARIABLE); const char *r_port = switch_channel_get_variable(channel, SWITCH_REMOTE_MEDIA_PORT_VARIABLE); + const char *use_uuid; sofia_set_flag(tech_pvt, TFLAG_RECOVERING); + if ((use_uuid = switch_channel_get_variable(channel, "origination_uuid"))) { + if (switch_core_session_set_uuid(session, use_uuid) == SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s set UUID=%s\n", switch_channel_get_name(channel), + use_uuid); + } else { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "%s set UUID=%s FAILED\n", + switch_channel_get_name(channel), use_uuid); + } + } + if (!switch_channel_test_flag(channel, CF_PROXY_MODE) && ip && port) { const char *tmp; tech_pvt->iananame = tech_pvt->rm_encoding = (char *) switch_channel_get_variable(channel, "sip_use_codec_name"); diff --git a/src/mod/endpoints/mod_sofia/sofia_presence.c b/src/mod/endpoints/mod_sofia/sofia_presence.c index 143666ceb8..f0cade3e61 100644 --- a/src/mod/endpoints/mod_sofia/sofia_presence.c +++ b/src/mod/endpoints/mod_sofia/sofia_presence.c @@ -90,6 +90,7 @@ switch_status_t sofia_presence_chat_send(const char *proto, const char *from, co char *user_via = NULL; char *contact_str = NULL; char *dup_dest = NULL; + char *remote_host = NULL; if (!to) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Missing To: header.\n"); @@ -185,11 +186,9 @@ switch_status_t sofia_presence_chat_send(const char *proto, const char *from, co /* sofia_glue is running sofia_overcome_sip_uri_weakness we do not, not sure if it matters */ - remote_ip = malloc(sizeof(80)); dup_dest = strdup(dst->contact); if (switch_stristr("fs_path", dst->contact)) { - char *remote_host = NULL; const char *s; if ((s = switch_stristr("fs_path=", dst->contact))) { @@ -202,7 +201,6 @@ switch_status_t sofia_presence_chat_send(const char *proto, const char *from, co if (!zstr(remote_host)) { switch_split_user_domain(remote_host, NULL, &remote_ip); } - switch_safe_free(remote_host); } if (zstr(remote_ip)) { @@ -236,7 +234,7 @@ switch_status_t sofia_presence_chat_send(const char *proto, const char *from, co } switch_safe_free(dup_dest); - free(remote_ip); + switch_safe_free(remote_host); status = SWITCH_STATUS_SUCCESS; @@ -820,7 +818,7 @@ static void actual_sofia_presence_event_handler(switch_event_t *event) sofia_glue_execute_sql_callback(profile, profile->ireg_mutex, sql, sofia_presence_dialog_callback, &dh); switch_safe_free(sql); - if ((sql = switch_mprintf("select sip_subscriptions.proto,sip_subscriptions.sip_user,sip_subscriptions.sip_host," + if ((sql = switch_mprintf("select distinct sip_subscriptions.proto,sip_subscriptions.sip_user,sip_subscriptions.sip_host," "sip_subscriptions.sub_to_user,sip_subscriptions.sub_to_host,sip_subscriptions.event," "sip_subscriptions.contact,sip_subscriptions.call_id,sip_subscriptions.full_from," "sip_subscriptions.full_via,sip_subscriptions.expires,sip_subscriptions.user_agent," diff --git a/src/mod/endpoints/mod_sofia/sofia_reg.c b/src/mod/endpoints/mod_sofia/sofia_reg.c index 570e297f6d..945740eb57 100644 --- a/src/mod/endpoints/mod_sofia/sofia_reg.c +++ b/src/mod/endpoints/mod_sofia/sofia_reg.c @@ -1139,30 +1139,24 @@ uint8_t sofia_reg_handle_register(nua_t *nua, sofia_profile_t *profile, nua_hand } if (auth_res != AUTH_OK && !stale) { - if (sofia_test_pflag(profile, PFLAG_LOG_AUTH_FAIL)) { - if (regtype == REG_REGISTER) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "SIP auth %s (REGISTER) on sofia profile '%s' " - "for [%s@%s] from ip %s\n", forbidden ? "failure" : "challenge", profile->name, to_user, to_host, network_ip); - } + if (auth_res == AUTH_FORBIDDEN) { + nua_respond(nh, SIP_403_FORBIDDEN, NUTAG_WITH_THIS(nua), TAG_END()); + forbidden = 1; + } else { + nua_respond(nh, SIP_401_UNAUTHORIZED, NUTAG_WITH_THIS(nua), TAG_END()); } if (profile->debug) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Send %s for [%s@%s]\n", forbidden ? "forbidden" : "challenge", to_user, to_host); } - if (auth_res == AUTH_FORBIDDEN) { - nua_respond(nh, SIP_403_FORBIDDEN, NUTAG_WITH_THIS(nua), TAG_END()); - - /* Log line added to support Fail2Ban */ - if (sofia_test_pflag(profile, PFLAG_LOG_AUTH_FAIL)) { - if (regtype == REG_INVITE) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "SIP auth failure (INVITE) on sofia profile '%s' " - "for [%s@%s] from ip %s\n", profile->name, to_user, to_host, network_ip); - } - } - } else { - nua_respond(nh, SIP_401_UNAUTHORIZED, NUTAG_WITH_THIS(nua), TAG_END()); + /* Log line added to support Fail2Ban */ + if (sofia_test_pflag(profile, PFLAG_LOG_AUTH_FAIL)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "SIP auth %s (%s) on sofia profile '%s' " + "for [%s@%s] from ip %s\n", forbidden ? "failure" : "challenge", + (regtype == REG_INVITE) ? "INVITE" : "REGISTER", profile->name, to_user, to_host, network_ip); } + switch_goto_int(r, 1, end); } } @@ -1193,14 +1187,18 @@ uint8_t sofia_reg_handle_register(nua_t *nua, sofia_profile_t *profile, nua_hand realm = from_host; } - if (regtype == REG_REGISTER) { - sofia_reg_auth_challenge(nua, profile, nh, regtype, realm, stale); - if (profile->debug) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Requesting Registration from: [%s@%s]\n", to_user, to_host); - } - } else { - sofia_reg_auth_challenge(nua, profile, nh, regtype, realm, stale); + sofia_reg_auth_challenge(nua, profile, nh, regtype, realm, stale); + + if (profile->debug) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Send challenge for [%s@%s]\n", to_user, to_host); } + /* Log line added to support Fail2Ban */ + if (sofia_test_pflag(profile, PFLAG_LOG_AUTH_FAIL)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "SIP auth challenge (%s) on sofia profile '%s' " + "for [%s@%s] from ip %s\n", (regtype == REG_INVITE) ? "INVITE" : "REGISTER", + profile->name, to_user, to_host, network_ip); + } + switch_goto_int(r, 1, end); } reg: diff --git a/src/mod/event_handlers/mod_event_socket/mod_event_socket.c b/src/mod/event_handlers/mod_event_socket/mod_event_socket.c index ee7cfc9eaf..596a953dcb 100644 --- a/src/mod/event_handlers/mod_event_socket/mod_event_socket.c +++ b/src/mod/event_handlers/mod_event_socket/mod_event_socket.c @@ -31,8 +31,8 @@ */ #include #define CMD_BUFLEN 1024 * 1000 -#define MAX_QUEUE_LEN 5000 -#define MAX_MISSED 200 +#define MAX_QUEUE_LEN 25000 +#define MAX_MISSED 2000 SWITCH_MODULE_LOAD_FUNCTION(mod_event_socket_load); SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_event_socket_shutdown); SWITCH_MODULE_RUNTIME_FUNCTION(mod_event_socket_runtime); @@ -170,7 +170,7 @@ static switch_status_t socket_logger(const switch_log_node_t *node, switch_log_l if (switch_test_flag(l, LFLAG_LOG) && l->level >= node->level) { switch_log_node_t *dnode = switch_log_node_dup(node); - if (switch_queue_trypush(l->log_queue, dnode) == SWITCH_STATUS_SUCCESS) { + if (switch_queue_push(l->log_queue, dnode) == SWITCH_STATUS_SUCCESS) { if (l->lost_logs) { int ll = l->lost_logs; switch_event_t *event; @@ -366,7 +366,7 @@ static void event_handler(switch_event_t *event) if (send) { if (switch_event_dup(&clone, event) == SWITCH_STATUS_SUCCESS) { - if (switch_queue_trypush(l->event_queue, clone) == SWITCH_STATUS_SUCCESS) { + if (switch_queue_push(l->event_queue, clone) == SWITCH_STATUS_SUCCESS) { if (l->lost_events) { int le = l->lost_events; l->lost_events = 0; @@ -1233,7 +1233,7 @@ static switch_status_t read_packet(listener_t *listener, switch_event_t **event, if (switch_channel_get_state(chan) < CS_HANGUP && switch_channel_test_flag(chan, CF_DIVERT_EVENTS)) { switch_event_t *e = NULL; while (switch_core_session_dequeue_event(listener->session, &e, SWITCH_TRUE) == SWITCH_STATUS_SUCCESS) { - if (switch_queue_trypush(listener->event_queue, e) != SWITCH_STATUS_SUCCESS) { + if (switch_queue_push(listener->event_queue, e) != SWITCH_STATUS_SUCCESS) { switch_core_session_queue_event(listener->session, &e); break; } diff --git a/src/mod/languages/mod_managed/freeswitch_wrap.2010.cxx b/src/mod/languages/mod_managed/freeswitch_wrap.2010.cxx index 8033a8faa5..1ad1b16b9a 100644 --- a/src/mod/languages/mod_managed/freeswitch_wrap.2010.cxx +++ b/src/mod/languages/mod_managed/freeswitch_wrap.2010.cxx @@ -28290,15 +28290,33 @@ SWIGEXPORT int SWIGSTDCALL CSharp_switch_rtp_activate_rtcp(void * jarg1, int jar } -SWIGEXPORT int SWIGSTDCALL CSharp_switch_rtp_activate_jitter_buffer(void * jarg1, unsigned long jarg2) { +SWIGEXPORT int SWIGSTDCALL CSharp_switch_rtp_activate_jitter_buffer(void * jarg1, unsigned long jarg2, unsigned long jarg3, unsigned long jarg4, unsigned long jarg5) { int jresult ; switch_rtp_t *arg1 = (switch_rtp_t *) 0 ; uint32_t arg2 ; + uint32_t arg3 ; + uint32_t arg4 ; + uint32_t arg5 ; switch_status_t result; arg1 = (switch_rtp_t *)jarg1; arg2 = (uint32_t)jarg2; - result = (switch_status_t)switch_rtp_activate_jitter_buffer(arg1,arg2); + arg3 = (uint32_t)jarg3; + arg4 = (uint32_t)jarg4; + arg5 = (uint32_t)jarg5; + result = (switch_status_t)switch_rtp_activate_jitter_buffer(arg1,arg2,arg3,arg4,arg5); + jresult = result; + return jresult; +} + + +SWIGEXPORT int SWIGSTDCALL CSharp_switch_rtp_deactivate_jitter_buffer(void * jarg1) { + int jresult ; + switch_rtp_t *arg1 = (switch_rtp_t *) 0 ; + switch_status_t result; + + arg1 = (switch_rtp_t *)jarg1; + result = (switch_status_t)switch_rtp_deactivate_jitter_buffer(arg1); jresult = result; return jresult; } diff --git a/src/mod/languages/mod_managed/freeswitch_wrap.cxx b/src/mod/languages/mod_managed/freeswitch_wrap.cxx index a65d82d9cb..1d3c5d60ce 100644 --- a/src/mod/languages/mod_managed/freeswitch_wrap.cxx +++ b/src/mod/languages/mod_managed/freeswitch_wrap.cxx @@ -28993,15 +28993,33 @@ SWIGEXPORT int SWIGSTDCALL CSharp_switch_rtp_activate_rtcp(void * jarg1, int jar } -SWIGEXPORT int SWIGSTDCALL CSharp_switch_rtp_activate_jitter_buffer(void * jarg1, unsigned long jarg2) { +SWIGEXPORT int SWIGSTDCALL CSharp_switch_rtp_activate_jitter_buffer(void * jarg1, unsigned long jarg2, unsigned long jarg3, unsigned long jarg4, unsigned long jarg5) { int jresult ; switch_rtp_t *arg1 = (switch_rtp_t *) 0 ; uint32_t arg2 ; + uint32_t arg3 ; + uint32_t arg4 ; + uint32_t arg5 ; switch_status_t result; arg1 = (switch_rtp_t *)jarg1; arg2 = (uint32_t)jarg2; - result = (switch_status_t)switch_rtp_activate_jitter_buffer(arg1,arg2); + arg3 = (uint32_t)jarg3; + arg4 = (uint32_t)jarg4; + arg5 = (uint32_t)jarg5; + result = (switch_status_t)switch_rtp_activate_jitter_buffer(arg1,arg2,arg3,arg4,arg5); + jresult = result; + return jresult; +} + + +SWIGEXPORT int SWIGSTDCALL CSharp_switch_rtp_deactivate_jitter_buffer(void * jarg1) { + int jresult ; + switch_rtp_t *arg1 = (switch_rtp_t *) 0 ; + switch_status_t result; + + arg1 = (switch_rtp_t *)jarg1; + result = (switch_status_t)switch_rtp_deactivate_jitter_buffer(arg1); jresult = result; return jresult; } diff --git a/src/mod/languages/mod_managed/managed/swig.2010.cs b/src/mod/languages/mod_managed/managed/swig.2010.cs index 4d14f10879..4b9ce71e60 100644 --- a/src/mod/languages/mod_managed/managed/swig.2010.cs +++ b/src/mod/languages/mod_managed/managed/swig.2010.cs @@ -4640,8 +4640,13 @@ public class freeswitch { return ret; } - public static switch_status_t switch_rtp_activate_jitter_buffer(SWIGTYPE_p_switch_rtp rtp_session, uint queue_frames) { - switch_status_t ret = (switch_status_t)freeswitchPINVOKE.switch_rtp_activate_jitter_buffer(SWIGTYPE_p_switch_rtp.getCPtr(rtp_session), queue_frames); + public static switch_status_t switch_rtp_activate_jitter_buffer(SWIGTYPE_p_switch_rtp rtp_session, uint queue_frames, uint max_queue_frames, uint samples_per_packet, uint samples_per_second) { + switch_status_t ret = (switch_status_t)freeswitchPINVOKE.switch_rtp_activate_jitter_buffer(SWIGTYPE_p_switch_rtp.getCPtr(rtp_session), queue_frames, max_queue_frames, samples_per_packet, samples_per_second); + return ret; + } + + public static switch_status_t switch_rtp_deactivate_jitter_buffer(SWIGTYPE_p_switch_rtp rtp_session) { + switch_status_t ret = (switch_status_t)freeswitchPINVOKE.switch_rtp_deactivate_jitter_buffer(SWIGTYPE_p_switch_rtp.getCPtr(rtp_session)); return ret; } @@ -12448,7 +12453,10 @@ class freeswitchPINVOKE { public static extern int switch_rtp_activate_rtcp(HandleRef jarg1, int jarg2, ushort jarg3); [DllImport("mod_managed", EntryPoint="CSharp_switch_rtp_activate_jitter_buffer")] - public static extern int switch_rtp_activate_jitter_buffer(HandleRef jarg1, uint jarg2); + public static extern int switch_rtp_activate_jitter_buffer(HandleRef jarg1, uint jarg2, uint jarg3, uint jarg4, uint jarg5); + + [DllImport("mod_managed", EntryPoint="CSharp_switch_rtp_deactivate_jitter_buffer")] + public static extern int switch_rtp_deactivate_jitter_buffer(HandleRef jarg1); [DllImport("mod_managed", EntryPoint="CSharp_switch_rtp_set_flag")] public static extern void switch_rtp_set_flag(HandleRef jarg1, uint jarg2); @@ -21554,6 +21562,7 @@ public enum switch_channel_flag_t { CF_PASSTHRU_PTIME_MISMATCH, CF_BRIDGE_NOWRITE, CF_RECOVERED, + CF_JITTERBUFFER, CF_FLAG_MAX } @@ -23243,6 +23252,7 @@ public enum switch_core_session_message_types_t { SWITCH_MESSAGE_INDICATE_T38_DESCRIPTION, SWITCH_MESSAGE_INDICATE_UDPTL_MODE, SWITCH_MESSAGE_INDICATE_CLEAR_PROGRESS, + SWITCH_MESSAGE_INDICATE_JITTER_BUFFER, SWITCH_MESSAGE_INVALID } diff --git a/src/mod/languages/mod_managed/managed/swig.cs b/src/mod/languages/mod_managed/managed/swig.cs index e024c586f8..9decf74045 100644 --- a/src/mod/languages/mod_managed/managed/swig.cs +++ b/src/mod/languages/mod_managed/managed/swig.cs @@ -4630,8 +4630,13 @@ public class freeswitch { return ret; } - public static switch_status_t switch_rtp_activate_jitter_buffer(SWIGTYPE_p_switch_rtp rtp_session, uint queue_frames) { - switch_status_t ret = (switch_status_t)freeswitchPINVOKE.switch_rtp_activate_jitter_buffer(SWIGTYPE_p_switch_rtp.getCPtr(rtp_session), queue_frames); + public static switch_status_t switch_rtp_activate_jitter_buffer(SWIGTYPE_p_switch_rtp rtp_session, uint queue_frames, uint max_queue_frames, uint samples_per_packet, uint samples_per_second) { + switch_status_t ret = (switch_status_t)freeswitchPINVOKE.switch_rtp_activate_jitter_buffer(SWIGTYPE_p_switch_rtp.getCPtr(rtp_session), queue_frames, max_queue_frames, samples_per_packet, samples_per_second); + return ret; + } + + public static switch_status_t switch_rtp_deactivate_jitter_buffer(SWIGTYPE_p_switch_rtp rtp_session) { + switch_status_t ret = (switch_status_t)freeswitchPINVOKE.switch_rtp_deactivate_jitter_buffer(SWIGTYPE_p_switch_rtp.getCPtr(rtp_session)); return ret; } @@ -12434,7 +12439,10 @@ class freeswitchPINVOKE { public static extern int switch_rtp_activate_rtcp(HandleRef jarg1, int jarg2, ushort jarg3); [DllImport("mod_managed", EntryPoint="CSharp_switch_rtp_activate_jitter_buffer")] - public static extern int switch_rtp_activate_jitter_buffer(HandleRef jarg1, uint jarg2); + public static extern int switch_rtp_activate_jitter_buffer(HandleRef jarg1, uint jarg2, uint jarg3, uint jarg4, uint jarg5); + + [DllImport("mod_managed", EntryPoint="CSharp_switch_rtp_deactivate_jitter_buffer")] + public static extern int switch_rtp_deactivate_jitter_buffer(HandleRef jarg1); [DllImport("mod_managed", EntryPoint="CSharp_switch_rtp_set_flag")] public static extern void switch_rtp_set_flag(HandleRef jarg1, uint jarg2); @@ -21500,6 +21508,7 @@ public enum switch_channel_flag_t { CF_PASSTHRU_PTIME_MISMATCH, CF_BRIDGE_NOWRITE, CF_RECOVERED, + CF_JITTERBUFFER, CF_FLAG_MAX } @@ -23167,6 +23176,7 @@ public enum switch_core_session_message_types_t { SWITCH_MESSAGE_INDICATE_T38_DESCRIPTION, SWITCH_MESSAGE_INDICATE_UDPTL_MODE, SWITCH_MESSAGE_INDICATE_CLEAR_PROGRESS, + SWITCH_MESSAGE_INDICATE_JITTER_BUFFER, SWITCH_MESSAGE_INVALID } diff --git a/src/mod/languages/mod_perl/mod_perl_wrap.cpp b/src/mod/languages/mod_perl/mod_perl_wrap.cpp index 2efbdf1abc..370c88bc99 100644 --- a/src/mod/languages/mod_perl/mod_perl_wrap.cpp +++ b/src/mod/languages/mod_perl/mod_perl_wrap.cpp @@ -9732,17 +9732,17 @@ XS(SWIG_init) { SWIG_TypeClientData(SWIGTYPE_p_IVRMenu, (void*) "freeswitch::IVRMenu"); SWIG_TypeClientData(SWIGTYPE_p_API, (void*) "freeswitch::API"); SWIG_TypeClientData(SWIGTYPE_p_input_callback_state, (void*) "freeswitch::input_callback_state_t"); - /*@SWIG:/usr/local/share/swig/1.3.35/perl5/perltypemaps.swg,64,%set_constant@*/ do { + /*@SWIG:/usr/share/swig/1.3.35/perl5/perltypemaps.swg,64,%set_constant@*/ do { SV *sv = get_sv((char*) SWIG_prefix "S_HUP", TRUE | 0x2 | GV_ADDMULTI); sv_setsv(sv, SWIG_From_int SWIG_PERL_CALL_ARGS_1(static_cast< int >(S_HUP))); SvREADONLY_on(sv); } while(0) /*@SWIG@*/; - /*@SWIG:/usr/local/share/swig/1.3.35/perl5/perltypemaps.swg,64,%set_constant@*/ do { + /*@SWIG:/usr/share/swig/1.3.35/perl5/perltypemaps.swg,64,%set_constant@*/ do { SV *sv = get_sv((char*) SWIG_prefix "S_FREE", TRUE | 0x2 | GV_ADDMULTI); sv_setsv(sv, SWIG_From_int SWIG_PERL_CALL_ARGS_1(static_cast< int >(S_FREE))); SvREADONLY_on(sv); } while(0) /*@SWIG@*/; - /*@SWIG:/usr/local/share/swig/1.3.35/perl5/perltypemaps.swg,64,%set_constant@*/ do { + /*@SWIG:/usr/share/swig/1.3.35/perl5/perltypemaps.swg,64,%set_constant@*/ do { SV *sv = get_sv((char*) SWIG_prefix "S_RDLOCK", TRUE | 0x2 | GV_ADDMULTI); sv_setsv(sv, SWIG_From_int SWIG_PERL_CALL_ARGS_1(static_cast< int >(S_RDLOCK))); SvREADONLY_on(sv); diff --git a/src/mod/say/mod_say_es/mod_say_es.c b/src/mod/say/mod_say_es/mod_say_es.c index cf4d2f9b12..ff0ee944c2 100644 --- a/src/mod/say/mod_say_es/mod_say_es.c +++ b/src/mod/say/mod_say_es/mod_say_es.c @@ -39,8 +39,9 @@ * * Anthony Minessale II * Michael B. Murdock + * François Delawarde * - * mod_say_es.c -- Say for English + * mod_say_es.c -- Say for Spanish * */ @@ -102,7 +103,7 @@ static switch_status_t play_group(switch_say_method_t method, int a, int b, int break; default: say_file("digits/%d.wav", a); - say_file("digits/hundred.wav"); + say_file("digits/hundreds.wav"); break; } } @@ -175,7 +176,12 @@ static switch_status_t es_say_general_count(switch_core_session_t *session, char switch (say_args->method) { case SSM_COUNTED: case SSM_PRONOUNCED: - if ((status = play_group(SSM_PRONOUNCED, places[8], places[7], places[6], "digits/million.wav", session, args)) != SWITCH_STATUS_SUCCESS) { + /* specific case, one million => un millón */ + if (!places[8] && !places[7] && (places[6] == 1)) { + say_file("digits/un.wav"); + say_file("digits/million.wav"); + } + else if ((status = play_group(SSM_PRONOUNCED, places[8], places[7], places[6], "digits/millions.wav", session, args)) != SWITCH_STATUS_SUCCESS) { return status; } if ((status = play_group(SSM_PRONOUNCED, places[5], places[4], places[3], "digits/thousand.wav", session, args)) != SWITCH_STATUS_SUCCESS) { diff --git a/src/mod/say/mod_say_pt/Makefile b/src/mod/say/mod_say_pt/Makefile new file mode 100644 index 0000000000..2c35e6e98f --- /dev/null +++ b/src/mod/say/mod_say_pt/Makefile @@ -0,0 +1,2 @@ +BASE=../../../.. +include $(BASE)/build/modmake.rules diff --git a/src/mod/say/mod_say_pt/mod_say_pt.2008.vcproj b/src/mod/say/mod_say_pt/mod_say_pt.2008.vcproj new file mode 100644 index 0000000000..ee0fffde02 --- /dev/null +++ b/src/mod/say/mod_say_pt/mod_say_pt.2008.vcproj @@ -0,0 +1,283 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/mod/say/mod_say_pt/mod_say_pt.2010.vcxproj b/src/mod/say/mod_say_pt/mod_say_pt.2010.vcxproj new file mode 100644 index 0000000000..8c94e2cb65 --- /dev/null +++ b/src/mod/say/mod_say_pt/mod_say_pt.2010.vcxproj @@ -0,0 +1,131 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + mod_say_pt + {7C22BDFF-CC09-400C-8A09-660733980028} + mod_say_pt + Win32Proj + + + + DynamicLibrary + MultiByte + + + DynamicLibrary + MultiByte + + + DynamicLibrary + MultiByte + + + DynamicLibrary + MultiByte + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + + + + + + + + false + + + + + + + X64 + + + + + + + false + + + MachineX64 + + + + + + + + + false + + + + + + + X64 + + + + + + + false + + + MachineX64 + + + + + + + + {202d7a4e-760d-4d0e-afa1-d7459ced30ff} + false + + + + + + diff --git a/src/mod/say/mod_say_pt/mod_say_pt.c b/src/mod/say/mod_say_pt/mod_say_pt.c new file mode 100644 index 0000000000..747a0c8984 --- /dev/null +++ b/src/mod/say/mod_say_pt/mod_say_pt.c @@ -0,0 +1,548 @@ +/* + * Copyright (c) 2007, Anthony Minessale II + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of the original author; nor the names of any contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The Initial Developer of the Original Code is + * Anthony Minessale II + * Portions created by the Initial Developer are Copyright (C) + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Anthony Minessale II + * Michael B. Murdock + * António Silva + * + * mod_say_pt.c -- Say for Portuguese + * + */ + +#include +#include +#include + +SWITCH_MODULE_LOAD_FUNCTION(mod_say_pt_load); +SWITCH_MODULE_DEFINITION(mod_say_pt, mod_say_pt_load, NULL, NULL); + +#define say_num(num, meth) { \ + char tmp[80]; \ + switch_status_t tstatus; \ + switch_say_method_t smeth = say_args->method; \ + switch_say_type_t stype = say_args->type; \ + say_args->type = SST_ITEMS; say_args->method = meth; \ + switch_snprintf(tmp, sizeof(tmp), "%u", (unsigned)num); \ + if ((tstatus = \ + pt_say_general_count(session, tmp, say_args, args)) \ + != SWITCH_STATUS_SUCCESS) { \ + return tstatus; \ + } \ + say_args->method = smeth; say_args->type = stype; \ + } \ + + +#define say_file(...) { \ + char tmp[80]; \ + switch_status_t tstatus; \ + switch_snprintf(tmp, sizeof(tmp), __VA_ARGS__); \ + if ((tstatus = \ + switch_ivr_play_file(session, NULL, tmp, args)) \ + != SWITCH_STATUS_SUCCESS){ \ + return tstatus; \ + } \ + if (!switch_channel_ready(switch_core_session_get_channel(session))) { \ + return SWITCH_STATUS_FALSE; \ + }} \ + + +static switch_status_t play_group(switch_say_method_t method, int a, int b, int c, char *what, switch_core_session_t *session, switch_input_args_t *args) +{ + + /*a => 1xx-9xx*/ + if (a) { + switch (a) { + case 1: + if (b || c) { + say_file("digits/hundred.wav"); + } else { + say_file("digits/100.wav"); + } + break; + case 2: + say_file("digits/200.wav"); + break; + case 3: + say_file("digits/300.wav"); + break; + case 5: + say_file("digits/500.wav"); + break; + default: + say_file("digits/%d.wav", a); + say_file("digits/hundreds.wav"); + break; + } + if (b || c) { + say_file("currency/and.wav"); + } + } + /* b => 1x - 9x */ + if (b) { + if (b > 1) { + if (method == SSM_COUNTED) { + say_file("digits/h-%d0.wav", b); + } else { + say_file("digits/%d0.wav", b); + if (c > 0) { + say_file("currency/and.wav"); + } + } + } else { + say_file("digits/%d%d.wav", b, c); + c = 0; + } + } + /* c => 0 - 9*/ + if (c) { + if (method == SSM_COUNTED) { + say_file("digits/h-%d.wav", c); + } else { + say_file("digits/%d.wav", c); + } + } + + if (what && (a || b || c)) { + say_file(what); + } + + return SWITCH_STATUS_SUCCESS; +} + +static switch_status_t pt_say_general_count(switch_core_session_t *session, char *tosay, switch_say_args_t *say_args, switch_input_args_t *args) +{ + int in; + int x = 0; + int places[9] = { 0 }; + char sbuf[128] = ""; + switch_status_t status; + + if (say_args->method == SSM_ITERATED) { + if ((tosay = switch_strip_commas(tosay, sbuf, sizeof(sbuf)))) { + char *p; + for (p = tosay; p && *p; p++) { + say_file("digits/%c.wav", *p); + } + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Parse Error!\n"); + return SWITCH_STATUS_GENERR; + } + return SWITCH_STATUS_SUCCESS; + } + + if (!(tosay = switch_strip_commas(tosay, sbuf, sizeof(sbuf))) || strlen(tosay) > 9) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Parse Error!\n"); + return SWITCH_STATUS_GENERR; + } + + in = atoi(tosay); + + if (in != 0) { + for (x = 8; x >= 0; x--) { + int num = (int) pow(10, x); + if ((places[(uint32_t) x] = in / num)) { + in -= places[(uint32_t) x] * num; + } + } + + switch (say_args->method) { + case SSM_COUNTED: + case SSM_PRONOUNCED: + /* specific case, one million => um milhão */ + if (!places[8] && !places[7] && (places[6] == 1)) { + say_file("digits/1.wav"); + say_file("digits/million.wav"); + } else if ((status = play_group(SSM_PRONOUNCED, places[8], places[7], places[6], "digits/millions.wav", session, args)) != SWITCH_STATUS_SUCCESS) { + return status; + } + if ((status = play_group(SSM_PRONOUNCED, places[5], places[4], places[3], "digits/thousand.wav", session, args)) != SWITCH_STATUS_SUCCESS) { + return status; + } + if ((status = play_group(say_args->method, places[2], places[1], places[0], NULL, session, args)) != SWITCH_STATUS_SUCCESS) { + return status; + } + break; + default: + break; + } + } else { + say_file("digits/0.wav"); + } + + return SWITCH_STATUS_SUCCESS; +} + +static switch_status_t pt_say_time(switch_core_session_t *session, char *tosay, switch_say_args_t *say_args, switch_input_args_t *args) +{ + int32_t t; + switch_time_t target = 0, target_now = 0; + switch_time_exp_t tm, tm_now; + uint8_t say_date = 0, say_time = 0, say_year = 0, say_month = 0, say_dow = 0, say_day = 0, say_yesterday = 0, say_today = 0; + switch_channel_t *channel = switch_core_session_get_channel(session); + const char *tz = switch_channel_get_variable(channel, "timezone"); + + if (say_args->type == SST_TIME_MEASUREMENT) { + int64_t hours = 0; + int64_t minutes = 0; + int64_t seconds = 0; + int64_t r = 0; + + if (strchr(tosay, ':')) { + char *tme = switch_core_session_strdup(session, tosay); + char *p; + + if ((p = strrchr(tme, ':'))) { + *p++ = '\0'; + seconds = atoi(p); + if ((p = strchr(tme, ':'))) { + *p++ = '\0'; + minutes = atoi(p); + if (tme) { + hours = atoi(tme); + } + } else { + minutes = atoi(tme); + } + } + } else { + if ((seconds = atol(tosay)) <= 0) { + seconds = (int64_t) switch_epoch_time_now(NULL); + } + + if (seconds >= 60) { + minutes = seconds / 60; + r = seconds % 60; + seconds = r; + } + + if (minutes >= 60) { + hours = minutes / 60; + r = minutes % 60; + minutes = r; + } + } + + if (hours) { + say_num(hours, SSM_PRONOUNCED); + if (hours == 1) { + say_file("time/hour.wav"); + } else { + say_file("time/hours.wav"); + } + } else { + say_file("digits/0.wav"); + say_file("time/hours.wav"); + } + + if (minutes) { + say_num(minutes, SSM_PRONOUNCED); + if (minutes == 1) { + say_file("time/minute.wav"); + } else { + say_file("time/minutes.wav"); + } + } else { + say_file("digits/0.wav"); + say_file("time/minutes.wav"); + } + + if (seconds) { + say_num(seconds, SSM_PRONOUNCED); + if (seconds == 1) { + say_file("time/second.wav"); + } else { + say_file("time/seconds.wav"); + } + } else { + say_file("digits/0.wav"); + say_file("time/seconds.wav"); + } + + return SWITCH_STATUS_SUCCESS; + } + + if ((t = atol(tosay)) > 0) { + target = switch_time_make(t, 0); + target_now = switch_micro_time_now(); + } else { + target = switch_micro_time_now(); + target_now = switch_micro_time_now(); + } + + if (tz) { + int check = atoi(tz); + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Timezone is [%s]\n", tz); + if (check) { + switch_time_exp_tz(&tm, target, check); + switch_time_exp_tz(&tm_now, target_now, check); + } else { + switch_time_exp_tz_name(tz, &tm, target); + switch_time_exp_tz_name(tz, &tm_now, target_now); + } + } else { + switch_time_exp_lt(&tm, target); + switch_time_exp_lt(&tm_now, target_now); + } + + switch (say_args->type) { + case SST_CURRENT_DATE_TIME: + say_date = say_time = 1; + break; + case SST_CURRENT_DATE: + say_date = 1; + break; + case SST_CURRENT_TIME: + say_time = 1; + break; + case SST_SHORT_DATE_TIME: + say_time = 1; + if (tm.tm_year != tm_now.tm_year) { + say_date = 1; + break; + } + if (tm.tm_yday == tm_now.tm_yday) { + say_today = 1; + break; + } + if (tm.tm_yday == tm_now.tm_yday - 1) { + say_yesterday = 1; + break; + } + if (tm.tm_yday >= tm_now.tm_yday - 5) { + say_dow = 1; + break; + } + if (tm.tm_mon != tm_now.tm_mon) { + say_month = say_day = say_dow = 1; + break; + } + + say_month = say_day = say_dow = 1; + + break; + default: + break; + } + + if (say_today) { + say_file("time/today.wav"); + } + if (say_yesterday) { + say_file("time/yesterday.wav"); + } + if (say_dow) { + say_file("time/day-%d.wav", tm.tm_wday); + } + + if (say_date) { + say_year = say_month = say_day = say_dow = 1; + say_today = say_yesterday = 0; + } + + if (say_month) { + say_file("time/mon-%d.wav", tm.tm_mon); + } + if (say_day) { + say_num(tm.tm_mday, SSM_COUNTED); + } + if (say_year) { + say_num(tm.tm_year + 1900, SSM_PRONOUNCED); + } + + if (say_time) { + int32_t hour = tm.tm_hour, pm = 0; + + if (say_date || say_today || say_yesterday || say_dow) { + if (hour == 1) { + say_file("time/at.wav"); + } else { + say_file("time/ats.wav"); + } + } + + if (hour > 12) { + hour -= 12; + pm = 1; + } else if (hour == 12) { + pm = 1; + } else if (hour == 0) { + hour = 12; + pm = 0; + } + + say_num(hour, SSM_PRONOUNCED); + + if (tm.tm_min) { + say_file("currency/and.wav"); + say_num(tm.tm_min, SSM_PRONOUNCED); + } else { + say_file("time/oclock.wav"); + } + + say_file("time/%s.wav", pm ? "p-m" : "a-m"); + } + + return SWITCH_STATUS_SUCCESS; +} + + +static switch_status_t pt_say_money(switch_core_session_t *session, char *tosay, switch_say_args_t *say_args, switch_input_args_t *args) +{ + char sbuf[16] = ""; /* enough for 999,999,999,999.99 (w/o the commas or leading $) */ + char *dollars = NULL; + char *cents = NULL; + + if (strlen(tosay) > 15 || !(tosay = switch_strip_nonnumerics(tosay, sbuf, sizeof(sbuf)))) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Parse Error!\n"); + return SWITCH_STATUS_GENERR; + } + + dollars = sbuf; + + if ((cents = strchr(sbuf, '.'))) { + *cents++ = '\0'; + if (strlen(cents) > 2) { + cents[2] = '\0'; + } + } + + /* If positive sign - skip over" */ + if (sbuf[0] == '+') { + dollars++; + } + + /* If negative say "negative" */ + if (sbuf[0] == '-') { + say_file("currency/negative.wav"); + dollars++; + } + + /* Say dollar amount */ + pt_say_general_count(session, dollars, say_args, args); + if (atoi(dollars) == 1) { + say_file("currency/dollar.wav"); + } else { + say_file("currency/dollars.wav"); + } + + /* Say "and" */ + say_file("currency/and.wav"); + + /* Say cents */ + if (cents) { + pt_say_general_count(session, cents, say_args, args); + if (atoi(cents) == 1) { + say_file("currency/cent.wav"); + } else { + say_file("currency/cents.wav"); + } + } else { + say_file("digits/0.wav"); + say_file("currency/cents.wav"); + } + + return SWITCH_STATUS_SUCCESS; +} + + + +static switch_status_t pt_say(switch_core_session_t *session, char *tosay, switch_say_args_t *say_args, switch_input_args_t *args) +{ + + switch_say_callback_t say_cb = NULL; + + switch (say_args->type) { + case SST_NUMBER: + case SST_ITEMS: + case SST_PERSONS: + case SST_MESSAGES: + say_cb = pt_say_general_count; + break; + case SST_TIME_MEASUREMENT: + case SST_CURRENT_DATE: + case SST_CURRENT_TIME: + case SST_CURRENT_DATE_TIME: + case SST_SHORT_DATE_TIME: + say_cb = pt_say_time; + break; + case SST_IP_ADDRESS: + return switch_ivr_say_ip(session, tosay, pt_say_general_count, say_args, args); + break; + case SST_NAME_SPELLED: + case SST_NAME_PHONETIC: + return switch_ivr_say_spell(session, tosay, say_args, args); + break; + case SST_CURRENCY: + say_cb = pt_say_money; + break; + default: + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unknown Say type=[%d]\n", say_args->type); + break; + } + + if (say_cb) { + return say_cb(session, tosay, say_args, args); + } + + return SWITCH_STATUS_FALSE; +} + +SWITCH_MODULE_LOAD_FUNCTION(mod_say_pt_load) +{ + switch_say_interface_t *say_interface; + /* connect my internal structure to the blank pointer passed to me */ + *module_interface = switch_loadable_module_create_module_interface(pool, modname); + say_interface = switch_loadable_module_create_interface(*module_interface, SWITCH_SAY_INTERFACE); + say_interface->interface_name = "pt"; + say_interface->say_function = pt_say; + + /* indicate that the module should continue to be loaded */ + return SWITCH_STATUS_SUCCESS; +} + +/* For Emacs: + * Local Variables: + * mode:c + * indent-tabs-mode:t + * tab-width:4 + * c-basic-offset:4 + * End: + * For VIM: + * vim:set softtabstop=4 shiftwidth=4 tabstop=4: + */ diff --git a/src/mod/say/mod_say_pt/mod_say_pt.vcproj b/src/mod/say/mod_say_pt/mod_say_pt.vcproj new file mode 100644 index 0000000000..ce2a3344fc --- /dev/null +++ b/src/mod/say/mod_say_pt/mod_say_pt.vcproj @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/switch_apr.c b/src/switch_apr.c index dccc37be96..c0e51f9766 100644 --- a/src/switch_apr.c +++ b/src/switch_apr.c @@ -729,6 +729,28 @@ SWITCH_DECLARE(switch_status_t) switch_socket_recv(switch_socket_t *sock, char * return apr_socket_recv(sock, buf, len); } +SWITCH_DECLARE(switch_status_t) switch_sockaddr_create(switch_sockaddr_t **sa, switch_memory_pool_t *pool) +{ + switch_sockaddr_t *new_sa; + unsigned short family = APR_INET; + + new_sa = apr_pcalloc(pool, sizeof(apr_sockaddr_t)); + switch_assert(new_sa); + new_sa->pool = pool; + memset(new_sa, 0, sizeof(new_sa)); + + new_sa->family = family; + new_sa->sa.sin.sin_family = family; + + new_sa->salen = sizeof(struct sockaddr_in); + new_sa->addr_str_len = 16; + new_sa->ipaddr_ptr = &(new_sa->sa.sin.sin_addr); + new_sa->ipaddr_len = sizeof(struct in_addr); + + *sa = new_sa; + return SWITCH_STATUS_SUCCESS; +} + SWITCH_DECLARE(switch_status_t) switch_sockaddr_info_get(switch_sockaddr_t ** sa, const char *hostname, int32_t family, switch_port_t port, int32_t flags, switch_memory_pool_t *pool) { diff --git a/src/switch_channel.c b/src/switch_channel.c index a9c87c5954..aa7f6699b7 100644 --- a/src/switch_channel.c +++ b/src/switch_channel.c @@ -2382,10 +2382,48 @@ SWITCH_DECLARE(switch_status_t) switch_channel_caller_extension_masquerade(switc return status; } +SWITCH_DECLARE(void) switch_channel_sort_cid(switch_channel_t *channel, switch_bool_t in) +{ + + if (in) { + if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND && !switch_channel_test_flag(channel, CF_DIALPLAN)) { + switch_channel_set_flag(channel, CF_DIALPLAN); + + switch_mutex_lock(channel->profile_mutex); + if (channel->caller_profile->callee_id_name) { + switch_channel_set_variable(channel, "pre_transfer_caller_id_name", channel->caller_profile->caller_id_name); + channel->caller_profile->caller_id_name = switch_core_strdup(channel->caller_profile->pool, channel->caller_profile->callee_id_name); + } + channel->caller_profile->callee_id_name = SWITCH_BLANK_STRING; + + if (channel->caller_profile->callee_id_number) { + switch_channel_set_variable(channel, "pre_transfer_caller_id_number", channel->caller_profile->caller_id_number); + channel->caller_profile->caller_id_number = switch_core_strdup(channel->caller_profile->pool, channel->caller_profile->callee_id_number); + } + channel->caller_profile->callee_id_number = SWITCH_BLANK_STRING; + switch_mutex_unlock(channel->profile_mutex); + } + + return; + } + + if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND && switch_channel_test_flag(channel, CF_DIALPLAN)) { + switch_channel_clear_flag(channel, CF_DIALPLAN); + switch_mutex_lock(channel->profile_mutex); + channel->caller_profile->callee_id_name = SWITCH_BLANK_STRING; + channel->caller_profile->callee_id_number = SWITCH_BLANK_STRING; + switch_mutex_unlock(channel->profile_mutex); + } + +} + + SWITCH_DECLARE(void) switch_channel_set_caller_extension(switch_channel_t *channel, switch_caller_extension_t *caller_extension) { switch_assert(channel != NULL); + switch_channel_sort_cid(channel, SWITCH_TRUE); + switch_mutex_lock(channel->profile_mutex); caller_extension->next = channel->caller_profile->caller_extension; channel->caller_profile->caller_extension = caller_extension; @@ -2622,7 +2660,7 @@ SWITCH_DECLARE(switch_status_t) switch_channel_perform_pre_answer(switch_channel return SWITCH_STATUS_SUCCESS; } - if (!switch_channel_test_flag(channel, CF_OUTBOUND)) { + if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_INBOUND) { msg.message_id = SWITCH_MESSAGE_INDICATE_PROGRESS; msg.from = channel->name; status = switch_core_session_perform_receive_message(channel->session, &msg, file, func, line); @@ -2657,7 +2695,7 @@ SWITCH_DECLARE(switch_status_t) switch_channel_perform_ring_ready_value(switch_c return SWITCH_STATUS_SUCCESS; } - if (!switch_channel_test_flag(channel, CF_OUTBOUND)) { + if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_INBOUND) { msg.message_id = SWITCH_MESSAGE_INDICATE_RINGING; msg.from = channel->name; msg.numeric_arg = rv; @@ -2800,7 +2838,7 @@ SWITCH_DECLARE(switch_status_t) switch_channel_perform_answer(switch_channel_t * switch_assert(channel != NULL); - if (switch_channel_test_flag(channel, CF_OUTBOUND)) { + if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) { return SWITCH_STATUS_SUCCESS; } diff --git a/src/switch_core_io.c b/src/switch_core_io.c index 6f3e65a9f4..c3113e9680 100644 --- a/src/switch_core_io.c +++ b/src/switch_core_io.c @@ -235,7 +235,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_read_frame(switch_core_sessi if (switch_test_flag(*frame, SFF_CNG)) { status = SWITCH_STATUS_SUCCESS; - if (!session->bugs) { + if (!session->bugs && !session->plc) { goto done; } is_cng = 1; @@ -303,7 +303,13 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_read_frame(switch_core_sessi session->raw_read_frame.datalen = session->raw_read_frame.buflen; if (is_cng) { - memset(session->raw_read_frame.data, 255, read_frame->codec->implementation->decoded_bytes_per_packet); + if (session->plc) { + plc_fillin(session->plc, session->raw_read_frame.data, read_frame->codec->implementation->decoded_bytes_per_packet / 2); + is_cng = 0; + flag &= !SFF_CNG; + } else { + memset(session->raw_read_frame.data, 255, read_frame->codec->implementation->decoded_bytes_per_packet); + } session->raw_read_frame.datalen = read_frame->codec->implementation->decoded_bytes_per_packet; session->raw_read_frame.samples = session->raw_read_frame.datalen / sizeof(int16_t); read_frame = &session->raw_read_frame; @@ -319,13 +325,37 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_read_frame(switch_core_sessi switch_thread_rwlock_unlock(session->bug_rwlock); } - status = switch_core_codec_decode(use_codec, - session->read_codec, - read_frame->data, - read_frame->datalen, - session->read_impl.actual_samples_per_second, - session->raw_read_frame.data, &session->raw_read_frame.datalen, &session->raw_read_frame.rate, - &read_frame->flags); + if (switch_test_flag(read_frame, SFF_PLC)) { + session->raw_read_frame.datalen = read_frame->codec->implementation->decoded_bytes_per_packet; + session->raw_read_frame.samples = session->raw_read_frame.datalen / sizeof(int16_t); + memset(session->raw_read_frame.data, 255, session->raw_read_frame.datalen); + status = SWITCH_STATUS_SUCCESS; + } else { + status = switch_core_codec_decode(use_codec, + session->read_codec, + read_frame->data, + read_frame->datalen, + session->read_impl.actual_samples_per_second, + session->raw_read_frame.data, &session->raw_read_frame.datalen, &session->raw_read_frame.rate, + &read_frame->flags); + } + + if (status == SWITCH_STATUS_SUCCESS) { + if (switch_channel_test_flag(session->channel, CF_JITTERBUFFER) && !session->plc) { + session->plc = plc_init(NULL); + } + + if (session->plc) { + if (switch_test_flag(read_frame, SFF_PLC)) { + plc_fillin(session->plc, session->raw_read_frame.data, session->raw_read_frame.datalen / 2); + switch_clear_flag(read_frame, SFF_PLC); + } else { + plc_rx(session->plc, session->raw_read_frame.data, session->raw_read_frame.datalen / 2); + } + } + } + + } if (do_resample && ((status == SWITCH_STATUS_SUCCESS) || is_cng)) { @@ -361,6 +391,10 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_read_frame(switch_core_sessi session->raw_read_frame.seq = read_frame->seq; session->raw_read_frame.m = read_frame->m; session->raw_read_frame.payload = read_frame->payload; + session->raw_read_frame.flags = 0; + if (switch_test_flag(read_frame, SFF_PLC)) { + session->raw_read_frame.flags |= SFF_PLC; + } read_frame = &session->raw_read_frame; break; case SWITCH_STATUS_NOOP: @@ -383,6 +417,11 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_read_frame(switch_core_sessi session->raw_read_frame.seq = read_frame->seq; session->raw_read_frame.m = read_frame->m; session->raw_read_frame.payload = read_frame->payload; + session->raw_read_frame.flags = 0; + if (switch_test_flag(read_frame, SFF_PLC)) { + session->raw_read_frame.flags |= SFF_PLC; + } + read_frame = &session->raw_read_frame; status = SWITCH_STATUS_SUCCESS; break; @@ -462,7 +501,6 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_read_frame(switch_core_sessi read_frame->datalen = session->read_resampler->to_len * 2; read_frame->rate = session->read_resampler->to_rate; switch_mutex_unlock(session->resample_mutex); - } if (read_frame->datalen == session->read_impl.decoded_bytes_per_packet) { @@ -481,7 +519,6 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_read_frame(switch_core_sessi } } - if (perfect || switch_buffer_inuse(session->raw_read_buffer) >= session->read_impl.decoded_bytes_per_packet) { if (perfect) { enc_frame = read_frame; @@ -810,6 +847,11 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_write_frame(switch_core_sess session->raw_write_frame.ssrc = frame->ssrc; session->raw_write_frame.seq = frame->seq; session->raw_write_frame.payload = frame->payload; + session->raw_write_frame.flags = 0; + if (switch_test_flag(frame, SFF_PLC)) { + session->raw_write_frame.flags |= SFF_PLC; + } + write_frame = &session->raw_write_frame; break; case SWITCH_STATUS_BREAK: diff --git a/src/switch_core_session.c b/src/switch_core_session.c index 2567d17712..c2766170a8 100644 --- a/src/switch_core_session.c +++ b/src/switch_core_session.c @@ -1118,6 +1118,11 @@ SWITCH_DECLARE(void) switch_core_session_perform_destroy(switch_core_session_t * } switch_mutex_unlock(runtime.session_hash_mutex); + if ((*session)->plc) { + plc_free((*session)->plc); + (*session)->plc = NULL; + } + if (switch_event_create(&event, SWITCH_EVENT_CHANNEL_DESTROY) == SWITCH_STATUS_SUCCESS) { switch_channel_event_set_data((*session)->channel, event); switch_event_fire(&event); diff --git a/src/switch_core_sqldb.c b/src/switch_core_sqldb.c index 4364ff2844..b561ebe775 100644 --- a/src/switch_core_sqldb.c +++ b/src/switch_core_sqldb.c @@ -1624,6 +1624,7 @@ switch_status_t switch_core_sqldb_start(switch_memory_pool_t *pool, switch_bool_ runtime.odbc_dsn = NULL; runtime.odbc_user = NULL; runtime.odbc_pass = NULL; + runtime.odbc_dbtype = DBTYPE_DEFAULT; switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Falling back to core_db.\n"); goto top; } diff --git a/src/switch_core_state_machine.c b/src/switch_core_state_machine.c index c77f3f1a68..ccd6dacc9c 100644 --- a/src/switch_core_state_machine.c +++ b/src/switch_core_state_machine.c @@ -124,7 +124,7 @@ static void switch_core_standard_on_routing(switch_core_session_t *session) } if (!count) { - if (switch_channel_test_flag(session->channel, CF_OUTBOUND)) { + if (switch_channel_direction(session->channel) == SWITCH_CALL_DIRECTION_OUTBOUND) { if (switch_channel_test_flag(session->channel, CF_ANSWERED)) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "No Dialplan on answered channel, changing state to HANGUP\n"); diff --git a/src/switch_cpp.cpp b/src/switch_cpp.cpp index 40462db567..1ba850d7e4 100644 --- a/src/switch_cpp.cpp +++ b/src/switch_cpp.cpp @@ -1206,7 +1206,7 @@ SWITCH_DECLARE(void) bridge(CoreSession &session_a, CoreSession &session_b) if (switch_channel_ready(channel_a) && switch_channel_ready(channel_b)) { session_a.begin_allow_threads(); - if (!switch_channel_test_flag(channel_a, CF_OUTBOUND) && !switch_channel_media_ready(channel_a)) { + if (switch_channel_direction(channel_a) == SWITCH_CALL_DIRECTION_INBOUND && !switch_channel_media_ready(channel_a)) { switch_channel_pre_answer(channel_a); } diff --git a/src/switch_event.c b/src/switch_event.c index f782c15900..dce42f8e29 100644 --- a/src/switch_event.c +++ b/src/switch_event.c @@ -339,7 +339,7 @@ static void *SWITCH_THREAD_FUNC switch_event_thread(switch_thread_t *thread, voi launch_dispatch_threads(SOFT_MAX_DISPATCH + 1, DISPATCH_QUEUE_LEN, RUNTIME_POOL); switch_mutex_unlock(EVENT_QUEUE_MUTEX); } else { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Out of threads!\n"); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Out of event dispatch threads! Slowing things down.\n"); switch_yield(1000000); } } diff --git a/src/switch_ivr.c b/src/switch_ivr.c index 46ba4e6659..cd74c332b7 100644 --- a/src/switch_ivr.c +++ b/src/switch_ivr.c @@ -140,7 +140,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_sleep(switch_core_session_t *session, const char *var; /* - if (!switch_channel_test_flag(channel, CF_OUTBOUND) && !switch_channel_test_flag(channel, CF_PROXY_MODE) && + if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_INBOUND && !switch_channel_test_flag(channel, CF_PROXY_MODE) && !switch_channel_media_ready(channel) && !switch_channel_test_flag(channel, CF_SERVICE)) { if ((status = switch_channel_pre_answer(channel)) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Cannot establish media.\n"); @@ -1544,21 +1544,6 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_session_transfer(switch_core_session_ new_profile->destination_number = switch_core_strdup(new_profile->pool, extension); new_profile->rdnis = switch_core_strdup(new_profile->pool, profile->destination_number); - if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) { - if (profile->callee_id_name) { - switch_channel_set_variable(channel, "pre_transfer_caller_id_name", new_profile->caller_id_name); - new_profile->caller_id_name = switch_core_strdup(new_profile->pool, profile->callee_id_name); - profile->callee_id_name = SWITCH_BLANK_STRING; - } - - if (profile->callee_id_number) { - switch_channel_set_variable(channel, "pre_transfer_caller_id_number", new_profile->caller_id_number); - new_profile->caller_id_number = switch_core_strdup(new_profile->pool, profile->callee_id_number); - profile->callee_id_number = SWITCH_BLANK_STRING; - } - } - - switch_channel_set_variable(channel, SWITCH_SIGNAL_BOND_VARIABLE, NULL); /* If HANGUP_AFTER_BRIDGE is set to 'true', SWITCH_SIGNAL_BRIDGE_VARIABLE @@ -2290,7 +2275,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, 0); + jb = stfu_n_init(qlen, qlen, read_impl.samples_per_packet, read_impl.samples_per_second); write_frame.codec = switch_core_session_get_read_codec(session); diff --git a/src/switch_ivr_bridge.c b/src/switch_ivr_bridge.c index afd33f16a0..2f2dcdbc95 100644 --- a/src/switch_ivr_bridge.c +++ b/src/switch_ivr_bridge.c @@ -100,7 +100,7 @@ static void send_display(switch_core_session_t *session, switch_core_session_t * caller_channel = switch_core_session_get_channel(session); caller_profile = switch_channel_get_caller_profile(caller_channel); - if (switch_channel_direction(caller_channel) == SWITCH_CALL_DIRECTION_OUTBOUND) { + if (switch_channel_direction(caller_channel) == SWITCH_CALL_DIRECTION_OUTBOUND && !switch_channel_test_flag(caller_channel, CF_DIALPLAN)) { name = caller_profile->callee_id_name; number = caller_profile->callee_id_number; @@ -435,8 +435,8 @@ static void *audio_bridge_thread(switch_thread_t *thread, void *obj) switch_channel_t *un = ans_a ? chan_b : chan_a; switch_channel_t *a = un == chan_b ? chan_a : chan_b; - if (!switch_channel_test_flag(un, CF_OUTBOUND)) { - if (switch_channel_test_flag(a, CF_OUTBOUND) || (un == chan_a && !originator)) { + if (switch_channel_direction(un) == SWITCH_CALL_DIRECTION_INBOUND) { + if (switch_channel_direction(a) == SWITCH_CALL_DIRECTION_OUTBOUND || (un == chan_a && !originator)) { switch_channel_pass_callee_id(a, un); } @@ -1052,6 +1052,8 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_signal_bridge(switch_core_session_t * switch_channel_set_variable(caller_channel, "signal_bridge", "true"); switch_channel_set_variable(peer_channel, "signal_bridge", "true"); + switch_channel_sort_cid(peer_channel, SWITCH_FALSE); + /* fire events that will change the data table from "show channels" */ if (switch_event_create(&event, SWITCH_EVENT_CHANNEL_EXECUTE) == SWITCH_STATUS_SUCCESS) { switch_channel_event_set_data(caller_channel, event); @@ -1117,6 +1119,8 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_multi_threaded_bridge(switch_core_ses switch_channel_set_flag_recursive(caller_channel, CF_BRIDGE_ORIGINATOR); switch_channel_clear_flag(peer_channel, CF_BRIDGE_ORIGINATOR); + switch_channel_sort_cid(peer_channel, SWITCH_FALSE); + b_leg->session = peer_session; switch_copy_string(b_leg->b_uuid, switch_core_session_get_uuid(session), sizeof(b_leg->b_uuid)); b_leg->stream_id = stream_id; diff --git a/src/switch_ivr_originate.c b/src/switch_ivr_originate.c index e61534798b..87a47e65aa 100644 --- a/src/switch_ivr_originate.c +++ b/src/switch_ivr_originate.c @@ -1751,6 +1751,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess early_state_t early_state = { 0 }; int read_packet = 0; int check_reject = 1; + switch_codec_implementation_t read_impl = { 0 }; if (strstr(bridgeto, SWITCH_ENT_ORIGINATE_DELIM)) { return switch_ivr_enterprise_originate(session, bleg, cause, bridgeto, timelimit_sec, table, cid_name_override, cid_num_override, @@ -1777,6 +1778,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess switch_channel_set_flag(caller_channel, CF_ORIGINATOR); oglobals.session = session; + switch_core_session_get_read_impl(session, &read_impl); if ((to_var = switch_channel_get_variable(caller_channel, SWITCH_CALL_TIMEOUT_VARIABLE))) { timelimit_sec = atoi(to_var); @@ -2381,24 +2383,6 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess new_profile->chan_name = SWITCH_BLANK_STRING; new_profile->destination_number = switch_core_strdup(new_profile->pool, chan_data); - if (switch_channel_direction(caller_channel) == SWITCH_CALL_DIRECTION_OUTBOUND) { - const char *callee_id_name = new_profile->callee_id_name; - const char *callee_id_number = new_profile->callee_id_number; - - if (zstr(callee_id_number)) { - callee_id_number = caller_caller_profile->destination_number; - } - - if (zstr(callee_id_name)) { - callee_id_name = callee_id_number; - } - - new_profile->caller_id_name = callee_id_name; - new_profile->caller_id_number = callee_id_number; - new_profile->callee_id_name = SWITCH_BLANK_STRING; - new_profile->callee_id_number = SWITCH_BLANK_STRING; - } - if (cid_name_override) { new_profile->caller_id_name = switch_core_strdup(new_profile->pool, cid_name_override); } @@ -3066,7 +3050,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess if ((ringback.fh || silence || ringback.audio_buffer || oglobals.bridge_early_media > -1) && write_frame.codec && write_frame.datalen) { if (silence) { - write_frame.datalen = write_frame.codec->implementation->decoded_bytes_per_packet; + write_frame.datalen = read_impl.decoded_bytes_per_packet; switch_generate_sln_silence((int16_t *) write_frame.data, write_frame.datalen / 2, silence); } diff --git a/src/switch_ivr_play_say.c b/src/switch_ivr_play_say.c index 3c8fa5e10f..710c0a738c 100644 --- a/src/switch_ivr_play_say.c +++ b/src/switch_ivr_play_say.c @@ -1573,10 +1573,10 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_play_file(switch_core_session_t *sess switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "done playing file\n"); if (read_impl.samples_per_second) { - switch_channel_set_variable_printf(channel, "playback_seconds", "%d", fh->samples_out / read_impl.samples_per_second); - switch_channel_set_variable_printf(channel, "playback_ms", "%d", fh->samples_out / (read_impl.samples_per_second / 1000)); + switch_channel_set_variable_printf(channel, "playback_seconds", "%d", fh->samples_in / read_impl.samples_per_second); + switch_channel_set_variable_printf(channel, "playback_ms", "%d", fh->samples_in / (read_impl.samples_per_second / 1000)); } - switch_channel_set_variable_printf(channel, "playback_samples", "%d", fh->samples_out); + switch_channel_set_variable_printf(channel, "playback_samples", "%d", fh->samples_in); switch_core_session_io_write_lock(session); switch_channel_set_private(channel, "__fh", NULL); @@ -1761,6 +1761,10 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_read(switch_core_session_t *session, switch_assert(session); + if (!digit_timeout) { + digit_timeout = timeout; + } + if (max_digits < min_digits) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Max digits %u is less than Min %u, forcing Max to %u\n", max_digits, min_digits, min_digits); diff --git a/src/switch_odbc.c b/src/switch_odbc.c index a1c476e4a1..5a88ba7690 100644 --- a/src/switch_odbc.c +++ b/src/switch_odbc.c @@ -160,11 +160,6 @@ static int db_is_up(switch_odbc_handle_t *handle) strcpy((char *) sql, "select 1"); } - if (stmt) { - SQLFreeHandle(SQL_HANDLE_STMT, stmt); - stmt = NULL; - } - if (SQLAllocHandle(SQL_HANDLE_STMT, handle->con, &stmt) != SQL_SUCCESS) { code = __LINE__; goto error; @@ -229,6 +224,11 @@ static int db_is_up(switch_odbc_handle_t *handle) goto done; } + if (stmt) { + SQLFreeHandle(SQL_HANDLE_STMT, stmt); + stmt = NULL; + } + switch_safe_free(err_str); switch_yield(1000000); goto top; diff --git a/src/switch_rtp.c b/src/switch_rtp.c index ee1c4acf5e..4e667fb49b 100644 --- a/src/switch_rtp.c +++ b/src/switch_rtp.c @@ -229,7 +229,7 @@ struct switch_rtp { uint32_t sync_packets; int rtcp_interval; switch_bool_t rtcp_fresh_frame; - + uint8_t checked_jb; #ifdef ENABLE_ZRTP zrtp_session_t *zrtp_session; zrtp_profile_t *zrtp_profile; @@ -1367,9 +1367,10 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_create(switch_rtp_t **new_rtp_session switch_rtp_set_flag(rtp_session, flags); /* for from address on recvfrom calls */ - switch_sockaddr_info_get(&rtp_session->from_addr, NULL, SWITCH_UNSPEC, 0, 0, pool); + switch_sockaddr_create(&rtp_session->from_addr, pool); + if (switch_test_flag(rtp_session, SWITCH_RTP_FLAG_ENABLE_RTCP)) { - switch_sockaddr_info_get(&rtp_session->rtcp_from_addr, NULL, SWITCH_UNSPEC, 0, 0, pool); + switch_sockaddr_create(&rtp_session->rtcp_from_addr, pool); } rtp_session->seq = (uint16_t) rand(); rtp_session->ssrc = (uint32_t) ((intptr_t) rtp_session + (uint32_t) switch_epoch_time_now(NULL)); @@ -1618,14 +1619,94 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_activate_stun_ping(switch_rtp_t *rtp_ return SWITCH_STATUS_SUCCESS; } -SWITCH_DECLARE(switch_status_t) switch_rtp_activate_jitter_buffer(switch_rtp_t *rtp_session, uint32_t queue_frames) +static void jb_callback(stfu_instance_t *i, void *udata) +{ + switch_core_session_t *session = (switch_core_session_t *) udata; + stfu_report_t r = { 0 }; + + stfu_n_report(i, &r); + + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG1, + "%s JB REPORT:\nlen: %u\nin: %u\nclean: %u\ngood: %u\nbad: %u\n", + switch_core_session_get_name(session), + r.qlen, + r.packet_in_count, + r.clean_count, + r.consecutive_good_count, + r.consecutive_bad_count + ); + +} + +SWITCH_DECLARE(switch_status_t) switch_rtp_deactivate_jitter_buffer(switch_rtp_t *rtp_session) +{ + + if (!switch_rtp_ready(rtp_session) || !rtp_session->jb) { + return SWITCH_STATUS_FALSE; + } + + READ_INC(rtp_session); + stfu_n_destroy(&rtp_session->jb); + READ_DEC(rtp_session); + + return SWITCH_STATUS_SUCCESS; +} + +static void jb_logger(const char *file, const char *func, int line, int level, const char *fmt, ...) +{ + int ret; + char *data; + va_list ap; + + va_start(ap, fmt); + ret = switch_vasprintf(&data, fmt, ap); + if (ret != -1) { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_CONSOLE, "%s", data); + free(data); + } + + //switch_log_printf(SWITCH_CHANNEL_ID_LOG_CLEAN, file, func, line, NULL, level, fmt, ap); + va_end(ap); +} + +SWITCH_DECLARE(switch_status_t) switch_rtp_debug_jitter_buffer(switch_rtp_t *rtp_session, const char *name) { - rtp_session->jb = stfu_n_init(queue_frames, 0); + stfu_n_debug(rtp_session->jb, name); + stfu_global_set_logger(jb_logger); return SWITCH_STATUS_SUCCESS; } +SWITCH_DECLARE(switch_status_t) switch_rtp_activate_jitter_buffer(switch_rtp_t *rtp_session, + uint32_t queue_frames, + uint32_t max_queue_frames, + uint32_t samples_per_packet, + uint32_t samples_per_second) +{ + + if (!switch_rtp_ready(rtp_session)) { + return SWITCH_STATUS_FALSE; + } + + READ_INC(rtp_session); + if (rtp_session->jb) { + stfu_n_resize(rtp_session->jb, queue_frames); + } else { + rtp_session->jb = stfu_n_init(queue_frames, max_queue_frames ? max_queue_frames : 50, samples_per_packet, samples_per_second); + } + READ_DEC(rtp_session); + + if (rtp_session->jb) { + switch_core_session_t *session = switch_core_memory_pool_get_data(rtp_session->pool, "__session"); + stfu_n_call_me(rtp_session->jb, jb_callback, session); + + return SWITCH_STATUS_SUCCESS; + } + + return SWITCH_STATUS_FALSE; +} + SWITCH_DECLARE(switch_status_t) switch_rtp_activate_rtcp(switch_rtp_t *rtp_session, int send_rate, switch_port_t remote_port) { const char *err = NULL; @@ -2016,14 +2097,18 @@ static void do_flush(switch_rtp_t *rtp_session) switch_size_t bytes; switch_status_t status; - if (!switch_rtp_ready(rtp_session) || switch_test_flag(rtp_session, SWITCH_RTP_FLAG_PROXY_MEDIA)) { + if (!switch_rtp_ready(rtp_session) || + switch_test_flag(rtp_session, SWITCH_RTP_FLAG_PROXY_MEDIA) || + switch_test_flag(rtp_session, SWITCH_RTP_FLAG_VIDEO) + ) { return; } READ_INC(rtp_session); if (switch_rtp_ready(rtp_session)) { - + uint32_t flushed = 0; + if (switch_test_flag(rtp_session, SWITCH_RTP_FLAG_DEBUG_RTP_READ)) { switch_core_session_t *session = switch_core_memory_pool_get_data(rtp_session->pool, "__session"); if (!session) { @@ -2047,6 +2132,22 @@ static void do_flush(switch_rtp_t *rtp_session) bytes = sizeof(rtp_msg_t); status = switch_socket_recvfrom(rtp_session->from_addr, rtp_session->sock_input, 0, (void *) &rtp_session->recv_msg, &bytes); if (bytes) { + + flushed++; + +#ifdef _MSC_VER +#pragma warning(push) /* remove this stuff when "if (0" is removed */ +#pragma warning(disable:4127) +#endif + if (0 && rtp_session->jb) { + stfu_n_eat(rtp_session->jb, ntohl(rtp_session->recv_msg.header.ts), + rtp_session->recv_msg.header.pt, + rtp_session->recv_msg.body, bytes - rtp_header_len); + } +#ifdef _MSC_VER +#pragma warning(pop) +#endif + rtp_session->stats.inbound.raw_bytes += bytes; rtp_session->stats.inbound.flush_packet_count++; rtp_session->stats.inbound.packet_count++; @@ -2056,6 +2157,10 @@ static void do_flush(switch_rtp_t *rtp_session) } } while (bytes > 0); + if (rtp_session->jb && flushed) { + stfu_n_sync(rtp_session->jb, flushed); + } + if (was_blocking && switch_rtp_ready(rtp_session)) { switch_clear_flag_locked(rtp_session, SWITCH_RTP_FLAG_NOBLOCK); switch_socket_opt_set(rtp_session->sock_input, SWITCH_SO_NONBLOCK, FALSE); @@ -2104,7 +2209,8 @@ static switch_status_t read_rtp_packet(switch_rtp_t *rtp_session, switch_size_t stfu_n_reset(rtp_session->jb); } - stfu_n_eat(rtp_session->jb, ntohl(rtp_session->recv_msg.header.ts), rtp_session->recv_msg.header.pt, + stfu_n_eat(rtp_session->jb, ntohl(rtp_session->recv_msg.header.ts), + rtp_session->recv_msg.header.pt, rtp_session->recv_msg.body, *bytes - rtp_header_len); *bytes = 0; status = SWITCH_STATUS_FALSE; @@ -2114,16 +2220,16 @@ static switch_status_t read_rtp_packet(switch_rtp_t *rtp_session, switch_size_t if ((jb_frame = stfu_n_read_a_frame(rtp_session->jb))) { memcpy(rtp_session->recv_msg.body, jb_frame->data, jb_frame->dlen); if (jb_frame->plc) { - *flags |= SFF_PLC; + (*flags) |= SFF_PLC; } else { rtp_session->stats.inbound.jb_packet_count++; } *bytes = jb_frame->dlen + rtp_header_len; rtp_session->recv_msg.header.ts = htonl(jb_frame->ts); rtp_session->recv_msg.header.pt = jb_frame->pt; - status = SWITCH_STATUS_SUCCESS; } + rtp_session->checked_jb++; } return status; @@ -2268,6 +2374,8 @@ static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_ READ_INC(rtp_session); + rtp_session->checked_jb = 0; + while (switch_rtp_ready(rtp_session)) { int do_cng = 0; bytes = 0; @@ -2820,11 +2928,11 @@ static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_ if (do_cng) { uint8_t *data = (uint8_t *) rtp_session->recv_msg.body; int fdr; - + if ((poll_status = switch_poll(rtp_session->read_pollfd, 1, &fdr, 0)) == SWITCH_STATUS_SUCCESS) { goto recvfrom; } - + memset(data, 0, 2); data[0] = 65; rtp_session->recv_msg.header.pt = (uint32_t) rtp_session->cng_pt ? rtp_session->cng_pt : SWITCH_RTP_CNG_PAYLOAD; @@ -3053,6 +3161,7 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_zerocopy_read_frame(switch_rtp_t *rtp frame->packet = &rtp_session->recv_msg; frame->packetlen = bytes; frame->source = __FILE__; + switch_set_flag(frame, SFF_RAW_RTP); if (frame->payload == rtp_session->recv_te) { switch_set_flag(frame, SFF_RFC2833); diff --git a/w32/Console/FreeSwitchConsole.2008.vcproj b/w32/Console/FreeSwitchConsole.2008.vcproj index 80f062abe0..7fc1784d14 100644 --- a/w32/Console/FreeSwitchConsole.2008.vcproj +++ b/w32/Console/FreeSwitchConsole.2008.vcproj @@ -46,7 +46,7 @@ Disabled - %(RootDir)%(Directory)include;%(RootDir)%(Directory)..\libs\include;%(AdditionalIncludeDirectories) + %(RootDir)%(Directory)include;..\..\libs\spandsp\src\msvc;..\..\libs\spandsp\src;..\..\libs\tiff-3.8.2\libtiff;%(RootDir)%(Directory)..\libs\include;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) true EnableFastChecks @@ -109,7 +109,7 @@ Disabled - %(RootDir)%(Directory)include;%(RootDir)%(Directory)..\libs\include;%(AdditionalIncludeDirectories) + %(RootDir)%(Directory)include;..\..\libs\spandsp\src\msvc;..\..\libs\spandsp\src;..\..\libs\tiff-3.8.2\libtiff;%(RootDir)%(Directory)..\libs\include;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) true EnableFastChecks @@ -134,7 +134,7 @@ - %(RootDir)%(Directory)include;%(RootDir)%(Directory)..\libs\include;%(AdditionalIncludeDirectories) + %(RootDir)%(Directory)include;..\..\libs\spandsp\src\msvc;..\..\libs\spandsp\src;..\..\libs\tiff-3.8.2\libtiff;%(RootDir)%(Directory)..\libs\include;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) MultiThreadedDLL @@ -161,7 +161,7 @@ X64 - %(RootDir)%(Directory)include;%(RootDir)%(Directory)..\libs\include;%(AdditionalIncludeDirectories) + %(RootDir)%(Directory)include;..\..\libs\spandsp\src\msvc;..\..\libs\spandsp\src;..\..\libs\tiff-3.8.2\libtiff;%(RootDir)%(Directory)..\libs\include;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) MultiThreadedDLL diff --git a/w32/Library/FreeSwitchCore.2008.vcproj b/w32/Library/FreeSwitchCore.2008.vcproj index ca15da8b52..6ba5b95959 100644 --- a/w32/Library/FreeSwitchCore.2008.vcproj +++ b/w32/Library/FreeSwitchCore.2008.vcproj @@ -47,7 +47,7 @@ Disabled - ..\..\src\include;..\..\libs\include;..\..\libs\srtp\include;..\..\libs\srtp\crypto\include;..\..\libs\libteletone\src;..\..\libs\win32\sqlite;..\..\libs\pcre;..\..\libs\stfu;..\..\libs\speex\include;%(AdditionalIncludeDirectories) + ..\..\src\include;..\..\libs\include;..\..\libs\srtp\include;..\..\libs\srtp\crypto\include;..\..\libs\libteletone\src;..\..\libs\win32\sqlite;..\..\libs\pcre;..\..\libs\stfu;..\..\libs\speex\include;..\..\libs\spandsp\src\msvc;..\..\libs\spandsp\src;..\..\libs\tiff-3.8.2\libtiff;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;_USRDLL;FREESWITCHCORE_EXPORTS;PCRE_STATIC;STATICLIB;%(PreprocessorDefinitions) true EnableFastChecks @@ -147,7 +147,7 @@ if not exist "$(OutDir)htdocs" xcopy "$(SolutionDir)htdocs\*.*" "$(OutDir)htdocs Disabled - ..\..\src\include;..\..\libs\include;..\..\libs\srtp\include;..\..\libs\srtp\crypto\include;..\..\libs\libteletone\src;..\..\libs\win32\sqlite;..\..\libs\pcre;..\..\libs\stfu;..\..\libs\speex\include;%(AdditionalIncludeDirectories) + ..\..\src\include;..\..\libs\include;..\..\libs\srtp\include;..\..\libs\srtp\crypto\include;..\..\libs\libteletone\src;..\..\libs\win32\sqlite;..\..\libs\pcre;..\..\libs\stfu;..\..\libs\speex\include;..\..\libs\spandsp\src\msvc;..\..\libs\spandsp\src;..\..\libs\tiff-3.8.2\libtiff;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;_USRDLL;FREESWITCHCORE_EXPORTS;PCRE_STATIC;STATICLIB;%(PreprocessorDefinitions) true EnableFastChecks @@ -199,7 +199,7 @@ if not exist "$(OutDir)htdocs" xcopy "$(SolutionDir)htdocs\*.*" "$(OutDir)htdocs Disabled - ..\..\src\include;..\..\libs\include;..\..\libs\srtp\include;..\..\libs\srtp\crypto\include;..\..\libs\libteletone\src;..\..\libs\win32\sqlite;..\..\libs\pcre;..\..\libs\stfu;..\..\libs\speex\include;%(AdditionalIncludeDirectories) + ..\..\src\include;..\..\libs\include;..\..\libs\srtp\include;..\..\libs\srtp\crypto\include;..\..\libs\libteletone\src;..\..\libs\win32\sqlite;..\..\libs\pcre;..\..\libs\stfu;..\..\libs\speex\include;..\..\libs\spandsp\src\msvc;..\..\libs\spandsp\src;..\..\libs\tiff-3.8.2\libtiff;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_USRDLL;FREESWITCHCORE_EXPORTS;STATICLIB;CRASH_PROT;PCRE_STATIC;%(PreprocessorDefinitions) MultiThreadedDLL Use @@ -248,7 +248,7 @@ if not exist "$(OutDir)htdocs" xcopy "$(SolutionDir)htdocs\*.*" "$(OutDir)htdocs Disabled - ..\..\src\include;..\..\libs\include;..\..\libs\srtp\include;..\..\libs\srtp\crypto\include;..\..\libs\libteletone\src;..\..\libs\win32\sqlite;..\..\libs\pcre;..\..\libs\stfu;..\..\libs\speex\include;%(AdditionalIncludeDirectories) + ..\..\src\include;..\..\libs\include;..\..\libs\srtp\include;..\..\libs\srtp\crypto\include;..\..\libs\libteletone\src;..\..\libs\win32\sqlite;..\..\libs\pcre;..\..\libs\stfu;..\..\libs\speex\include;..\..\libs\spandsp\src\msvc;..\..\libs\spandsp\src;..\..\libs\tiff-3.8.2\libtiff;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_USRDLL;FREESWITCHCORE_EXPORTS;STATICLIB;CRASH_PROT;PCRE_STATIC;%(PreprocessorDefinitions) MultiThreadedDLL Use @@ -766,6 +766,9 @@ if not exist "$(OutDir)htdocs" xcopy "$(SolutionDir)htdocs\*.*" "$(OutDir)htdocs {89385c74-5860-4174-9caf-a39e7c48909c} false + + {1cbb0077-18c5-455f-801c-0a0ce7b0bbf5} + {03207781-0d1c-4db3-a71d-45c608f28dbd} false diff --git a/w32/Setup/Setup.wixproj b/w32/Setup/Setup.wixproj index fa6c832777..f97000b585 100644 --- a/w32/Setup/Setup.wixproj +++ b/w32/Setup/Setup.wixproj @@ -723,6 +723,15 @@ Binaries;Content;Satellites MODLOCATION + + mod_say_pt + {7c22bdff-cc09-400c-8a09-660733980028} + True + + + Binaries;Content;Satellites + MODLOCATION + mod_say_ru {0382e8fd-cfdc-41c0-8b03-792c7c84fc31}