diff --git a/Freeswitch.2008.sln b/Freeswitch.2008.sln index 27c94a2dc4..8e6df5cc57 100644 --- a/Freeswitch.2008.sln +++ b/Freeswitch.2008.sln @@ -2213,10 +2213,12 @@ Global {834E2B2F-5483-4B80-8FE3-FE48FF76E5C0}.All|x64.ActiveCfg = Release|Any CPU {834E2B2F-5483-4B80-8FE3-FE48FF76E5C0}.Debug|Win32.ActiveCfg = Debug|Any CPU {834E2B2F-5483-4B80-8FE3-FE48FF76E5C0}.Debug|Win32.Build.0 = Debug|Any CPU - {834E2B2F-5483-4B80-8FE3-FE48FF76E5C0}.Debug|x64.ActiveCfg = Debug|Any CPU + {834E2B2F-5483-4B80-8FE3-FE48FF76E5C0}.Debug|x64.ActiveCfg = Debug|x64 + {834E2B2F-5483-4B80-8FE3-FE48FF76E5C0}.Debug|x64.Build.0 = Debug|x64 {834E2B2F-5483-4B80-8FE3-FE48FF76E5C0}.Release|Win32.ActiveCfg = Release|Any CPU {834E2B2F-5483-4B80-8FE3-FE48FF76E5C0}.Release|Win32.Build.0 = Release|Any CPU - {834E2B2F-5483-4B80-8FE3-FE48FF76E5C0}.Release|x64.ActiveCfg = Release|Any CPU + {834E2B2F-5483-4B80-8FE3-FE48FF76E5C0}.Release|x64.ActiveCfg = Release|x64 + {834E2B2F-5483-4B80-8FE3-FE48FF76E5C0}.Release|x64.Build.0 = Release|x64 {E796E337-DE78-4303-8614-9A590862EE95}.All|Win32.ActiveCfg = Release|Win32 {E796E337-DE78-4303-8614-9A590862EE95}.All|Win32.Build.0 = Release|Win32 {E796E337-DE78-4303-8614-9A590862EE95}.All|x64.ActiveCfg = Release|Win32 diff --git a/Freeswitch.2010.sln b/Freeswitch.2010.sln index c865b6861a..4729745778 100644 --- a/Freeswitch.2010.sln +++ b/Freeswitch.2010.sln @@ -703,6 +703,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_directory", "src\mod\ap EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_h323", "src\mod\endpoints\mod_h323\mod_h323.2010.vcxproj", "{05C9FB27-480E-4D53-B3B7-7338E2514666}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_distributor", "src\mod\applications\mod_distributor\mod_distributor.2010.vcxproj", "{5C2B4D88-3BEA-4FE0-90DF-FA9836099D5F}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution All|Win32 = All|Win32 @@ -2424,6 +2426,13 @@ Global {05C9FB27-480E-4D53-B3B7-7338E2514666}.Debug|x64.ActiveCfg = Debug|x64 {05C9FB27-480E-4D53-B3B7-7338E2514666}.Release|Win32.ActiveCfg = Release|Win32 {05C9FB27-480E-4D53-B3B7-7338E2514666}.Release|x64.ActiveCfg = Release|x64 + {5C2B4D88-3BEA-4FE0-90DF-FA9836099D5F}.All|Win32.ActiveCfg = Release|x64 + {5C2B4D88-3BEA-4FE0-90DF-FA9836099D5F}.All|x64.ActiveCfg = Release|x64 + {5C2B4D88-3BEA-4FE0-90DF-FA9836099D5F}.All|x64.Build.0 = Release|x64 + {5C2B4D88-3BEA-4FE0-90DF-FA9836099D5F}.Debug|Win32.ActiveCfg = Debug|Win32 + {5C2B4D88-3BEA-4FE0-90DF-FA9836099D5F}.Debug|x64.ActiveCfg = Debug|x64 + {5C2B4D88-3BEA-4FE0-90DF-FA9836099D5F}.Release|Win32.ActiveCfg = Release|Win32 + {5C2B4D88-3BEA-4FE0-90DF-FA9836099D5F}.Release|x64.ActiveCfg = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -2470,6 +2479,7 @@ Global {1E21AFE0-6FDB-41D2-942D-863607C24B91} = {E72B5BCB-6462-4D23-B419-3AF1A4AC3D78} {2E250296-0C08-4342-9C8A-BCBDD0E7DF65} = {E72B5BCB-6462-4D23-B419-3AF1A4AC3D78} {B889A18E-70A7-44B5-B2C9-47798D4F43B3} = {E72B5BCB-6462-4D23-B419-3AF1A4AC3D78} + {5C2B4D88-3BEA-4FE0-90DF-FA9836099D5F} = {E72B5BCB-6462-4D23-B419-3AF1A4AC3D78} {07113B25-D3AF-4E04-BA77-4CD1171F022C} = {C5F182F9-754A-4EC5-B50F-76ED02BE13F4} {A27CCA23-1541-4337-81A4-F0A6413078A0} = {C5F182F9-754A-4EC5-B50F-76ED02BE13F4} {E7BC026C-7CC5-45A3-BC7C-3B88EEF01F24} = {C5F182F9-754A-4EC5-B50F-76ED02BE13F4} diff --git a/conf/autoload_configs/switch.conf.xml b/conf/autoload_configs/switch.conf.xml index 7a68a7f2bd..e861b1b61a 100644 --- a/conf/autoload_configs/switch.conf.xml +++ b/conf/autoload_configs/switch.conf.xml @@ -15,6 +15,11 @@ + + + + + diff --git a/conf/sip_profiles/internal.xml b/conf/sip_profiles/internal.xml index 50833bfbec..93558a3584 100644 --- a/conf/sip_profiles/internal.xml +++ b/conf/sip_profiles/internal.xml @@ -42,6 +42,26 @@ + + + + + + diff --git a/conf/skinny_profiles/internal.xml b/conf/skinny_profiles/internal.xml index 5feac1ffbf..52da89741d 100644 --- a/conf/skinny_profiles/internal.xml +++ b/conf/skinny_profiles/internal.xml @@ -16,7 +16,7 @@ - + diff --git a/devel-bootstrap.sh b/devel-bootstrap.sh old mode 100644 new mode 100755 diff --git a/docs/ChangeLog b/docs/ChangeLog index 412ab9ff18..d6fddd6bfa 100644 --- a/docs/ChangeLog +++ b/docs/ChangeLog @@ -16,6 +16,9 @@ freeswitch (1.0.7) build: VS 2010 - Change to V4 framework, add SWIG v2.0 files to fix release build exceptions(temp fix till we upgrade all SWIG files) (r:812f4309) build: Windows VS2010 build - remove strange characters (r:ba1546e0/FSBUILD-297) build: Make bootstrap.sh Bourne shell compatible (r:8dbd62ff/FSBUILD-301) + build: add mod_osp Makefile to configure generated Makefiles (r:dc06a039/FS-122) + 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) 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 @@ -26,6 +29,7 @@ freeswitch (1.0.7) config: move enum to the bottom of default. (r:4d448c97) config: Add att_xfer example to default dialplan (r:20ec962a) 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) 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 @@ -95,7 +99,19 @@ freeswitch (1.0.7) core: avoid segfault when sofia tries to update the callee id at the same time as the outbound call is transferred (r:df63657e) core: make code more automagic to shut up the dude on the list (r:d093a4a4) core: Fix memory leak if we fail to enqueue new event to EVENT_QUEUE in switch_event.c (r:ef773e07/FS-2148) + core: fix endless loop on startup when specifying -nosql (r:b6a533ee) + core: Buffer for url encode in switch_ivr_set_xml_chan_vars() too small by 1 (r:0cc28f37/FS-2167) + core: fix switch_ivr_collect_digits_callback to allow an args pointer with null callback to work like other apis (r:89d99a91) + core: ERROR_PARTIAL and BAD_PARTIAL are regarded as PARTIAL in switch_regex_match_partial (r:b4548a60/FS-2238) + core: sprinkle digit_timeout into switch_ivr_read and switch_ivr_play_and_get_digits and the higher level variants (r:cfa30468) + core: Fix parse of variable absolute_codec_string when inside [] (r:54bf6575/FS-2126) + core: Fix SWITCH_IO_FLAG_NOBLOCK needed for mod_sangoma_codec (r:bc304153/FS-2017) + core: fix coredump in rtcp socket handling (r:6c1070ea/FS-2009) + core: add bitrate patch from moc with some extra stuff for late neg mode (r:633f193d) + core: refactor fmtp parser as a core func (r:56f8c11f) + core: add switch_ivr_dmachine async digit parser to core (r:7f3319dc) 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) libdingaling: Fix crash in new GV interface when exceeding 24 calls (r:be00609a/FS-2171) libesl: Fix potential race condition (ESL-36) @@ -113,9 +129,11 @@ freeswitch (1.0.7) 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) + libgnutls: link to libgcrypt as well, please report any platforms this breaks, but it should be portable (r:c569fb0f/FS-1248) libopenzap: Add CLI tracing libs: Merged OpenZAP and FreeTDM into the FreeSWITCH tree. libs: Add support for TLS on Windows using openssl (r:1abe3b93/MODSOFIA-92) + libs: fix bsd shell incompatibility (r:e2b85e94/FS-287) libsofiasip: Fix random crashes (r:c15ee980/SFSIP-219) libsofiasip: Fix T.38 bug in sofia_glue (r:2843f1ad/MODSOFIA-94) libsofiasip: VS2010 sofia posix problem (r:46dd24c2/SFSIP-220) @@ -139,6 +157,8 @@ freeswitch (1.0.7) mod_callcenter: Add more channel variable and event and fix a mem leak (r:2d3d8c8d) mod_callcenter: Make more sence to bridge the caller to the agent. Before, in the xml_cdr you saw it it like the agent initiated the call to the member (r:0be95658) mod_callcenter: Added max-wait-time and max-wait-time-with-no-agent param to a queue. (r:3482f95e) + mod_callcenter: Make sure we fail to load if config is not present (r:e1fb79a1) + mod_callcenter: Fix invalid update of agent field (r:426a448f/FS-2738) 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 @@ -152,6 +172,7 @@ freeswitch (1.0.7) mod_commands: Fix user_data returning the first value found instead of the last. Also add support to get variable from the group. (r:402f2391) mod_commands: Allow cond API to return empty false value (r:c8a897b9) mod_commands: ***BEHAVIOUR CHANGE*** reloadacl, load , reload will now explicitly call reloadxml (r:42c9df72) + mod_commands: add nat_map usage (r:7577b8aa) 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 @@ -170,6 +191,7 @@ freeswitch (1.0.7) mod_dptools: add eavesdrop_enable_dtmf chan var (r:596c0012) mod_dptools: Make park app not send 183 session progress (r:76932995/FSCORE-567) mod_dptools: add block_dtmf and unblock_dtmf apps (r:d9eb0197) + mod_dptools: refactor export code and add new bridge_export app which is like export but exports across when one channel bridges another (r:4aa9a838) mod_erlang_event: Make XML fetch reply ACKs distinguishable, update freeswitch.erl (r:9d44ed04) mod_erlang_event: Add 3 new commands; session_event, session_noevents, session_nixevent (r:698fa045) mod_erlang_event: generate long node names the same as erlang does (r:9ad509c2) @@ -181,6 +203,7 @@ freeswitch (1.0.7) mod_fifo: add taking_calls param to fifo member add and config file (r:821488bf) mod_fifo: add nomedia flag (r:2d30a8c2) mod_fifo: Fix inconsistency between the fifo queue and the channels (num callers in queue can become "-1") (r:07487114/FS-1659) + mod_fifo: fix issue leaving stale records in fifo_bridge table (r:b36d015f) mod_freetdm: Fix for TON and NPI not passed through to channel variables on incoming calls mod_freetdm: add pvt data to freetdm channels fix fxs features (r:9d456900) mod_freetdm: export and import boost custom data (r:edb2d582) @@ -244,6 +267,7 @@ freeswitch (1.0.7) mod_lcr: don't count twice (r:eaeabc7b/FS-1810) mod_loopback: add loopback_bowout_on_execute var to make 1 legged loopback calls bow out of the picture mod_loopback: only execute app once in app mode (r:64f58f2d) + mod_loopback: fix bug in mod_loopback where bowout=false (r:e9ab5368) mod_lua: Add switch_core_sqldb functionality from inside Lua script (r:26f2e095/FS-1384) mod_lua: Made 2nd arg to freeswitch.Dbh:query (cb func) optional (r:87db11af) mod_lua: Added SAF_ROUTING_EXEC flag to lua app, so it can be run inline (r:7d5ca1c0) @@ -268,6 +292,7 @@ freeswitch (1.0.7) mod_sangoma_codec: rename load/noload to register/noregister mod_sangoma_codec: silence suppression (r:73d9d56f) mod_say_es: fix grammar when saying dates and time (r:6bed19b2/MODAPP-429) + mod_say_ja: initial commit, still needs sound files (r:b2423158/FS-2755) mod_say_ru: Fix saying time with +1 hour of current time (r:68d74c31/MODAPP-444) mod_say_zh: Number reading should now be OK for the whole range of integers for Cantonese and Mandarin mod_silk: Fix mod_silk compliance and performance issues (r:2ddbc457/MODCODEC-20) @@ -350,6 +375,22 @@ freeswitch (1.0.7) mod_sofia: add inline lists for tab complete db using ::[a:b syntax (r:445731ee) mod_sofia: add sofia profile gwlist up|down to list up or downed profiles for feeding into mod distributor to exclude dead gateways (r:0477cb67) mod_sofia: add 'sofia global siptrace on' so we don't have to always teach people to enable sip trace on each profile (r:09fa6678) + mod_sofia: fix seg on subscribe with no contact host (r:c236541e) + mod_sofia: fix typo and printf specifier resulting in incorrect output of call counts on profiles and gateways (r:29ea6e29) + mod_sofia: fix t38 passthru when port changes on re-invite (r:72baaf6d) + mod_sofia: let ~ signify that multipart content will contain headers (r:3548168d) + mod_sofia: Fix rash with rxfax when no remote host (r:a9446ac1/FS-677) + mod_sofia: Handle incorrectly formatted T.38 booleans (r:8f731f42/FS-957) + mod_sofia: fix crash in sofia_reg_find_gateway_by_realm__ (r:721c8019/FS-488) + mod_sofia: Handle 301 moved permanently. (r:ba59c51d/FS-2739) + mod_sofia: don't passthru when its proxy media, bypass media or there is no rtp session, fixes seg (r:45e2b99d) + mod_sofia: improve video support for new polycom phones (r:84a383fe) + mod_sofia: Forward unsolicited MWI nofity (r:e946da9a/FS-861) + mod_sofia: Support display updates for Cisco SIP endpoints (tested on SPA series) (r:6937ca39/FS-884) + mod_sofia: BLF compliance with RFC-4235: dialog-info 'version=' field is reset to 0 on every new call instead of being incremented (r:589502d3/FS-2747) + mod_sofia: fix parsing of sofia tracelevel param, moved param from profile params to global_settings as its global, and it only worked on reparse before anyways. Please correct any documentation on this issue on the wiki (r:82c4c4cc/FS-523) + mod_sofia: fix nat acl count check to check against the number of nat acls (r:e11550e7/FS-502) + mod_sofia: add sofia_glue_find_parameter_value function to get a specific value from a url params string (r:c701d41c) 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) @@ -358,6 +399,9 @@ freeswitch (1.0.7) mod_spandsp: Moved spandsp to a more recent version. A huge number of little changes occur here, as recently spandsp lost all the $Id$ entries the source files had for the dark old days of CVS (r:f029f7ef) mod_spandsp: move app flag into 'T38' namespace for the sake of housekeeping (r:0d0b4b43) mod_spandsp: make t38 terminal mode more reliable (r:83da7bd3) + mod_spandsp: deadlock in mod_spandsp (mod_spandsp_fax.c) (r:b02c69bb/FS-1690) + mod_spandsp: T.38 reINVITE glare condition causes FAX processing to stop. (r:04aa7ef9/FS-1682) + mod_spandsp: improve nat handling when using stun or host as ext-rtp-ip (r:03e74c51/FS-526) mod_spidermonkey: allow vars to be set containing vars from languages (r:5cd072a3) mod_spidermonkey: fix seg in js hangup (r:7d554c11) mod_spidermonkey: Fix mod_spidermonkey build on FreeBSD, (Undefined symbol PR_LocalTimeParameters). (r:3edb8419) @@ -366,6 +410,7 @@ freeswitch (1.0.7) mod_unimrcp: fix fortify findings for mod_unimrcp (r:336f0b4e/FSMOD-67) mod_valet_parking: add event data to valet parking hold event mod_valet_parking: add event for Valet Parking action exit + mod_valet_parking: pass hold class on transfer (r:76a065ec) mod_voicemail: Fix vm_prefs profile lock (MODAPP-417) mod_voicemail: add 'vm-enabled' param (default true) mod_voicemail: fix vm msg being deleted when pressing key to forward to email (MODAPP-403) @@ -374,11 +419,13 @@ freeswitch (1.0.7) mod_voicemail: Allow to forward a message or send it via email key during the playback of the recording, not just when the menu is playing. (r:83aeda79) mod_voicemail: fix vm_inject to a group and change syntax for sending to a whole domain to domain= for clarity sake (r:f30a1cc6) mod_voicemail: add quotes to vm_cc command generated internally to escape spaces in the caller id name (r:5f012813) + mod_voicemail: Play caller id of callee prior to playing a vmail (r:e7b97907/FS-2719) mod_xml_cdr: add force_process_cdr var to process b leg cdr on a case by case basis when b leg cdr is disabled (XML-17) mod_xml_cdr: add leg param to query string (XML-24) mod_xml_cdr: fix locked sessions (XML-26) 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) 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) diff --git a/docs/phrase/phrase_en.xml b/docs/phrase/phrase_en.xml index 6d582e77a1..318aba18dd 100644 --- a/docs/phrase/phrase_en.xml +++ b/docs/phrase/phrase_en.xml @@ -419,6 +419,9 @@ + + + diff --git a/freeswitch.spec b/freeswitch.spec index 52e6226830..a2c975b5a9 100644 --- a/freeswitch.spec +++ b/freeswitch.spec @@ -5,7 +5,7 @@ # # includes module(s): freeswitch-devel freeswitch-codec-passthru-amr freeswitch-codec-passthru-amrwb freeswitch-codec-passthru-g729 # freeswitch-codec-passthru-g7231 freeswitch-lua freeswitch-perl freeswitch-python freeswitch-spidermonkey -# freeswitch-lan-de freeswitch-lang-en freeswitch-lang-fr freeswitch-lang-ru freeswitch-openzap +# freeswitch-lan-de freeswitch-lang-en freeswitch-lang-fr freeswitch-lang-ru freeswitch-freetdm # # Initial Version Copyright (C) 2007 Peter Nixon and Michal Bielicki, All Rights Reserved. # @@ -54,23 +54,23 @@ Vendor: http://www.freeswitch.org/ # ###################################################################################################################### Source0: http://files.freeswitch.org/%{name}-%{version}.tar.bz2 -Source1: http://files.freeswitch.org/downloads/libs/celt-0.7.0.tar.gz -Source2: http://files.freeswitch.org/downloads/libs/flite-1.3.99-latest.tar.gz -Source3: http://files.freeswitch.org/downloads/libs/lame-3.97.tar.gz -Source4: http://files.freeswitch.org/downloads/libs/libshout-2.2.2.tar.gz -Source5: http://files.freeswitch.org/downloads/libs/mpg123.tar.gz -Source6: http://files.freeswitch.org/downloads/libs/openldap-2.4.11.tar.gz -Source7: http://files.freeswitch.org/downloads/libs/pocketsphinx-0.5.99-20091212.tar.gz -Source8: http://files.freeswitch.org/downloads/libs/soundtouch-1.3.1.tar.gz -Source9: http://files.freeswitch.org/downloads/libs/sphinxbase-0.4.99-20091212.tar.gz -Source10: http://files.freeswitch.org/downloads/libs/communicator_semi_6000_20080321.tar.gz -Source11: http://files.freeswitch.org/downloads/libs/libmemcached-0.32.tar.gz -Prefix: %{prefix} +Source1: http://files.freeswitch.org/downloads/libs/celt-0.7.1.tar.gz +Source2: http://files.freeswitch.org/downloads/libs/flite-1.3.99-latest.tar.gz +Source3: http://files.freeswitch.org/downloads/libs/lame-3.97.tar.gz +Source4: http://files.freeswitch.org/downloads/libs/libshout-2.2.2.tar.gz +Source5: http://files.freeswitch.org/downloads/libs/mpg123.tar.gz +Source6: http://files.freeswitch.org/downloads/libs/openldap-2.4.11.tar.gz +Source7: http://files.freeswitch.org/downloads/libs/pocketsphinx-0.5.99-20091212.tar.gz +Source8: http://files.freeswitch.org/downloads/libs/soundtouch-1.3.1.tar.gz +Source9: http://files.freeswitch.org/downloads/libs/sphinxbase-0.4.99-20091212.tar.gz +Source10: http://files.freeswitch.org/downloads/libs/communicator_semi_6000_20080321.tar.gz +Source11: http://files.freeswitch.org/downloads/libs/libmemcached-0.32.tar.gz +Prefix: %{prefix} ###################################################################################################################### # -# Build Dependencies +# Build Dependencies # ###################################################################################################################### @@ -103,6 +103,7 @@ BuildRequires: alsa-lib-devel BuildRequires: which BuildRequires: zlib-devel BuildRequires: e2fsprogs-devel +BuildRequires: libtheora-devel Requires: alsa-lib Requires: libogg Requires: libvorbis @@ -115,6 +116,9 @@ Requires: openldap Requires: db4 Requires: gdbm Requires: zlib +Requires: libtiff +Requires: python +Requires: libtheora %if %{?suse_version:1}0 %if 0%{?suse_version} > 910 @@ -269,13 +273,17 @@ Group: System/LibrariesRequires: %{name} = %{version}-%{release} German language phrases module and directory structure for say module and voicemail -%package openzap +%package freetdm Summary: Provides a unified interface to hardware TDM cards and ss7 stacks for FreeSWITCH Group: System/Libraries Requires: %{name} = %{version}-%{release} +%{?with_sang_isdn: Requires: wanpipe } +%{?with_sang_isdn: Requires: libsng_isdn } +%{?with_sang_isdn: BuildRequires: wanpipe } +%{?with_sang_isdn: BuildRequires: libang_isdn } -%description openzap -OpenZAP +%description freetdm +FreeTDM ###################################################################################################################### # @@ -322,13 +330,15 @@ export QA_RPATHS=$[ 0x0001|0x0002 ] # Application Modules # ###################################################################################################################### -APPLICATION_MODULES_AE="applications/mod_avmd applications/mod_callcenter applications/mod_cluechoo applications/mod_commands applications/mod_conference applications/mod_db applications/mod_directory applications/mod_distributor applications/mod_dptools applications/mod_easyroute applications/mod_enum applications/mod_esf applications/mod_expr" - -APPLICATION_MODULES_FM="applications/mod_fifo applications/mod_fsv applications/mod_hash applications/mod_lcr applications/mod_limit applications/mod_memcache" - -APPLICATION_MODULES_NY="applications/mod_nibblebill applications/mod_redis applications/mod_rss applications/mod_soundtouch applications/mod_spandsp applications/mod_stress applications/mod_spy " - -APPLICATION_MODULES_VZ="applications/mod_valet_parking applications/mod_vmd applications/mod_voicemail" +APPLICATION_MODULES_AE="applications/mod_avmd applications/mod_callcenter applications/mod_cidlookup applications/mod_cluechoo \ + applications/mod_commands applications/mod_conference applications/mod_db applications/mod_directory \ + applications/mod_distributor applications/mod_dptools applications/mod_easyroute applications/mod_enum \ + applications/mod_esf applications/mod_expr" +APPLICATION_MODULES_FM="applications/mod_fifo applications/mod_fsv applications/mod_hash applications/mod_lcr applications/mod_limit \ + applications/mod_memcache" +APPLICATION_MODULES_NY="applications/mod_nibblebill applications/mod_redis applications/mod_rss applications/mod_snom \ + applications/mod_soundtouch applications/mod_spandsp applications/mod_spy applications/mod_stress \ + applications/mod_valet_parking applications/mod_vmd applications/mod_voicemail" APPLICATIONS_MODULES="$APPLICATION_MODULES_AE $APPLICATION_MODULES_FM $APPLICATION_MODULES_NY $APPLICATION_MODULES_VZ" ###################################################################################################################### @@ -342,7 +352,8 @@ ASR_TTS_MODULES="asr_tts/mod_pocketsphinx asr_tts/mod_flite asr_tts/mod_unimrcp" # Codecs # ###################################################################################################################### -CODECS_MODULES="codecs/mod_ilbc codecs/mod_h26x codecs/mod_speex codecs/mod_celt codecs/mod_siren codecs/mod_bv" +CODECS_MODULES="codecs/mod_bv codecs/mod_h26x codecs/mod_speex codecs/mod_celt codecs/mod_codec2 codecs/mod_ilbc codecs/mod_mp4v \ + codecs/mod_silk codecs/mod_siren codecs/mod_theora" ###################################################################################################################### # # Dialplan Modules @@ -360,19 +371,23 @@ DIRECTORIES_MODULES="" # Endpoints # ###################################################################################################################### -ENDPOINTS_MODULES="endpoints/mod_dingaling endpoints/mod_portaudio endpoints/mod_sofia ../../libs/openzap/mod_openzap endpoints/mod_loopback" +ENDPOINTS_MODULES="endpoints/mod_dingaling endpoints/mod_loopback ../../libs/freetdm/mod_freetdm endpoints/mod_portaudio \ + endpoints/mod_sofia" + ###################################################################################################################### # # Event Handlers # ###################################################################################################################### -EVENT_HANDLERS_MODULES="event_handlers/mod_event_multicast event_handlers/mod_event_socket event_handlers/mod_cdr_csv" +EVENT_HANDLERS_MODULES="event_handlers/mod_cdr_csv event_handlers/mod_event_socket event_handlers/mod_event_multicast" ###################################################################################################################### # # File and Audio Format Handlers # ###################################################################################################################### -FORMATS_MODULES="formats/mod_local_stream formats/mod_native_file formats/mod_sndfile formats/mod_portaudio_stream formats/mod_tone_stream formats/mod_shout formats/mod_file_string" +FORMATS_MODULES="formats/mod_file_string formats/mod_local_stream formats/mod_native_file formats/mod_portaudio_stream \ + formats/mod_shout formats/mod_sndfile formats/mod_tone_stream" + ###################################################################################################################### # # Embedded Languages @@ -414,7 +429,9 @@ XML_INT_MODULES="xml_int/mod_xml_cdr xml_int/mod_xml_curl xml_int/mod_xml_rpc" # Create one environment variable out of all the module defs # ###################################################################################################################### -MYMODULES="$PASSTHRU_CODEC_MODULES $APPLICATIONS_MODULES $CODECS_MODULES $DIALPLANS_MODULES $DIRECTORIES_MODULES $ENDPOINTS_MODULES $ASR_TTS_MODULES $EVENT_HANDLERS_MODULES $FORMATS_MODULES $LANGUAGES_MODULES $LOGGERS_MODULES $SAY_MODULES $TIMERS_MODULES $XML_INT_MODULES" +MYMODULES="$PASSTHRU_CODEC_MODULES $APPLICATIONS_MODULES $CODECS_MODULES $DIALPLANS_MODULES $DIRECTORIES_MODULES \ +$ENDPOINTS_MODULES $ASR_TTS_MODULES $EVENT_HANDLERS_MODULES $FORMATS_MODULES $LANGUAGES_MODULES $LOGGERS_MODULES \ +$SAY_MODULES $TIMERS_MODULES $XML_INT_MODULES" ###################################################################################################################### # @@ -447,10 +464,10 @@ fi --prefix=%{prefix} \ --infodir=%{_infodir} \ --mandir=%{_mandir} \ - --sysconfdir=%{sysconfdir} \ - --libdir=%{prefix}/lib \ - --enable-core-libedit-support \ - --enable-core-odbc-support \ + --sysconfdir=%{sysconfdir} \ + --libdir=%{prefix}/lib \ + --enable-core-libedit-support \ + --enable-core-odbc-support \ %ifos linux %if 0%{?fedora_version} >= 8 %else @@ -730,7 +747,9 @@ fi %{prefix}/mod/mod_callcenter.so* %{prefix}/mod/mod_cdr_csv.so* %{prefix}/mod/mod_celt.so* +%{prefix}/mod/mod_cidlookup.so* %{prefix}/mod/mod_cluechoo.so* +%{prefix}/mod/mod_codec2.so* %{prefix}/mod/mod_console.so* %{prefix}/mod/mod_commands.so* %{prefix}/mod/mod_conference.so* @@ -761,6 +780,7 @@ fi %{prefix}/mod/mod_logfile.so* %{prefix}/mod/mod_loopback.so* %{prefix}/mod/mod_memcache.so* +%{prefix}/mod/mod_mp4v.so* %{prefix}/mod/mod_native_file.so* %{prefix}/mod/mod_nibblebill.so* %{prefix}/mod/mod_pocketsphinx.so* @@ -769,8 +789,10 @@ fi %{prefix}/mod/mod_redis.so* %{prefix}/mod/mod_rss.so* %{prefix}/mod/mod_shout.so* +%{prefix}/mod/mod_silk.so* %{prefix}/mod/mod_siren.so* %{prefix}/mod/mod_sndfile.so* +%{prefix}/mod/mod_snom.so* %{prefix}/mod/mod_sofia.so* %{prefix}/mod/mod_soundtouch.so* %{prefix}/mod/mod_spandsp.so* @@ -778,6 +800,7 @@ fi %{prefix}/mod/mod_spy.so* %{prefix}/mod/mod_stress.so* %{prefix}/mod/mod_syslog.so* +%{prefix}/mod/mod_theora.so* %{prefix}/mod/mod_tone_stream.so* %{prefix}/mod/mod_unimrcp.so* %{prefix}/mod/mod_valet_parking.so* @@ -804,17 +827,17 @@ fi # OpenZAP Module for TDM Interaction # ###################################################################################################################### -%files openzap +%files freetdm %defattr(-, freeswitch, daemon) %config(noreplace) %attr(0640, freeswitch, daemon) %{prefix}/conf/tones.conf -%config(noreplace) %attr(0640, freeswitch, daemon) %{prefix}/conf/autoload_configs/openzap.conf.xml +%config(noreplace) %attr(0640, freeswitch, daemon) %{prefix}/conf/autoload_configs/freetdm.conf.xml %config(noreplace) %attr(0640, freeswitch, daemon) %{prefix}/conf/pika.conf -%config(noreplace) %attr(0640, freeswitch, daemon) %{prefix}/conf/openzap.conf +%config(noreplace) %attr(0640, freeswitch, daemon) %{prefix}/conf/freetdm.conf %config(noreplace) %attr(0640, freeswitch, daemon) %{prefix}/conf/wanpipe.conf %config(noreplace) %attr(0640, freeswitch, daemon) %{prefix}/conf/zt.conf -%{prefix}/lib/libopenzap.so* -%{prefix}/mod/mod_openzap.so* -%{prefix}/mod/ozmod_*.so* +%{prefix}/lib/libfreetdm.so* +%{prefix}/mod/mod_freetdm.so* +%{prefix}/mod/ftm*.so* ###################################################################################################################### # @@ -926,6 +949,13 @@ fi # ###################################################################################################################### %changelog +* Sat Oct 09 2010 - michal.bielicki@seventhsignal.de +- added mod_silk +- added mod_codec2 +- moved from openzap to freetdm to make way for inclusion of libsng_isdn and wanpipe +- added mod_freetdm +- added mod_cidlookup +- added more runtime dependencies * Thu Sep 30 2010 - michal.bielicki@seventhsignal.de - added mod_nibblebill to standard modules * Sun Sep 26 2010 - michal.bielicki@seventhsignal.de diff --git a/libs/esl/src/esl.c b/libs/esl/src/esl.c index 75a52d6bd2..4a02a8fe38 100644 --- a/libs/esl/src/esl.c +++ b/libs/esl/src/esl.c @@ -765,6 +765,7 @@ ESL_DECLARE(esl_status_t) esl_connect_timeout(esl_handle_t *handle, const char * fail: handle->connected = 0; + esl_disconnect(handle); return ESL_FAIL; } diff --git a/libs/freetdm/configure.ac b/libs/freetdm/configure.ac index a8ed67f228..18f83d8f1d 100644 --- a/libs/freetdm/configure.ac +++ b/libs/freetdm/configure.ac @@ -205,6 +205,18 @@ if test "${have_sng_isdn}" = "yes"; then fi fi +if test "${have_sng_ss7}" = "yes"; then + if test "${build}" == "${host}" + then + case "${host}" in + x86_64-*) + # X86_64 machines need additional flags when compiling against libsng_isdn + CFLAGS="$CFLAGS -DBIT_64 -DALIGN_64BIT" + ;; + esac + fi +fi + COMP_VENDOR_CFLAGS="$COMP_VENDOR_CFLAGS" AC_SUBST(COMP_VENDOR_CFLAGS) AC_CONFIG_FILES([Makefile diff --git a/libs/freetdm/src/ftmod/ftmod_libpri/ftmod_libpri.c b/libs/freetdm/src/ftmod/ftmod_libpri/ftmod_libpri.c index bb62f07754..444b907911 100644 --- a/libs/freetdm/src/ftmod/ftmod_libpri/ftmod_libpri.c +++ b/libs/freetdm/src/ftmod/ftmod_libpri/ftmod_libpri.c @@ -374,7 +374,7 @@ static ftdm_state_map_t isdn_state_map = { ZSD_OUTBOUND, ZSM_UNACCEPTABLE, {FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_END}, - {FTDM_CHANNEL_STATE_HANGUP_COMPLETE, FTDM_CHANNEL_STATE_DOWN, FTDM_END} + {FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_HANGUP_COMPLETE, FTDM_CHANNEL_STATE_DOWN, FTDM_END} }, { ZSD_OUTBOUND, @@ -424,7 +424,7 @@ static ftdm_state_map_t isdn_state_map = { ZSD_INBOUND, ZSM_UNACCEPTABLE, {FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_END}, - {FTDM_CHANNEL_STATE_HANGUP_COMPLETE, FTDM_CHANNEL_STATE_DOWN, FTDM_END}, + {FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_HANGUP_COMPLETE, FTDM_CHANNEL_STATE_DOWN, FTDM_END}, }, { ZSD_INBOUND, @@ -605,10 +605,9 @@ static __inline__ void state_advance(ftdm_channel_t *ftdmchan) if (call) { pri_hangup(isdn_data->spri.pri, call, ftdmchan->caller_data.hangup_cause); pri_destroycall(isdn_data->spri.pri, call); - ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN); - } else { - ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_RESTART); - } + ftdmchan->call_data = NULL; + } + ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN); } break; case FTDM_CHANNEL_STATE_HANGUP_COMPLETE: @@ -617,8 +616,7 @@ static __inline__ void state_advance(ftdm_channel_t *ftdmchan) { sig.event_id = FTDM_SIGEVENT_STOP; status = ftdm_span_send_signal(ftdmchan->span, &sig); - ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN); - + /* user moves us to HANGUP and from there we go to DOWN */ } default: break; @@ -641,10 +639,12 @@ static __inline__ void check_state(ftdm_span_t *span) for(j = 1; j <= span->chan_count; j++) { if (ftdm_test_flag((span->channels[j]), FTDM_CHANNEL_STATE_CHANGE)) { ftdm_mutex_lock(span->channels[j]->mutex); + ftdm_channel_lock(span->channels[j]); ftdm_clear_flag((span->channels[j]), FTDM_CHANNEL_STATE_CHANGE); state_advance(span->channels[j]); ftdm_channel_complete_state(span->channels[j]); ftdm_mutex_unlock(span->channels[j]->mutex); + ftdm_channel_unlock(span->channels[j]); } } } @@ -682,18 +682,35 @@ static int on_hangup(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_even q931_call *call = NULL; ftdmchan = span->channels[pevent->hangup.channel]; - if (ftdmchan) { - call = (q931_call *) ftdmchan->call_data; - ftdm_log(FTDM_LOG_DEBUG, "-- Hangup on channel %d:%d\n", spri->span->span_id, pevent->hangup.channel); - ftdmchan->caller_data.hangup_cause = pevent->hangup.cause; - pri_release(spri->pri, call, 0); - pri_destroycall(spri->pri, call); - ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING); - } else { - ftdm_log(FTDM_LOG_DEBUG, "-- Hangup on channel %d:%d %s but it's not in use?\n", spri->span->span_id, - pevent->hangup.channel, ftdmchan->chan_id); + if (!ftdmchan) { + ftdm_log(FTDM_LOG_CRIT, "-- Hangup on channel %d:%d %s but it's not in use?\n", spri->span->span_id, pevent->hangup.channel); + return 0; } + ftdm_channel_lock(ftdmchan); + + if (ftdmchan->state >= FTDM_CHANNEL_STATE_TERMINATING) { + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Ignoring remote hangup in state %s\n", ftdm_channel_state2str(ftdmchan->state)); + goto done; + } + + if (!ftdmchan->call_data) { + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Ignoring remote hangup in state %s with no call data\n", ftdm_channel_state2str(ftdmchan->state)); + goto done; + } + + call = (q931_call *) ftdmchan->call_data; + ftdm_log(FTDM_LOG_DEBUG, "-- Hangup on channel %d:%d\n", spri->span->span_id, pevent->hangup.channel); + ftdmchan->caller_data.hangup_cause = pevent->hangup.cause; + pri_release(spri->pri, call, 0); + pri_destroycall(spri->pri, call); + ftdmchan->call_data = NULL; + ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING); + +done: + + ftdm_channel_unlock(ftdmchan); + return 0; } 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 803e6371d7..8dbbda7a65 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 @@ -265,10 +265,12 @@ static void *ftdm_sangoma_isdn_run(ftdm_thread_t *me, void *obj) } while (ftdm_running() && !(ftdm_test_flag(span, FTDM_SPAN_STOP_THREAD))) { - /* find out why we returned from the interrupt queue */ - ret_status = ftdm_interrupt_multiple_wait(ftdm_sangoma_isdn_int, 2, sleep); + /* Check if there are any timers to process */ ftdm_sched_run(signal_data->sched); + + ret_status = ftdm_interrupt_multiple_wait(ftdm_sangoma_isdn_int, 2, sleep); + /* find out why we returned from the interrupt queue */ switch (ret_status) { case FTDM_SUCCESS: /* there was a state change on the span */ /* process all pending state changes */ @@ -289,13 +291,30 @@ static void *ftdm_sangoma_isdn_run(ftdm_thread_t *me, void *obj) /* twiddle */ break; case FTDM_FAIL: - ftdm_log(FTDM_LOG_ERROR,"ftdm_interrupt_wait returned error!\non span = %s\n", span->name); + ftdm_log(FTDM_LOG_ERROR,"%s:ftdm_interrupt_wait returned error!\n", span->name); break; default: - ftdm_log(FTDM_LOG_ERROR,"ftdm_interrupt_wait returned with unknown code on span = %s\n", span->name); + ftdm_log(FTDM_LOG_ERROR,"%s:ftdm_interrupt_wait returned with unknown code\n", span->name); break; } + + /* Poll for events, e.g HW DTMF */ + ret_status = ftdm_span_poll_event(span, 0); + switch(ret_status) { + case FTDM_SUCCESS: + { + ftdm_event_t *event; + while (ftdm_span_next_event(span, &event) == FTDM_SUCCESS); + } + break; + case FTDM_TIMEOUT: + /* No events pending */ + break; + default: + ftdm_log(FTDM_LOG_WARNING, "%s:Failed to poll span event\n", span->name); + } + if (ftdm_sched_get_time_to_next_timer(signal_data->sched, &sleep) == FTDM_SUCCESS) { if (sleep < 0 || sleep > SNGISDN_EVENT_POLL_RATE) { sleep = SNGISDN_EVENT_POLL_RATE; 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 725e1bbf11..9adcc08296 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 @@ -80,6 +80,7 @@ void sngisdn_process_con_ind (sngisdn_event_data_t *sngisdn_event) sngisdn_info->suInstId = get_unique_suInstId((int8_t) suId); sngisdn_info->spInstId = spInstId; + if (conEvnt->cdPtyNmb.eh.pres && signal_data->num_local_numbers) { uint8_t local_number_matched = 0; @@ -129,14 +130,12 @@ void sngisdn_process_con_ind (sngisdn_event_data_t *sngisdn_event) #if 0 /* Export ftdmchan variables here if we need to */ ftdm_channel_add_var(ftdmchan, "isdn_specific_var", "1"); - ftdm_channel_add_var(ftdmchan, "isdn_crap", "morecrap"); - ftdm_channel_add_var(ftdmchan, "isdn_stuff", "s"); - ftdm_channel_add_var(ftdmchan, "isdn_d", "asdsadasdasdsad"); #endif /* Fill in call information */ cpy_calling_num_from_stack(&ftdmchan->caller_data, &conEvnt->cgPtyNmb); cpy_called_num_from_stack(&ftdmchan->caller_data, &conEvnt->cdPtyNmb); cpy_calling_name_from_stack(&ftdmchan->caller_data, &conEvnt->display); + ftdm_log_chan(sngisdn_info->ftdmchan, FTDM_LOG_INFO, "Incoming call: Called No:[%s] Calling No:[%s]\n", ftdmchan->caller_data.dnis.digits, ftdmchan->caller_data.cid_num.digits); if (conEvnt->bearCap[0].eh.pres) { ftdmchan->caller_data.bearer_layer1 = sngisdn_get_infoTranCap_from_stack(conEvnt->bearCap[0].usrInfoLyr1Prot.val); @@ -977,6 +976,18 @@ void sngisdn_process_sta_cfm (sngisdn_event_data_t *sngisdn_event) //ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_RESTART); break; } + break; + case 25: /* Overlap receiving */ + switch (ftdmchan->state) { + case FTDM_CHANNEL_STATE_COLLECT: + /* do nothing */ + break; + default: + ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "Don't know how to handle incompatible state. remote call state:%d our state:%s\n", call_state, ftdm_channel_state2str(ftdmchan->state)); + //ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_RESTART); + break; + } + break; default: ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "Don't know how to handle incompatible state. remote call state:%d our state:%s\n", call_state, ftdm_channel_state2str(ftdmchan->state)); //ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_RESTART); 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 80a85ceec8..3284d54165 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 @@ -143,6 +143,7 @@ void sngisdn_snd_setup(ftdm_channel_t *ftdmchan) signal_data->signalling == SNGISDN_SIGNALING_NET) { sngisdn_info->ces = CES_MNGMNT; } + 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); cpy_called_num_from_user(&conEvnt.cdPtyNmb, &ftdmchan->caller_data); cpy_calling_num_from_user(&conEvnt.cgPtyNmb, &ftdmchan->caller_data); 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 12ffd14b39..5cc17a539a 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 @@ -188,11 +188,11 @@ ftdm_status_t cpy_called_num_from_stack(ftdm_caller_data_t *ftdm, CdPtyNmb *cdPt } if (cdPtyNmb->nmbPlanId.pres == PRSNT_NODEF) { - ftdm->cid_num.plan = cdPtyNmb->nmbPlanId.val; + ftdm->dnis.plan = cdPtyNmb->nmbPlanId.val; } if (cdPtyNmb->typeNmb0.pres == PRSNT_NODEF) { - ftdm->cid_num.type = cdPtyNmb->typeNmb0.val; + ftdm->dnis.type = cdPtyNmb->typeNmb0.val; } if (cdPtyNmb->nmbDigits.pres == PRSNT_NODEF) { 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 92284edba3..38d3723061 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 @@ -616,8 +616,8 @@ static ftdm_status_t handle_print_usuage(ftdm_stream_handle_t *stream) stream->write_function(stream, "Sangoma SS7 CLI usuage:\n\n"); stream->write_function(stream, "Ftmod_sangoma_ss7 general control:\n"); - stream->write_function(stream, "ftdm ss7 set ftace X Y\n"); - stream->write_function(stream, "ftdm ss7 set mtace X Y\n"); + stream->write_function(stream, "ftdm ss7 set ftrace X Y\n"); + stream->write_function(stream, "ftdm ss7 set mtrace X Y\n"); stream->write_function(stream, "\n"); stream->write_function(stream, "Ftmod_sangoma_ss7 information:\n"); stream->write_function(stream, "ftdm ss7 show status link X\n"); @@ -1064,7 +1064,7 @@ static ftdm_status_t handle_show_status(ftdm_stream_handle_t *stream, int span, /* grab the signaling_status */ ftdm_channel_get_sig_status(ftdmchan, &sigstatus); - stream->write_function(stream, "span=%2d|chan=%2d|cic=%4d|sig_status=%s|state=%s|", + stream->write_function(stream, "span=%2d|chan=%2d|cic=%4d|sig_status=%4s|state=%s|", ckt->span, ckt->chan, ckt->cic, @@ -1281,13 +1281,17 @@ static ftdm_status_t handle_status_link(ftdm_stream_handle_t *stream, char *name (sta.t.ssta.s.snDLSAP.remBlkd) ? "Y":"N", (sta.t.ssta.s.snDLSAP.locInhbt) ? "Y":"N", (sta.t.ssta.s.snDLSAP.rmtInhbt) ? "Y":"N"); - break; + + goto success; } /* move to the next link */ x++; } /* while (id != 0) */ + stream->write_function(stream, "Failed to find link=\"%s\"\n", name); + +success: return FTDM_SUCCESS; } @@ -1313,13 +1317,17 @@ static ftdm_status_t handle_status_linkset(ftdm_stream_handle_t *stream, char *n name, DECODE_LSN_LINKSET_STATUS(sta.t.ssta.s.snLnkSet.state), sta.t.ssta.s.snLnkSet.nmbActLnks); - break; + + goto success; } /* move to the next linkset */ x++; } /* while (id != 0) */ + stream->write_function(stream, "Failed to find link=\"%s\"\n", name); + +success: return FTDM_SUCCESS; } @@ -1342,13 +1350,16 @@ static ftdm_status_t handle_set_inhibit(ftdm_stream_handle_t *stream, char *name /* print the new status of the link */ handle_status_link(stream, &name[0]); - break; + goto success; } /* move to the next linkset */ x++; } /* while (id != 0) */ + stream->write_function(stream, "Failed to find link=\"%s\"\n", name); + +success: return FTDM_SUCCESS; } @@ -1371,13 +1382,16 @@ static ftdm_status_t handle_set_uninhibit(ftdm_stream_handle_t *stream, char *na /* print the new status of the link */ handle_status_link(stream, &name[0]); - break; + goto success; } /* move to the next linkset */ x++; } /* while (id != 0) */ + stream->write_function(stream, "Failed to find link=\"%s\"\n", name); + +success: return FTDM_SUCCESS; } @@ -1440,6 +1454,10 @@ static ftdm_status_t handle_tx_rsc(ftdm_stream_handle_t *stream, int span, int c /* go the next circuit */ x++; } /* while (g_ftdm_sngss7_data.cfg.isupCkt[x]id != 0) */ + + /* print the status of channels */ + handle_show_status(stream, span, chan, verbose); + return FTDM_SUCCESS; @@ -1505,6 +1523,24 @@ static ftdm_status_t handle_tx_grs(ftdm_stream_handle_t *stream, int span, int c x++; } /* while (g_ftdm_sngss7_data.cfg.isupCkt[x]id != 0) */ + x=1; + while (g_ftdm_sngss7_data.cfg.isupCkt[x].id != 0) { + if (g_ftdm_sngss7_data.cfg.isupCkt[x].type == VOICE) { + + sngss7_info = (sngss7_chan_data_t *)g_ftdm_sngss7_data.cfg.isupCkt[x].obj; + ftdmchan = sngss7_info->ftdmchan; + sngss7_span = ftdmchan->span->mod_data; + + if ((ftdmchan->physical_span_id == span) && + ((ftdmchan->physical_chan_id >= chan) && (ftdmchan->physical_chan_id < (chan+range)))) { + + handle_show_status(stream, span, chan, verbose); + } + } /* if ( cic == voice) */ + + /* go the next circuit */ + x++; + } /* while (g_ftdm_sngss7_data.cfg.isupCkt[x]id != 0) */ return FTDM_SUCCESS; } @@ -1585,6 +1621,25 @@ static ftdm_status_t handle_tx_cgb(ftdm_stream_handle_t *stream, int span, int c /* send the circuit group block */ ft_to_sngss7_cgb(main_chan); + + x=1; + while (g_ftdm_sngss7_data.cfg.isupCkt[x].id != 0) { + if (g_ftdm_sngss7_data.cfg.isupCkt[x].type == VOICE) { + + sngss7_info = (sngss7_chan_data_t *)g_ftdm_sngss7_data.cfg.isupCkt[x].obj; + ftdmchan = sngss7_info->ftdmchan; + sngss7_span = ftdmchan->span->mod_data; + + if ((ftdmchan->physical_span_id == span) && + ((ftdmchan->physical_chan_id >= chan) && (ftdmchan->physical_chan_id < (chan+range)))) { + + handle_show_status(stream, span, chan, verbose); + } + } /* if ( cic == voice) */ + + /* go the next circuit */ + x++; + } /* while (g_ftdm_sngss7_data.cfg.isupCkt[x]id != 0) */ return FTDM_SUCCESS; @@ -1666,6 +1721,25 @@ static ftdm_status_t handle_tx_cgu(ftdm_stream_handle_t *stream, int span, int c /* send the circuit group block */ ft_to_sngss7_cgu(main_chan); + + x=1; + while (g_ftdm_sngss7_data.cfg.isupCkt[x].id != 0) { + if (g_ftdm_sngss7_data.cfg.isupCkt[x].type == VOICE) { + + sngss7_info = (sngss7_chan_data_t *)g_ftdm_sngss7_data.cfg.isupCkt[x].obj; + ftdmchan = sngss7_info->ftdmchan; + sngss7_span = ftdmchan->span->mod_data; + + if ((ftdmchan->physical_span_id == span) && + ((ftdmchan->physical_chan_id >= chan) && (ftdmchan->physical_chan_id < (chan+range)))) { + + handle_show_status(stream, span, chan, verbose); + } + } /* if ( cic == voice) */ + + /* go the next circuit */ + x++; + } /* while (g_ftdm_sngss7_data.cfg.isupCkt[x]id != 0) */ return FTDM_SUCCESS; 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 ac58abd412..807b3b62c7 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 @@ -51,6 +51,8 @@ ftdm_status_t handle_dat_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circ ftdm_status_t handle_fac_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, uint8_t evntType, SiFacEvnt *siFacEvnt); ftdm_status_t handle_fac_cfm(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, uint8_t evntType, SiFacEvnt *siFacEvnt); ftdm_status_t handle_umsg_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circuit); +ftdm_status_t handle_susp_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, SiSuspEvnt *siSuspEvnt); +ftdm_status_t handle_resm_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, SiResmEvnt *siResmEvnt); ftdm_status_t handle_sta_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, uint8_t globalFlg, uint8_t evntType, SiStaEvnt *siStaEvnt); ftdm_status_t handle_reattempt(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, uint8_t globalFlg, uint8_t evntType, SiStaEvnt *siStaEvnt); @@ -298,8 +300,21 @@ ftdm_status_t handle_con_sta(uint32_t suInstId, uint32_t spInstId, uint32_t circ /* need to grab the sp instance id */ sngss7_info->spInstId = spInstId; - /* go to PROGRESS */ - ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_PROGRESS); + if ((siCnStEvnt->optBckCalInd.eh.pres) && + (siCnStEvnt->optBckCalInd.inbndInfoInd.pres)) { + + if (siCnStEvnt->optBckCalInd.inbndInfoInd.val) { + /* go to PROGRESS_MEDIA */ + ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_PROGRESS_MEDIA); + } else { + /* go to PROGRESS */ + ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_PROGRESS); + } /* if (inband) */ + } else { + /* go to PROGRESS_MEDIA */ + ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_PROGRESS_MEDIA); + } + break; /**********************************************************************/ default: /* incorrect state...reset the CIC */ @@ -733,6 +748,60 @@ ftdm_status_t handle_umsg_ind(uint32_t suInstId, uint32_t spInstId, uint32_t cir return FTDM_SUCCESS; } +/******************************************************************************/ +ftdm_status_t handle_susp_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, SiSuspEvnt *siSuspEvnt) +{ + SS7_FUNC_TRACE_ENTER(__FUNCTION__); + + sngss7_chan_data_t *sngss7_info ; + ftdm_channel_t *ftdmchan; + + /* get the ftdmchan and ss7_chan_data from the circuit */ + if (extract_chan_data(circuit, &sngss7_info, &ftdmchan)) { + SS7_ERROR("Failed to extract channel data for circuit = %d!\n", circuit); + SS7_FUNC_TRACE_EXIT(__FUNCTION__); + return FTDM_FAIL; + } + + /* lock the channel */ + ftdm_mutex_lock(ftdmchan->mutex); + + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Rx Call-Suspend msg\n", sngss7_info->circuit->cic); + + /* unlock the channel */ + ftdm_mutex_unlock(ftdmchan->mutex); + + SS7_FUNC_TRACE_EXIT(__FUNCTION__); + return FTDM_SUCCESS; +} + +/******************************************************************************/ +ftdm_status_t handle_resm_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, SiResmEvnt *siResmEvnt) +{ + SS7_FUNC_TRACE_ENTER(__FUNCTION__); + + sngss7_chan_data_t *sngss7_info ; + ftdm_channel_t *ftdmchan; + + /* get the ftdmchan and ss7_chan_data from the circuit */ + if (extract_chan_data(circuit, &sngss7_info, &ftdmchan)) { + SS7_ERROR("Failed to extract channel data for circuit = %d!\n", circuit); + SS7_FUNC_TRACE_EXIT(__FUNCTION__); + return FTDM_FAIL; + } + + /* lock the channel */ + ftdm_mutex_lock(ftdmchan->mutex); + + SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Rx Call-Resume msg\n", sngss7_info->circuit->cic); + + /* unlock the channel */ + ftdm_mutex_unlock(ftdmchan->mutex); + + SS7_FUNC_TRACE_EXIT(__FUNCTION__); + return FTDM_SUCCESS; +} + /******************************************************************************/ ftdm_status_t handle_sta_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, uint8_t globalFlg, uint8_t evntType, SiStaEvnt *siStaEvnt) { diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_in.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_in.c index 34893cf5aa..06fae0cd37 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_in.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_in.c @@ -52,7 +52,9 @@ void sngss7_dat_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, SiIn void sngss7_fac_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, uint8_t evntType, SiFacEvnt *siFacEvnt); void sngss7_fac_cfm(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, uint8_t evntType, SiFacEvnt *siFacEvnt); void sngss7_umsg_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circuit); - +void sngss7_resm_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, SiResmEvnt *siResmEvnt); +void sngss7_susp_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, SiSuspEvnt *siSuspEvnt); +void sngss7_ssp_sta_cfm(uint32_t infId); /******************************************************************************/ /* FUNCTIONS ******************************************************************/ @@ -442,7 +444,127 @@ void sngss7_sta_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, uint } /******************************************************************************/ +void sngss7_susp_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, SiSuspEvnt *siSuspEvnt) +{ + SS7_FUNC_TRACE_ENTER(__FUNCTION__); + sngss7_chan_data_t *sngss7_info = NULL; + ftdm_channel_t *ftdmchan = NULL; + sngss7_event_data_t *sngss7_event = NULL; + + /* get the ftdmchan and ss7_chan_data from the circuit */ + if (extract_chan_data(circuit, &sngss7_info, &ftdmchan)) { + SS7_ERROR("Failed to extract channel data for circuit = %d!\n", circuit); + SS7_FUNC_TRACE_EXIT(__FUNCTION__); + return; + } + + /* initalize the sngss7_event */ + sngss7_event = ftdm_malloc(sizeof(*sngss7_event)); + if (sngss7_event == NULL) { + SS7_ERROR("Failed to allocate memory for sngss7_event!\n"); + SS7_FUNC_TRACE_EXIT(__FUNCTION__); + return; + } + memset(sngss7_event, 0x0, sizeof(*sngss7_event)); + + /* fill in the sngss7_event struct */ + sngss7_event->spInstId = spInstId; + sngss7_event->suInstId = suInstId; + sngss7_event->circuit = circuit; + sngss7_event->event_id = SNGSS7_SUSP_IND_EVENT; + if (siSuspEvnt != NULL) { + memcpy(&sngss7_event->event.siSuspEvnt, siSuspEvnt, sizeof(*siSuspEvnt)); + } + + /* enqueue this event */ + ftdm_queue_enqueue(((sngss7_span_data_t*)sngss7_info->ftdmchan->span->mod_data)->event_queue, sngss7_event); + + SS7_FUNC_TRACE_EXIT(__FUNCTION__); + +} + +/******************************************************************************/ +void sngss7_resm_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, SiResmEvnt *siResmEvnt) +{ + SS7_FUNC_TRACE_ENTER(__FUNCTION__); + + sngss7_chan_data_t *sngss7_info = NULL; + ftdm_channel_t *ftdmchan = NULL; + sngss7_event_data_t *sngss7_event = NULL; + + /* get the ftdmchan and ss7_chan_data from the circuit */ + if (extract_chan_data(circuit, &sngss7_info, &ftdmchan)) { + SS7_ERROR("Failed to extract channel data for circuit = %d!\n", circuit); + SS7_FUNC_TRACE_EXIT(__FUNCTION__); + return; + } + + /* initalize the sngss7_event */ + sngss7_event = ftdm_malloc(sizeof(*sngss7_event)); + if (sngss7_event == NULL) { + SS7_ERROR("Failed to allocate memory for sngss7_event!\n"); + SS7_FUNC_TRACE_EXIT(__FUNCTION__); + return; + } + memset(sngss7_event, 0x0, sizeof(*sngss7_event)); + + /* fill in the sngss7_event struct */ + sngss7_event->spInstId = spInstId; + sngss7_event->suInstId = suInstId; + sngss7_event->circuit = circuit; + sngss7_event->event_id = SNGSS7_RESM_IND_EVENT; + if (siResmEvnt != NULL) { + memcpy(&sngss7_event->event.siResmEvnt, siResmEvnt, sizeof(*siResmEvnt)); + } + + /* enqueue this event */ + ftdm_queue_enqueue(((sngss7_span_data_t*)sngss7_info->ftdmchan->span->mod_data)->event_queue, sngss7_event); + + SS7_FUNC_TRACE_EXIT(__FUNCTION__); + +} + +/******************************************************************************/ +void sngss7_ssp_sta_cfm(uint32_t infId) +{ + SS7_FUNC_TRACE_ENTER(__FUNCTION__); +#if 0 + sngss7_chan_data_t *sngss7_info = NULL; + ftdm_channel_t *ftdmchan = NULL; + sngss7_event_data_t *sngss7_event = NULL; + + /* get the ftdmchan and ss7_chan_data from the circuit */ + if (extract_chan_data(circuit, &sngss7_info, &ftdmchan)) { + SS7_ERROR("Failed to extract channel data for circuit = %d!\n", circuit); + SS7_FUNC_TRACE_EXIT(__FUNCTION__); + return; + } + + /* initalize the sngss7_event */ + sngss7_event = ftdm_malloc(sizeof(*sngss7_event)); + if (sngss7_event == NULL) { + SS7_ERROR("Failed to allocate memory for sngss7_event!\n"); + SS7_FUNC_TRACE_EXIT(__FUNCTION__); + return; + } + memset(sngss7_event, 0x0, sizeof(*sngss7_event)); + + /* fill in the sngss7_event struct */ + sngss7_event->spInstId = spInstId; + sngss7_event->suInstId = suInstId; + sngss7_event->circuit = circuit; + sngss7_event->event_id = SNGSS7_RESM_IND_EVENT; + if (siSuspEvnt != NULL) { + memcpy(&sngss7_event->event.siResmEvnt, siResmEvnt, sizeof(*siResmEvnt)); + } + + /* enqueue this event */ + ftdm_queue_enqueue(((sngss7_span_data_t*)sngss7_info->ftdmchan->span->mod_data)->event_queue, sngss7_event); +#endif + SS7_FUNC_TRACE_EXIT(__FUNCTION__); + +} /******************************************************************************/ /* For Emacs: * Local Variables: 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 30cb31691d..587242d94e 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 @@ -208,7 +208,7 @@ ftdm_state_map_t sangoma_ss7_state_map = { {FTDM_CHANNEL_STATE_SUSPENDED, FTDM_CHANNEL_STATE_RESTART, FTDM_CHANNEL_STATE_CANCEL, FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_PROGRESS, - FTDM_CHANNEL_STATE_UP, FTDM_END} + FTDM_CHANNEL_STATE_PROGRESS_MEDIA ,FTDM_CHANNEL_STATE_UP, FTDM_END} }, { ZSD_OUTBOUND, @@ -448,6 +448,17 @@ static void ftdm_sangoma_ss7_process_stack_event (sngss7_event_data_t *sngss7_ev handle_sta_ind(sngss7_event->suInstId, sngss7_event->spInstId, sngss7_event->circuit, sngss7_event->globalFlg, sngss7_event->evntType, &sngss7_event->event.siStaEvnt); break; /**************************************************************************/ + case (SNGSS7_SUSP_IND_EVENT): + handle_susp_ind(sngss7_event->suInstId, sngss7_event->spInstId, sngss7_event->circuit, &sngss7_event->event.siSuspEvnt); + break; + /**************************************************************************/ + case (SNGSS7_RESM_IND_EVENT): + handle_resm_ind(sngss7_event->suInstId, sngss7_event->spInstId, sngss7_event->circuit, &sngss7_event->event.siResmEvnt); + break; + /**************************************************************************/ + case (SNGSS7_SSP_STA_CFM_EVENT): + break; + /**************************************************************************/ default: SS7_ERROR("Unknown Event Id!\n"); break; @@ -469,6 +480,7 @@ static void ftdm_sangoma_ss7_process_stack_event (sngss7_event_data_t *sngss7_ev void ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) { sngss7_chan_data_t *sngss7_info = ftdmchan->call_data; + sng_isup_inf_t *isup_intf = NULL; int i = 0; ftdm_sigmsg_t sigev; @@ -589,17 +601,16 @@ void ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) } /*check if the channel is inbound or outbound */ - if (ftdm_test_flag (ftdmchan, FTDM_CHANNEL_OUTBOUND)) { + if (ftdm_test_flag (ftdmchan, FTDM_CHANNEL_OUTBOUND)) { /*OUTBOUND...so we were told by the line of this so noifiy the user */ sigev.event_id = FTDM_SIGEVENT_PROGRESS; ftdm_span_send_signal (ftdmchan->span, &sigev); + /* move to progress media */ ftdm_set_state_locked (ftdmchan, FTDM_CHANNEL_STATE_PROGRESS_MEDIA); } else { /* inbound call so we need to send out ACM */ - ft_to_sngss7_acm (ftdmchan); - - ftdm_set_state_locked (ftdmchan, FTDM_CHANNEL_STATE_PROGRESS_MEDIA); + ft_to_sngss7_acm(ftdmchan); } break; @@ -611,6 +622,13 @@ void ftdm_sangoma_ss7_process_state_change (ftdm_channel_t * ftdmchan) break; } + if (ftdm_test_flag (ftdmchan, FTDM_CHANNEL_OUTBOUND)) { + /* inform the user there is media avai */ + sigev.event_id = FTDM_SIGEVENT_PROGRESS_MEDIA; + ftdm_span_send_signal (ftdmchan->span, &sigev); + } + + /* nothing to do at this time */ break; /**************************************************************************/ @@ -1155,11 +1173,15 @@ suspend_goto_restart: ftdm_set_state_locked (ftdmchan, FTDM_CHANNEL_STATE_RESTART); break; -/**************************************************************************/ + /**************************************************************************/ case FTDM_CHANNEL_STATE_IN_LOOP: /* COT test */ - /* send the lpa */ - ft_to_sngss7_lpa (ftdmchan); + isup_intf = &g_ftdm_sngss7_data.cfg.isupIntf[sngss7_info->circuit->infId]; + + if (sngss7_test_options(isup_intf, SNGSS7_LPA_FOR_COT)) { + /* send the lpa */ + ft_to_sngss7_lpa (ftdmchan); + } break; /**************************************************************************/ @@ -1332,7 +1354,7 @@ static ftdm_status_t ftdm_sangoma_ss7_start(ftdm_span_t * span) sngss7_clear_flag(sngss7_info, FLAG_INFID_PAUSED); sngss7_set_flag(sngss7_info, FLAG_INFID_RESUME); } -#if 1 +#if 0 /* throw the grp reset flag */ sngss7_set_flag(sngss7_info, FLAG_GRP_RESET_TX); if (x == 1) { @@ -1480,7 +1502,7 @@ static FIO_SIG_LOAD_FUNCTION(ftdm_sangoma_ss7_init) sngss7_id = 0; - cmbLinkSetId = 1; + cmbLinkSetId = 0; /* initalize the global gen_config flag */ g_ftdm_sngss7_data.gen_config = 0; @@ -1507,9 +1529,9 @@ static FIO_SIG_LOAD_FUNCTION(ftdm_sangoma_ss7_init) sng_event.cc.sng_fac_cfm = sngss7_fac_cfm; sng_event.cc.sng_sta_ind = sngss7_sta_ind; sng_event.cc.sng_umsg_ind = sngss7_umsg_ind; - sng_event.cc.sng_susp_ind = NULL; - sng_event.cc.sng_resm_ind = NULL; - sng_event.cc.sng_ssp_sta_cfm = NULL; + sng_event.cc.sng_susp_ind = sngss7_susp_ind; + sng_event.cc.sng_resm_ind = sngss7_resm_ind; + sng_event.cc.sng_ssp_sta_cfm = sngss7_ssp_sta_cfm; sng_event.sm.sng_log = handle_sng_log; sng_event.sm.sng_mtp1_alarm = handle_sng_mtp1_alarm; 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 a358236ed0..27833cb2a2 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 @@ -58,6 +58,8 @@ #define SNGSS7_EVENT_QUEUE_SIZE 100 +#define MAX_SIZEOF_SUBADDR_IE 24 /* as per Q931 4.5.9 */ + typedef enum { SNGSS7_CON_IND_EVENT = 0, SNGSS7_CON_CFM_EVENT, @@ -68,7 +70,10 @@ typedef enum { SNGSS7_FAC_IND_EVENT, SNGSS7_FAC_CFM_EVENT, SNGSS7_UMSG_IND_EVENT, - SNGSS7_STA_IND_EVENT + SNGSS7_STA_IND_EVENT, + SNGSS7_SUSP_IND_EVENT, + SNGSS7_RESM_IND_EVENT, + SNGSS7_SSP_STA_CFM_EVENT } sng_event_type_t; typedef enum { @@ -83,6 +88,16 @@ typedef enum { SNGSS7_PAUSED = (1 << 7) } sng_flag_t; +typedef enum { + SNGSS7_LPA_FOR_COT = (1 << 0), /* send LPA when COT arrives */ + SNGSS7_ACM_OBCI_BITA = (1 << 10) /* in-band indication */ +} sng_intf_options_t; + +typedef enum { + SNG_CALLED = 1, + SNG_CALLING = 2 +} sng_addr_type_t; + typedef struct sng_mtp_link { char name[MAX_NAME_LEN]; uint32_t id; @@ -198,6 +213,7 @@ typedef struct sng_route { typedef struct sng_isup_intf { uint32_t id; char name[MAX_NAME_LEN]; + uint32_t options; uint32_t flags; uint32_t spc; uint32_t dpc; @@ -385,6 +401,8 @@ typedef struct sngss7_event_data SiInfoEvnt siInfoEvnt; SiFacEvnt siFacEvnt; SiStaEvnt siStaEvnt; + SiSuspEvnt siSuspEvnt; + SiResmEvnt siResmEvnt; } event; } sngss7_event_data_t; @@ -514,6 +532,9 @@ void sngss7_fac_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, uint void sngss7_fac_cfm(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, uint8_t evntType, SiFacEvnt *siFacEvnt); void sngss7_sta_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, uint8_t globalFlg, uint8_t evntType, SiStaEvnt *siStaEvnt); void sngss7_umsg_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circuit); +void sngss7_resm_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, SiResmEvnt *siResmEvnt); +void sngss7_susp_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, SiSuspEvnt *siSuspEvnt); +void sngss7_ssp_sta_cfm(uint32_t infId); /* in ftmod_sangoma_ss7_handle.c */ ftdm_status_t handle_con_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, SiConEvnt *siConEvnt); @@ -525,6 +546,8 @@ ftdm_status_t handle_dat_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circ ftdm_status_t handle_fac_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, uint8_t evntType, SiFacEvnt *siFacEvnt); ftdm_status_t handle_fac_cfm(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, uint8_t evntType, SiFacEvnt *siFacEvnt); ftdm_status_t handle_umsg_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circuit); +ftdm_status_t handle_susp_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, SiSuspEvnt *siSuspEvnt); +ftdm_status_t handle_resm_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, SiResmEvnt *siResmEvnt); ftdm_status_t handle_sta_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, uint8_t globalFlg, uint8_t evntType, SiStaEvnt *siStaEvnt); ftdm_status_t handle_reattempt(uint32_t suInstId, uint32_t spInstId, uint32_t circuit, uint8_t globalFlg, uint8_t evntType, SiStaEvnt *siStaEvnt); @@ -579,6 +602,8 @@ ftdm_status_t clear_rx_grs_data(sngss7_chan_data_t *sngss7_info); ftdm_status_t clear_rx_gra_data(sngss7_chan_data_t *sngss7_info); ftdm_status_t clear_tx_grs_data(sngss7_chan_data_t *sngss7_info); +ftdm_status_t encode_subAddrIE_nsap(const char *subAddr, char *subAddrIE, int type); +ftdm_status_t encode_subAddrIE_nat(const char *subAddr, char *subAddrIE, int type); /* in ftmod_sangoma_ss7_timers.c */ void handle_isup_t35(void *userdata); @@ -712,6 +737,11 @@ void handle_isup_t35(void *userdata); #define sngss7_clear_flag(obj, flag) ((obj)->flags &= ~(flag)) #define sngss7_set_flag(obj, flag) ((obj)->flags |= (flag)) +#define sngss7_test_options(obj, option) ((obj)->options & option) +#define sngss7_clear_options(obj, option) ((obj)->options &= ~(option)) +#define sngss7_set_options(obj, option) ((obj)->options |= (option)) + + #ifdef SS7_PRODUCTION # define SS7_ASSERT \ SS7_INFO_CHAN(ftdmchan,"Production Mode, continuing%s\n", ""); 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 973fbf47c7..8cbe6d9498 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 @@ -76,6 +76,9 @@ void ft_to_sngss7_iam (ftdm_channel_t * ftdmchan) sngss7_chan_data_t *sngss7_info = ftdmchan->call_data;; const char *clg_nadi = NULL; const char *cld_nadi = NULL; + const char *clg_subAddr = NULL; + const char *cld_subAddr = NULL; + char subAddrIE[MAX_SIZEOF_SUBADDR_IE]; SiConEvnt iam; sngss7_info->suInstId = get_unique_id (); @@ -186,7 +189,7 @@ void ft_to_sngss7_iam (ftdm_channel_t * ftdmchan) /* 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"); if ((clg_nadi != NULL) && (*clg_nadi)) { - SS7_DEBUG_CHAN(ftdmchan,"Found user supplied NADI value \"%s\"\n", clg_nadi); + SS7_DEBUG_CHAN(ftdmchan,"Found user supplied Calling NADI value \"%s\"\n", clg_nadi); iam.cgPtyNum.natAddrInd.val = atoi(clg_nadi); } else { iam.cgPtyNum.natAddrInd.val = g_ftdm_sngss7_data.cfg.isupIntf[sngss7_info->circuit->infId].clg_nadi; @@ -195,14 +198,93 @@ void ft_to_sngss7_iam (ftdm_channel_t * ftdmchan) cld_nadi = ftdm_channel_get_var(ftdmchan, "ss7_cld_nadi"); if ((cld_nadi != NULL) && (*cld_nadi)) { - SS7_DEBUG_CHAN(ftdmchan,"Found user supplied NADI value \"%s\"\n", cld_nadi); + SS7_DEBUG_CHAN(ftdmchan,"Found user supplied Called NADI value \"%s\"\n", cld_nadi); iam.cdPtyNum.natAddrInd.val = atoi(cld_nadi); } else { iam.cdPtyNum.natAddrInd.val = g_ftdm_sngss7_data.cfg.isupIntf[sngss7_info->circuit->infId].cld_nadi; SS7_DEBUG_CHAN(ftdmchan,"No user supplied NADI value found for CLD, using \"%d\"\n", iam.cdPtyNum.natAddrInd.val); - } + /* check if the user would like us to send a clg_sub-address */ + clg_subAddr = ftdm_channel_get_var(ftdmchan, "ss7_clg_subaddr"); + if ((clg_subAddr != NULL) && (*clg_subAddr)) { + SS7_DEBUG_CHAN(ftdmchan,"Found user supplied Calling Sub-Address value \"%s\"\n", clg_subAddr); + + /* clean out the subAddrIE */ + memset(subAddrIE, 0x0, sizeof(subAddrIE)); + + /* check the first character in the sub-address to see what type of encoding to use */ + switch (clg_subAddr[0]) { + case '0': /* NSAP */ + encode_subAddrIE_nsap(&clg_subAddr[1], subAddrIE, SNG_CALLING); + break; + case '1': /* national variant */ + encode_subAddrIE_nat(&clg_subAddr[1], subAddrIE, SNG_CALLING); + break; + default: + SS7_ERROR_CHAN(ftdmchan,"Invalid Calling Sub-Address encoding requested: %c\n", clg_subAddr[0]); + break; + } /* switch (cld_subAddr[0]) */ + + + /* if subaddIE is still empty don't copy it in */ + if (subAddrIE[0] != '0') { + /* check if the clg_subAddr has already been added */ + if (iam.accTrnspt.eh.pres == PRSNT_NODEF) { + /* append the subAddrIE */ + memcpy(&iam.accTrnspt.infoElmts.val[iam.accTrnspt.infoElmts.len], subAddrIE, (subAddrIE[1] + 2)); + iam.accTrnspt.infoElmts.len = iam.accTrnspt.infoElmts.len +subAddrIE[1] + 2; + } else { + /* fill in from the beginning */ + iam.accTrnspt.eh.pres = PRSNT_NODEF; + iam.accTrnspt.infoElmts.pres = PRSNT_NODEF; + memcpy(iam.accTrnspt.infoElmts.val, subAddrIE, (subAddrIE[1] + 2)); + iam.accTrnspt.infoElmts.len = subAddrIE[1] + 2; + } /* if (iam.accTrnspt.eh.pres */ + } /* if (subAddrIE[0] != '0') */ + } + + /* check if the user would like us to send a cld_sub-address */ + cld_subAddr = ftdm_channel_get_var(ftdmchan, "ss7_cld_subaddr"); + if ((cld_subAddr != NULL) && (*cld_subAddr)) { + SS7_DEBUG_CHAN(ftdmchan,"Found user supplied Called Sub-Address value \"%s\"\n", cld_subAddr); + + /* clean out the subAddrIE */ + memset(subAddrIE, 0x0, sizeof(subAddrIE)); + + /* check the first character in the sub-address to see what type of encoding to use */ + switch (cld_subAddr[0]) { + case '0': /* NSAP */ + encode_subAddrIE_nsap(&cld_subAddr[1], subAddrIE, SNG_CALLED); + break; + case '1': /* national variant */ + encode_subAddrIE_nat(&cld_subAddr[1], subAddrIE, SNG_CALLED); + break; + default: + SS7_ERROR_CHAN(ftdmchan,"Invalid Called Sub-Address encoding requested: %c\n", cld_subAddr[0]); + break; + } /* switch (cld_subAddr[0]) */ + + /* if subaddIE is still empty don't copy it in */ + if (subAddrIE[0] != '0') { + /* check if the cld_subAddr has already been added */ + if (iam.accTrnspt.eh.pres == PRSNT_NODEF) { + /* append the subAddrIE */ + memcpy(&iam.accTrnspt.infoElmts.val[iam.accTrnspt.infoElmts.len], subAddrIE, (subAddrIE[1] + 2)); + iam.accTrnspt.infoElmts.len = iam.accTrnspt.infoElmts.len +subAddrIE[1] + 2; + } else { + /* fill in from the beginning */ + iam.accTrnspt.eh.pres = PRSNT_NODEF; + iam.accTrnspt.infoElmts.pres = PRSNT_NODEF; + memcpy(iam.accTrnspt.infoElmts.val, subAddrIE, (subAddrIE[1] + 2)); + iam.accTrnspt.infoElmts.len = subAddrIE[1] + 2; + } /* if (iam.accTrnspt.eh.pres */ + } /* if (subAddrIE[0] != '0') */ + } /* if ((cld_subAddr != NULL) && (*cld_subAddr)) */ + + + + sng_cc_con_request (sngss7_info->spId, sngss7_info->suInstId, sngss7_info->spInstId, @@ -226,7 +308,8 @@ void ft_to_sngss7_acm (ftdm_channel_t * ftdmchan) { SS7_FUNC_TRACE_ENTER (__FUNCTION__); - sngss7_chan_data_t *sngss7_info = ftdmchan->call_data; + sngss7_chan_data_t *sngss7_info = ftdmchan->call_data; + sng_isup_inf_t *isup_intf = &g_ftdm_sngss7_data.cfg.isupIntf[sngss7_info->circuit->infId]; SiCnStEvnt acm; memset (&acm, 0x0, sizeof (acm)); @@ -255,7 +338,18 @@ void ft_to_sngss7_acm (ftdm_channel_t * ftdmchan) acm.bckCallInd.echoCtrlDevInd.val = 0x1; /* ec device present */ acm.bckCallInd.sccpMethInd.pres = PRSNT_NODEF; acm.bckCallInd.sccpMethInd.val = SCCPMTH_NOIND; - + + /* fill in any optional parameters */ + if (sngss7_test_options(isup_intf, SNGSS7_ACM_OBCI_BITA)) { + acm.optBckCalInd.eh.pres = PRSNT_NODEF; + acm.optBckCalInd.inbndInfoInd.pres = PRSNT_NODEF; + acm.optBckCalInd.inbndInfoInd.val = sngss7_test_options(isup_intf, SNGSS7_ACM_OBCI_BITA); + acm.optBckCalInd.caFwdMayOcc.pres = PRSNT_DEF; + acm.optBckCalInd.simpleSegmInd.pres = PRSNT_DEF; + acm.optBckCalInd.mlppUserInd.pres = PRSNT_DEF; + acm.optBckCalInd.usrNetIneractInd.pres = PRSNT_DEF; + } /* if (sngss7_test_options(isup_intf, SNGSS7_ACM_OBCI_BITA)) */ + /* send the ACM request to LibSngSS7 */ sng_cc_con_status (1, sngss7_info->suInstId, diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_sta.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_sta.c index d238462046..1235238452 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_sta.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_sta.c @@ -50,27 +50,41 @@ int ftmod_ss7_mtplinkSet_sta(uint32_t id, SnMngmt *cfm); int ftmod_ss7_mtplink_sta(uint32_t id, SnMngmt *cfm) { SnMngmt sta; + Pst pst; memset(&sta, 0x0, sizeof(sta)); + /* initalize the post structure */ + smPstInit(&pst); + + /* insert the destination Entity */ + pst.dstEnt = ENTSN; + sta.hdr.elmId.elmnt = STDLSAP; sta.hdr.elmId.elmntInst1 = g_ftdm_sngss7_data.cfg.mtpLink[id].id; - return(sng_sta_mtp3(&sta, cfm)); + return(sng_sta_mtp3(&pst, &sta, cfm)); } /******************************************************************************/ int ftmod_ss7_mtplinkSet_sta(uint32_t id, SnMngmt *cfm) { SnMngmt sta; + Pst pst; memset(&sta, 0x0, sizeof(sta)); + /* initalize the post structure */ + smPstInit(&pst); + + /* insert the destination Entity */ + pst.dstEnt = ENTSN; + sta.hdr.elmId.elmnt = STLNKSET; sta.hdr.elmId.elmntInst1 = g_ftdm_sngss7_data.cfg.mtpLinkSet[id].id; sta.hdr.elmId.elmntInst2 = g_ftdm_sngss7_data.cfg.mtpLinkSet[id].links[0]; - return(sng_sta_mtp3(&sta, cfm)); + return(sng_sta_mtp3(&pst, &sta, cfm)); } /******************************************************************************/ diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c index 41db1fe140..718663950a 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c @@ -71,6 +71,9 @@ ftdm_status_t clear_tx_rsc_flags(sngss7_chan_data_t *sngss7_info); ftdm_status_t clear_rx_grs_data(sngss7_chan_data_t *sngss7_info); ftdm_status_t clear_rx_gra_data(sngss7_chan_data_t *sngss7_info); ftdm_status_t clear_tx_grs_data(sngss7_chan_data_t *sngss7_info); + +ftdm_status_t encode_subAddrIE_nsap(const char *subAddr, char *subAddrIE, int type); +ftdm_status_t encode_subAddrIE_nat(const char *subAddr, char *subAddrIE, int type); /******************************************************************************/ /* FUNCTIONS ******************************************************************/ @@ -884,6 +887,214 @@ ftdm_status_t clear_tx_rsc_flags(sngss7_chan_data_t *sngss7_info) } /******************************************************************************/ +ftdm_status_t encode_subAddrIE_nsap(const char *subAddr, char *subAddrIE, int type) +{ + /* Q931 4.5.9 + * 8 7 6 5 4 3 2 1 (octet) + * + * 0 1 1 1 0 0 0 1 (spare 8) ( IE id 1-7) + * X X X X X X X X (length of IE contents) + * 1 0 0 0 Z 0 0 0 (ext 8) (NSAP type 5-7) (odd/even 4) (spare 1-3) + * X X X X X X X X (sub address encoded in ia5) + */ + + int x = 0; + int p = 0; + int len = 0; + char tmp[2]; + + /* initalize the second element of tmp to \0 so that atoi doesn't go to far */ + tmp[1]='\0'; + + /* set octet 1 aka IE id */ + p = 0; + switch(type) { + /**************************************************************************/ + case SNG_CALLED: /* called party sub address */ + subAddrIE[p] = 0x71; + break; + /**************************************************************************/ + case SNG_CALLING: /* calling party sub address */ + subAddrIE[p] = 0x6d; + break; + /**************************************************************************/ + default: /* not good */ + SS7_ERROR("Sub-Address type is invalid: %d\n", type); + return FTDM_FAIL; + break; + /**************************************************************************/ + } /* switch(type) */ + + /* set octet 3 aka type and o/e */ + p = 2; + subAddrIE[p] = 0x80; + + /* set the subAddrIE pointer octet 4 */ + p = 3; + + /* loop through all digits in subAddr and insert them into subAddrIE */ + while (subAddr[x] != '\0') { + + /* grab a character */ + tmp[0] = subAddr[x]; + + /* confirm it is a digit */ + if (!isdigit(tmp[0])) { + /* move to the next character in subAddr */ + x++; + + /* restart the loop */ + continue; + } + + /* convert the character to IA5 encoding and write into subAddrIE */ + subAddrIE[p] = atoi(&tmp[0]); /* lower nibble is the digit */ + subAddrIE[p] |= 0x3 << 4; /* upper nibble is 0x3 */ + + /* increment address length counter */ + len++; + + /* increment the subAddrIE pointer */ + p++; + + /* move to the next character in subAddr */ + x++; + + } /* while (subAddr[x] != '\0') */ + + /* set octet 2 aka length of subaddr */ + p = 1; + subAddrIE[p] = len + 1; + + + return FTDM_SUCCESS; +} + +/******************************************************************************/ +ftdm_status_t encode_subAddrIE_nat(const char *subAddr, char *subAddrIE, int type) +{ + /* Q931 4.5.9 + * 8 7 6 5 4 3 2 1 (octet) + * + * 0 1 1 1 0 0 0 1 (spare 8) ( IE id 1-7) + * X X X X X X X X (length of IE contents) + * 1 0 0 0 Z 0 0 0 (ext 8) (NSAP type 5-7) (odd/even 4) (spare 1-3) + * X X X X X X X X (sub address encoded in ia5) + */ + + int x = 0; + int p = 0; + int len = 0; + char tmp[2]; + int flag = 0; + int odd = 0; + uint8_t lower = 0x0; + uint8_t upper = 0x0; + + /* initalize the second element of tmp to \0 so that atoi doesn't go to far */ + tmp[1]='\0'; + + /* set octet 1 aka IE id */ + p = 0; + switch(type) { + /**************************************************************************/ + case SNG_CALLED: /* called party sub address */ + subAddrIE[p] = 0x71; + break; + /**************************************************************************/ + case SNG_CALLING: /* calling party sub address */ + subAddrIE[p] = 0x6d; + break; + /**************************************************************************/ + default: /* not good */ + SS7_ERROR("Sub-Address type is invalid: %d\n", type); + return FTDM_FAIL; + break; + /**************************************************************************/ + } /* switch(type) */ + + /* set the subAddrIE pointer octet 4 */ + p = 3; + + /* loop through all digits in subAddr and insert them into subAddrIE */ + while (1) { + + /* grab a character */ + tmp[0] = subAddr[x]; + + /* confirm it is a hex digit */ + while ((!isxdigit(tmp[0])) && (tmp[0] != '\0')) { + /* move to the next character in subAddr */ + x++; + tmp[0] = subAddr[x]; + } + + /* check if tmp is null or a digit */ + if (tmp[0] != '\0') { + /* push it into the lower nibble using strtol to allow a-f chars */ + lower = strtol(&tmp[0], (char **)NULL, 16); + /* move to the next digit */ + x++; + /* grab a digit from the ftdm digits */ + tmp[0] = subAddr[x]; + + /* check if the digit is a hex digit and that is not null */ + while (!(isxdigit(tmp[0])) && (tmp[0] != '\0')) { + x++; + tmp[0] = subAddr[x]; + } /* while(!(isdigit(tmp))) */ + + /* check if tmp is null or a digit */ + if (tmp[0] != '\0') { + /* push the digit into the upper nibble using strtol to allow a-f chars */ + upper = (strtol(&tmp[0], (char **)NULL, 16)) << 4; + } else { + /* there is no upper ... fill in spare */ + upper = 0x00; + /* throw the odd flag since we need to buffer */ + odd = 1; + /* throw the end flag */ + flag = 1; + } /* if (tmp != '\0') */ + } else { + /* keep the odd flag down */ + odd = 0; + + /* throw the flag */ + flag = 1; + + /* bounce out right away */ + break; + } + + /* fill in the octet */ + subAddrIE[p] = upper | lower; + + /* increment address length counter */ + len++; + + /* if the flag is we're through all the digits */ + if (flag) break; + + /* increment the subAddrIE pointer */ + p++; + + /* move to the next character in subAddr */ + x++; + + } /* while (subAddr[x] != '\0') */ + + /* set octet 2 aka length of subaddr */ + p = 1; + subAddrIE[p] = len + 1; + + /* set octet 3 aka type and o/e */ + p = 2; + subAddrIE[p] = 0xa0 | (odd << 3); + + + return FTDM_SUCCESS; +} /******************************************************************************/ /* For Emacs: 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 842782052d..0f81d61f25 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 @@ -47,6 +47,23 @@ typedef struct sng_timeslot int hole; }sng_timeslot_t; +typedef struct sng_isupCkt +{ + ftdm_span_t *span; + uint32_t cicbase; + uint32_t typeCntrl; + char ch_map[MAX_CIC_MAP_LENGTH]; + uint32_t isupInf; + uint32_t t3; + uint32_t t12; + uint32_t t13; + uint32_t t14; + uint32_t t15; + uint32_t t16; + uint32_t t17; + uint32_t tval; +} sng_isupCkt_t; + int cmbLinkSetId; /******************************************************************************/ @@ -77,7 +94,7 @@ static int ftmod_ss7_fill_in_isap(sng_isap_t *sng_isap); static int ftmod_ss7_fill_in_self_route(int spc, int linkType, int switchType, int ssf); -static int ftmod_ss7_fill_in_circuits(char *ch_map, int cicbase, int typeCntrl, int isup_id, ftdm_span_t *span); +static int ftmod_ss7_fill_in_circuits(sng_isupCkt_t *isupCkt); static int ftmod_ss7_next_timeslot(char *ch_map, sng_timeslot_t *timeslot); /******************************************************************************/ @@ -91,9 +108,10 @@ int ftmod_ss7_parse_xml(ftdm_conf_parameter_t *ftdm_parameters, ftdm_span_t *spa const char *val = NULL; ftdm_conf_node_t *ptr = NULL; sng_route_t self_route; - char ch_map[MAX_CIC_MAP_LENGTH]; - int typeCntrl = 0; - int cicbase = 0; + sng_isupCkt_t isupCkt; + + /* clean out the isup ckt */ + memset(&isupCkt, 0x0, sizeof(sng_isupCkt_t)); /* clean out the self route */ memset(&self_route, 0x0, sizeof(sng_route_t)); @@ -124,24 +142,24 @@ int ftmod_ss7_parse_xml(ftdm_conf_parameter_t *ftdm_parameters, ftdm_span_t *spa if (!strcasecmp(var, "ch_map")) { /**********************************************************************/ - strcpy(ch_map, val); - SS7_DEBUG("\tFound channel map \"%s\"\n", ch_map); + strcpy(isupCkt.ch_map, val); + SS7_DEBUG("\tFound channel map \"%s\"\n", isupCkt.ch_map); /**********************************************************************/ } else if (!strcasecmp(var, "typeCntrl")) { if (!strcasecmp(val, "bothway")) { - typeCntrl = BOTHWAY; + isupCkt.typeCntrl = BOTHWAY; SS7_DEBUG("\tFound control type \"bothway\"\n"); } else if (!strcasecmp(val, "incoming")) { - typeCntrl = INCOMING; + isupCkt.typeCntrl = INCOMING; SS7_DEBUG("\tFound control type \"incoming\"\n"); } else if (!strcasecmp(val, "outgoing")) { - typeCntrl = OUTGOING; + isupCkt.typeCntrl = OUTGOING; SS7_DEBUG("\tFound control type \"outgoing\"\n"); } else if (!strcasecmp(val, "controlled")) { - typeCntrl = CONTROLLED; + isupCkt.typeCntrl = CONTROLLED; SS7_DEBUG("\tFound control type \"controlled\"\n"); } else if (!strcasecmp(val, "controlling")) { - typeCntrl = CONTROLLING; + isupCkt.typeCntrl = CONTROLLING; SS7_DEBUG("\tFound control type \"controlling\"\n"); } else { SS7_ERROR("Found invalid circuit control type \"%s\"!", val); @@ -149,8 +167,8 @@ int ftmod_ss7_parse_xml(ftdm_conf_parameter_t *ftdm_parameters, ftdm_span_t *spa } /**********************************************************************/ } else if (!strcasecmp(var, "cicbase")) { - cicbase = atoi(val); - SS7_DEBUG("\tFound cicbase = %d\n", cicbase); + isupCkt.cicbase = atoi(val); + SS7_DEBUG("\tFound cicbase = %d\n", isupCkt.cicbase); /**********************************************************************/ } else if (!strcasecmp(var, "dialplan")) { /* do i give a shit about this??? */ @@ -169,7 +187,41 @@ int ftmod_ss7_parse_xml(ftdm_conf_parameter_t *ftdm_parameters, ftdm_span_t *spa /* move on to the next one */ x++; } - SS7_DEBUG("\tFound isup_interface = %s\n",g_ftdm_sngss7_data.cfg.isupIntf[x].name ); + + isupCkt.isupInf = x; + SS7_DEBUG("\tFound isup_interface = %s\n",g_ftdm_sngss7_data.cfg.isupIntf[x].name); + /**********************************************************************/ + } else if (!strcasecmp(var, "isup.t3")) { + isupCkt.t3 = atoi(val); + SS7_DEBUG("\tFound isup t3 = \"%d\"\n", isupCkt.t3); + /**********************************************************************/ + } else if (!strcasecmp(var, "isup.t12")) { + isupCkt.t12 = atoi(val); + SS7_DEBUG("\tFound isup t12 = \"%d\"\n", isupCkt.t12); + /**********************************************************************/ + } else if (!strcasecmp(var, "isup.t13")) { + isupCkt.t13 = atoi(val); + SS7_DEBUG("\tFound isup t13 = \"%d\"\n", isupCkt.t13); + /**********************************************************************/ + } else if (!strcasecmp(var, "isup.t14")) { + isupCkt.t14 = atoi(val); + SS7_DEBUG("\tFound isup t14 = \"%d\"\n", isupCkt.t14); + /**********************************************************************/ + } else if (!strcasecmp(var, "isup.t15")) { + isupCkt.t15 = atoi(val); + SS7_DEBUG("\tFound isup t15 = \"%d\"\n", isupCkt.t15); + /**********************************************************************/ + } else if (!strcasecmp(var, "isup.t16")) { + isupCkt.t16 = atoi(val); + SS7_DEBUG("\tFound isup t16 = \"%d\"\n", isupCkt.t16); + /**********************************************************************/ + } else if (!strcasecmp(var, "isup.t17")) { + isupCkt.t17 = atoi(val); + SS7_DEBUG("\tFound isup t17 = \"%d\"\n", isupCkt.t17); + /**********************************************************************/ + } else if (!strcasecmp(var, "isup.tval")) { + isupCkt.tval = atoi(val); + SS7_DEBUG("\tFound isup tval = \"%d\"\n", isupCkt.tval); /**********************************************************************/ } else { SS7_ERROR("Unknown parameter found =\"%s\"...ignoring it!\n", var); @@ -192,10 +244,11 @@ int ftmod_ss7_parse_xml(ftdm_conf_parameter_t *ftdm_parameters, ftdm_span_t *spa } + /* fill the pointer to span into isupCkt */ + isupCkt.span = span; /* setup the circuits structure */ - if(ftmod_ss7_fill_in_circuits(ch_map, cicbase, typeCntrl, - g_ftdm_sngss7_data.cfg.isupIntf[x].id, span)) { + if(ftmod_ss7_fill_in_circuits(&isupCkt)) { SS7_ERROR("Failed to fill in circuits structure!\n"); goto ftmod_ss7_parse_xml_error; } @@ -582,6 +635,130 @@ static int ftmod_ss7_parse_mtp_link(ftdm_conf_node_t *mtp_link, sng_mtp_link_t * mtpLink->mtp3.slc = atoi(parm->val); SS7_DEBUG("\tFound mtpLink->slc = \"%d\"\n",mtpLink->mtp3.slc); /**********************************************************************/ + } else if (!strcasecmp(parm->var, "mtp2.t1")) { + mtpLink->mtp2.t1 = atoi(parm->val); + SS7_DEBUG("\tFound mtp2 t1 = \"%d\"\n",mtpLink->mtp2.t1); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "mtp2.t2")) { + mtpLink->mtp2.t2 = atoi(parm->val); + SS7_DEBUG("\tFound mtp2 t2 = \"%d\"\n",mtpLink->mtp2.t2); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "mtp2.t3")) { + mtpLink->mtp2.t3 = atoi(parm->val); + SS7_DEBUG("\tFound mtp2 t3 = \"%d\"\n",mtpLink->mtp2.t3); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "mtp2.t4n")) { + mtpLink->mtp2.t4n = atoi(parm->val); + SS7_DEBUG("\tFound mtp2 t4n = \"%d\"\n",mtpLink->mtp2.t4n); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "mtp2.t4e")) { + mtpLink->mtp2.t4e = atoi(parm->val); + SS7_DEBUG("\tFound mtp2 t4e = \"%d\"\n",mtpLink->mtp2.t4e); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "mtp2.t5")) { + mtpLink->mtp2.t5 = atoi(parm->val); + SS7_DEBUG("\tFound mtp2 t5 = \"%d\"\n",mtpLink->mtp2.t5); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "mtp2.t6")) { + mtpLink->mtp2.t6 = atoi(parm->val); + SS7_DEBUG("\tFound mtp2 t6 = \"%d\"\n",mtpLink->mtp2.t6); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "mtp2.t7")) { + mtpLink->mtp2.t7 = atoi(parm->val); + SS7_DEBUG("\tFound mtp2 t7 = \"%d\"\n",mtpLink->mtp2.t7); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "mtp3.t1")) { + mtpLink->mtp3.t1 = atoi(parm->val); + SS7_DEBUG("\tFound mtp3 t1 = \"%d\"\n",mtpLink->mtp3.t1); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "mtp3.t2")) { + mtpLink->mtp3.t2 = atoi(parm->val); + SS7_DEBUG("\tFound mtp3 t2 = \"%d\"\n",mtpLink->mtp3.t2); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "mtp3.t3")) { + mtpLink->mtp3.t3 = atoi(parm->val); + SS7_DEBUG("\tFound mtp3 t3 = \"%d\"\n",mtpLink->mtp3.t3); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "mtp3.t4")) { + mtpLink->mtp3.t4 = atoi(parm->val); + SS7_DEBUG("\tFound mtp3 t4 = \"%d\"\n",mtpLink->mtp3.t4); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "mtp3.t5")) { + mtpLink->mtp3.t5 = atoi(parm->val); + SS7_DEBUG("\tFound mtp3 t5 = \"%d\"\n",mtpLink->mtp3.t5); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "mtp3.t7")) { + mtpLink->mtp3.t7 = atoi(parm->val); + SS7_DEBUG("\tFound mtp3 t7 = \"%d\"\n",mtpLink->mtp3.t7); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "mtp3.t12")) { + mtpLink->mtp3.t12 = atoi(parm->val); + SS7_DEBUG("\tFound mtp3 t12 = \"%d\"\n",mtpLink->mtp3.t12); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "mtp3.t13")) { + mtpLink->mtp3.t13 = atoi(parm->val); + SS7_DEBUG("\tFound mtp3 t13 = \"%d\"\n",mtpLink->mtp3.t13); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "mtp3.t14")) { + mtpLink->mtp3.t14 = atoi(parm->val); + SS7_DEBUG("\tFound mtp3 t14 = \"%d\"\n",mtpLink->mtp3.t14); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "mtp3.t17")) { + mtpLink->mtp3.t17 = atoi(parm->val); + SS7_DEBUG("\tFound mtp3 t17 = \"%d\"\n",mtpLink->mtp3.t17); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "mtp3.t22")) { + mtpLink->mtp3.t22 = atoi(parm->val); + SS7_DEBUG("\tFound mtp3 t22 = \"%d\"\n",mtpLink->mtp3.t22); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "mtp3.t23")) { + mtpLink->mtp3.t23 = atoi(parm->val); + SS7_DEBUG("\tFound mtp3 t23 = \"%d\"\n",mtpLink->mtp3.t23); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "mtp3.t24")) { + mtpLink->mtp3.t24 = atoi(parm->val); + SS7_DEBUG("\tFound mtp3 t24 = \"%d\"\n",mtpLink->mtp3.t24); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "mtp3.t31")) { + mtpLink->mtp3.t31 = atoi(parm->val); + SS7_DEBUG("\tFound mtp3 t31 = \"%d\"\n",mtpLink->mtp3.t31); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "mtp3.t32")) { + mtpLink->mtp3.t32 = atoi(parm->val); + SS7_DEBUG("\tFound mtp3 t32 = \"%d\"\n",mtpLink->mtp3.t32); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "mtp3.t33")) { + mtpLink->mtp3.t33 = atoi(parm->val); + SS7_DEBUG("\tFound mtp3 t33 = \"%d\"\n",mtpLink->mtp3.t33); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "mtp3.t34")) { + mtpLink->mtp3.t34 = atoi(parm->val); + SS7_DEBUG("\tFound mtp3 t34 = \"%d\"\n",mtpLink->mtp3.t34); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "mtp3.t35")) { + mtpLink->mtp3.t35 = atoi(parm->val); + SS7_DEBUG("\tFound mtp3 t35 = \"%d\"\n",mtpLink->mtp3.t35); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "mtp3.t36")) { + mtpLink->mtp3.t36 = atoi(parm->val); + SS7_DEBUG("\tFound mtp3 t36 = \"%d\"\n",mtpLink->mtp3.t36); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "mtp3.t37")) { + mtpLink->mtp3.t37 = atoi(parm->val); + SS7_DEBUG("\tFound mtp3 t37 = \"%d\"\n",mtpLink->mtp3.t37); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "mtp3.tcraft")) { + mtpLink->mtp3.tcraft = atoi(parm->val); + SS7_DEBUG("\tFound mtp3 tcraft = \"%d\"\n",mtpLink->mtp3.tcraft); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "mtp3.tflc")) { + mtpLink->mtp3.tflc = atoi(parm->val); + SS7_DEBUG("\tFound mtp3 tflc = \"%d\"\n",mtpLink->mtp3.tflc); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "mtp3.tbnd")) { + mtpLink->mtp3.tbnd = atoi(parm->val); + SS7_DEBUG("\tFound mtp3 tbnd = \"%d\"\n",mtpLink->mtp3.tbnd); + /**********************************************************************/ } else { SS7_ERROR("\tFound an invalid parameter \"%s\"!\n", parm->val); return FTDM_FAIL; @@ -697,6 +874,50 @@ static int ftmod_ss7_parse_mtp_route(ftdm_conf_node_t *mtp_route) return FTDM_FAIL; } /**********************************************************************/ + } else if (!strcasecmp(parm->var, "mtp3.t6")) { + mtpRoute.t6 = atoi(parm->val); + SS7_DEBUG("\tFound mtp3 t6 = \"%d\"\n",mtpRoute.t6); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "mtp3.t8")) { + mtpRoute.t8 = atoi(parm->val); + SS7_DEBUG("\tFound mtp3 t8 = \"%d\"\n",mtpRoute.t8); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "mtp3.t10")) { + mtpRoute.t10 = atoi(parm->val); + SS7_DEBUG("\tFound mtp3 t10 = \"%d\"\n",mtpRoute.t10); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "mtp3.t11")) { + mtpRoute.t11 = atoi(parm->val); + SS7_DEBUG("\tFound mtp3 t11 = \"%d\"\n",mtpRoute.t11); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "mtp3.t15")) { + mtpRoute.t15 = atoi(parm->val); + SS7_DEBUG("\tFound mtp3 t15 = \"%d\"\n",mtpRoute.t15); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "mtp3.t16")) { + mtpRoute.t16 = atoi(parm->val); + SS7_DEBUG("\tFound mtp3 t16 = \"%d\"\n",mtpRoute.t16); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "mtp3.t18")) { + mtpRoute.t18 = atoi(parm->val); + SS7_DEBUG("\tFound mtp3 t18 = \"%d\"\n",mtpRoute.t18); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "mtp3.t19")) { + mtpRoute.t19 = atoi(parm->val); + SS7_DEBUG("\tFound mtp3 t19 = \"%d\"\n",mtpRoute.t19); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "mtp3.t21")) { + mtpRoute.t21 = atoi(parm->val); + SS7_DEBUG("\tFound mtp3 t21 = \"%d\"\n",mtpRoute.t21); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "mtp3.t25")) { + mtpRoute.t25 = atoi(parm->val); + SS7_DEBUG("\tFound mtp3 t25 = \"%d\"\n",mtpRoute.t25); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "mtp3.t26")) { + mtpRoute.t26 = atoi(parm->val); + SS7_DEBUG("\tFound mtp3 t26 = \"%d\"\n",mtpRoute.t26); + /**********************************************************************/ } else { SS7_ERROR("\tFound an invalid parameter \"%s\"!\n", parm->val); return FTDM_FAIL; @@ -842,6 +1063,178 @@ static int ftmod_ss7_parse_isup_interface(ftdm_conf_node_t *isup_interface) 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); /**********************************************************************/ + } else if (!strcasecmp(parm->var, "isup.t1")) { + sng_isap.t1 = atoi(parm->val); + SS7_DEBUG("\tFound isup t1 = \"%d\"\n",sng_isap.t1); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "isup.t2")) { + sng_isap.t2 = atoi(parm->val); + SS7_DEBUG("\tFound isup t2 = \"%d\"\n",sng_isap.t2); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "isup.t4")) { + sng_isup.t4 = atoi(parm->val); + SS7_DEBUG("\tFound isup t4 = \"%d\"\n",sng_isup.t4); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "isup.t5")) { + sng_isap.t5 = atoi(parm->val); + SS7_DEBUG("\tFound isup t5 = \"%d\"\n",sng_isap.t5); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "isup.t6")) { + sng_isap.t6 = atoi(parm->val); + SS7_DEBUG("\tFound isup t6 = \"%d\"\n",sng_isap.t6); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "isup.t7")) { + sng_isap.t7 = atoi(parm->val); + SS7_DEBUG("\tFound isup t7 = \"%d\"\n",sng_isap.t7); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "isup.t8")) { + sng_isap.t8 = atoi(parm->val); + SS7_DEBUG("\tFound isup t8 = \"%d\"\n",sng_isap.t8); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "isup.t9")) { + sng_isap.t9 = atoi(parm->val); + SS7_DEBUG("\tFound isup t9 = \"%d\"\n",sng_isap.t9); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "isup.t10")) { + sng_isup.t10 = atoi(parm->val); + SS7_DEBUG("\tFound isup t10 = \"%d\"\n",sng_isup.t10); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "isup.t11")) { + sng_isup.t11 = atoi(parm->val); + SS7_DEBUG("\tFound isup t11 = \"%d\"\n",sng_isup.t11); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "isup.t18")) { + sng_isup.t18 = atoi(parm->val); + SS7_DEBUG("\tFound isup t18 = \"%d\"\n",sng_isup.t18); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "isup.t19")) { + sng_isup.t19 = atoi(parm->val); + SS7_DEBUG("\tFound isup t19 = \"%d\"\n",sng_isup.t19); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "isup.t20")) { + sng_isup.t20 = atoi(parm->val); + SS7_DEBUG("\tFound isup t20 = \"%d\"\n",sng_isup.t20); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "isup.t21")) { + sng_isup.t21 = atoi(parm->val); + SS7_DEBUG("\tFound isup t21 = \"%d\"\n",sng_isup.t21); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "isup.t22")) { + sng_isup.t22 = atoi(parm->val); + SS7_DEBUG("\tFound isup t22 = \"%d\"\n",sng_isup.t22); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "isup.t23")) { + sng_isup.t23 = atoi(parm->val); + SS7_DEBUG("\tFound isup t23 = \"%d\"\n",sng_isup.t23); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "isup.t24")) { + sng_isup.t24 = atoi(parm->val); + SS7_DEBUG("\tFound isup t24 = \"%d\"\n",sng_isup.t24); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "isup.t25")) { + sng_isup.t25 = atoi(parm->val); + SS7_DEBUG("\tFound isup t25 = \"%d\"\n",sng_isup.t25); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "isup.t26")) { + sng_isup.t26 = atoi(parm->val); + SS7_DEBUG("\tFound isup t26 = \"%d\"\n",sng_isup.t26); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "isup.t28")) { + sng_isup.t28 = atoi(parm->val); + SS7_DEBUG("\tFound isup t28 = \"%d\"\n",sng_isup.t28); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "isup.t29")) { + sng_isup.t29 = atoi(parm->val); + SS7_DEBUG("\tFound isup t29 = \"%d\"\n",sng_isup.t29); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "isup.t30")) { + sng_isup.t30 = atoi(parm->val); + SS7_DEBUG("\tFound isup t30 = \"%d\"\n",sng_isup.t30); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "isup.t31")) { + sng_isap.t31 = atoi(parm->val); + SS7_DEBUG("\tFound isup t31 = \"%d\"\n",sng_isap.t31); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "isup.t32")) { + sng_isup.t32 = atoi(parm->val); + SS7_DEBUG("\tFound isup t32 = \"%d\"\n",sng_isup.t32); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "isup.t33")) { + sng_isap.t33 = atoi(parm->val); + SS7_DEBUG("\tFound isup t33 = \"%d\"\n",sng_isap.t33); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "isup.t34")) { + sng_isap.t34 = atoi(parm->val); + SS7_DEBUG("\tFound isup t34 = \"%d\"\n",sng_isap.t34); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "isup.t35")) { + sng_isup.t35 = atoi(parm->val); + SS7_DEBUG("\tFound isup t35 = \"%d\"\n",sng_isup.t35); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "isup.t36")) { + sng_isap.t36 = atoi(parm->val); + SS7_DEBUG("\tFound isup t36 = \"%d\"\n",sng_isap.t36); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "isup.t37")) { + sng_isup.t37 = atoi(parm->val); + SS7_DEBUG("\tFound isup t37 = \"%d\"\n",sng_isup.t37); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "isup.t38")) { + sng_isup.t38 = atoi(parm->val); + SS7_DEBUG("\tFound isup t38 = \"%d\"\n",sng_isup.t38); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "isup.t39")) { + sng_isup.t39 = atoi(parm->val); + SS7_DEBUG("\tFound isup t39 = \"%d\"\n",sng_isup.t39); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "isup.tccr")) { + sng_isap.tccr = atoi(parm->val); + SS7_DEBUG("\tFound isup tccr = \"%d\"\n",sng_isap.tccr); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "isup.tccrt")) { + sng_isap.tccrt = atoi(parm->val); + SS7_DEBUG("\tFound isup tccrt = \"%d\"\n",sng_isap.tccrt); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "isup.tex")) { + sng_isap.tex = atoi(parm->val); + SS7_DEBUG("\tFound isup tex = \"%d\"\n",sng_isap.tex); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "isup.tect")) { + sng_isap.tect = atoi(parm->val); + SS7_DEBUG("\tFound isup tect = \"%d\"\n",sng_isap.tect); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "isup.tcrm")) { + sng_isap.tcrm = atoi(parm->val); + SS7_DEBUG("\tFound isup tcrm = \"%d\"\n",sng_isap.tcrm); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "isup.tcra")) { + sng_isap.tcra = atoi(parm->val); + SS7_DEBUG("\tFound isup tcra = \"%d\"\n",sng_isap.tcra); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "isup.tfgr")) { + sng_isup.tfgr = atoi(parm->val); + SS7_DEBUG("\tFound isup tfgr = \"%d\"\n",sng_isup.tfgr); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "isup.trelrsp")) { + sng_isap.trelrsp = atoi(parm->val); + SS7_DEBUG("\tFound isup trelrsp = \"%d\"\n",sng_isap.trelrsp); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "isup.tfnlrelrsp")) { + sng_isap.tfnlrelrsp = atoi(parm->val); + SS7_DEBUG("\tFound isup tfnlrelrsp = \"%d\"\n",sng_isap.tfnlrelrsp); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "isup.tfnlrelrsp")) { + sng_isap.tfnlrelrsp = atoi(parm->val); + SS7_DEBUG("\tFound isup tfnlrelrsp = \"%d\"\n",sng_isap.tfnlrelrsp); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "isup.tpause")) { + sng_isup.tpause = atoi(parm->val); + SS7_DEBUG("\tFound isup tpause = \"%d\"\n",sng_isup.tpause); + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "isup.tstaenq")) { + sng_isup.tstaenq = atoi(parm->val); + SS7_DEBUG("\tFound isup tstaenq = \"%d\"\n",sng_isup.tstaenq); + /**********************************************************************/ } else if (!strcasecmp(parm->var, "clg_nadi")) { /**********************************************************************/ /* throw the flag so that we know we got this optional parameter */ @@ -856,6 +1249,30 @@ static int ftmod_ss7_parse_isup_interface(ftdm_conf_node_t *isup_interface) sng_isup.cld_nadi = atoi(parm->val); SS7_DEBUG("\tFound default CLD_NADI value = %d\n", sng_isup.cld_nadi); /**********************************************************************/ + } else if (!strcasecmp(parm->var, "obci_bita")) { + /**********************************************************************/ + if (*parm->val == '1') { + sngss7_set_options(&sng_isup, SNGSS7_ACM_OBCI_BITA); + SS7_DEBUG("\tFound Optional Backwards Indicator: Bit A (early media) enable option\n"); + } else if (*parm->val == '0') { + sngss7_clear_options(&sng_isup, SNGSS7_ACM_OBCI_BITA); + SS7_DEBUG("\tFound Optional Backwards Indicator: Bit A (early media) disable option\n"); + } else { + SS7_DEBUG("\tInvalid value for \"obci_bita\" option\n"); + } + /**********************************************************************/ + } else if (!strcasecmp(parm->var, "lpa_on_cot")) { + /**********************************************************************/ + if (*parm->val == '1') { + sngss7_set_options(&sng_isup, SNGSS7_LPA_FOR_COT); + SS7_DEBUG("\tFound Tx LPA on COT enable option\n"); + } else if (*parm->val == '0') { + sngss7_clear_options(&sng_isup, SNGSS7_LPA_FOR_COT); + SS7_DEBUG("\tFound Tx LPA on COT disable option\n"); + } else { + SS7_DEBUG("\tInvalid value for \"lpa_on_cot\" option\n"); + } + /**********************************************************************/ } else { SS7_ERROR("\tFound an invalid parameter \"%s\"!\n", parm->val); return FTDM_FAIL; @@ -1278,7 +1695,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].options = sng_isup->options; if (sng_isup->t4 != 0) { g_ftdm_sngss7_data.cfg.isupIntf[i].t4 = sng_isup->t4; } else { @@ -1573,7 +1990,7 @@ static int ftmod_ss7_fill_in_self_route(int spc, int linkType, int switchType, i } /******************************************************************************/ -static int ftmod_ss7_fill_in_circuits(char *ch_map, int cicbase, int typeCntrl, int isup_id, ftdm_span_t *span) +static int ftmod_ss7_fill_in_circuits(sng_isupCkt_t *isupCkt) { sngss7_chan_data_t *ss7_info = NULL; ftdm_channel_t *ftdmchan = NULL; @@ -1584,10 +2001,10 @@ static int ftmod_ss7_fill_in_circuits(char *ch_map, int cicbase, int typeCntrl, count = 1; - while (ch_map[0] != '\0') { + while (isupCkt->ch_map[0] != '\0') { /* pull out the next timeslot */ - if (ftmod_ss7_next_timeslot(ch_map, ×lot)) { + if (ftmod_ss7_next_timeslot(isupCkt->ch_map, ×lot)) { SS7_ERROR("Failed to parse the channel map!\n"); return FTDM_FAIL; } @@ -1597,10 +2014,10 @@ static int ftmod_ss7_fill_in_circuits(char *ch_map, int cicbase, int typeCntrl, x = 1; while (g_ftdm_sngss7_data.cfg.isupCkt[x].id != 0) { if ((g_ftdm_sngss7_data.cfg.isupCkt[x].chan == count) && - (g_ftdm_sngss7_data.cfg.isupCkt[x].span == span->channels[1]->physical_span_id)) { + (g_ftdm_sngss7_data.cfg.isupCkt[x].span == isupCkt->span->channels[1]->physical_span_id)) { SS7_DEVEL_DEBUG("Circuit for span=%d, chan=%d is already exists...id=%d\n", - span->channels[1]->physical_span_id, + isupCkt->span->channels[1]->physical_span_id, count, x); @@ -1614,7 +2031,7 @@ static int ftmod_ss7_fill_in_circuits(char *ch_map, int cicbase, int typeCntrl, /* check why we exited the while loop */ if (g_ftdm_sngss7_data.cfg.isupCkt[x].id == 0) { SS7_DEVEL_DEBUG("Circuit for span=%d, chan=%d is new...id=%d\n", - span->channels[1]->physical_span_id, + isupCkt->span->channels[1]->physical_span_id, count, x); @@ -1625,7 +2042,7 @@ static int ftmod_ss7_fill_in_circuits(char *ch_map, int cicbase, int typeCntrl, /* circuit is new so fill in the needed information */ g_ftdm_sngss7_data.cfg.isupCkt[x].id = x; - g_ftdm_sngss7_data.cfg.isupCkt[x].span = span->channels[1]->physical_span_id; + g_ftdm_sngss7_data.cfg.isupCkt[x].span = isupCkt->span->channels[1]->physical_span_id; g_ftdm_sngss7_data.cfg.isupCkt[x].chan = count; if (timeslot.siglink) { g_ftdm_sngss7_data.cfg.isupCkt[x].type = SIG; @@ -1634,22 +2051,14 @@ static int ftmod_ss7_fill_in_circuits(char *ch_map, int cicbase, int typeCntrl, } if (timeslot.channel) { - g_ftdm_sngss7_data.cfg.isupCkt[x].cic = cicbase; - cicbase++; + g_ftdm_sngss7_data.cfg.isupCkt[x].cic = isupCkt->cicbase; + isupCkt->cicbase++; } else { g_ftdm_sngss7_data.cfg.isupCkt[x].cic = 0; } - g_ftdm_sngss7_data.cfg.isupCkt[x].infId = isup_id; - g_ftdm_sngss7_data.cfg.isupCkt[x].typeCntrl = typeCntrl; - g_ftdm_sngss7_data.cfg.isupCkt[x].t3 = 1200; - g_ftdm_sngss7_data.cfg.isupCkt[x].t12 = 300; - g_ftdm_sngss7_data.cfg.isupCkt[x].t13 = 3000; - g_ftdm_sngss7_data.cfg.isupCkt[x].t14 = 300; - g_ftdm_sngss7_data.cfg.isupCkt[x].t15 = 3000; - g_ftdm_sngss7_data.cfg.isupCkt[x].t16 = 300; - g_ftdm_sngss7_data.cfg.isupCkt[x].t17 = 3000; - g_ftdm_sngss7_data.cfg.isupCkt[x].tval = 10; - g_ftdm_sngss7_data.cfg.isupCkt[x].ssf = g_ftdm_sngss7_data.cfg.isupIntf[isup_id].ssf; + g_ftdm_sngss7_data.cfg.isupCkt[x].infId = isupCkt->isupInf; + g_ftdm_sngss7_data.cfg.isupCkt[x].typeCntrl = isupCkt->typeCntrl; + g_ftdm_sngss7_data.cfg.isupCkt[x].ssf = g_ftdm_sngss7_data.cfg.isupIntf[isupCkt->isupInf].ssf; g_ftdm_sngss7_data.cfg.isupCkt[x].obj = ss7_info; } /* if (g_ftdm_sngss7_data.cfg.isupCkt[x].id == 0) */ @@ -1660,26 +2069,26 @@ static int ftmod_ss7_fill_in_circuits(char *ch_map, int cicbase, int typeCntrl, } else { /* if ((timeslot.siglink) || (timeslot.gap)) */ /* find the ftdm the channel structure for this channel*/ i = 1; - while (span->channels[i] != NULL) { - if (span->channels[i]->physical_chan_id == timeslot.channel) { + while (isupCkt->span->channels[i] != NULL) { + if (isupCkt->span->channels[i]->physical_chan_id == timeslot.channel) { break; } i++; } /* while (span->channels[i] != NULL) */ - if (span->channels[i] == NULL) { + if (isupCkt->span->channels[i] == NULL) { /* we weren't able to find the channel in the ftdm channels */ SS7_ERROR("Unable to find the requested channel %d in the FreeTDM channels!\n", timeslot.channel); return FTDM_FAIL; } else { - ftdmchan = span->channels[i]; + ftdmchan = isupCkt->span->channels[i]; } /* try to find a match for the physical span and chan */ x = 1; while (g_ftdm_sngss7_data.cfg.isupCkt[x].id != 0) { - if ((g_ftdm_sngss7_data.cfg.isupCkt[x].chan == ftdmchan->physical_chan_id) - && (g_ftdm_sngss7_data.cfg.isupCkt[x].span == ftdmchan->physical_span_id)) { + if ((g_ftdm_sngss7_data.cfg.isupCkt[x].chan == ftdmchan->physical_chan_id) && + (g_ftdm_sngss7_data.cfg.isupCkt[x].span == ftdmchan->physical_span_id)) { /* we have a match so this circuit already exists in the structure */ break; @@ -1702,33 +2111,65 @@ static int ftmod_ss7_fill_in_circuits(char *ch_map, int cicbase, int typeCntrl, ftdmchan->call_data = ss7_info; /* prepare the timer structures */ - ss7_info->t35.sched = ((sngss7_span_data_t *)span->mod_data)->sched; + ss7_info->t35.sched = ((sngss7_span_data_t *)isupCkt->span->mod_data)->sched; ss7_info->t35.counter = 1; - ss7_info->t35.beat = g_ftdm_sngss7_data.cfg.isupIntf[isup_id].t35*100; /* beat is in ms, t35 is in 100ms */ + ss7_info->t35.beat = g_ftdm_sngss7_data.cfg.isupIntf[isupCkt->isupInf].t35*100; /* beat is in ms, t35 is in 100ms */ ss7_info->t35.callback = handle_isup_t35; ss7_info->t35.sngss7_info = ss7_info; /* circuit is new so fill in the needed information */ - g_ftdm_sngss7_data.cfg.isupCkt[x].id = x; + g_ftdm_sngss7_data.cfg.isupCkt[x].id = x; g_ftdm_sngss7_data.cfg.isupCkt[x].span = ftdmchan->physical_span_id; g_ftdm_sngss7_data.cfg.isupCkt[x].chan = ftdmchan->physical_chan_id; g_ftdm_sngss7_data.cfg.isupCkt[x].type = VOICE; - g_ftdm_sngss7_data.cfg.isupCkt[x].cic = cicbase; - g_ftdm_sngss7_data.cfg.isupCkt[x].infId = isup_id; - g_ftdm_sngss7_data.cfg.isupCkt[x].typeCntrl = typeCntrl; - g_ftdm_sngss7_data.cfg.isupCkt[x].t3 = 1200; - g_ftdm_sngss7_data.cfg.isupCkt[x].t12 = 300; - g_ftdm_sngss7_data.cfg.isupCkt[x].t13 = 3000; - g_ftdm_sngss7_data.cfg.isupCkt[x].t14 = 300; - g_ftdm_sngss7_data.cfg.isupCkt[x].t15 = 3000; - g_ftdm_sngss7_data.cfg.isupCkt[x].t16 = 300; - g_ftdm_sngss7_data.cfg.isupCkt[x].t17 = 3000; - g_ftdm_sngss7_data.cfg.isupCkt[x].tval = 10; + g_ftdm_sngss7_data.cfg.isupCkt[x].cic = isupCkt->cicbase; + g_ftdm_sngss7_data.cfg.isupCkt[x].infId = isupCkt->isupInf; + g_ftdm_sngss7_data.cfg.isupCkt[x].typeCntrl = isupCkt->typeCntrl; + if (isupCkt->t3 == 0) { + g_ftdm_sngss7_data.cfg.isupCkt[x].t3 = 1200; + } else { + g_ftdm_sngss7_data.cfg.isupCkt[x].t3 = isupCkt->t3; + } + if (isupCkt->t12 == 0) { + g_ftdm_sngss7_data.cfg.isupCkt[x].t12 = 300; + } else { + g_ftdm_sngss7_data.cfg.isupCkt[x].t12 = isupCkt->t12; + } + if (isupCkt->t13 == 0) { + g_ftdm_sngss7_data.cfg.isupCkt[x].t13 = 3000; + } else { + g_ftdm_sngss7_data.cfg.isupCkt[x].t13 = isupCkt->t13; + } + if (isupCkt->t14 == 0) { + g_ftdm_sngss7_data.cfg.isupCkt[x].t14 = 300; + } else { + g_ftdm_sngss7_data.cfg.isupCkt[x].t14 = isupCkt->t14; + } + if (isupCkt->t15 == 0) { + g_ftdm_sngss7_data.cfg.isupCkt[x].t15 = 3000; + } else { + g_ftdm_sngss7_data.cfg.isupCkt[x].t15 = isupCkt->t15; + } + if (isupCkt->t16 == 0) { + g_ftdm_sngss7_data.cfg.isupCkt[x].t16 = 300; + } else { + g_ftdm_sngss7_data.cfg.isupCkt[x].t16 = isupCkt->t16; + } + if (isupCkt->t17 == 0) { + g_ftdm_sngss7_data.cfg.isupCkt[x].t17 = 3000; + } else { + g_ftdm_sngss7_data.cfg.isupCkt[x].t17 = isupCkt->t17; + } + if (isupCkt->tval == 0) { + g_ftdm_sngss7_data.cfg.isupCkt[x].tval = 10; + } else { + g_ftdm_sngss7_data.cfg.isupCkt[x].tval = isupCkt->tval; + } g_ftdm_sngss7_data.cfg.isupCkt[x].obj = ss7_info; - g_ftdm_sngss7_data.cfg.isupCkt[x].ssf = g_ftdm_sngss7_data.cfg.isupIntf[isup_id].ssf; + g_ftdm_sngss7_data.cfg.isupCkt[x].ssf = g_ftdm_sngss7_data.cfg.isupIntf[isupCkt->isupInf].ssf; /* increment the cicbase */ - cicbase++; + isupCkt->cicbase++; } else { /* if (g_ftdm_sngss7_data.cfg.isupCkt[x].id == 0) */ SS7_DEBUG("Circuit for span=%d, chan=%d is new...id=%d\n", ftdmchan->physical_span_id, @@ -1774,12 +2215,12 @@ static int ftmod_ss7_fill_in_circuits(char *ch_map, int cicbase, int typeCntrl, /******************************************************************************/ static int ftmod_ss7_next_timeslot(char *ch_map, sng_timeslot_t *timeslot) { - int i; - int x; - int lower; - int upper; - char tmp[5]; /*KONRAD FIX ME*/ - char new_ch_map[MAX_CIC_LENGTH]; + int i; + int x; + int lower; + int upper; + char tmp[5]; /*KONRAD FIX ME*/ + char new_ch_map[MAX_CIC_LENGTH]; memset(&tmp[0], '\0', sizeof(tmp)); memset(&new_ch_map[0], '\0', sizeof(new_ch_map)); diff --git a/libs/spandsp/src/spandsp/t38_core.h b/libs/spandsp/src/spandsp/t38_core.h index 1476969eeb..3d8e864513 100644 --- a/libs/spandsp/src/spandsp/t38_core.h +++ b/libs/spandsp/src/spandsp/t38_core.h @@ -286,7 +286,7 @@ SPAN_DECLARE(int) t38_core_send_data_multi_field(t38_core_state_t *s, int data_t \param len The length of the packet contents. \param seq_no The packet sequence number. \return 0 for OK, else -1. */ -SPAN_DECLARE(int) t38_core_rx_ifp_packet(t38_core_state_t *s, const uint8_t *buf, int len, uint16_t seq_no); +SPAN_DECLARE_NONSTD(int) t38_core_rx_ifp_packet(t38_core_state_t *s, const uint8_t *buf, int len, uint16_t seq_no); /*! Set the method to be used for data rate management, as per the T.38 spec. \param s The T.38 context. diff --git a/libs/spandsp/src/t38_core.c b/libs/spandsp/src/t38_core.c index 551d6c0155..e7ee967e93 100644 --- a/libs/spandsp/src/t38_core.c +++ b/libs/spandsp/src/t38_core.c @@ -325,7 +325,7 @@ static __inline__ int classify_seq_no_offset(int expected, int actual) } /*- End of function --------------------------------------------------------*/ -SPAN_DECLARE(int) t38_core_rx_ifp_packet(t38_core_state_t *s, const uint8_t *buf, int len, uint16_t seq_no) +SPAN_DECLARE_NONSTD(int) t38_core_rx_ifp_packet(t38_core_state_t *s, const uint8_t *buf, int len, uint16_t seq_no) { int i; int t30_indicator; diff --git a/src/include/private/switch_core_pvt.h b/src/include/private/switch_core_pvt.h index e77d5f74ef..ea02f22fa0 100644 --- a/src/include/private/switch_core_pvt.h +++ b/src/include/private/switch_core_pvt.h @@ -167,6 +167,7 @@ struct switch_core_session { uint32_t track_id; switch_log_level_t loglevel; uint32_t soft_lock; + switch_ivr_dmachine_t *dmachine; }; struct switch_media_bug { @@ -198,6 +199,7 @@ struct switch_runtime { int64_t offset; switch_event_t *global_vars; switch_hash_t *mime_types; + switch_hash_t *ptimes; switch_memory_pool_t *memory_pool; const switch_state_handler_table_t *state_handlers[SWITCH_MAX_STATE_HANDLERS]; int state_handler_index; diff --git a/src/include/switch_core.h b/src/include/switch_core.h index 466dc51186..3f636d00c4 100644 --- a/src/include/switch_core.h +++ b/src/include/switch_core.h @@ -704,7 +704,8 @@ SWITCH_DECLARE(switch_log_level_t) switch_core_session_get_loglevel(switch_core_ SWITCH_DECLARE(void) switch_core_session_soft_lock(switch_core_session_t *session, uint32_t sec); SWITCH_DECLARE(void) switch_core_session_soft_unlock(switch_core_session_t *session); - +SWITCH_DECLARE(void) switch_core_session_set_dmachine(switch_core_session_t *session, switch_ivr_dmachine_t *dmachine); +SWITCH_DECLARE(switch_ivr_dmachine_t *) switch_core_session_get_dmachine(switch_core_session_t *session); /*! \brief Retrieve the unique identifier from the core @@ -2167,6 +2168,7 @@ SWITCH_DECLARE(uint32_t) switch_core_debug_level(void); SWITCH_DECLARE(void) switch_cache_db_flush_handles(void); SWITCH_DECLARE(const char *) switch_core_banner(void); SWITCH_DECLARE(switch_bool_t) switch_core_session_in_thread(switch_core_session_t *session); +SWITCH_DECLARE(uint32_t) switch_default_ptime(const char *name, uint32_t number); SWITCH_END_EXTERN_C #endif diff --git a/src/include/switch_ivr.h b/src/include/switch_ivr.h index 5fee7baefa..fb023848ec 100644 --- a/src/include/switch_ivr.h +++ b/src/include/switch_ivr.h @@ -557,6 +557,7 @@ SWITCH_DECLARE(uint32_t) switch_ivr_schedule_broadcast(time_t runtime, const cha \return SWITCH_STATUS_SUCCESS if all is well */ SWITCH_DECLARE(switch_status_t) switch_ivr_broadcast(const char *uuid, const char *path, switch_media_flag_t flags); +SWITCH_DECLARE(void) switch_ivr_broadcast_in_thread(switch_core_session_t *session, const char *app, int flags); /*! \brief Transfer variables from one session to another @@ -845,24 +846,31 @@ SWITCH_DECLARE(switch_bool_t) switch_ivr_uuid_exists(const char *uuid); SWITCH_DECLARE(switch_status_t) switch_ivr_dmachine_create(switch_ivr_dmachine_t **dmachine_p, - switch_memory_pool_t *pool, - uint32_t digit_timeout, uint32_t input_timeout); + const char *name, + switch_memory_pool_t *pool, + uint32_t digit_timeout, uint32_t input_timeout, + switch_ivr_dmachine_callback_t match_callback, + switch_ivr_dmachine_callback_t nonmatch_callback, + void *user_data); SWITCH_DECLARE(void) switch_ivr_dmachine_destroy(switch_ivr_dmachine_t **dmachine); SWITCH_DECLARE(switch_status_t) switch_ivr_dmachine_bind(switch_ivr_dmachine_t *dmachine, - const char *digits, - int32_t key, - switch_ivr_dmachine_callback_t callback, - void *user_data); + const char *realm, + const char *digits, + int32_t key, + switch_ivr_dmachine_callback_t callback, + void *user_data); SWITCH_DECLARE(switch_status_t) switch_ivr_dmachine_feed(switch_ivr_dmachine_t *dmachine, const char *digits, switch_ivr_dmachine_match_t **match); SWITCH_DECLARE(switch_status_t) switch_ivr_dmachine_clear(switch_ivr_dmachine_t *dmachine); SWITCH_DECLARE(switch_status_t) switch_ivr_dmachine_ping(switch_ivr_dmachine_t *dmachine, switch_ivr_dmachine_match_t **match_p); SWITCH_DECLARE(switch_ivr_dmachine_match_t *) switch_ivr_dmachine_get_match(switch_ivr_dmachine_t *dmachine); - - - +SWITCH_DECLARE(const char *) switch_ivr_dmachine_get_failed_digits(switch_ivr_dmachine_t *dmachine); +SWITCH_DECLARE(void) switch_ivr_dmachine_set_digit_timeout_ms(switch_ivr_dmachine_t *dmachine, uint32_t digit_timeout_ms); +SWITCH_DECLARE(void) switch_ivr_dmachine_set_input_timeout_ms(switch_ivr_dmachine_t *dmachine, uint32_t input_timeout_ms); +SWITCH_DECLARE(switch_status_t) switch_ivr_dmachine_clear_realm(switch_ivr_dmachine_t *dmachine, const char *realm); +SWITCH_DECLARE(switch_status_t) switch_ivr_dmachine_set_realm(switch_ivr_dmachine_t *dmachine, const char *realm); /** @} */ diff --git a/src/include/switch_types.h b/src/include/switch_types.h index 32fb141d42..b1fc627354 100644 --- a/src/include/switch_types.h +++ b/src/include/switch_types.h @@ -123,6 +123,7 @@ SWITCH_BEGIN_EXTERN_C #define SWITCH_CURRENT_APPLICATION_VARIABLE "current_application" #define SWITCH_CURRENT_APPLICATION_DATA_VARIABLE "current_application_data" #define SWITCH_CURRENT_APPLICATION_RESPONSE_VARIABLE "current_application_response" +#define SWITCH_PASSTHRU_PTIME_MISMATCH_VARIABLE "passthru_ptime_mismatch" #define SWITCH_ENABLE_HEARTBEAT_EVENTS_VARIABLE "enable_heartbeat_events" #define SWITCH_BYPASS_MEDIA_AFTER_BRIDGE_VARIABLE "bypass_media_after_bridge" #define SWITCH_READ_RESULT_VARIABLE "read_result" @@ -189,9 +190,14 @@ SWITCH_BEGIN_EXTERN_C #define SWITCH_DTMF_LOG_LEN 1000 typedef uint8_t switch_byte_t; +typedef enum { + DTMF_FLAG_SKIP_PROCESS = (1 << 0) +} dtmf_flag_t; + typedef struct { char digit; uint32_t duration; + int32_t flags; } switch_dtmf_t; typedef enum { @@ -1055,6 +1061,8 @@ typedef enum { CF_EARLY_HANGUP, CF_MEDIA_SET, CF_CONSUME_ON_ORIGINATE, + CF_PASSTHRU_PTIME_MISMATCH, + CF_BRIDGE_NOWRITE, /* WARNING: DO NOT ADD ANY FLAGS BELOW THIS LINE */ CF_FLAG_MAX } switch_channel_flag_t; @@ -1686,6 +1694,13 @@ typedef switch_status_t (*switch_input_callback_function_t) (switch_core_session typedef switch_status_t (*switch_read_frame_callback_function_t) (switch_core_session_t *session, switch_frame_t *frame, void *user_data); typedef struct switch_say_interface switch_say_interface_t; +#define DMACHINE_MAX_DIGIT_LEN 512 + +typedef enum { + DM_MATCH_POSITIVE, + DM_MATCH_NEGATIVE +} dm_match_type_t; + struct switch_ivr_dmachine; typedef struct switch_ivr_dmachine switch_ivr_dmachine_t; @@ -1693,6 +1708,7 @@ struct switch_ivr_dmachine_match { switch_ivr_dmachine_t *dmachine; const char *match_digits; int32_t match_key; + dm_match_type_t type; void *user_data; }; diff --git a/src/include/switch_utils.h b/src/include/switch_utils.h index e5d70c43cc..945583ee07 100644 --- a/src/include/switch_utils.h +++ b/src/include/switch_utils.h @@ -376,15 +376,6 @@ switch_mutex_unlock(obj->flag_mutex); #define switch_set_string(_dst, _src) switch_copy_string(_dst, _src, sizeof(_dst)) -static inline uint32_t switch_default_ptime(const char *name, uint32_t number) -{ - if (!strcasecmp(name, "G723")) { - return 30; - } - - return 20; -} - static inline char *switch_sanitize_number(char *number) { char *p = number, *q; diff --git a/src/mod/applications/mod_conference/mod_conference.c b/src/mod/applications/mod_conference/mod_conference.c index e1570a7af5..ed62da107b 100644 --- a/src/mod/applications/mod_conference/mod_conference.c +++ b/src/mod/applications/mod_conference/mod_conference.c @@ -2580,7 +2580,10 @@ static void conference_loop_output(conference_member_t *member) if (member->fnode) { member_add_file_data(member, write_frame.data, write_frame.datalen); } - switch_core_session_write_frame(member->session, &write_frame, SWITCH_IO_FLAG_NONE, 0); + if (switch_core_session_write_frame(member->session, &write_frame, SWITCH_IO_FLAG_NONE, 0) != SWITCH_STATUS_SUCCESS) { + switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); + break; + } } } @@ -2590,7 +2593,10 @@ static void conference_loop_output(conference_member_t *member) write_frame.samples = samples; memset(write_frame.data, 255, write_frame.datalen); member_add_file_data(member, write_frame.data, write_frame.datalen); - switch_core_session_write_frame(member->session, &write_frame, SWITCH_IO_FLAG_NONE, 0); + if (switch_core_session_write_frame(member->session, &write_frame, SWITCH_IO_FLAG_NONE, 0) != SWITCH_STATUS_SUCCESS) { + switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); + break; + } } else if (!switch_test_flag(member->conference, CFLAG_WASTE_BANDWIDTH)) { if (switch_test_flag(member, MFLAG_WASTE_BANDWIDTH)) { if (member->conference->comfort_noise_level) { @@ -2603,7 +2609,10 @@ static void conference_loop_output(conference_member_t *member) write_frame.samples = samples; write_frame.timestamp = timer.samplecount; - switch_core_session_write_frame(member->session, &write_frame, SWITCH_IO_FLAG_NONE, 0); + if (switch_core_session_write_frame(member->session, &write_frame, SWITCH_IO_FLAG_NONE, 0) != SWITCH_STATUS_SUCCESS) { + switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); + break; + } } } diff --git a/src/mod/applications/mod_distributor/mod_distributor.2010.vcxproj b/src/mod/applications/mod_distributor/mod_distributor.2010.vcxproj new file mode 100644 index 0000000000..368cfa18d7 --- /dev/null +++ b/src/mod/applications/mod_distributor/mod_distributor.2010.vcxproj @@ -0,0 +1,130 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + mod_distributor + {5C2B4D88-3BEA-4FE0-90DF-FA9836099D5F} + mod_distributor + 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} + + + + + + \ No newline at end of file diff --git a/src/mod/applications/mod_dptools/mod_dptools.c b/src/mod/applications/mod_dptools/mod_dptools.c index 9fb6b1b454..06f545928d 100755 --- a/src/mod/applications/mod_dptools/mod_dptools.c +++ b/src/mod/applications/mod_dptools/mod_dptools.c @@ -95,6 +95,176 @@ SWITCH_STANDARD_DIALPLAN(inline_dialplan_hunt) return extension; } +struct action_binding { + char *realm; + char *input; + char *string; + char *value; + switch_core_session_t *session; +}; + +static switch_status_t digit_nomatch_action_callback(switch_ivr_dmachine_match_t *match) +{ + switch_core_session_t *session = (switch_core_session_t *) match->user_data; + switch_channel_t *channel = switch_core_session_get_channel(session); + char str[DMACHINE_MAX_DIGIT_LEN + 2]; + switch_event_t *event; + switch_status_t status; + + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s Digit NOT match binding [%s]\n", + switch_channel_get_name(channel), match->match_digits); + + if (switch_event_create_plain(&event, SWITCH_EVENT_CHANNEL_DATA) == SWITCH_STATUS_SUCCESS) { + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "digits", match->match_digits); + + if ((status = switch_core_session_queue_event(session, &event)) != SWITCH_STATUS_SUCCESS) { + switch_event_destroy(&event); + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "%s event queue faiure.\n", + switch_core_session_get_name(session)); + } + } + + /* send it back around flagged to skip the dmachine */ + switch_snprintf(str, sizeof(str), "!%s", match->match_digits); + + switch_channel_queue_dtmf_string(channel, str); + + return SWITCH_STATUS_SUCCESS; +} + +static switch_status_t digit_action_callback(switch_ivr_dmachine_match_t *match) +{ + struct action_binding *act = (struct action_binding *) match->user_data; + switch_event_t *event; + switch_status_t status; + int exec = 0; + char *string = act->string; + switch_channel_t *channel = switch_core_session_get_channel(act->session); + + if (switch_event_create_plain(&event, SWITCH_EVENT_CHANNEL_DATA) == SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(act->session), SWITCH_LOG_DEBUG, "%s Digit match binding [%s][%s]\n", + switch_channel_get_name(channel), act->string, act->value); + + if (!strncasecmp(string, "exec:", 5)) { + string += 5; + exec = 1; + } + + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, string, act->value); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "digits", match->match_digits); + + if (exec) { + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "execute", exec == 2 ? "non-blocking" : "blocking"); + } + + if ((status = switch_core_session_queue_event(act->session, &event)) != SWITCH_STATUS_SUCCESS) { + switch_event_destroy(&event); + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(act->session), SWITCH_LOG_WARNING, "%s event queue faiure.\n", + switch_core_session_get_name(act->session)); + } + } + + if (exec) { + char *cmd = switch_core_session_sprintf(act->session, "%s::%s", string, act->value); + switch_ivr_broadcast_in_thread(act->session, cmd, SMF_ECHO_ALEG|SMF_HOLD_BLEG); + } + + return SWITCH_STATUS_SUCCESS; +} + +#define CLEAR_DIGIT_ACTION_USAGE "|all" +SWITCH_STANDARD_APP(clear_digit_action_function) +{ + //switch_channel_t *channel = switch_core_session_get_channel(session); + switch_ivr_dmachine_t *dmachine; + char *realm = (char *) data; + + if ((dmachine = switch_core_session_get_dmachine(session))) { + if (zstr(realm) || !strcasecmp(realm, "all")) { + switch_core_session_set_dmachine(session, NULL); + switch_ivr_dmachine_destroy(&dmachine); + } else { + switch_ivr_dmachine_clear_realm(dmachine, realm); + } + } +} + +#define DIGIT_ACTION_SET_REALM_USAGE "" +SWITCH_STANDARD_APP(digit_action_set_realm_function) +{ + switch_ivr_dmachine_t *dmachine; + char *realm = (char *) data; + + if (zstr(data)) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Syntax Error, USAGE %s\n", DIGIT_ACTION_SET_REALM_USAGE); + return; + } + + if ((dmachine = switch_core_session_get_dmachine(session))) { + switch_ivr_dmachine_set_realm(dmachine, realm); + } + +} + +#define BIND_DIGIT_ACTION_USAGE ",,," +SWITCH_STANDARD_APP(bind_digit_action_function) +{ + switch_channel_t *channel = switch_core_session_get_channel(session); + switch_ivr_dmachine_t *dmachine; + char *mydata; + int argc = 0; + char *argv[4] = { 0 }; + struct action_binding *act; + + if (zstr(data)) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Syntax Error, USAGE %s\n", BIND_DIGIT_ACTION_USAGE); + return; + } + + mydata = switch_core_session_strdup(session, data); + + argc = switch_separate_string(mydata, ',', argv, (sizeof(argv) / sizeof(argv[0]))); + + if (argc < 4 || zstr(argv[0]) || zstr(argv[1]) || zstr(argv[2]) || zstr(argv[3])) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Syntax Error, USAGE %s\n", BIND_DIGIT_ACTION_USAGE); + return; + } + + + if (!(dmachine = switch_core_session_get_dmachine(session))) { + uint32_t digit_timeout = 1500; + uint32_t input_timeout = 0; + const char *var; + uint32_t tmp; + + if ((var = switch_channel_get_variable(channel, "bind_digit_digit_timeout"))) { + tmp = (uint32_t) atol(var); + if (tmp < 0) tmp = 0; + digit_timeout = tmp; + } + + if ((var = switch_channel_get_variable(channel, "bind_digit_input_timeout"))) { + tmp = (uint32_t) atol(var); + if (tmp < 0) tmp = 0; + input_timeout = tmp; + } + + switch_ivr_dmachine_create(&dmachine, "DPTOOLS", NULL, digit_timeout, input_timeout, NULL, digit_nomatch_action_callback, session); + switch_core_session_set_dmachine(session, dmachine); + } + + + act = switch_core_session_alloc(session, sizeof(*act)); + act->realm = argv[0]; + act->input = argv[1]; + act->string = argv[2]; + act->value = argv[3]; + act->session = session; + + switch_ivr_dmachine_bind(dmachine, act->realm, act->input, 0, digit_action_callback, act); +} + + #define DETECT_SPEECH_SYNTAX " [] OR grammar [] OR pause OR resume" SWITCH_STANDARD_APP(detect_speech_function) { @@ -3277,6 +3447,17 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_dptools_load) SWITCH_ADD_API(api_interface, "chat", "chat", chat_api_function, "||||[]"); SWITCH_ADD_API(api_interface, "strftime", "strftime", strftime_api_function, ""); SWITCH_ADD_API(api_interface, "presence", "presence", presence_api_function, PRESENCE_USAGE); + + SWITCH_ADD_APP(app_interface, "bind_digit_action", "bind a key sequence or regex to an action", + "bind a key sequence or regex to an action", bind_digit_action_function, BIND_DIGIT_ACTION_USAGE, SAF_SUPPORT_NOMEDIA); + + SWITCH_ADD_APP(app_interface, "clear_digit_action", "clear all digit bindings", "", + clear_digit_action_function, CLEAR_DIGIT_ACTION_USAGE, SAF_SUPPORT_NOMEDIA); + + SWITCH_ADD_APP(app_interface, "digit_action_set_realm", "change binding realm", "", + digit_action_set_realm_function, DIGIT_ACTION_SET_REALM_USAGE, SAF_SUPPORT_NOMEDIA); + + SWITCH_ADD_APP(app_interface, "privacy", "Set privacy on calls", "Set caller privacy on calls.", privacy_function, "off|on|name|full|number", SAF_SUPPORT_NOMEDIA); diff --git a/src/mod/applications/mod_redis/mod_redis.c b/src/mod/applications/mod_redis/mod_redis.c index 75dfd6fdd7..d20ab934f3 100755 --- a/src/mod/applications/mod_redis/mod_redis.c +++ b/src/mod/applications/mod_redis/mod_redis.c @@ -34,7 +34,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_redis_load); SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_redis_shutdown); -SWITCH_MODULE_DEFINITION(mod_redis, mod_redis_load, NULL, mod_redis_shutdown); +SWITCH_MODULE_DEFINITION(mod_redis, mod_redis_load, mod_redis_shutdown, NULL); static struct{ char *host; diff --git a/src/mod/applications/mod_voicemail/mod_voicemail.c b/src/mod/applications/mod_voicemail/mod_voicemail.c index 860f89788b..758e5dcf25 100644 --- a/src/mod/applications/mod_voicemail/mod_voicemail.c +++ b/src/mod/applications/mod_voicemail/mod_voicemail.c @@ -2317,7 +2317,7 @@ static switch_status_t deliver_vm(vm_profile_t *profile, const char *caller_id_name, const char *caller_id_number, const char *forwarded_by, - switch_bool_t copy, const char *use_uuid) + switch_bool_t copy, const char *use_uuid, switch_core_session_t *session) { char *file_path = NULL, *dir_path = NULL; const char *myid = switch_xml_attr(x_user, "id"); @@ -2342,7 +2342,9 @@ static switch_status_t deliver_vm(vm_profile_t *profile, switch_status_t ret = SWITCH_STATUS_SUCCESS; char *convert_cmd = profile->convert_cmd; char *convert_ext = profile->convert_ext; + int del_file = 0; + if (!params) { switch_event_create(&local_event, SWITCH_EVENT_REQUEST_PARAMS); params = local_event; @@ -2634,14 +2636,35 @@ static switch_status_t deliver_vm(vm_profile_t *profile, } if (!insert_db) { - if (unlink(file_path) != 0) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Failed to delete file [%s]\n", file_path); + del_file = 1; + } + } + + if (session) { + switch_channel_t *channel = switch_core_session_get_channel(session); + const char *vm_cc; + + if ((vm_cc = switch_channel_get_variable(channel, "vm_cc"))) { + char *cmd = switch_core_session_sprintf(session, "%s %s %s '%s' %s@%s %s", + vm_cc, file_path, caller_id_number, caller_id_name, myid, domain_name, read_flags); + + if (voicemail_inject(cmd, session) == SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_NOTICE, "Sent Carbon Copy to %s\n", vm_cc); + } else { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Failed to Carbon Copy to %s\n", vm_cc); } } } + failed: + if (del_file && file_path) { + if (unlink(file_path) != 0) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Failed to delete file [%s]\n", file_path); + } + } + switch_event_destroy(&local_event); switch_safe_free(dir_path); @@ -2785,7 +2808,7 @@ static switch_status_t voicemail_inject(const char *data, switch_core_session_t switch_event_create(&my_params, SWITCH_EVENT_REQUEST_PARAMS); status = deliver_vm(profile, ux, domain, path, 0, read_flags, my_params, pool, cid_name, cid_num, forwarded_by, - SWITCH_TRUE, session ? switch_core_session_get_uuid(session) : NULL); + SWITCH_TRUE, session ? switch_core_session_get_uuid(session) : NULL, NULL); switch_event_destroy(&my_params); } continue; @@ -2794,7 +2817,7 @@ static switch_status_t voicemail_inject(const char *data, switch_core_session_t switch_event_create(&my_params, SWITCH_EVENT_REQUEST_PARAMS); status = deliver_vm(profile, ut, domain, path, 0, read_flags, my_params, pool, cid_name, cid_num, forwarded_by, SWITCH_TRUE, - session ? switch_core_session_get_uuid(session) : NULL); + session ? switch_core_session_get_uuid(session) : NULL, NULL); switch_event_destroy(&my_params); } } @@ -2817,7 +2840,7 @@ static switch_status_t voicemail_inject(const char *data, switch_core_session_t switch_event_create(&my_params, SWITCH_EVENT_REQUEST_PARAMS); status = deliver_vm(profile, ut, domain, path, 0, read_flags, my_params, pool, cid_name, cid_num, forwarded_by, SWITCH_TRUE, - session ? switch_core_session_get_uuid(session) : NULL); + session ? switch_core_session_get_uuid(session) : NULL, NULL); switch_event_destroy(&my_params); } } @@ -2831,7 +2854,7 @@ static switch_status_t voicemail_inject(const char *data, switch_core_session_t switch_event_create(&my_params, SWITCH_EVENT_REQUEST_PARAMS); status = deliver_vm(profile, ut, domain, path, 0, read_flags, my_params, pool, cid_name, cid_num, forwarded_by, SWITCH_TRUE, - session ? switch_core_session_get_uuid(session) : NULL); + session ? switch_core_session_get_uuid(session) : NULL, NULL); switch_event_destroy(&my_params); } else { status = SWITCH_STATUS_FALSE; @@ -2889,7 +2912,7 @@ static switch_status_t voicemail_leave_main(switch_core_session_t *session, vm_p const char *caller_id_number = NULL; switch_xml_t x_user = NULL, x_params = NULL, x_param = NULL; switch_event_t *vars = NULL; - const char *vm_cc = NULL, *vtmp, *vm_ext = NULL; + const char *vtmp, *vm_ext = NULL; int disk_quota = 0; switch_bool_t skip_greeting = switch_true(switch_channel_get_variable(channel, "skip_greeting")); switch_bool_t skip_instructions = switch_true(switch_channel_get_variable(channel, "skip_instructions")); @@ -3175,20 +3198,9 @@ static switch_status_t voicemail_leave_main(switch_core_session_t *session, vm_p switch_channel_get_variables(channel, &vars); status = deliver_vm(profile, x_user, domain_name, file_path, message_len, read_flags, vars, switch_core_session_get_pool(session), caller_id_name, caller_id_number, NULL, SWITCH_FALSE, - session ? switch_core_session_get_uuid(session) : NULL); + session ? switch_core_session_get_uuid(session) : NULL, session); switch_event_destroy(&vars); - if (status == SWITCH_STATUS_SUCCESS) { - if ((vm_cc = switch_channel_get_variable(channel, "vm_cc"))) { - char *cmd = switch_core_session_sprintf(session, "%s %s %s '%s' %s@%s %s", - vm_cc, file_path, caller_id_number, caller_id_name, id, domain_name, read_flags); - - if (voicemail_inject(cmd, session) == SWITCH_STATUS_SUCCESS) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_NOTICE, "Sent Carbon Copy to %s\n", vm_cc); - } else { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Failed to Carbon Copy to %s\n", vm_cc); - } - } - } else { + if (status != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Failed to deliver message\n"); TRY_CODE(switch_ivr_phrase_macro(session, VM_ACK_MACRO, "deleted", NULL, NULL)); } @@ -3213,7 +3225,7 @@ static switch_status_t voicemail_leave_main(switch_core_session_t *session, vm_p #define VM_DESC "voicemail" -#define VM_USAGE "[check|auth] []" +#define VM_USAGE "[check] [auth] []" SWITCH_STANDARD_APP(voicemail_function) { diff --git a/src/mod/codecs/mod_sangoma_codec/mod_sangoma_codec.c b/src/mod/codecs/mod_sangoma_codec/mod_sangoma_codec.c index ae7468ebcc..c84dac4509 100644 --- a/src/mod/codecs/mod_sangoma_codec/mod_sangoma_codec.c +++ b/src/mod/codecs/mod_sangoma_codec/mod_sangoma_codec.c @@ -65,9 +65,6 @@ unsigned long long g_next_session_id = 0; /* hash of sessions (I think a linked list suits better here, but FS does not have the data type) */ static switch_hash_t *g_sessions_hash = NULL; -/* global memory pool provided by FS */ -static switch_memory_pool_t *g_pool = NULL; - typedef struct vocallo_codec_s { int codec_id; /* vocallo codec ID */ int iana; /* IANA code to register in FS */ @@ -450,25 +447,31 @@ static switch_status_t switch_sangoma_encode(switch_codec_t *codec, switch_codec *encoded_data_len = encoded_frame.datalen; } - /* update encoding stats */ - sess->encoder.rx++; - - now_time = switch_micro_time_now(); - if (!sess->encoder.last_rx_time) { - sess->encoder.last_rx_time = now_time; - } else { - difftime = now_time - sess->encoder.last_rx_time; - sess->encoder.avgrxus = sess->encoder.avgrxus ? ((sess->encoder.avgrxus + difftime)/2) : difftime; - sess->encoder.last_rx_time = now_time; - } - - /* check sequence and bump lost rx packets count if needed */ - if (sess->encoder.lastrxseqno >= 0) { - if (encoded_frame.seq > (sess->encoder.lastrxseqno + 2) ) { - sess->encoder.rxlost += encoded_frame.seq - sess->encoder.lastrxseqno - 1; + /* update encoding stats if we received a frame */ + if (*encoded_data_len) { + if (*encoded_data_len != codec->implementation->encoded_bytes_per_packet) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Returning odd encoded frame of %d bytes intead of %d bytes\n", *encoded_data_len, codec->implementation->encoded_bytes_per_packet); } + sess->encoder.rx++; + now_time = switch_micro_time_now(); + if (!sess->encoder.last_rx_time) { + sess->encoder.last_rx_time = now_time; + } else { + difftime = now_time - sess->encoder.last_rx_time; + sess->encoder.avgrxus = sess->encoder.avgrxus ? ((sess->encoder.avgrxus + difftime)/2) : difftime; + sess->encoder.last_rx_time = now_time; + } + + /* check sequence and bump lost rx packets count if needed */ + if (sess->encoder.lastrxseqno >= 0) { + if (encoded_frame.seq > (sess->encoder.lastrxseqno + 2) ) { + sess->encoder.rxlost += encoded_frame.seq - sess->encoder.lastrxseqno - 1; + } + } + sess->encoder.lastrxseqno = encoded_frame.seq; + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "No output from sangoma encoder\n"); } - sess->encoder.lastrxseqno = encoded_frame.seq; return SWITCH_STATUS_SUCCESS; } @@ -573,25 +576,34 @@ static switch_status_t switch_sangoma_decode(switch_codec_t *codec, /* codec ses *decoded_data_len = i * 2; } - /* update decoding stats */ - sess->decoder.rx++; - - now_time = switch_micro_time_now(); - if (!sess->decoder.last_rx_time) { - sess->decoder.last_rx_time = now_time; - } else { - difftime = now_time - sess->decoder.last_rx_time; - sess->decoder.avgrxus = sess->decoder.avgrxus ? ((sess->decoder.avgrxus + difftime)/2) : difftime; - sess->decoder.last_rx_time = now_time; - } - - /* check sequence and bump lost rx packets count if needed */ - if (sess->decoder.lastrxseqno >= 0) { - if (ulaw_frame.seq > (sess->decoder.lastrxseqno + 2) ) { - sess->decoder.rxlost += ulaw_frame.seq - sess->decoder.lastrxseqno - 1; + if (*decoded_data_len) { + if (*decoded_data_len != codec->implementation->decoded_bytes_per_packet) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Returning odd decoded frame of %d bytes intead of %d bytes\n", *decoded_data_len, codec->implementation->decoded_bytes_per_packet); } + /* update decoding stats */ + sess->decoder.rx++; + + now_time = switch_micro_time_now(); + if (!sess->decoder.last_rx_time) { + sess->decoder.last_rx_time = now_time; + } else { + difftime = now_time - sess->decoder.last_rx_time; + sess->decoder.avgrxus = sess->decoder.avgrxus ? ((sess->decoder.avgrxus + difftime)/2) : difftime; + sess->decoder.last_rx_time = now_time; + } + + /* check sequence and bump lost rx packets count if needed */ + if (sess->decoder.lastrxseqno >= 0) { + if (ulaw_frame.seq > (sess->decoder.lastrxseqno + 2) ) { + sess->decoder.rxlost += ulaw_frame.seq - sess->decoder.lastrxseqno - 1; + } + } + sess->decoder.lastrxseqno = ulaw_frame.seq; + } else { + *decoded_data_len = codec->implementation->decoded_bytes_per_packet; + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "No output from sangoma decoder, returning silent frame of %d bytes\n", *decoded_data_len); + memset(dbuf_linear, 0, *decoded_data_len); } - sess->decoder.lastrxseqno = ulaw_frame.seq; return SWITCH_STATUS_SUCCESS; } @@ -740,10 +752,14 @@ SWITCH_STANDARD_API(sangoma_function) stream->write_function(stream, "Failed to find session %lu\n", sessid); goto done; } - stream->write_function(stream, "Session: %lu\n", sessid); + stream->write_function(stream, "Stats for transcoding session: %lu\n", sessid); if (sess->encoder.rxrtp) { stats = switch_rtp_get_stats(sess->encoder.rxrtp, NULL); + stream->write_function(stream, "=== Encoder ===\n"); + + stream->write_function(stream, "Remote address: %s:%d\n\n", switch_rtp_get_remote_host(sess->encoder.rxrtp), switch_rtp_get_remote_port(sess->encoder.rxrtp)); + stream->write_function(stream, "-- Encoder Inbound Stats --\n"); stream->write_function(stream, "Rx Discarded: %lu\n", sess->encoder.rxdiscarded); sangoma_print_stats(stream, &stats->inbound); @@ -752,10 +768,16 @@ SWITCH_STANDARD_API(sangoma_function) stats = switch_rtp_get_stats(sess->encoder.txrtp, NULL); stream->write_function(stream, "-- Encoder Outbound Stats --\n"); sangoma_print_stats(stream, &stats->outbound); + } else { + stream->write_function(stream, "\n=== No Encoder ===\n\n"); } if (sess->decoder.rxrtp) { stats = switch_rtp_get_stats(sess->decoder.rxrtp, NULL); + + stream->write_function(stream, "=== Decoder ===\n"); + stream->write_function(stream, "Remote address: %s:%d\n\n", switch_rtp_get_remote_host(sess->decoder.rxrtp), switch_rtp_get_remote_port(sess->decoder.rxrtp)); + stream->write_function(stream, "-- Decoder Inbound Stats --\n"); stream->write_function(stream, "Rx Discarded: %lu\n", sess->decoder.rxdiscarded); sangoma_print_stats(stream, &stats->inbound); @@ -763,6 +785,8 @@ SWITCH_STANDARD_API(sangoma_function) stats = switch_rtp_get_stats(sess->decoder.txrtp, NULL); stream->write_function(stream, "-- Decoder Outbound Stats --\n"); sangoma_print_stats(stream, &stats->outbound); + } else { + stream->write_function(stream, "\n=== No Decoder ===\n\n"); } } else { stream->write_function(stream, "Unknown Command [%s]\n", argv[0]); @@ -894,8 +918,6 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_sangoma_codec_load) return SWITCH_STATUS_FALSE; } - g_pool = pool; - g_init_cfg.log = sangoma_logger; g_init_cfg.create_rtp = sangoma_create_rtp; g_init_cfg.create_rtp_port = sangoma_create_rtp_port; diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.c b/src/mod/endpoints/mod_sofia/mod_sofia.c index 13d304d9ce..36954d2904 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.c +++ b/src/mod/endpoints/mod_sofia/mod_sofia.c @@ -242,19 +242,18 @@ static switch_status_t sofia_on_execute(switch_core_session_t *session) return SWITCH_STATUS_SUCCESS; } -char *generate_pai_str(switch_core_session_t *session) +char *generate_pai_str(private_object_t *tech_pvt) { - private_object_t *tech_pvt = (private_object_t *) switch_core_session_get_private(session); + switch_core_session_t *session = tech_pvt->session; const char *callee_name = NULL, *callee_number = NULL; const char *var, *header, *ua = switch_channel_get_variable(tech_pvt->channel, "sip_user_agent"); char *pai = NULL; - if (!sofia_test_pflag(tech_pvt->profile, PFLAG_CID_IN_1XX) || + if (!sofia_test_pflag(tech_pvt->profile, PFLAG_PASS_CALLEE_ID) || !sofia_test_pflag(tech_pvt->profile, PFLAG_CID_IN_1XX) || ((var = switch_channel_get_variable(tech_pvt->channel, "sip_cid_in_1xx")) && switch_false(var))) { return NULL; } - if (zstr((callee_name = switch_channel_get_variable(tech_pvt->channel, "effective_callee_id_name"))) && zstr((callee_name = switch_channel_get_variable(tech_pvt->channel, "sip_callee_id_name")))) { callee_name = switch_channel_get_variable(tech_pvt->channel, "callee_id_name"); @@ -521,7 +520,7 @@ switch_status_t sofia_on_hangup(switch_core_session_t *session) switch_channel_set_variable(channel, "sip_hangup_disposition", "send_refuse"); } if (!sofia_test_flag(tech_pvt, TFLAG_BYE)) { - char *cid = generate_pai_str(session); + char *cid = generate_pai_str(tech_pvt); nua_respond(tech_pvt->nh, sip_cause, sip_status_phrase(sip_cause), TAG_IF(!zstr(reason), SIPTAG_REASON_STR(reason)), @@ -703,9 +702,9 @@ static switch_status_t sofia_answer_channel(switch_core_session_t *session) char *extra_headers = sofia_glue_get_extra_headers(channel, SOFIA_SIP_RESPONSE_HEADER_PREFIX); char *cid = NULL; - if (sofia_test_pflag(tech_pvt->profile, PFLAG_PASS_CALLEE_ID)) { - cid = generate_pai_str(session); - } + + cid = generate_pai_str(tech_pvt); + if (switch_channel_test_flag(tech_pvt->channel, CF_PROXY_MODE) && tech_pvt->early_sdp && strcmp(tech_pvt->early_sdp, tech_pvt->local_sdp_str)) { /* The SIP RFC for SOA forbids sending a 183 with one sdp then a 200 with another but it won't do us much good unless @@ -1968,7 +1967,7 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi } else if (code == 484 && msg->numeric_arg) { const char *to = switch_channel_get_variable(channel, "sip_to_uri"); const char *max_forwards = switch_channel_get_variable(channel, SWITCH_MAX_FORWARDS_VARIABLE); - char *cid = generate_pai_str(session); + char *cid = generate_pai_str(tech_pvt); char *to_uri = NULL; if (to) { @@ -2066,7 +2065,7 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi !switch_channel_test_flag(channel, CF_EARLY_MEDIA) && !switch_channel_test_flag(channel, CF_ANSWERED)) { char *extra_header = sofia_glue_get_extra_headers(channel, SOFIA_SIP_PROGRESS_HEADER_PREFIX); const char *call_info = switch_channel_get_variable(channel, "presence_call_info_full"); - char *cid = generate_pai_str(session); + char *cid = generate_pai_str(tech_pvt); switch (ring_ready_val) { @@ -2187,9 +2186,8 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi char *extra_header = sofia_glue_get_extra_headers(channel, SOFIA_SIP_PROGRESS_HEADER_PREFIX); char *cid = NULL; - if (sofia_test_pflag(tech_pvt->profile, PFLAG_PASS_CALLEE_ID)) { - cid = generate_pai_str(session); - } + cid = generate_pai_str(tech_pvt); + if (switch_channel_test_flag(tech_pvt->channel, CF_PROXY_MODE) && tech_pvt->early_sdp && strcmp(tech_pvt->early_sdp, tech_pvt->local_sdp_str)) { @@ -3176,6 +3174,17 @@ static switch_status_t cmd_profile(char **argv, int argc, switch_stream_handle_t goto done; } + if (!strcasecmp(argv[1], "watchdog")) { + if (argc > 2) { + int value = switch_true(argv[2]); + profile->watchdog_enabled = value; + stream->write_function(stream, "%s sip debugging on %s", value ? "Enabled" : "Disabled", profile->name); + } else { + stream->write_function(stream, "Usage: sofia profile watchdog \n"); + } + goto done; + } + if (!strcasecmp(argv[1], "gwlist")) { int up = 1; @@ -3512,18 +3521,16 @@ SWITCH_STANDARD_API(sofia_function) "[register|unregister] [|all]|" "killgw |" "[stun-auto-disable|stun-enabled] [true|false]]|" - "siptrace [on|off]\n" + "siptrace |" + "watchdog \n" "sofia status|xmlstatus profile [ reg ] | [ pres ] | [ user ]\n" "sofia status|xmlstatus gateway \n" "sofia loglevel [0-9]\n" "sofia tracelevel \n" - "sofa global siptrace [on|off]\n" + "sofia global siptrace |" + "watchdog \n" "--------------------------------------------------------------------------------\n"; - if (session) { - return SWITCH_STATUS_FALSE; - } - if (zstr(cmd)) { stream->write_function(stream, "%s", usage_string); goto done; @@ -3574,21 +3581,30 @@ SWITCH_STANDARD_API(sofia_function) stream->write_function(stream, "%s", usage_string); goto done; } else if (!strcasecmp(argv[0], "global")) { - int on = -1; + int ston = -1; + int wdon = -1; if (argc > 1) { if (!strcasecmp(argv[1], "siptrace")) { if (argc > 2) { - on = switch_true(argv[2]); + ston = switch_true(argv[2]); + } + } + if (!strcasecmp(argv[1], "watchdog")) { + if (argc > 2) { + wdon = switch_true(argv[2]); } } } - if (on != -1) { - sofia_glue_global_siptrace(on); - stream->write_function(stream, "+OK Global siptrace %s", on ? "on" : "off"); + if (ston != -1) { + sofia_glue_global_siptrace(ston); + stream->write_function(stream, "+OK Global siptrace %s", ston ? "on" : "off"); + } else if (wdon != -1) { + sofia_glue_global_watchdog(wdon); + stream->write_function(stream, "+OK Global watchdog %s", wdon ? "on" : "off"); } else { - stream->write_function(stream, "-ERR Usage: siptrace on|off"); + stream->write_function(stream, "-ERR Usage: siptrace |watchdog "); } goto done; @@ -4670,6 +4686,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_sofia_load) switch_console_set_complete("add sofia tracelevel ::[console:alert:crit:err:warning:notice:info:debug"); switch_console_set_complete("add sofia global siptrace ::[on:off"); + switch_console_set_complete("add sofia global watchdog ::[on:off"); switch_console_set_complete("add sofia profile"); switch_console_set_complete("add sofia profile restart all"); @@ -4685,6 +4702,8 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_sofia_load) switch_console_set_complete("add sofia profile ::sofia::list_profiles killgw ::sofia::list_profile_gateway"); switch_console_set_complete("add sofia profile ::sofia::list_profiles siptrace on"); switch_console_set_complete("add sofia profile ::sofia::list_profiles siptrace off"); + switch_console_set_complete("add sofia profile ::sofia::list_profiles watchdog on"); + switch_console_set_complete("add sofia profile ::sofia::list_profiles watchdog off"); switch_console_set_complete("add sofia profile ::sofia::list_profiles gwlist up"); switch_console_set_complete("add sofia profile ::sofia::list_profiles gwlist down"); diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.h b/src/mod/endpoints/mod_sofia/mod_sofia.h index f0ebb55a46..cf4b9a3759 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.h +++ b/src/mod/endpoints/mod_sofia/mod_sofia.h @@ -562,6 +562,11 @@ struct sofia_profile { char *contact_user; char *local_network; uint32_t trans_timeout; + switch_time_t last_sip_event; + switch_time_t last_root_step; + uint32_t step_timeout; + uint32_t event_timeout; + int watchdog_enabled; }; struct private_object { @@ -1016,6 +1021,7 @@ void sofia_glue_tech_simplify(private_object_t *tech_pvt); switch_console_callback_match_t *sofia_reg_find_reg_url_multi(sofia_profile_t *profile, const char *user, const char *host); switch_bool_t sofia_glue_profile_exists(const char *key); void sofia_glue_global_siptrace(switch_bool_t on); +void sofia_glue_global_watchdog(switch_bool_t on); void sofia_glue_proxy_codec(switch_core_session_t *session, const char *r_sdp); switch_status_t sofia_glue_sdp_map(const char *r_sdp, switch_event_t **fmtp, switch_event_t **pt); void sofia_glue_build_vid_refresh_message(switch_core_session_t *session, const char *pl); diff --git a/src/mod/endpoints/mod_sofia/sofia.c b/src/mod/endpoints/mod_sofia/sofia.c index 38e62de4f8..0d69bdb4bb 100644 --- a/src/mod/endpoints/mod_sofia/sofia.c +++ b/src/mod/endpoints/mod_sofia/sofia.c @@ -731,6 +731,7 @@ void sofia_event_callback(nua_event_t event, int locked = 0; int check_destroy = 1; + profile->last_sip_event = switch_time_now(); /* sofia_private will be == &mod_sofia_globals.keep_private whenever a request is done with a new handle that has to be freed whenever the request is done */ @@ -1309,6 +1310,40 @@ void *SWITCH_THREAD_FUNC sofia_profile_worker_thread_run(switch_thread_t *thread } if (++loops >= 1000) { + + + + if (profile->watchdog_enabled) { + uint32_t event_diff = 0, step_diff = 0, event_fail = 0, step_fail = 0; + + if (profile->step_timeout) { + step_diff = (uint32_t) ((switch_time_now() - profile->last_root_step) / 1000); + + if (step_diff > profile->step_timeout) { + step_fail = 1; + } + } + + if (profile->event_timeout) { + event_diff = (uint32_t) ((switch_time_now() - profile->last_sip_event) / 1000); + + if (event_diff > profile->event_timeout) { + event_fail = 1; + } + } + + if (step_fail && profile->event_timeout && !event_fail) { + step_fail = 0; + } + + if (event_fail || step_fail) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Profile %s: SIP STACK FAILURE DETECTED!\n" + "GOODBYE CRUEL WORLD, I'M LEAVING YOU TODAY....GOODBYE, GOODBYE, GOOD BYE\n", profile->name); + switch_yield(2000); + abort(); + } + } + if (++ireg_loops >= IREG_SECONDS) { time_t now = switch_epoch_time_now(NULL); sofia_reg_check_expire(profile, now, 0); @@ -1548,6 +1583,7 @@ void *SWITCH_THREAD_FUNC sofia_profile_thread_run(switch_thread_t *thread, void while (mod_sofia_globals.running == 1 && sofia_test_pflag(profile, PFLAG_RUNNING) && sofia_test_pflag(profile, PFLAG_WORKER_RUNNING)) { su_root_step(profile->s_root, 1000); + profile->last_root_step = switch_time_now(); } sofia_clear_pflag_locked(profile, PFLAG_RUNNING); @@ -2298,6 +2334,12 @@ switch_status_t reconfig_sofia(sofia_profile_t *profile) } else { sofia_clear_pflag(profile, PFLAG_DEL_SUBS_ON_REG); } + } else if (!strcasecmp(var, "watchdog-enabled")) { + profile->watchdog_enabled = switch_true(val); + } else if (!strcasecmp(var, "watchdog-step-timeout")) { + profile->step_timeout = (unsigned long) atol(val); + } else if (!strcasecmp(var, "watchdog-event-timeout")) { + profile->event_timeout = (unsigned long) atol(val); } else if (!strcasecmp(var, "in-dialog-chat")) { if (switch_true(val)) { sofia_set_pflag(profile, PFLAG_IN_DIALOG_CHAT); @@ -2978,6 +3020,13 @@ switch_status_t config_sofia(int reload, char *profile_name) } else { sofia_clear_pflag(profile, PFLAG_LOG_AUTH_FAIL); } + } else if (!strcasecmp(var, "watchdog-enabled")) { + profile->watchdog_enabled = switch_true(val); + } else if (!strcasecmp(var, "watchdog-step-timeout")) { + profile->step_timeout = atoi(val); + } else if (!strcasecmp(var, "watchdog-event-timeout")) { + profile->event_timeout = atoi(val); + } else if (!strcasecmp(var, "in-dialog-chat")) { if (switch_true(val)) { sofia_set_pflag(profile, PFLAG_IN_DIALOG_CHAT); @@ -5028,7 +5077,7 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status, } if (channel) { - if (sofia_test_flag(tech_pvt, TFLAG_EARLY_MEDIA)) { + if (sofia_test_flag(tech_pvt, TFLAG_EARLY_MEDIA) && !sofia_test_flag(tech_pvt, TFLAG_ANS)) { sofia_set_flag_locked(tech_pvt, TFLAG_ANS); sofia_set_flag(tech_pvt, TFLAG_SDP); switch_channel_mark_answered(channel); diff --git a/src/mod/endpoints/mod_sofia/sofia_glue.c b/src/mod/endpoints/mod_sofia/sofia_glue.c index 9d6cff78e7..cb8b257e58 100644 --- a/src/mod/endpoints/mod_sofia/sofia_glue.c +++ b/src/mod/endpoints/mod_sofia/sofia_glue.c @@ -1425,9 +1425,12 @@ void sofia_glue_tech_patch_sdp(private_object_t *tech_pvt) } if (tech_pvt->adv_sdp_audio_ip && !strncmp("c=IN IP", p, 7)) { - strncpy(q, p, 9); - p += 9; - q += 9; + strncpy(q, p, 7); + p += 7; + q += 7; + strncpy(q, strchr(tech_pvt->adv_sdp_audio_ip, ':') ? "6 " : "4 ", 2); + p +=2; + q +=2; strncpy(q, tech_pvt->adv_sdp_audio_ip, strlen(tech_pvt->adv_sdp_audio_ip)); q += strlen(tech_pvt->adv_sdp_audio_ip); @@ -4752,6 +4755,26 @@ void sofia_glue_global_siptrace(switch_bool_t on) } +void sofia_glue_global_watchdog(switch_bool_t on) +{ + switch_hash_index_t *hi; + const void *var; + void *val; + sofia_profile_t *pptr; + + switch_mutex_lock(mod_sofia_globals.hash_mutex); + if (mod_sofia_globals.profile_hash) { + for (hi = switch_hash_first(NULL, mod_sofia_globals.profile_hash); hi; hi = switch_hash_next(hi)) { + switch_hash_this(hi, &var, NULL, &val); + if ((pptr = (sofia_profile_t *) val)) { + pptr->watchdog_enabled = (on ? 1 : 0); + } + } + } + switch_mutex_unlock(mod_sofia_globals.hash_mutex); + +} + void sofia_glue_del_profile(sofia_profile_t *profile) { sofia_gateway_t *gp; diff --git a/src/mod/endpoints/mod_sofia/sofia_presence.c b/src/mod/endpoints/mod_sofia/sofia_presence.c index 3a01e1e003..55b0c5c5ca 100644 --- a/src/mod/endpoints/mod_sofia/sofia_presence.c +++ b/src/mod/endpoints/mod_sofia/sofia_presence.c @@ -571,22 +571,22 @@ static void actual_sofia_presence_event_handler(switch_event_t *event) switch_safe_free(sql); - sql = switch_mprintf("select sip_registrations.sip_user, sip_registrations.orig_hostname, sip_registrations.status, " + sql = switch_mprintf("select sip_registrations.sip_user, sip_registrations.sip_host, sip_registrations.status, " "sip_registrations.rpid,'', sip_dialogs.uuid, sip_dialogs.state, sip_dialogs.direction, " "sip_dialogs.sip_to_user, sip_dialogs.sip_to_host, sip_presence.status,sip_presence.rpid,sip_presence.open_closed," "'%q','%q' " "from sip_registrations left join sip_dialogs on " "(sip_dialogs.sip_from_user = sip_registrations.sip_user " - "and (sip_dialogs.sip_from_host = sip_registrations.orig_hostname or " + "and (sip_dialogs.sip_from_host = sip_registrations.orig_server_host or " "sip_dialogs.sip_from_host = sip_registrations.sip_host) ) " "left join sip_presence on " - "(sip_registrations.sip_user=sip_presence.sip_user and sip_registrations.orig_hostname=sip_presence.sip_host and " + "(sip_registrations.sip_user=sip_presence.sip_user and sip_registrations.orig_server_host=sip_presence.sip_host and " "sip_registrations.profile_name=sip_presence.profile_name) " "where sip_registrations.sip_user='%q' and " - "(sip_registrations.orig_hostname='%q' or sip_registrations.sip_host='%q' " + "(sip_registrations.orig_server_host='%q' or sip_registrations.sip_host='%q' " "or sip_registrations.presence_hosts like '%%%q%%')", dh.status, dh.rpid, probe_euser, probe_host, probe_host, probe_host); switch_assert(sql); @@ -742,8 +742,8 @@ static void actual_sofia_presence_event_handler(switch_event_t *event) } sofia_glue_execute_sql_callback(profile, NULL, sql, sofia_presence_sub_callback, &helper); - - + switch_safe_free(sql); + sql = switch_mprintf("update sip_subscriptions set version=version+1 where event='dialog' and sub_to_user='%q' " "and (sub_to_host='%q' or presence_hosts like '%%%q%%') " "and (profile_name = '%q' or presence_hosts != sub_to_host)", @@ -757,8 +757,6 @@ static void actual_sofia_presence_event_handler(switch_event_t *event) event->event_id == SWITCH_EVENT_PRESENCE_IN ? "IN" : "OUT", profile->name); } - switch_safe_free(sql); - if (!zstr((char *) helper.stream.data)) { char *this_sql = (char *) helper.stream.data; char *next = NULL; diff --git a/src/mod/languages/mod_managed/freeswitch_wrap.2010.cxx b/src/mod/languages/mod_managed/freeswitch_wrap.2010.cxx index 882f0626f4..5a2a757e57 100644 Binary files a/src/mod/languages/mod_managed/freeswitch_wrap.2010.cxx and b/src/mod/languages/mod_managed/freeswitch_wrap.2010.cxx differ diff --git a/src/mod/languages/mod_managed/freeswitch_wrap.cxx b/src/mod/languages/mod_managed/freeswitch_wrap.cxx index b3696899ac..82ad8ab61b 100644 Binary files a/src/mod/languages/mod_managed/freeswitch_wrap.cxx and b/src/mod/languages/mod_managed/freeswitch_wrap.cxx differ diff --git a/src/mod/languages/mod_managed/managed/FreeSWITCH.Managed.csproj b/src/mod/languages/mod_managed/managed/FreeSWITCH.Managed.csproj index 7875d8e6a8..9b8f827202 100644 --- a/src/mod/languages/mod_managed/managed/FreeSWITCH.Managed.csproj +++ b/src/mod/languages/mod_managed/managed/FreeSWITCH.Managed.csproj @@ -19,7 +19,7 @@ true full false - ..\..\..\..\..\managed\debug\ + ..\..\..\..\..\Debug\mod\ DEBUG;TRACE prompt 4 @@ -27,11 +27,27 @@ pdbonly true - ..\..\..\..\..\managed\release\ + ..\..\..\..\..\Release\mod\ TRACE prompt 4 + + true + ..\..\..\..\..\x64\Debug\mod\ + DEBUG;TRACE + full + x64 + prompt + + + ..\..\..\..\..\x64\Release\mod\ + TRACE + true + pdbonly + x64 + prompt + diff --git a/src/mod/languages/mod_managed/managed/swig.2010.cs b/src/mod/languages/mod_managed/managed/swig.2010.cs index 1d89787ebb..682b3bd0c5 100644 Binary files a/src/mod/languages/mod_managed/managed/swig.2010.cs and b/src/mod/languages/mod_managed/managed/swig.2010.cs differ diff --git a/src/mod/languages/mod_managed/managed/swig.cs b/src/mod/languages/mod_managed/managed/swig.cs index f30750a191..2beb015ffc 100644 Binary files a/src/mod/languages/mod_managed/managed/swig.cs and b/src/mod/languages/mod_managed/managed/swig.cs differ diff --git a/src/mod/languages/mod_managed/runswig.2010.cmd b/src/mod/languages/mod_managed/runswig.2010.cmd new file mode 100644 index 0000000000..288c420efe --- /dev/null +++ b/src/mod/languages/mod_managed/runswig.2010.cmd @@ -0,0 +1,10 @@ +move freeswitch_wrap.cxx freeswitch_wrap.bak +\dev\swig20\swig.exe -I..\..\..\include -v -O -c++ -csharp -namespace FreeSWITCH.Native -dllimport mod_managed -DSWIG_CSHARP_NO_STRING_HELPER freeswitch.i +del swig.csx +move freeswitch_wrap.cxx freeswitch_wrap.2010.cxx +move freeswitch_wrap.bak freeswitch_wrap.cxx +@ECHO OFF +for %%X in (*.cs) do type %%X >> swig.csx +@ECHO ON +move swig.csx managed\swig.2010.cs +del *.cs diff --git a/src/mod/languages/mod_managed/runswig.cmd b/src/mod/languages/mod_managed/runswig.cmd index 9b1a659061..631a507a20 100644 --- a/src/mod/languages/mod_managed/runswig.cmd +++ b/src/mod/languages/mod_managed/runswig.cmd @@ -1,4 +1,4 @@ -\dev\swig\swig.exe -I..\..\..\include -v -O -c++ -csharp -namespace FreeSWITCH.Native -dllimport mod_managed -DSWIG_CSHARP_NO_STRING_HELPER freeswitch.i +\dev\swig135\swig.exe -I..\..\..\include -v -O -c++ -csharp -namespace FreeSWITCH.Native -dllimport mod_managed -DSWIG_CSHARP_NO_STRING_HELPER freeswitch.i del swig.csx @ECHO OFF for %%X in (*.cs) do type %%X >> swig.csx diff --git a/src/mod/languages/mod_perl/mod_perl_wrap.cpp b/src/mod/languages/mod_perl/mod_perl_wrap.cpp index 370c88bc99..2efbdf1abc 100644 Binary files a/src/mod/languages/mod_perl/mod_perl_wrap.cpp and b/src/mod/languages/mod_perl/mod_perl_wrap.cpp differ diff --git a/src/mod/say/mod_say_ja/mod_say_ja.c b/src/mod/say/mod_say_ja/mod_say_ja.c new file mode 100644 index 0000000000..407d2d4a91 --- /dev/null +++ b/src/mod/say/mod_say_ja/mod_say_ja.c @@ -0,0 +1,502 @@ +/* + * 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 + * Braga Bruno + * + * + * mod_say_ja.c -- Say for Japanese. + * + */ + +#include +#include +#include +#include + +SWITCH_MODULE_LOAD_FUNCTION(mod_say_ja_load); +SWITCH_MODULE_DEFINITION(mod_say_ja, mod_say_ja_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 = \ + ja_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 ja_say_general_count(switch_core_session_t *session, char *tosay, switch_say_args_t *say_args, switch_input_args_t *args) +{ + int in; + char sbuf[13] = ""; + char digits[11]; + int i; + + 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) { + snprintf(digits, sizeof(digits), "%10.10d", in); + switch (say_args->method) { + case SSM_COUNTED: + say_file("digits/ordinal.wav"); + /* Fall through */ + case SSM_PRONOUNCED: + for (i = 0; i <= 9; i++) { + switch (i) { + case 0: + /* Billions column */ + if (digits[i] != '0') { + if (digits[i] != '1') + say_file("digits/%c.wav", digits[i]); + say_file("digits/10.wav"); + if (memcmp(digits + 1, "0", 1) == 0) + say_file("digits/100000000.wav", digits[i]); + } + break; + case 1: + /* Hundred millions columns */ + if (digits[i] != '0') { + say_file("digits/%c.wav", digits[i]); + say_file("digits/100000000.wav", digits[i]); + } + break; + case 2: + /* Ten millions column */ + if (digits[i] != '0') { + say_file("digits/%c.wav", digits[i]); + say_file("digits/1000.wav"); + if (memcmp(digits + 3, "000", 3) == 0) + say_file("digits/10000.wav", digits[i]); + } + break; + case 3: + /* Millions column */ + if (digits[i] != '0') { + say_file("digits/%c.wav", digits[i]); + say_file("digits/100.wav"); + if (memcmp(digits + 4, "00", 2) == 0) + say_file("digits/10000.wav", digits[i]); + } + break; + case 4: + /* Hundred thousands column */ + if (digits[i] != '0') { + if (digits[i] != '1') + say_file("digits/%c.wav", digits[i]); + say_file("digits/10.wav"); + if (memcmp(digits + 5, "0", 1) == 0) + say_file("digits/10000.wav", digits[i]); + } + break; + + case 5: + /* Ten thousands column */ + if (digits[i] != '0') { + say_file("digits/%c.wav", digits[i]); + say_file("digits/10000.wav"); + } + break; + case 6: + /* thousands column */ + if (digits[i] != '0') { + + switch (digits[i]) { + case '1': + if (memcmp(digits, "000000", 6) != 0) { + say_file("digits/1000s.wav"); + } else { + say_file("digits/1000.wav"); + } + break; + case '3': + say_file("digits/3000.wav"); + break; + default: + say_file("digits/%c.wav", digits[i]); + say_file("digits/1000.wav"); + break; + } + } + break; + case 7: + /* hundreds column */ + if (digits[i] != '0') { + switch (digits[i]) { + case '1': + say_file("digits/100.wav"); + break; + case '3': + say_file("digits/300.wav"); + break; + case '6': + say_file("digits/600.wav"); + break; + case '8': + say_file("digits/800.wav"); + break; + default: + say_file("digits/%c.wav", digits[i]); + say_file("digits/100.wav"); + break; + } + } + break; + case 8: + /* Tens column */ + if (digits[i] != '0') { + if (digits[i] != '1') + say_file("digits/%c.wav", digits[i]); + say_file("digits/10.wav"); + } + break; + case 9: + /* Units column */ + if (digits[i] != '0') + say_file("digits/%c.wav", digits[i]); + break; + } + } + break; + case SSM_ITERATED: + { + char *p; + for (p = tosay; p && *p; p++) + say_file("digits/%c.wav", *p); + } + break; + default: + break; + } + } else { + say_file("digits/0.wav"); + } + + return SWITCH_STATUS_SUCCESS; +} + +static switch_status_t ja_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; + switch_time_exp_t tm; + uint8_t say_date = 0; + uint8_t say_time = 0; + + int mod_min; + char buffer[3]; + + + 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 = atoi(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); + say_file("time/hours.wav"); + } + if (minutes) { + say_num(minutes, SSM_PRONOUNCED); + say_file("time/minute.wav"); + } else { + if (hours) { + say_file("digits/0.wav"); + say_file("time/minute.wav"); + } + } + + if (seconds) { + say_num(hours, SSM_PRONOUNCED); + say_file("time/seconds.wav"); + } else { + if (hours || minutes) { + say_file("digits/0.wav"); + say_file("time/second.wav"); + } + } + + return SWITCH_STATUS_SUCCESS; + } + + if ((t = atoi(tosay)) > 0) + target = switch_time_make(t, 0); + else + target = switch_micro_time_now(); + switch_time_exp_lt(&tm, target); + + 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; + default: + break; + } + + if (say_date) { + say_num(tm.tm_year + 1900, SSM_PRONOUNCED); + say_file("time/year.wav"); + say_file("time/month-%d.wav", tm.tm_mon); + say_file("time/day-%d.wav", tm.tm_mday); + } + + if (say_time) { + int32_t hour = tm.tm_hour; + + if (hour < 12) { + say_file("time/am.wav"); + } else { + say_file("time/pm.wav"); + } + say_file("time/hour-%d.wav", tm.tm_hour); + if (tm.tm_min > 10) { + int temp; + char tch[1+1]; + mod_min = tm.tm_min % 10; + memset(buffer,0,sizeof(buffer)); + memset(tch,0,sizeof(tch)); + sprintf(buffer, "%d", tm.tm_min); + memcpy(tch,buffer,1); + temp = atoi(tch); + if (temp > 1){ + say_num(temp,SSM_PRONOUNCED); + } + if (mod_min != 0){ + say_file("digits/10.wav"); + } + else{ + mod_min = 10; + } + } else { + mod_min = tm.tm_min; + } + switch(mod_min) { + case 0: + say_file("time/oclock.wav", mod_min); + break; + case 1: + case 3: + case 4: + case 6: + case 8: + case 10: + say_file("time/min-%d.wav", mod_min); + break; + default: + say_num(mod_min, SSM_PRONOUNCED); + say_file("time/minute.wav"); + break; + } + } + return SWITCH_STATUS_SUCCESS; +} + +static switch_status_t ja_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 */ + ja_say_general_count(session, dollars, say_args, args); + say_file("currency/dollar.wav"); + + /* Say cents */ + if (cents) { + ja_say_general_count(session, cents, say_args, args); + } else { + say_file("digits/0.wav"); + } + say_file("currency/cent.wav"); + + return SWITCH_STATUS_SUCCESS; +} + +static switch_status_t ja_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 = ja_say_general_count; + break; + case SST_TIME_MEASUREMENT: + case SST_CURRENT_DATE: + case SST_CURRENT_TIME: + case SST_CURRENT_DATE_TIME: + say_cb = ja_say_time; + break; + case SST_IP_ADDRESS: + return switch_ivr_say_ip(session, tosay, ja_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 = ja_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_ja_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 = "ja"; + say_interface->say_function = ja_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/switch_channel.c b/src/switch_channel.c index 81baa2f40d..9e76b46a5a 100644 --- a/src/switch_channel.c +++ b/src/switch_channel.c @@ -400,7 +400,7 @@ SWITCH_DECLARE(switch_status_t) switch_channel_queue_dtmf(switch_channel_t *chan SWITCH_DECLARE(switch_status_t) switch_channel_queue_dtmf_string(switch_channel_t *channel, const char *dtmf_string) { char *p; - switch_dtmf_t dtmf = { 0, switch_core_default_dtmf_duration(0) }; + switch_dtmf_t dtmf = { 0, switch_core_default_dtmf_duration(0), 0}; int sent = 0, dur; char *string; int i, argc; @@ -410,6 +410,11 @@ SWITCH_DECLARE(switch_status_t) switch_channel_queue_dtmf_string(switch_channel_ return SWITCH_STATUS_FALSE; } + if (*dtmf_string == '!') { + dtmf_string++; + dtmf.flags = DTMF_FLAG_SKIP_PROCESS; + } + string = switch_core_session_strdup(channel->session, dtmf_string); argc = switch_separate_string(string, '+', argv, (sizeof(argv) / sizeof(argv[0]))); @@ -2559,6 +2564,10 @@ SWITCH_DECLARE(switch_status_t) switch_channel_perform_mark_pre_answered(switch_ switch_core_session_execute_application(channel->session, app, arg); } + if ((var = switch_channel_get_variable(channel, SWITCH_PASSTHRU_PTIME_MISMATCH_VARIABLE))) { + switch_channel_set_flag(channel, CF_PASSTHRU_PTIME_MISMATCH); + } + /* if we're the child of another channel and the other channel is in a blocking read they will never realize we have answered so send a SWITCH_SIG_BREAK to interrupt any blocking reads on that channel */ @@ -2686,6 +2695,10 @@ SWITCH_DECLARE(switch_status_t) switch_channel_perform_mark_answered(switch_chan switch_core_session_rwunlock(other_session); } + if ((var = switch_channel_get_variable(channel, SWITCH_PASSTHRU_PTIME_MISMATCH_VARIABLE))) { + switch_channel_set_flag(channel, CF_PASSTHRU_PTIME_MISMATCH); + } + if ((var = switch_channel_get_variable(channel, SWITCH_ENABLE_HEARTBEAT_EVENTS_VARIABLE))) { uint32_t seconds = 60; int tmp; @@ -2894,14 +2907,15 @@ SWITCH_DECLARE(char *) switch_channel_expand_variables(switch_channel_t *channel } p = e > endof_indup ? endof_indup : e; - if ((vval = strchr(vname, '('))) { + if ((vval = strchr(vname, '(')) || (vval = strchr(vname, ' '))) { + if (*vval == '(') br = 1; e = vval - 1; *vval++ = '\0'; while (*e == ' ') { *e-- = '\0'; } e = vval; - br = 1; + while (e && *e) { if (*e == '(') { br++; diff --git a/src/switch_core.c b/src/switch_core.c index 2c33b341de..1275b906e7 100644 --- a/src/switch_core.c +++ b/src/switch_core.c @@ -1275,6 +1275,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_init(switch_core_flag_t flags, switc switch_core_session_init(runtime.memory_pool); switch_event_create_plain(&runtime.global_vars, SWITCH_EVENT_CHANNEL_DATA); switch_core_hash_init(&runtime.mime_types, runtime.memory_pool); + switch_core_hash_init_case(&runtime.ptimes, runtime.memory_pool, SWITCH_FALSE); load_mime_types(); runtime.flags |= flags; runtime.sps_total = 30; @@ -1405,13 +1406,56 @@ static void handle_SIGHUP(int sig) } +SWITCH_DECLARE(uint32_t) switch_default_ptime(const char *name, uint32_t number) +{ + uint32_t *p; + + if ((p = switch_core_hash_find(runtime.ptimes, name))) { + return *p; + } + + return 20; +} + +static uint32_t d_30 = 30; + static void switch_load_core_config(const char *file) { switch_xml_t xml = NULL, cfg = NULL; + switch_core_hash_insert(runtime.ptimes, "ilbc", &d_30); + switch_core_hash_insert(runtime.ptimes, "G723", &d_30); + if ((xml = switch_xml_open_cfg(file, &cfg, NULL))) { switch_xml_t settings, param; + if ((settings = switch_xml_child(cfg, "default-ptimes"))) { + for (param = switch_xml_child(settings, "codec"); param; param = param->next) { + const char *var = switch_xml_attr_soft(param, "name"); + const char *val = switch_xml_attr_soft(param, "ptime"); + + if (!zstr(var) && !zstr(val)) { + uint32_t *p; + uint32_t v = (unsigned long) atol(val); + + if (!strcasecmp(var, "G723") || !strcasecmp(var, "iLBC")) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Error adding %s, defaults cannot be changed\n", var); + continue; + } + + if (v < 0) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Error adding %s, invalid ptime\n", var); + continue; + } + + p = switch_core_alloc(runtime.memory_pool, sizeof(*p)); + *p = v; + switch_core_hash_insert(runtime.ptimes, var, p); + } + + } + } + if ((settings = switch_xml_child(cfg, "settings"))) { for (param = switch_xml_child(settings, "param"); param; param = param->next) { const char *var = switch_xml_attr_soft(param, "name"); @@ -1973,6 +2017,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_destroy(void) switch_safe_free(SWITCH_GLOBAL_dirs.temp_dir); switch_event_destroy(&runtime.global_vars); + switch_core_hash_destroy(&runtime.ptimes); switch_core_hash_destroy(&runtime.mime_types); if (IP_LIST.hash) { diff --git a/src/switch_core_codec.c b/src/switch_core_codec.c index d45d73ed76..9b607ea873 100644 --- a/src/switch_core_codec.c +++ b/src/switch_core_codec.c @@ -137,9 +137,11 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_set_read_codec(switch_core_s memset(&session->read_impl, 0, sizeof(session->read_impl)); } old->next = NULL; + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s Restore previous codec %s:%d.\n", switch_channel_get_name(session->channel), - session->read_codec->implementation->iananame, session->read_codec->implementation->ianacode); + session->read_impl.iananame ? session->read_impl.iananame : "N/A", session->read_impl.ianacode); + } else if (session->real_read_codec) { session->read_codec = session->real_read_codec; diff --git a/src/switch_core_io.c b/src/switch_core_io.c index 1eb224bda1..4e6d2fc6a2 100644 --- a/src/switch_core_io.c +++ b/src/switch_core_io.c @@ -126,7 +126,11 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_read_frame(switch_core_sessi switch_mutex_lock(session->read_codec->mutex); top: - + + if (session->dmachine && !switch_channel_test_flag(session->channel, CF_BROADCAST)) { + switch_ivr_dmachine_ping(session->dmachine, NULL); + } + if (switch_channel_down(session->channel) || !switch_core_codec_ready(session->read_codec)) { *frame = NULL; status = SWITCH_STATUS_FALSE; @@ -653,7 +657,8 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_write_frame(switch_core_sess if (session->write_impl.codec_id == frame->codec->implementation->codec_id || session->write_impl.microseconds_per_packet != frame->codec->implementation->microseconds_per_packet) { ptime_mismatch = TRUE; - if (switch_test_flag(frame->codec, SWITCH_CODEC_FLAG_PASSTHROUGH) || switch_test_flag(session->read_codec, SWITCH_CODEC_FLAG_PASSTHROUGH)) { + if ((switch_test_flag(frame->codec, SWITCH_CODEC_FLAG_PASSTHROUGH) || switch_test_flag(session->read_codec, SWITCH_CODEC_FLAG_PASSTHROUGH)) || + switch_channel_test_flag(session->channel, CF_PASSTHRU_PTIME_MISMATCH)) { status = perform_write(session, frame, flags, stream_id); goto error; } @@ -1149,6 +1154,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_recv_dtmf(switch_core_sessio switch_io_event_hook_recv_dtmf_t *ptr; switch_status_t status; switch_dtmf_t new_dtmf; + int fed = 0; if (switch_channel_down(session->channel)) { return SWITCH_STATUS_FALSE; @@ -1170,12 +1176,21 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_recv_dtmf(switch_core_sessio new_dtmf.duration = switch_core_default_dtmf_duration(0); } - for (ptr = session->event_hooks.recv_dtmf; ptr; ptr = ptr->next) { - if ((status = ptr->recv_dtmf(session, &new_dtmf, SWITCH_DTMF_RECV)) != SWITCH_STATUS_SUCCESS) { - return status; + if (!switch_test_flag(dtmf, DTMF_FLAG_SKIP_PROCESS)) { + if (session->dmachine && !switch_channel_test_flag(session->channel, CF_BROADCAST)) { + char str[2] = { dtmf->digit, '\0' }; + switch_ivr_dmachine_feed(session->dmachine, str, NULL); + fed = 1; + } + + for (ptr = session->event_hooks.recv_dtmf; ptr; ptr = ptr->next) { + if ((status = ptr->recv_dtmf(session, &new_dtmf, SWITCH_DTMF_RECV)) != SWITCH_STATUS_SUCCESS) { + return status; + } } } - return SWITCH_STATUS_SUCCESS; + + return fed ? SWITCH_STATUS_FALSE : SWITCH_STATUS_SUCCESS; } SWITCH_DECLARE(switch_status_t) switch_core_session_send_dtmf(switch_core_session_t *session, const switch_dtmf_t *dtmf) diff --git a/src/switch_core_session.c b/src/switch_core_session.c index 9e942fea5e..c8aca7dbc6 100644 --- a/src/switch_core_session.c +++ b/src/switch_core_session.c @@ -38,6 +38,16 @@ struct switch_session_manager session_manager; +SWITCH_DECLARE(void) switch_core_session_set_dmachine(switch_core_session_t *session, switch_ivr_dmachine_t *dmachine) +{ + session->dmachine = dmachine; +} + +SWITCH_DECLARE(switch_ivr_dmachine_t *) switch_core_session_get_dmachine(switch_core_session_t *session) +{ + return session->dmachine; +} + SWITCH_DECLARE(void) switch_core_session_soft_lock(switch_core_session_t *session, uint32_t sec) { session->soft_lock = sec; @@ -1094,6 +1104,10 @@ SWITCH_DECLARE(void) switch_core_session_perform_destroy(switch_core_session_t * switch_ivr_clear_speech_cache(*session); switch_channel_uninit((*session)->channel); + if ((*session)->dmachine) { + switch_ivr_dmachine_destroy(&(*session)->dmachine); + } + pool = (*session)->pool; //#ifndef NDEBUG //memset(*session, 0, sizeof(switch_core_session_t)); diff --git a/src/switch_core_sqldb.c b/src/switch_core_sqldb.c index 7e427b5f03..c467a23a62 100644 --- a/src/switch_core_sqldb.c +++ b/src/switch_core_sqldb.c @@ -871,7 +871,7 @@ static void *SWITCH_THREAD_FUNC switch_core_sql_db_thread(switch_thread_t *threa while (sql_manager.db_thread_running == 1) { if (++sec == SQL_CACHE_TIMEOUT) { sql_close(switch_epoch_time_now(NULL)); - wake_thread(1); + wake_thread(0); sec = 0; } switch_yield(1000); @@ -1425,7 +1425,7 @@ static void core_event_handler(switch_event_t *event) switch_queue_push(sql_manager.sql_queue[0], sql[i]); } sql[i] = NULL; - wake_thread(1); + wake_thread(0); } } } @@ -1705,7 +1705,7 @@ void switch_core_sqldb_stop(void) switch_queue_push(sql_manager.sql_queue[0], NULL); switch_queue_push(sql_manager.sql_queue[1], NULL); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Waiting for unfinished SQL transactions\n"); - wake_thread(1); + wake_thread(0); } sql_manager.thread_running = -1; diff --git a/src/switch_event.c b/src/switch_event.c index 4b1e28aebf..f782c15900 100644 --- a/src/switch_event.c +++ b/src/switch_event.c @@ -1644,14 +1644,15 @@ SWITCH_DECLARE(char *) switch_event_expand_headers(switch_event_t *event, const } p = e > endof_indup ? endof_indup : e; - if ((vval = strchr(vname, '('))) { + if ((vval = strchr(vname, '(')) || (vval = strchr(vname, ' '))) { + if (*vval == '(') br = 1; e = vval - 1; *vval++ = '\0'; while (*e == ' ') { *e-- = '\0'; } e = vval; - br = 1; + while (e && *e) { if (*e == '(') { br++; diff --git a/src/switch_ivr.c b/src/switch_ivr.c index ef360d3148..744072c145 100644 --- a/src/switch_ivr.c +++ b/src/switch_ivr.c @@ -232,7 +232,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_sleep(switch_core_session_t *session, if you return anything but SWITCH_STATUS_SUCCESS the playback will stop. */ if (switch_channel_has_dtmf(channel)) { - if (!args->input_callback && !args->buf) { + if (!args->input_callback && !args->buf && !args->dmachine) { status = SWITCH_STATUS_BREAK; break; } @@ -271,6 +271,12 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_sleep(switch_core_session_t *session, break; } + if (args && args->dmachine) { + if ((status = switch_ivr_dmachine_ping(args->dmachine, NULL)) != SWITCH_STATUS_SUCCESS) { + break; + } + } + if (sval && write_frame.datalen) { switch_generate_sln_silence((int16_t *) write_frame.data, write_frame.samples, sval); switch_core_session_write_frame(session, &write_frame, SWITCH_IO_FLAG_NONE, 0); @@ -923,12 +929,21 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_collect_digits_callback(switch_core_s if (switch_channel_has_dtmf(channel)) { - if (!args->input_callback && !args->buf) { + if (!args->input_callback && !args->buf && !args->dmachine) { status = SWITCH_STATUS_BREAK; break; } switch_channel_dequeue_dtmf(channel, &dtmf); - status = args->input_callback(session, (void *) &dtmf, SWITCH_INPUT_TYPE_DTMF, args->buf, args->buflen); + + if (args->dmachine) { + char ds[2] = {dtmf.digit, '\0'}; + if ((status = switch_ivr_dmachine_feed(args->dmachine, ds, NULL)) != SWITCH_STATUS_SUCCESS) { + break; + } + } else if (args->input_callback) { + status = args->input_callback(session, (void *) &dtmf, SWITCH_INPUT_TYPE_DTMF, args->buf, args->buflen); + } + if (digit_timeout) { digit_started = switch_micro_time_now(); } diff --git a/src/switch_ivr_async.c b/src/switch_ivr_async.c index 1fee5f99ab..9bfa27eae7 100644 --- a/src/switch_ivr_async.c +++ b/src/switch_ivr_async.c @@ -45,34 +45,45 @@ struct switch_ivr_dmachine_binding { }; typedef struct switch_ivr_dmachine_binding switch_ivr_dmachine_binding_t; -#define DM_MAX_DIGIT_LEN 512 +typedef struct { + switch_ivr_dmachine_binding_t *binding_list; + switch_ivr_dmachine_binding_t *tail; +} dm_binding_head_t; struct switch_ivr_dmachine { switch_memory_pool_t *pool; switch_byte_t my_pool; + char *name; uint32_t digit_timeout_ms; uint32_t input_timeout_ms; - switch_ivr_dmachine_binding_t *binding_list; - switch_ivr_dmachine_binding_t *tail; - switch_ivr_dmachine_binding_t *last_matching_binding; + switch_hash_t *binding_hash; switch_ivr_dmachine_match_t match; - char digits[DM_MAX_DIGIT_LEN]; - char last_matching_digits[DM_MAX_DIGIT_LEN]; + char digits[DMACHINE_MAX_DIGIT_LEN]; + char last_matching_digits[DMACHINE_MAX_DIGIT_LEN]; + char last_failed_digits[DMACHINE_MAX_DIGIT_LEN]; uint32_t cur_digit_len; uint32_t max_digit_len; switch_time_t last_digit_time; switch_byte_t is_match; + switch_ivr_dmachine_callback_t match_callback; + switch_ivr_dmachine_callback_t nonmatch_callback; + dm_binding_head_t *realm; + switch_ivr_dmachine_binding_t *last_matching_binding; + void *user_data; }; SWITCH_DECLARE(switch_status_t) switch_ivr_dmachine_create(switch_ivr_dmachine_t **dmachine_p, - switch_memory_pool_t *pool, - uint32_t digit_timeout_ms, uint32_t input_timeout_ms) + const char *name, + switch_memory_pool_t *pool, + uint32_t digit_timeout_ms, + uint32_t input_timeout_ms, + switch_ivr_dmachine_callback_t match_callback, + switch_ivr_dmachine_callback_t nonmatch_callback, + void *user_data) { switch_byte_t my_pool = !!pool; switch_ivr_dmachine_t *dmachine; - if (digit_timeout_ms < 1 || input_timeout_ms < 1) return SWITCH_STATUS_FALSE; - if (!pool) { switch_core_new_memory_pool(&pool); } @@ -83,12 +94,36 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_dmachine_create(switch_ivr_dmachine_t dmachine->digit_timeout_ms = digit_timeout_ms; dmachine->input_timeout_ms = input_timeout_ms; dmachine->match.dmachine = dmachine; - *dmachine_p = dmachine; + dmachine->name = switch_core_strdup(dmachine->pool, name); + + switch_core_hash_init(&dmachine->binding_hash, dmachine->pool); + + if (match_callback) { + dmachine->match_callback = match_callback; + } + if (nonmatch_callback) { + dmachine->nonmatch_callback = nonmatch_callback; + } + + dmachine->user_data = user_data; + + *dmachine_p = dmachine; + return SWITCH_STATUS_SUCCESS; } +SWITCH_DECLARE(void) switch_ivr_dmachine_set_digit_timeout_ms(switch_ivr_dmachine_t *dmachine, uint32_t digit_timeout_ms) +{ + dmachine->digit_timeout_ms = digit_timeout_ms; +} + +SWITCH_DECLARE(void) switch_ivr_dmachine_set_input_timeout_ms(switch_ivr_dmachine_t *dmachine, uint32_t input_timeout_ms) +{ + dmachine->input_timeout_ms = input_timeout_ms; +} + SWITCH_DECLARE(void) switch_ivr_dmachine_destroy(switch_ivr_dmachine_t **dmachine) { switch_memory_pool_t *pool; @@ -97,12 +132,42 @@ SWITCH_DECLARE(void) switch_ivr_dmachine_destroy(switch_ivr_dmachine_t **dmachin pool = (*dmachine)->pool; + switch_core_hash_destroy(&(*dmachine)->binding_hash); + if ((*dmachine)->my_pool) { switch_core_destroy_memory_pool(&pool); } } +SWITCH_DECLARE(switch_status_t) switch_ivr_dmachine_set_realm(switch_ivr_dmachine_t *dmachine, const char *realm) +{ + dm_binding_head_t *headp = switch_core_hash_find(dmachine->binding_hash, realm); + + if (headp) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Digit parser %s: Setting realm to %s\n", dmachine->name, realm); + dmachine->realm = headp; + return SWITCH_STATUS_SUCCESS; + } + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Digit parser %s: Error Setting realm to %s\n", dmachine->name, realm); + + return SWITCH_STATUS_FALSE; +} + +SWITCH_DECLARE(switch_status_t) switch_ivr_dmachine_clear_realm(switch_ivr_dmachine_t *dmachine, const char *realm) +{ + if (zstr(realm)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Digit parser %s: Error unknown realm: %s\n", dmachine->name, realm); + return SWITCH_STATUS_FALSE; + } + + /* pool alloc'd just ditch it and it will give back the memory when we destroy ourselves */ + switch_core_hash_delete(dmachine->binding_hash, realm); + return SWITCH_STATUS_SUCCESS; +} + SWITCH_DECLARE(switch_status_t) switch_ivr_dmachine_bind(switch_ivr_dmachine_t *dmachine, + const char *realm, const char *digits, int32_t key, switch_ivr_dmachine_callback_t callback, @@ -110,43 +175,59 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_dmachine_bind(switch_ivr_dmachine_t * { switch_ivr_dmachine_binding_t *binding; switch_size_t len; + dm_binding_head_t *headp; - if (strlen(digits) > DM_MAX_DIGIT_LEN -1) { + if (strlen(digits) > DMACHINE_MAX_DIGIT_LEN -1) { return SWITCH_STATUS_FALSE; } + if (zstr(realm)) { + realm = "default"; + } + + if (!(headp = switch_core_hash_find(dmachine->binding_hash, realm))) { + headp = switch_core_alloc(dmachine->pool, sizeof(*headp)); + switch_core_hash_insert(dmachine->binding_hash, realm, headp); + } + binding = switch_core_alloc(dmachine->pool, sizeof(*binding)); + if (*digits == '~') { binding->is_regex = 1; digits++; } + binding->key = key; binding->digits = switch_core_strdup(dmachine->pool, digits); binding->callback = callback; binding->user_data = user_data; - if (dmachine->tail) { - dmachine->tail->next = binding; + if (headp->tail) { + headp->tail->next = binding; } else { - dmachine->binding_list = binding; + headp->binding_list = binding; } - dmachine->tail = binding; + headp->tail = binding; len = strlen(digits); - if (binding->is_regex && dmachine->max_digit_len != DM_MAX_DIGIT_LEN -1) { - dmachine->max_digit_len = DM_MAX_DIGIT_LEN -1; + if (dmachine->realm != headp) { + switch_ivr_dmachine_set_realm(dmachine, realm); + } + + if (binding->is_regex && dmachine->max_digit_len != DMACHINE_MAX_DIGIT_LEN -1) { + dmachine->max_digit_len = DMACHINE_MAX_DIGIT_LEN -1; } else if (len > dmachine->max_digit_len) { dmachine->max_digit_len = (uint32_t) len; } if (binding->is_regex) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "binding regex: %s key: %.4d callback: %p data: %p\n", - digits, key, (void *)(intptr_t) callback, user_data); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Digit parser %s: binding realm: %s regex: %s key: %.4d callback: %p data: %p\n", + dmachine->name, realm, digits, key, (void *)(intptr_t) callback, user_data); } else { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "binding digits: %4s key: %.4d callback: %p data: %p\n", - digits, key, (void *)(intptr_t) callback, user_data); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Digit parser %s: binding realm %s digits: %4s key: %.4d callback: %p data: %p\n", + dmachine->name, realm, digits, key, (void *)(intptr_t) callback, user_data); } return SWITCH_STATUS_SUCCESS; @@ -167,9 +248,9 @@ static dm_match_t switch_ivr_dmachine_check_match(switch_ivr_dmachine_t *dmachin int exact_count = 0, partial_count = 0, both_count = 0; - if (!dmachine->cur_digit_len) goto end; + if (!dmachine->cur_digit_len || !dmachine->realm) goto end; - for(bp = dmachine->binding_list; bp; bp = bp->next) { + for(bp = dmachine->realm->binding_list; bp; bp = bp->next) { if (bp->is_regex) { switch_status_t r_status = switch_regex_match(dmachine->digits, bp->digits); @@ -229,9 +310,13 @@ static switch_bool_t switch_ivr_dmachine_check_timeout(switch_ivr_dmachine_t *dm { switch_time_t now = switch_time_now(); uint32_t timeout = dmachine->cur_digit_len ? dmachine->digit_timeout_ms : dmachine->input_timeout_ms; - - if ((uint32_t)((now - dmachine->last_digit_time) / 1000) > timeout) { - return SWITCH_TRUE; + + if (!dmachine->last_digit_time) dmachine->last_digit_time = now; + + if (timeout) { + if ((uint32_t)((now - dmachine->last_digit_time) / 1000) > timeout) { + return SWITCH_TRUE; + } } return SWITCH_FALSE; @@ -247,32 +332,46 @@ SWITCH_DECLARE(switch_ivr_dmachine_match_t *) switch_ivr_dmachine_get_match(swit return NULL; } +SWITCH_DECLARE(const char *) switch_ivr_dmachine_get_failed_digits(switch_ivr_dmachine_t *dmachine) +{ + + return dmachine->last_failed_digits; +} + SWITCH_DECLARE(switch_status_t) switch_ivr_dmachine_ping(switch_ivr_dmachine_t *dmachine, switch_ivr_dmachine_match_t **match_p) { switch_bool_t is_timeout = switch_ivr_dmachine_check_timeout(dmachine); dm_match_t is_match = switch_ivr_dmachine_check_match(dmachine, is_timeout); switch_status_t r; - - if (!dmachine->last_digit_time) { + + if (zstr(dmachine->digits) && !is_timeout) { r = SWITCH_STATUS_SUCCESS; } else if (dmachine->cur_digit_len > dmachine->max_digit_len) { r = SWITCH_STATUS_FALSE; } else if (is_match == DM_MATCH_EXACT || (is_match == DM_MATCH_BOTH && is_timeout)) { r = SWITCH_STATUS_FOUND; - + dmachine->match.match_digits = dmachine->last_matching_digits; dmachine->match.match_key = dmachine->last_matching_binding->key; dmachine->match.user_data = dmachine->last_matching_binding->user_data; - - if (dmachine->last_matching_binding->callback) { - dmachine->last_matching_binding->callback(&dmachine->match); - } - + if (match_p) { *match_p = &dmachine->match; } dmachine->is_match = 1; + + dmachine->match.type = DM_MATCH_POSITIVE; + + if (dmachine->last_matching_binding->callback) { + dmachine->last_matching_binding->callback(&dmachine->match); + } + + if (dmachine->match_callback) { + dmachine->match.user_data = dmachine->user_data; + dmachine->match_callback(&dmachine->match); + } + } else if (is_timeout) { r = SWITCH_STATUS_TIMEOUT; } else if (dmachine->cur_digit_len == dmachine->max_digit_len) { @@ -281,6 +380,18 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_dmachine_ping(switch_ivr_dmachine_t * r = SWITCH_STATUS_SUCCESS; } + if (r != SWITCH_STATUS_FOUND && r != SWITCH_STATUS_SUCCESS) { + switch_set_string(dmachine->last_failed_digits, dmachine->digits); + dmachine->match.match_digits = dmachine->last_failed_digits; + + dmachine->match.type = DM_MATCH_NEGATIVE; + + if (dmachine->nonmatch_callback) { + dmachine->match.user_data = dmachine->user_data; + dmachine->nonmatch_callback(&dmachine->match); + } + } + if (r != SWITCH_STATUS_SUCCESS) { switch_ivr_dmachine_clear(dmachine); } @@ -2489,7 +2600,7 @@ static void *SWITCH_THREAD_FUNC bcast_thread(switch_thread_t *thread, void *obj) return NULL; } -static void broadcast_in_thread(switch_core_session_t *session, const char *app, int flags) +SWITCH_DECLARE(void) switch_ivr_broadcast_in_thread(switch_core_session_t *session, const char *app, int flags) { switch_thread_t *thread; switch_threadattr_t *thd_attr = NULL; @@ -2594,7 +2705,7 @@ static switch_status_t meta_on_dtmf(switch_core_session_t *session, const switch switch_channel_get_name(channel), dtmf->digit, md->sr[direction].map[dval].app); if (switch_channel_test_flag(channel, CF_PROXY_MODE)) { - broadcast_in_thread(session, md->sr[direction].map[dval].app, flags | SMF_REBRIDGE); + switch_ivr_broadcast_in_thread(session, md->sr[direction].map[dval].app, flags | SMF_REBRIDGE); } else { switch_ivr_broadcast(switch_core_session_get_uuid(session), md->sr[direction].map[dval].app, flags); } diff --git a/src/switch_ivr_bridge.c b/src/switch_ivr_bridge.c index f92e254008..165df886fd 100644 --- a/src/switch_ivr_bridge.c +++ b/src/switch_ivr_bridge.c @@ -468,6 +468,10 @@ static void *audio_bridge_thread(switch_thread_t *thread, void *obj) continue; } + if (switch_channel_test_flag(chan_a, CF_BRIDGE_NOWRITE)) { + continue; + } + if (status != SWITCH_STATUS_BREAK && !switch_channel_test_flag(chan_a, CF_HOLD)) { if (switch_core_session_write_frame(session_b, read_frame, SWITCH_IO_FLAG_NONE, stream_id) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, @@ -839,13 +843,26 @@ static switch_status_t hanguphook(switch_core_session_t *session) { switch_core_session_message_t msg = { 0 }; switch_channel_t *channel = NULL; + switch_event_t *event; + switch_channel_state_t state; channel = switch_core_session_get_channel(session); + state = switch_channel_get_state(channel); msg.message_id = SWITCH_MESSAGE_INDICATE_UNBRIDGE; msg.from = __FILE__; msg.string_arg = switch_channel_get_variable(channel, SWITCH_SIGNAL_BRIDGE_VARIABLE); + if (state == CS_ROUTING) { + if (switch_channel_test_flag(channel, CF_BRIDGE_ORIGINATOR)) { + switch_channel_clear_flag_recursive(channel, CF_BRIDGE_ORIGINATOR); + if (switch_event_create(&event, SWITCH_EVENT_CHANNEL_UNBRIDGE) == SWITCH_STATUS_SUCCESS) { + switch_channel_event_set_data(channel, event); + switch_event_fire(&event); + } + } + } + switch_core_session_receive_message(session, &msg); switch_core_event_hook_remove_state_change(session, hanguphook); @@ -859,6 +876,7 @@ static switch_status_t signal_bridge_on_hibernate(switch_core_session_t *session const char *key; switch_core_session_message_t msg = { 0 }; switch_event_t *event = NULL; + switch_ivr_dmachine_t *dmachine; channel = switch_core_session_get_channel(session); switch_assert(channel != NULL); @@ -886,6 +904,19 @@ static switch_status_t signal_bridge_on_hibernate(switch_core_session_t *session } } + if ((dmachine = switch_core_session_get_dmachine(session))) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, + "%s not hibernating due to active digit parser, semi-hibernation engaged.\n", switch_channel_get_name(channel)); + + while(switch_channel_ready(channel) && switch_channel_get_state(channel) == CS_HIBERNATE) { + if (!switch_channel_test_flag(channel, CF_BROADCAST)) { + switch_ivr_dmachine_ping(dmachine, NULL); + } + switch_yield(20000); + } + } + + return SWITCH_STATUS_SUCCESS; } diff --git a/src/switch_ivr_play_say.c b/src/switch_ivr_play_say.c index c5b7a61000..c99745d57c 100644 --- a/src/switch_ivr_play_say.c +++ b/src/switch_ivr_play_say.c @@ -842,7 +842,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_gentones(switch_core_session_t *sessi if you return anything but SWITCH_STATUS_SUCCESS the playback will stop. */ if (switch_channel_has_dtmf(channel)) { - if (!args->input_callback && !args->buf) { + if (!args->input_callback && !args->buf && !args->dmachine) { status = SWITCH_STATUS_BREAK; done = 1; break; @@ -1253,7 +1253,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_play_file(switch_core_session_t *sess if you return anything but SWITCH_STATUS_SUCCESS the playback will stop. */ if (switch_channel_has_dtmf(channel)) { - if (!args->input_callback && !args->buf) { + if (!args->input_callback && !args->buf && !args->dmachine) { status = SWITCH_STATUS_BREAK; done = 1; break; @@ -1292,7 +1292,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_play_file(switch_core_session_t *sess if (framelen > FILE_STARTSAMPLES) { framelen = FILE_STARTSAMPLES; } - memset(abuf, 0, framelen); + memset(abuf, 255, framelen); olen = ilen; do_speed = 0; } else if (fh->sp_audio_buffer && (eof || (switch_buffer_inuse(fh->sp_audio_buffer) > (switch_size_t) (framelen)))) { @@ -1305,7 +1305,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_play_file(switch_core_session_t *sess } if (bread < framelen) { - memset(abuf + bread, 0, framelen - bread); + memset(abuf + bread, 255, framelen - bread); } olen = asis ? framelen : ilen; @@ -1320,7 +1320,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_play_file(switch_core_session_t *sess } if (bread < framelen) { - memset(abuf + bread, 0, framelen - bread); + memset(abuf + bread, 255, framelen - bread); } olen = asis ? framelen : ilen; @@ -1408,10 +1408,10 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_play_file(switch_core_session_t *sess last_speed = fh->speed; continue; } - + if (olen < llen) { uint8_t *dp = (uint8_t *) write_frame.data; - memset(dp + (int) olen, 0, (int) (llen - olen)); + memset(dp + (int) olen, 255, (int) (llen - olen)); olen = llen; } @@ -1476,7 +1476,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_play_file(switch_core_session_t *sess } #endif #endif - if (fh->vol) { + if (!asis && fh->vol) { switch_change_sln_volume(write_frame.data, write_frame.datalen / 2, fh->vol); } @@ -1959,7 +1959,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_speak_text_handle(switch_core_session * if you return anything but SWITCH_STATUS_SUCCESS the playback will stop. */ if (switch_channel_has_dtmf(channel)) { - if (!args->input_callback && !args->buf) { + if (!args->input_callback && !args->buf && !args->dmachine) { status = SWITCH_STATUS_BREAK; done = 1; break; diff --git a/src/tone2wav.c b/src/tone2wav.c index 4415860802..8d4978a57c 100644 --- a/src/tone2wav.c +++ b/src/tone2wav.c @@ -171,7 +171,7 @@ int main(int argc, char *argv[]) teletone_destroy_session(&ts); switch_core_file_close(&fh); - printf("File: %s generated.....\n\nPlease support:\nFreeSWITCH http://www.freeswitch.org\nClueCon http://www.cluecon.com\n", file); + printf("File: %s generated...\n\nPlease support:\nFreeSWITCH http://www.freeswitch.org\nClueCon http://www.cluecon.com\n", file); end: