diff --git a/.gitignore b/.gitignore index adcfda37f4..304b42c1f9 100644 --- a/.gitignore +++ b/.gitignore @@ -70,10 +70,12 @@ config.status configure.lineno /freeswitch /fs_cli +/fs_encode /fs_ivrd /libtool /modules.conf /quiet_libtool +/tone2wav /scripts/fsxs /scripts/gentls_cert /a.out.dSYM diff --git a/Freeswitch.2010.sln b/Freeswitch.2010.sln index 186969891a..4f48314f5b 100644 --- a/Freeswitch.2010.sln +++ b/Freeswitch.2010.sln @@ -964,7 +964,9 @@ Global {692F6330-4D87-4C82-81DF-40DB5892636E}.Release|Win32.ActiveCfg = Release|Win32 {692F6330-4D87-4C82-81DF-40DB5892636E}.Release|x64.ActiveCfg = Release|x64 {692F6330-4D87-4C82-81DF-40DB5892636E}.Release|x64 Setup.ActiveCfg = Release|x64 + {692F6330-4D87-4C82-81DF-40DB5892636E}.Release|x64 Setup.Build.0 = Release|x64 {692F6330-4D87-4C82-81DF-40DB5892636E}.Release|x86 Setup.ActiveCfg = Release|Win32 + {692F6330-4D87-4C82-81DF-40DB5892636E}.Release|x86 Setup.Build.0 = Release|Win32 {D3EC0AFF-76FC-4210-A825-9A17410660A3}.All|Win32.ActiveCfg = Release|x64 {D3EC0AFF-76FC-4210-A825-9A17410660A3}.All|x64.ActiveCfg = Release|x64 {D3EC0AFF-76FC-4210-A825-9A17410660A3}.All|x64.Build.0 = Release|x64 diff --git a/conf/autoload_configs/callcenter.conf.xml b/conf/autoload_configs/callcenter.conf.xml index 9140193b22..a069413ac6 100644 --- a/conf/autoload_configs/callcenter.conf.xml +++ b/conf/autoload_configs/callcenter.conf.xml @@ -13,6 +13,7 @@ + diff --git a/conf/autoload_configs/erlang_event.conf.xml b/conf/autoload_configs/erlang_event.conf.xml index ec14e21a25..62deb84f67 100644 --- a/conf/autoload_configs/erlang_event.conf.xml +++ b/conf/autoload_configs/erlang_event.conf.xml @@ -2,7 +2,16 @@ + + + + + diff --git a/conf/autoload_configs/modules.conf.xml b/conf/autoload_configs/modules.conf.xml index 90d66f5798..f5627fe965 100644 --- a/conf/autoload_configs/modules.conf.xml +++ b/conf/autoload_configs/modules.conf.xml @@ -1,17 +1,113 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/conf/autoload_configs/sangoma_codec.conf.xml b/conf/autoload_configs/sangoma_codec.conf.xml index 05d70de0a7..eed9d673e1 100644 --- a/conf/autoload_configs/sangoma_codec.conf.xml +++ b/conf/autoload_configs/sangoma_codec.conf.xml @@ -4,14 +4,15 @@ diff --git a/conf/autoload_configs/switch.conf.xml b/conf/autoload_configs/switch.conf.xml index 7a68a7f2bd..896dd0e712 100644 --- a/conf/autoload_configs/switch.conf.xml +++ b/conf/autoload_configs/switch.conf.xml @@ -15,6 +15,11 @@ + + + + + @@ -81,6 +86,7 @@ + diff --git a/conf/autoload_configs/voicemail.conf.xml b/conf/autoload_configs/voicemail.conf.xml index 14ad98b41c..06bd6f6dca 100644 --- a/conf/autoload_configs/voicemail.conf.xml +++ b/conf/autoload_configs/voicemail.conf.xml @@ -33,9 +33,10 @@ - - - + --> + + + diff --git a/conf/dialplan/default.xml b/conf/dialplan/default.xml index 9e762b97a2..a19f68399e 100644 --- a/conf/dialplan/default.xml +++ b/conf/dialplan/default.xml @@ -1,88 +1,763 @@ - + + - - - - - - - - - - - - - + -service - - - - - - - - - - - - + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/conf/directory/default.xml b/conf/directory/default.xml index 1e583033a9..8af7aea135 100644 --- a/conf/directory/default.xml +++ b/conf/directory/default.xml @@ -21,7 +21,7 @@ - + diff --git a/conf/sip_profiles/internal.xml b/conf/sip_profiles/internal.xml index 50833bfbec..3e756a85c0 100644 --- a/conf/sip_profiles/internal.xml +++ b/conf/sip_profiles/internal.xml @@ -42,6 +42,26 @@ + + + + + + @@ -112,6 +132,8 @@ + + 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/conf/vars.xml b/conf/vars.xml index c638a80582..fced2ef139 100644 --- a/conf/vars.xml +++ b/conf/vars.xml @@ -195,7 +195,7 @@ - + diff --git a/configure.in b/configure.in index de7261266e..77df2a614c 100644 --- a/configure.in +++ b/configure.in @@ -373,6 +373,11 @@ if test "x$have_libz" = "xyes" ; then APR_ADDTO(SWITCH_AM_LDFLAGS, -lz) fi +AC_CHECK_LIB(resolv, res_init, have_libresolv=yes, have_libresolv=no) +if test "x$have_libresolv" = "xyes" ; then +APR_ADDTO(SWITCH_AM_LDFLAGS, -lresolv) +fi + ESL_LDFLAGS= PLATFORM_CORE_DEPLIBS= # tweak platform specific flags diff --git a/libs/esl/perl/logger.pl b/libs/esl/perl/logger.pl index d0dbb1750e..08213c033f 100644 --- a/libs/esl/perl/logger.pl +++ b/libs/esl/perl/logger.pl @@ -17,13 +17,13 @@ my $USAGE = " FreeSWITCH Logger Utility USAGE: --h --helpThis help +-h --help This help -p --port Choose port -P -pass Choose password -f --file Output file -pb --paste-bin Post to FreeSWITCH Paste Bin -sp --sip-profiles List of SIP profiles to trace --sd --sip-debug Set SIP debug level +-sd --sip-debug Set SIP debug level No arguments given will trace profile 'internal' to STDOUT "; diff --git a/libs/freetdm/freetdm.2008.sln b/libs/freetdm/freetdm.2008.sln index f059d941d3..c7207a6216 100644 --- a/libs/freetdm/freetdm.2008.sln +++ b/libs/freetdm/freetdm.2008.sln @@ -64,6 +64,9 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ftmod_sangoma_isdn", "src\f EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ftmod_r2", "src\ftmod\ftmod_r2\ftmod_r2.2008.vcproj", "{08C3EA27-A51D-47F8-B47D-B189C649CF30}" + ProjectSection(ProjectDependencies) = postProject + {93B8812C-3EC4-4F78-8970-FFBFC99E167D} = {93B8812C-3EC4-4F78-8970-FFBFC99E167D} + EndProjectSection EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -131,7 +134,6 @@ Global {1A145EE9-BBD8-45E5-98CD-EB4BE99E1DCD}.Release|Win32.ActiveCfg = Release|Win32 {1A145EE9-BBD8-45E5-98CD-EB4BE99E1DCD}.Release|x64.ActiveCfg = Release|x64 {D021EF2A-460D-4827-A0F7-41FDECF46F1B}.Debug|Win32.ActiveCfg = Debug|Win32 - {D021EF2A-460D-4827-A0F7-41FDECF46F1B}.Debug|Win32.Build.0 = Debug|Win32 {D021EF2A-460D-4827-A0F7-41FDECF46F1B}.Debug|x64.ActiveCfg = Debug|x64 {D021EF2A-460D-4827-A0F7-41FDECF46F1B}.Debug|x64.Build.0 = Debug|x64 {D021EF2A-460D-4827-A0F7-41FDECF46F1B}.Release|Win32.ActiveCfg = Release|Win32 @@ -139,7 +141,6 @@ Global {D021EF2A-460D-4827-A0F7-41FDECF46F1B}.Release|x64.ActiveCfg = Release|x64 {D021EF2A-460D-4827-A0F7-41FDECF46F1B}.Release|x64.Build.0 = Release|x64 {2B1BAF36-0241-43E7-B865-A8338AD48E2E}.Debug|Win32.ActiveCfg = Debug|Win32 - {2B1BAF36-0241-43E7-B865-A8338AD48E2E}.Debug|Win32.Build.0 = Debug|Win32 {2B1BAF36-0241-43E7-B865-A8338AD48E2E}.Debug|x64.ActiveCfg = Debug|x64 {2B1BAF36-0241-43E7-B865-A8338AD48E2E}.Debug|x64.Build.0 = Debug|x64 {2B1BAF36-0241-43E7-B865-A8338AD48E2E}.Release|Win32.ActiveCfg = Release|Win32 @@ -147,7 +148,6 @@ Global {2B1BAF36-0241-43E7-B865-A8338AD48E2E}.Release|x64.ActiveCfg = Release|x64 {2B1BAF36-0241-43E7-B865-A8338AD48E2E}.Release|x64.Build.0 = Release|x64 {0DA69C18-4FA1-4E8C-89CE-12498637C5BE}.Debug|Win32.ActiveCfg = Debug|Win32 - {0DA69C18-4FA1-4E8C-89CE-12498637C5BE}.Debug|Win32.Build.0 = Debug|Win32 {0DA69C18-4FA1-4E8C-89CE-12498637C5BE}.Debug|x64.ActiveCfg = Debug|x64 {0DA69C18-4FA1-4E8C-89CE-12498637C5BE}.Debug|x64.Build.0 = Debug|x64 {0DA69C18-4FA1-4E8C-89CE-12498637C5BE}.Release|Win32.ActiveCfg = Release|Win32 @@ -155,13 +155,11 @@ Global {0DA69C18-4FA1-4E8C-89CE-12498637C5BE}.Release|x64.ActiveCfg = Release|x64 {0DA69C18-4FA1-4E8C-89CE-12498637C5BE}.Release|x64.Build.0 = Release|x64 {B2AF4EA6-0CD7-4529-9EB5-5AF43DB90395}.Debug|Win32.ActiveCfg = Debug|Win32 - {B2AF4EA6-0CD7-4529-9EB5-5AF43DB90395}.Debug|Win32.Build.0 = Debug|Win32 {B2AF4EA6-0CD7-4529-9EB5-5AF43DB90395}.Debug|x64.ActiveCfg = Debug|Win32 {B2AF4EA6-0CD7-4529-9EB5-5AF43DB90395}.Release|Win32.ActiveCfg = Release|Win32 {B2AF4EA6-0CD7-4529-9EB5-5AF43DB90395}.Release|Win32.Build.0 = Release|Win32 {B2AF4EA6-0CD7-4529-9EB5-5AF43DB90395}.Release|x64.ActiveCfg = Release|Win32 {08C3EA27-A51D-47F8-B47D-B189C649CF30}.Debug|Win32.ActiveCfg = Debug|Win32 - {08C3EA27-A51D-47F8-B47D-B189C649CF30}.Debug|Win32.Build.0 = Debug|Win32 {08C3EA27-A51D-47F8-B47D-B189C649CF30}.Debug|x64.ActiveCfg = Debug|Win32 {08C3EA27-A51D-47F8-B47D-B189C649CF30}.Release|Win32.ActiveCfg = Release|Win32 {08C3EA27-A51D-47F8-B47D-B189C649CF30}.Release|Win32.Build.0 = Release|Win32 diff --git a/libs/freetdm/freetdm.2010.sln b/libs/freetdm/freetdm.2010.sln new file mode 100644 index 0000000000..1806e9ea23 --- /dev/null +++ b/libs/freetdm/freetdm.2010.sln @@ -0,0 +1,137 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "freetdm", "msvc\freetdm.2010.vcxproj", "{93B8812C-3EC4-4F78-8970-FFBFC99E167D}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testanalog", "msvc\testanalog\testanalog.2010.vcxproj", "{BB833648-BAFF-4BE2-94DB-F8BB043C588C}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testisdn", "msvc\testisdn\testisdn.2010.vcxproj", "{6DA6FD42-641D-4147-92F5-3BC4AAA6589B}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_freetdm", "mod_freetdm\mod_freetdm.2010.vcxproj", "{FE3540C5-3303-46E0-A69E-D92F775687F1}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ftmod_analog", "src\ftmod\ftmod_analog\ftmod_analog.2010.vcxproj", "{37C94798-6E33-4B4F-8EE0-C72A7DC91157}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ftmod_analog_em", "src\ftmod\ftmod_analog_em\ftmod_analog_em.2010.vcxproj", "{B3F49375-2834-4937-9D8C-4AC2EC911010}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ftmod_isdn", "src\ftmod\ftmod_isdn\ftmod_isdn.2010.vcxproj", "{729344A5-D5E9-434D-8EE8-AF8C6C795D15}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ftmod_pika", "src\ftmod\ftmod_pika\ftmod_pika.2010.vcxproj", "{E886B4D5-AB4F-4092-B8F4-3B06E1E462EF}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ftmod_wanpipe", "src\ftmod\ftmod_wanpipe\ftmod_wanpipe.2010.vcxproj", "{1A145EE9-BBD8-45E5-98CD-EB4BE99E1DCD}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ftmod_sangoma_boost", "src\ftmod\ftmod_sangoma_boost\ftmod_sangoma_boost.2010.vcxproj", "{D021EF2A-460D-4827-A0F7-41FDECF46F1B}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testboost", "msvc\testboost\testboost.2010.vcxproj", "{2B1BAF36-0241-43E7-B865-A8338AD48E2E}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testsangomaboost", "msvc\testboost\testsangomaboost.2010.vcxproj", "{0DA69C18-4FA1-4E8C-89CE-12498637C5BE}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ftmod_sangoma_isdn", "src\ftmod\ftmod_sangoma_isdn\ftmod_sangoma_isdn.2010.vcxproj", "{B2AF4EA6-0CD7-4529-9EB5-5AF43DB90395}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ftmod_r2", "src\ftmod\ftmod_r2\ftmod_r2.2010.vcxproj", "{08C3EA27-A51D-47F8-B47D-B189C649CF30}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {93B8812C-3EC4-4F78-8970-FFBFC99E167D}.Debug|Win32.ActiveCfg = Debug|Win32 + {93B8812C-3EC4-4F78-8970-FFBFC99E167D}.Debug|Win32.Build.0 = Debug|Win32 + {93B8812C-3EC4-4F78-8970-FFBFC99E167D}.Debug|x64.ActiveCfg = Debug|x64 + {93B8812C-3EC4-4F78-8970-FFBFC99E167D}.Debug|x64.Build.0 = Debug|x64 + {93B8812C-3EC4-4F78-8970-FFBFC99E167D}.Release|Win32.ActiveCfg = Release|Win32 + {93B8812C-3EC4-4F78-8970-FFBFC99E167D}.Release|Win32.Build.0 = Release|Win32 + {93B8812C-3EC4-4F78-8970-FFBFC99E167D}.Release|x64.ActiveCfg = Release|x64 + {93B8812C-3EC4-4F78-8970-FFBFC99E167D}.Release|x64.Build.0 = Release|x64 + {BB833648-BAFF-4BE2-94DB-F8BB043C588C}.Debug|Win32.ActiveCfg = Debug|Win32 + {BB833648-BAFF-4BE2-94DB-F8BB043C588C}.Debug|Win32.Build.0 = Debug|Win32 + {BB833648-BAFF-4BE2-94DB-F8BB043C588C}.Debug|x64.ActiveCfg = Debug|x64 + {BB833648-BAFF-4BE2-94DB-F8BB043C588C}.Debug|x64.Build.0 = Debug|x64 + {BB833648-BAFF-4BE2-94DB-F8BB043C588C}.Release|Win32.ActiveCfg = Release|Win32 + {BB833648-BAFF-4BE2-94DB-F8BB043C588C}.Release|Win32.Build.0 = Release|Win32 + {BB833648-BAFF-4BE2-94DB-F8BB043C588C}.Release|x64.ActiveCfg = Release|x64 + {BB833648-BAFF-4BE2-94DB-F8BB043C588C}.Release|x64.Build.0 = Release|x64 + {6DA6FD42-641D-4147-92F5-3BC4AAA6589B}.Debug|Win32.ActiveCfg = Debug|Win32 + {6DA6FD42-641D-4147-92F5-3BC4AAA6589B}.Debug|x64.ActiveCfg = Debug|x64 + {6DA6FD42-641D-4147-92F5-3BC4AAA6589B}.Release|Win32.ActiveCfg = Release|Win32 + {6DA6FD42-641D-4147-92F5-3BC4AAA6589B}.Release|x64.ActiveCfg = Release|x64 + {FE3540C5-3303-46E0-A69E-D92F775687F1}.Debug|Win32.ActiveCfg = Debug|Win32 + {FE3540C5-3303-46E0-A69E-D92F775687F1}.Debug|Win32.Build.0 = Debug|Win32 + {FE3540C5-3303-46E0-A69E-D92F775687F1}.Debug|x64.ActiveCfg = Debug|x64 + {FE3540C5-3303-46E0-A69E-D92F775687F1}.Debug|x64.Build.0 = Debug|x64 + {FE3540C5-3303-46E0-A69E-D92F775687F1}.Release|Win32.ActiveCfg = Release|Win32 + {FE3540C5-3303-46E0-A69E-D92F775687F1}.Release|Win32.Build.0 = Release|Win32 + {FE3540C5-3303-46E0-A69E-D92F775687F1}.Release|x64.ActiveCfg = Release|x64 + {FE3540C5-3303-46E0-A69E-D92F775687F1}.Release|x64.Build.0 = Release|x64 + {37C94798-6E33-4B4F-8EE0-C72A7DC91157}.Debug|Win32.ActiveCfg = Debug|Win32 + {37C94798-6E33-4B4F-8EE0-C72A7DC91157}.Debug|Win32.Build.0 = Debug|Win32 + {37C94798-6E33-4B4F-8EE0-C72A7DC91157}.Debug|x64.ActiveCfg = Debug|x64 + {37C94798-6E33-4B4F-8EE0-C72A7DC91157}.Debug|x64.Build.0 = Debug|x64 + {37C94798-6E33-4B4F-8EE0-C72A7DC91157}.Release|Win32.ActiveCfg = Release|Win32 + {37C94798-6E33-4B4F-8EE0-C72A7DC91157}.Release|Win32.Build.0 = Release|Win32 + {37C94798-6E33-4B4F-8EE0-C72A7DC91157}.Release|x64.ActiveCfg = Release|x64 + {37C94798-6E33-4B4F-8EE0-C72A7DC91157}.Release|x64.Build.0 = Release|x64 + {B3F49375-2834-4937-9D8C-4AC2EC911010}.Debug|Win32.ActiveCfg = Debug|Win32 + {B3F49375-2834-4937-9D8C-4AC2EC911010}.Debug|Win32.Build.0 = Debug|Win32 + {B3F49375-2834-4937-9D8C-4AC2EC911010}.Debug|x64.ActiveCfg = Debug|x64 + {B3F49375-2834-4937-9D8C-4AC2EC911010}.Debug|x64.Build.0 = Debug|x64 + {B3F49375-2834-4937-9D8C-4AC2EC911010}.Release|Win32.ActiveCfg = Release|Win32 + {B3F49375-2834-4937-9D8C-4AC2EC911010}.Release|Win32.Build.0 = Release|Win32 + {B3F49375-2834-4937-9D8C-4AC2EC911010}.Release|x64.ActiveCfg = Release|x64 + {B3F49375-2834-4937-9D8C-4AC2EC911010}.Release|x64.Build.0 = Release|x64 + {729344A5-D5E9-434D-8EE8-AF8C6C795D15}.Debug|Win32.ActiveCfg = Debug|Win32 + {729344A5-D5E9-434D-8EE8-AF8C6C795D15}.Debug|x64.ActiveCfg = Debug|x64 + {729344A5-D5E9-434D-8EE8-AF8C6C795D15}.Release|Win32.ActiveCfg = Release|Win32 + {729344A5-D5E9-434D-8EE8-AF8C6C795D15}.Release|x64.ActiveCfg = Release|x64 + {E886B4D5-AB4F-4092-B8F4-3B06E1E462EF}.Debug|Win32.ActiveCfg = Debug|Win32 + {E886B4D5-AB4F-4092-B8F4-3B06E1E462EF}.Debug|x64.ActiveCfg = Debug|x64 + {E886B4D5-AB4F-4092-B8F4-3B06E1E462EF}.Release|Win32.ActiveCfg = Release|Win32 + {E886B4D5-AB4F-4092-B8F4-3B06E1E462EF}.Release|x64.ActiveCfg = Release|x64 + {1A145EE9-BBD8-45E5-98CD-EB4BE99E1DCD}.Debug|Win32.ActiveCfg = Debug|Win32 + {1A145EE9-BBD8-45E5-98CD-EB4BE99E1DCD}.Debug|Win32.Build.0 = Debug|Win32 + {1A145EE9-BBD8-45E5-98CD-EB4BE99E1DCD}.Debug|x64.ActiveCfg = Debug|x64 + {1A145EE9-BBD8-45E5-98CD-EB4BE99E1DCD}.Release|Win32.ActiveCfg = Release|Win32 + {1A145EE9-BBD8-45E5-98CD-EB4BE99E1DCD}.Release|x64.ActiveCfg = Release|x64 + {D021EF2A-460D-4827-A0F7-41FDECF46F1B}.Debug|Win32.ActiveCfg = Debug|Win32 + {D021EF2A-460D-4827-A0F7-41FDECF46F1B}.Debug|Win32.Build.0 = Debug|Win32 + {D021EF2A-460D-4827-A0F7-41FDECF46F1B}.Debug|x64.ActiveCfg = Debug|x64 + {D021EF2A-460D-4827-A0F7-41FDECF46F1B}.Debug|x64.Build.0 = Debug|x64 + {D021EF2A-460D-4827-A0F7-41FDECF46F1B}.Release|Win32.ActiveCfg = Release|Win32 + {D021EF2A-460D-4827-A0F7-41FDECF46F1B}.Release|Win32.Build.0 = Release|Win32 + {D021EF2A-460D-4827-A0F7-41FDECF46F1B}.Release|x64.ActiveCfg = Release|x64 + {D021EF2A-460D-4827-A0F7-41FDECF46F1B}.Release|x64.Build.0 = Release|x64 + {2B1BAF36-0241-43E7-B865-A8338AD48E2E}.Debug|Win32.ActiveCfg = Debug|Win32 + {2B1BAF36-0241-43E7-B865-A8338AD48E2E}.Debug|Win32.Build.0 = Debug|Win32 + {2B1BAF36-0241-43E7-B865-A8338AD48E2E}.Debug|x64.ActiveCfg = Debug|x64 + {2B1BAF36-0241-43E7-B865-A8338AD48E2E}.Debug|x64.Build.0 = Debug|x64 + {2B1BAF36-0241-43E7-B865-A8338AD48E2E}.Release|Win32.ActiveCfg = Release|Win32 + {2B1BAF36-0241-43E7-B865-A8338AD48E2E}.Release|Win32.Build.0 = Release|Win32 + {2B1BAF36-0241-43E7-B865-A8338AD48E2E}.Release|x64.ActiveCfg = Release|x64 + {2B1BAF36-0241-43E7-B865-A8338AD48E2E}.Release|x64.Build.0 = Release|x64 + {0DA69C18-4FA1-4E8C-89CE-12498637C5BE}.Debug|Win32.ActiveCfg = Debug|Win32 + {0DA69C18-4FA1-4E8C-89CE-12498637C5BE}.Debug|Win32.Build.0 = Debug|Win32 + {0DA69C18-4FA1-4E8C-89CE-12498637C5BE}.Debug|x64.ActiveCfg = Debug|x64 + {0DA69C18-4FA1-4E8C-89CE-12498637C5BE}.Debug|x64.Build.0 = Debug|x64 + {0DA69C18-4FA1-4E8C-89CE-12498637C5BE}.Release|Win32.ActiveCfg = Release|Win32 + {0DA69C18-4FA1-4E8C-89CE-12498637C5BE}.Release|Win32.Build.0 = Release|Win32 + {0DA69C18-4FA1-4E8C-89CE-12498637C5BE}.Release|x64.ActiveCfg = Release|x64 + {0DA69C18-4FA1-4E8C-89CE-12498637C5BE}.Release|x64.Build.0 = Release|x64 + {B2AF4EA6-0CD7-4529-9EB5-5AF43DB90395}.Debug|Win32.ActiveCfg = Debug|Win32 + {B2AF4EA6-0CD7-4529-9EB5-5AF43DB90395}.Debug|Win32.Build.0 = Debug|Win32 + {B2AF4EA6-0CD7-4529-9EB5-5AF43DB90395}.Debug|x64.ActiveCfg = Debug|Win32 + {B2AF4EA6-0CD7-4529-9EB5-5AF43DB90395}.Release|Win32.ActiveCfg = Release|Win32 + {B2AF4EA6-0CD7-4529-9EB5-5AF43DB90395}.Release|Win32.Build.0 = Release|Win32 + {B2AF4EA6-0CD7-4529-9EB5-5AF43DB90395}.Release|x64.ActiveCfg = Release|Win32 + {08C3EA27-A51D-47F8-B47D-B189C649CF30}.Debug|Win32.ActiveCfg = Debug|Win32 + {08C3EA27-A51D-47F8-B47D-B189C649CF30}.Debug|Win32.Build.0 = Debug|Win32 + {08C3EA27-A51D-47F8-B47D-B189C649CF30}.Debug|x64.ActiveCfg = Debug|Win32 + {08C3EA27-A51D-47F8-B47D-B189C649CF30}.Release|Win32.ActiveCfg = Release|Win32 + {08C3EA27-A51D-47F8-B47D-B189C649CF30}.Release|Win32.Build.0 = Release|Win32 + {08C3EA27-A51D-47F8-B47D-B189C649CF30}.Release|x64.ActiveCfg = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/libs/freetdm/mod_freetdm/mod_freetdm.c b/libs/freetdm/mod_freetdm/mod_freetdm.c index 07d4e88f33..6a23a4436d 100755 --- a/libs/freetdm/mod_freetdm/mod_freetdm.c +++ b/libs/freetdm/mod_freetdm/mod_freetdm.c @@ -841,9 +841,9 @@ static switch_status_t channel_receive_message_b(switch_core_session_t *session, assert(tech_pvt != NULL); if (switch_test_flag(tech_pvt, TFLAG_DEAD)) { - switch_channel_hangup(channel, SWITCH_CAUSE_LOSE_RACE); - return SWITCH_STATUS_FALSE; - } + switch_channel_hangup(channel, SWITCH_CAUSE_LOSE_RACE); + return SWITCH_STATUS_FALSE; + } if (ftdm_channel_call_check_hangup(tech_pvt->ftdmchan)) { return SWITCH_STATUS_SUCCESS; @@ -888,9 +888,9 @@ static switch_status_t channel_receive_message_fxo(switch_core_session_t *sessio assert(tech_pvt != NULL); if (switch_test_flag(tech_pvt, TFLAG_DEAD)) { - switch_channel_hangup(channel, SWITCH_CAUSE_LOSE_RACE); - return SWITCH_STATUS_FALSE; - } + switch_channel_hangup(channel, SWITCH_CAUSE_LOSE_RACE); + return SWITCH_STATUS_FALSE; + } if (switch_channel_test_flag(channel, CF_OUTBOUND)) { return SWITCH_STATUS_SUCCESS; @@ -3238,29 +3238,6 @@ static switch_status_t load_config(void) char *name = (char *) switch_xml_attr(myspan, "name"); ftdm_status_t zstatus = FTDM_FAIL; - /* strings */ - const char *variant = "itu"; - const char *category = "national_subscriber"; - const char *logdir = "/usr/local/freeswitch/log/"; /* FIXME: get PREFIX variable */ - const char *logging = "notice,warning,error"; - const char *advanced_protocol_file = ""; - - /* booleans */ - int call_files = 0; - int get_ani_first = -1; - int immediate_accept = -1; - int double_answer = -1; - int skip_category = -1; - int forced_release = -1; - int charge_calls = -1; - - /* integers */ - int mfback_timeout = -1; - int metering_pulse_timeout = -1; - int allow_collect_calls = -1; - int max_ani = 10; - int max_dnis = 4; - /* common non r2 stuff */ const char *context = "default"; const char *dialplan = "XML"; @@ -3269,53 +3246,16 @@ static switch_status_t load_config(void) uint32_t span_id = 0; ftdm_span_t *span = NULL; + ftdm_conf_parameter_t spanparameters[30]; + unsigned paramindex = 0; + memset(spanparameters, 0, sizeof(spanparameters)); for (param = switch_xml_child(myspan, "param"); param; param = param->next) { char *var = (char *) switch_xml_attr_soft(param, "name"); char *val = (char *) switch_xml_attr_soft(param, "value"); /* string parameters */ - if (!strcasecmp(var, "variant")) { - variant = val; - } else if (!strcasecmp(var, "category")) { - category = val; - } else if (!strcasecmp(var, "logdir")) { - logdir = val; - } else if (!strcasecmp(var, "logging")) { - logging = val; - } else if (!strcasecmp(var, "advanced_protocol_file")) { - advanced_protocol_file = val; - - /* booleans */ - } else if (!strcasecmp(var, "allow_collect_calls")) { - allow_collect_calls = switch_true(val); - } else if (!strcasecmp(var, "immediate_accept")) { - immediate_accept = switch_true(val); - } else if (!strcasecmp(var, "double_answer")) { - double_answer = switch_true(val); - } else if (!strcasecmp(var, "skip_category")) { - skip_category = switch_true(var); - } else if (!strcasecmp(var, "forced_release")) { - forced_release = switch_true(val); - } else if (!strcasecmp(var, "charge_calls")) { - charge_calls = switch_true(val); - } else if (!strcasecmp(var, "get_ani_first")) { - get_ani_first = switch_true(val); - } else if (!strcasecmp(var, "call_files")) { - call_files = switch_true(val); - - /* integers */ - } else if (!strcasecmp(var, "mfback_timeout")) { - mfback_timeout = atoi(val); - } else if (!strcasecmp(var, "metering_pulse_timeout")) { - metering_pulse_timeout = atoi(val); - } else if (!strcasecmp(var, "max_ani")) { - max_ani = atoi(val); - } else if (!strcasecmp(var, "max_dnis")) { - max_dnis = atoi(val); - - /* common non r2 stuff */ - } else if (!strcasecmp(var, "context")) { + if (!strcasecmp(var, "context")) { context = val; } else if (!strcasecmp(var, "dialplan")) { dialplan = val; @@ -3323,11 +3263,15 @@ static switch_status_t load_config(void) dial_regex = val; } else if (!strcasecmp(var, "fail-dial-regex")) { fail_dial_regex = val; + } else { + spanparameters[paramindex].var = var; + spanparameters[paramindex].val = val; + paramindex++; } } if (!id && !name) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "span missing required param 'id'\n"); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "either 'id' or 'name' required params are missing\n"); continue; } @@ -3353,25 +3297,7 @@ static switch_status_t load_config(void) span_id = ftdm_span_get_id(span); } - if (ftdm_configure_span(span, "r2", on_r2_signal, - "variant", variant, - "max_ani", max_ani, - "max_dnis", max_dnis, - "category", category, - "logdir", logdir, - "logging", logging, - "advanced_protocol_file", advanced_protocol_file, - "allow_collect_calls", allow_collect_calls, - "immediate_accept", immediate_accept, - "double_answer", double_answer, - "skip_category", skip_category, - "forced_release", forced_release, - "charge_calls", charge_calls, - "get_ani_first", get_ani_first, - "call_files", call_files, - "mfback_timeout", mfback_timeout, - "metering_pulse_timeout", metering_pulse_timeout, - FTDM_TAG_END) != FTDM_SUCCESS) { + if (ftdm_configure_span_signaling(span, "r2", on_r2_signal, spanparameters) != FTDM_SUCCESS) { ftdm_log(FTDM_LOG_ERROR, "Error configuring R2 FreeTDM span %d, error: %s\n", span_id, ftdm_span_get_last_error(span)); continue; diff --git a/libs/freetdm/msvc/freetdm.2010.vcxproj b/libs/freetdm/msvc/freetdm.2010.vcxproj new file mode 100644 index 0000000000..71eb6dbf22 --- /dev/null +++ b/libs/freetdm/msvc/freetdm.2010.vcxproj @@ -0,0 +1,223 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + freetdm + {93B8812C-3EC4-4F78-8970-FFBFC99E167D} + freetdm + Win32Proj + + + + DynamicLibrary + MultiByte + true + + + DynamicLibrary + MultiByte + + + DynamicLibrary + MultiByte + true + + + DynamicLibrary + MultiByte + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + $(SolutionDir)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\ + $(SolutionDir)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\ + $(SolutionDir)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\ + $(SolutionDir)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\ + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + $(IntDir)BuildLog-freetdm.htm + + + Disabled + ../src/include;../src/include/private;../src/isdn/include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;FREETDM_EXPORTS;TELETONE_EXPORTS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + false + false + + + Level4 + true + ProgramDatabase + CompileAsC + + + true + + + + + $(IntDir)BuildLog-freetdm.htm + + + ../src/include;../src/include/private;../src/isdn/include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;FREETDM_EXPORTS;TELETONE_EXPORTS;%(PreprocessorDefinitions) + MultiThreadedDLL + false + false + + + Level4 + true + ProgramDatabase + CompileAsC + + + + + $(IntDir)BuildLog-freetdm.htm + + + X64 + + + Disabled + ../src/include;../src/include/private;../src/isdn/include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;FREETDM_EXPORTS;TELETONE_EXPORTS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + false + false + + + Level4 + true + ProgramDatabase + CompileAsC + + + true + MachineX64 + + + + + $(IntDir)BuildLog-freetdm.htm + + + X64 + + + ../src/include;../src/include/private;../src/isdn/include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;FREETDM_EXPORTS;TELETONE_EXPORTS;%(PreprocessorDefinitions) + MultiThreadedDLL + false + false + + + Level4 + true + ProgramDatabase + CompileAsC + + + MachineX64 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/libs/freetdm/msvc/freetdm.2010.vcxproj.filters b/libs/freetdm/msvc/freetdm.2010.vcxproj.filters new file mode 100644 index 0000000000..ed642baf3d --- /dev/null +++ b/libs/freetdm/msvc/freetdm.2010.vcxproj.filters @@ -0,0 +1,128 @@ + + + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + \ No newline at end of file diff --git a/libs/freetdm/msvc/testanalog/testanalog.2010.vcxproj b/libs/freetdm/msvc/testanalog/testanalog.2010.vcxproj new file mode 100644 index 0000000000..719dc618a9 --- /dev/null +++ b/libs/freetdm/msvc/testanalog/testanalog.2010.vcxproj @@ -0,0 +1,213 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + testanalog + {BB833648-BAFF-4BE2-94DB-F8BB043C588C} + testanalog + Win32Proj + + + + Application + Unicode + true + + + Application + Unicode + + + Application + Unicode + true + + + Application + Unicode + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + $(SolutionDir)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\ + true + $(SolutionDir)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\ + false + $(SolutionDir)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\ + true + $(SolutionDir)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\ + false + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + $(IntDir)BuildLog-testanalog.htm + + + Disabled + ../../src/include;../../src/isdn/include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + + Level4 + true + EditAndContinue + 4100;%(DisableSpecificWarnings) + + + true + Console + false + + + MachineX86 + + + + + $(IntDir)BuildLog-testanalog.htm + + + ../../src/include;../../src/isdn/include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreadedDLL + + + Level4 + true + ProgramDatabase + 4100;%(DisableSpecificWarnings) + + + true + Console + true + true + false + + + MachineX86 + + + + + $(IntDir)BuildLog-testanalog.htm + + + X64 + + + Disabled + ../../src/include;../../src/isdn/include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + + Level4 + true + ProgramDatabase + 4100;%(DisableSpecificWarnings) + + + true + Console + false + + + MachineX64 + + + + + $(IntDir)BuildLog-testanalog.htm + + + X64 + + + ../../src/include;../../src/isdn/include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreadedDLL + + + Level4 + true + ProgramDatabase + 4100;%(DisableSpecificWarnings) + + + true + Console + true + true + false + + + MachineX64 + + + + + + + + {93b8812c-3ec4-4f78-8970-ffbfc99e167d} + false + + + + + + \ No newline at end of file diff --git a/libs/freetdm/msvc/testanalog/testanalog.2010.vcxproj.filters b/libs/freetdm/msvc/testanalog/testanalog.2010.vcxproj.filters new file mode 100644 index 0000000000..7ac3635cc5 --- /dev/null +++ b/libs/freetdm/msvc/testanalog/testanalog.2010.vcxproj.filters @@ -0,0 +1,14 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + + + Source Files + + + \ No newline at end of file diff --git a/libs/freetdm/msvc/testboost/testboost.2010.vcxproj b/libs/freetdm/msvc/testboost/testboost.2010.vcxproj new file mode 100644 index 0000000000..62061485c2 --- /dev/null +++ b/libs/freetdm/msvc/testboost/testboost.2010.vcxproj @@ -0,0 +1,218 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + testboost + {2B1BAF36-0241-43E7-B865-A8338AD48E2E} + testboost + Win32Proj + + + + Application + Unicode + true + + + Application + Unicode + + + Application + Unicode + true + + + Application + Unicode + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + $(SolutionDir)$(Platform)\$(Configuration)\ + $(Platform)\testboost\$(Configuration)\ + true + $(SolutionDir)$(Platform)\$(Configuration)\ + $(Platform)\testboost\$(Configuration)\ + false + $(SolutionDir)$(Platform)\$(Configuration)\ + $(Platform)\testboost\$(Configuration)\ + true + $(SolutionDir)$(Platform)\$(Configuration)\ + $(Platform)\testboost\$(Configuration)\ + false + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + $(IntDir)BuildLog-testboost.htm + + + Disabled + ../../src/include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + + Level4 + true + EditAndContinue + 4100;%(DisableSpecificWarnings) + + + ..\..\debug\freetdm.lib;%(AdditionalDependencies) + true + Console + false + + + MachineX86 + + + + + $(IntDir)BuildLog-testboost.htm + + + ../../src/include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreadedDLL + + + Level4 + true + ProgramDatabase + 4100;%(DisableSpecificWarnings) + + + true + Console + true + true + false + + + MachineX86 + + + + + $(IntDir)BuildLog-testboost.htm + + + X64 + + + Disabled + ../../src/include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + + Level4 + true + ProgramDatabase + 4100;%(DisableSpecificWarnings) + + + freetdm.lib;%(AdditionalDependencies) + true + Console + false + + + MachineX64 + ../../$(PlatformName)\$(Configuration);%(AdditionalLibraryDirectories) + + + + + $(IntDir)BuildLog-testboost.htm + + + X64 + + + ../../src/include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreadedDLL + + + Level4 + true + ProgramDatabase + 4100;%(DisableSpecificWarnings) + + + true + Console + true + true + false + + + MachineX64 + freetdm.lib;%(AdditionalDependencies) + ../../$(PlatformName)\$(Configuration);%(AdditionalLibraryDirectories) + + + + + + + + {93b8812c-3ec4-4f78-8970-ffbfc99e167d} + false + + + + + + \ No newline at end of file diff --git a/libs/freetdm/msvc/testboost/testboost.2010.vcxproj.filters b/libs/freetdm/msvc/testboost/testboost.2010.vcxproj.filters new file mode 100644 index 0000000000..74181d60a8 --- /dev/null +++ b/libs/freetdm/msvc/testboost/testboost.2010.vcxproj.filters @@ -0,0 +1,14 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + + + Source Files + + + \ No newline at end of file diff --git a/libs/freetdm/msvc/testboost/testsangomaboost.2010.vcxproj b/libs/freetdm/msvc/testboost/testsangomaboost.2010.vcxproj new file mode 100644 index 0000000000..b6c0518883 --- /dev/null +++ b/libs/freetdm/msvc/testboost/testsangomaboost.2010.vcxproj @@ -0,0 +1,218 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + testsangomaboost + {0DA69C18-4FA1-4E8C-89CE-12498637C5BE} + testsangomaboost + Win32Proj + + + + Application + Unicode + true + + + Application + Unicode + + + Application + Unicode + true + + + Application + Unicode + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + $(SolutionDir)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\ + true + $(SolutionDir)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\ + false + $(SolutionDir)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\ + true + $(SolutionDir)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\ + false + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + $(IntDir)BuildLog-testsangomaboost.htm + + + Disabled + ../../src/include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + + Level4 + true + EditAndContinue + 4100;%(DisableSpecificWarnings) + + + ..\..\debug\freetdm.lib;%(AdditionalDependencies) + true + Console + false + + + MachineX86 + + + + + $(IntDir)BuildLog-testsangomaboost.htm + + + ../../src/include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreadedDLL + + + Level4 + true + ProgramDatabase + 4100;%(DisableSpecificWarnings) + + + true + Console + true + true + false + + + MachineX86 + + + + + $(IntDir)BuildLog-testsangomaboost.htm + + + X64 + + + Disabled + ../../src/include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + + Level4 + false + ProgramDatabase + 4100;%(DisableSpecificWarnings) + + + freetdm.lib;%(AdditionalDependencies) + true + Console + false + + + MachineX64 + ../../$(PlatformName)\$(Configuration);%(AdditionalLibraryDirectories) + + + + + $(IntDir)BuildLog-testsangomaboost.htm + + + X64 + + + ../../src/include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreadedDLL + + + Level4 + true + ProgramDatabase + 4100;%(DisableSpecificWarnings) + + + true + Console + true + true + false + + + MachineX64 + freetdm.lib;%(AdditionalDependencies) + ../../$(PlatformName)\$(Configuration);%(AdditionalLibraryDirectories) + + + + + + + + {93b8812c-3ec4-4f78-8970-ffbfc99e167d} + false + + + + + + \ No newline at end of file diff --git a/libs/freetdm/msvc/testboost/testsangomaboost.2010.vcxproj.filters b/libs/freetdm/msvc/testboost/testsangomaboost.2010.vcxproj.filters new file mode 100644 index 0000000000..e72f14e161 --- /dev/null +++ b/libs/freetdm/msvc/testboost/testsangomaboost.2010.vcxproj.filters @@ -0,0 +1,14 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + + + Source Files + + + \ No newline at end of file diff --git a/libs/freetdm/msvc/testisdn/testisdn.2010.vcxproj b/libs/freetdm/msvc/testisdn/testisdn.2010.vcxproj new file mode 100644 index 0000000000..2dfdeb042f --- /dev/null +++ b/libs/freetdm/msvc/testisdn/testisdn.2010.vcxproj @@ -0,0 +1,213 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + testisdn + {6DA6FD42-641D-4147-92F5-3BC4AAA6589B} + testisdn + Win32Proj + + + + Application + Unicode + true + + + Application + Unicode + + + Application + Unicode + true + + + Application + Unicode + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + $(SolutionDir)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\ + true + $(SolutionDir)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\ + false + $(SolutionDir)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\ + true + $(SolutionDir)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\ + false + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + $(IntDir)BuildLog-testisdn.htm + + + Disabled + ../../src/include;../../src/isdn/include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + + Level4 + true + EditAndContinue + 4100;%(DisableSpecificWarnings) + + + true + Console + false + + + MachineX86 + + + + + $(IntDir)BuildLog-testisdn.htm + + + ../../src/include;../../src/isdn/include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreadedDLL + + + Level4 + true + ProgramDatabase + 4100;%(DisableSpecificWarnings) + + + true + Console + true + true + false + + + MachineX86 + + + + + $(IntDir)BuildLog-testisdn.htm + + + X64 + + + Disabled + ../../src/include;../../src/isdn/include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + + Level4 + true + ProgramDatabase + 4100;%(DisableSpecificWarnings) + + + true + Console + false + + + MachineX64 + + + + + $(IntDir)BuildLog-testisdn.htm + + + X64 + + + ../../src/include;../../src/isdn/include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreadedDLL + + + Level4 + true + ProgramDatabase + 4100;%(DisableSpecificWarnings) + + + true + Console + true + true + false + + + MachineX64 + + + + + + + + {93b8812c-3ec4-4f78-8970-ffbfc99e167d} + false + + + + + + \ No newline at end of file diff --git a/libs/freetdm/msvc/testisdn/testisdn.2010.vcxproj.filters b/libs/freetdm/msvc/testisdn/testisdn.2010.vcxproj.filters new file mode 100644 index 0000000000..9d48828d4a --- /dev/null +++ b/libs/freetdm/msvc/testisdn/testisdn.2010.vcxproj.filters @@ -0,0 +1,14 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + + + Source Files + + + \ No newline at end of file diff --git a/libs/freetdm/openzap.2005.sln b/libs/freetdm/openzap.2005.sln deleted file mode 100644 index c9f666b381..0000000000 --- a/libs/freetdm/openzap.2005.sln +++ /dev/null @@ -1,82 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 9.00 -# Visual Studio 2005 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "openzap", "msvc\openzap.2005.vcproj", "{93B8812C-3EC4-4F78-8970-FFBFC99E167D}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testanalog", "msvc\testanalog\testanalog.2005.vcproj", "{BB833648-BAFF-4BE2-94DB-F8BB043C588C}" - ProjectSection(ProjectDependencies) = postProject - {93B8812C-3EC4-4F78-8970-FFBFC99E167D} = {93B8812C-3EC4-4F78-8970-FFBFC99E167D} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testisdn", "msvc\testisdn\testisdn.2005.vcproj", "{6DA6FD42-641D-4147-92F5-3BC4AAA6589B}" - ProjectSection(ProjectDependencies) = postProject - {93B8812C-3EC4-4F78-8970-FFBFC99E167D} = {93B8812C-3EC4-4F78-8970-FFBFC99E167D} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_openzap", "mod_openzap\mod_openzap.2005.vcproj", "{FE3540C5-3303-46E0-A69E-D92F775687F1}" - ProjectSection(ProjectDependencies) = postProject - {93B8812C-3EC4-4F78-8970-FFBFC99E167D} = {93B8812C-3EC4-4F78-8970-FFBFC99E167D} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ozmod_analog", "src\ozmod\ozmod_analog\ozmod_analog.2005.vcproj", "{37C94798-6E33-4B4F-8EE0-C72A7DC91157}" - ProjectSection(ProjectDependencies) = postProject - {93B8812C-3EC4-4F78-8970-FFBFC99E167D} = {93B8812C-3EC4-4F78-8970-FFBFC99E167D} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ozmod_analog_em", "src\ozmod\ozmod_analog_em\ozmod_analog_em.2005.vcproj", "{C539D7C8-26A8-4A94-B938-77672165C130}" - ProjectSection(ProjectDependencies) = postProject - {93B8812C-3EC4-4F78-8970-FFBFC99E167D} = {93B8812C-3EC4-4F78-8970-FFBFC99E167D} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ozmod_isdn", "src\ozmod\ozmod_isdn\ozmod_isdn.2005.vcproj", "{729344A5-D5E9-434D-8EE8-AF8C6C795D15}" - ProjectSection(ProjectDependencies) = postProject - {93B8812C-3EC4-4F78-8970-FFBFC99E167D} = {93B8812C-3EC4-4F78-8970-FFBFC99E167D} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ozmod_wanpipe", "src\ozmod\ozmod_wanpipe\ozmod_wanpipe.2005.vcproj", "{1A145EE9-BBD8-45E5-98CD-EB4BE99E1DCD}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ozmod_pika", "src\ozmod\ozmod_pika\ozmod_pika.2005.vcproj", "{E886B4D5-AB4F-4092-B8F4-3B06E1E462EF}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Win32 = Debug|Win32 - Release|Win32 = Release|Win32 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {93B8812C-3EC4-4F78-8970-FFBFC99E167D}.Debug|Win32.ActiveCfg = Debug|Win32 - {93B8812C-3EC4-4F78-8970-FFBFC99E167D}.Debug|Win32.Build.0 = Debug|Win32 - {93B8812C-3EC4-4F78-8970-FFBFC99E167D}.Release|Win32.ActiveCfg = Release|Win32 - {93B8812C-3EC4-4F78-8970-FFBFC99E167D}.Release|Win32.Build.0 = Release|Win32 - {BB833648-BAFF-4BE2-94DB-F8BB043C588C}.Debug|Win32.ActiveCfg = Debug|Win32 - {BB833648-BAFF-4BE2-94DB-F8BB043C588C}.Debug|Win32.Build.0 = Debug|Win32 - {BB833648-BAFF-4BE2-94DB-F8BB043C588C}.Release|Win32.ActiveCfg = Release|Win32 - {BB833648-BAFF-4BE2-94DB-F8BB043C588C}.Release|Win32.Build.0 = Release|Win32 - {6DA6FD42-641D-4147-92F5-3BC4AAA6589B}.Debug|Win32.ActiveCfg = Debug|Win32 - {6DA6FD42-641D-4147-92F5-3BC4AAA6589B}.Debug|Win32.Build.0 = Debug|Win32 - {6DA6FD42-641D-4147-92F5-3BC4AAA6589B}.Release|Win32.ActiveCfg = Release|Win32 - {6DA6FD42-641D-4147-92F5-3BC4AAA6589B}.Release|Win32.Build.0 = Release|Win32 - {FE3540C5-3303-46E0-A69E-D92F775687F1}.Debug|Win32.ActiveCfg = Debug|Win32 - {FE3540C5-3303-46E0-A69E-D92F775687F1}.Debug|Win32.Build.0 = Debug|Win32 - {FE3540C5-3303-46E0-A69E-D92F775687F1}.Release|Win32.ActiveCfg = Release|Win32 - {FE3540C5-3303-46E0-A69E-D92F775687F1}.Release|Win32.Build.0 = Release|Win32 - {37C94798-6E33-4B4F-8EE0-C72A7DC91157}.Debug|Win32.ActiveCfg = Debug|Win32 - {37C94798-6E33-4B4F-8EE0-C72A7DC91157}.Debug|Win32.Build.0 = Debug|Win32 - {37C94798-6E33-4B4F-8EE0-C72A7DC91157}.Release|Win32.ActiveCfg = Release|Win32 - {37C94798-6E33-4B4F-8EE0-C72A7DC91157}.Release|Win32.Build.0 = Release|Win32 - {C539D7C8-26A8-4A94-B938-77672165C130}.Debug|Win32.ActiveCfg = Debug|Win32 - {C539D7C8-26A8-4A94-B938-77672165C130}.Debug|Win32.Build.0 = Debug|Win32 - {C539D7C8-26A8-4A94-B938-77672165C130}.Release|Win32.ActiveCfg = Release|Win32 - {C539D7C8-26A8-4A94-B938-77672165C130}.Release|Win32.Build.0 = Release|Win32 - {729344A5-D5E9-434D-8EE8-AF8C6C795D15}.Debug|Win32.ActiveCfg = Debug|Win32 - {729344A5-D5E9-434D-8EE8-AF8C6C795D15}.Debug|Win32.Build.0 = Debug|Win32 - {729344A5-D5E9-434D-8EE8-AF8C6C795D15}.Release|Win32.ActiveCfg = Release|Win32 - {729344A5-D5E9-434D-8EE8-AF8C6C795D15}.Release|Win32.Build.0 = Release|Win32 - {1A145EE9-BBD8-45E5-98CD-EB4BE99E1DCD}.Debug|Win32.ActiveCfg = Debug|Win32 - {1A145EE9-BBD8-45E5-98CD-EB4BE99E1DCD}.Release|Win32.ActiveCfg = Release|Win32 - {E886B4D5-AB4F-4092-B8F4-3B06E1E462EF}.Debug|Win32.ActiveCfg = Debug|Win32 - {E886B4D5-AB4F-4092-B8F4-3B06E1E462EF}.Release|Win32.ActiveCfg = Release|Win32 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/libs/freetdm/src/ftdm_io.c b/libs/freetdm/src/ftdm_io.c index 528e983646..fc6e849b48 100644 --- a/libs/freetdm/src/ftdm_io.c +++ b/libs/freetdm/src/ftdm_io.c @@ -1809,16 +1809,26 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_open_chan(ftdm_channel_t *ftdmchan) ftdm_mutex_lock(ftdmchan->mutex); - if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_SUSPENDED)) { - snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "%s", "Channel is suspended\n"); - ftdm_log_chan_msg(ftdmchan, FTDM_LOG_WARNING, "Cannot open channel when is suspended\n"); - goto done; - } - - if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_IN_ALARM) && !ftdm_test_flag(ftdmchan->span, FTDM_SPAN_PWR_SAVING)) { - snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "%s", "Channel is alarmed\n"); - ftdm_log_chan_msg(ftdmchan, FTDM_LOG_WARNING, "Cannot open channel when is alarmed\n"); - goto done; + if (FTDM_IS_VOICE_CHANNEL(ftdmchan)) { + if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_SUSPENDED)) { + snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "%s", "Channel is suspended\n"); + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_WARNING, "Cannot open channel when is suspended\n"); + goto done; + } + + if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_IN_ALARM) && !ftdm_test_flag(ftdmchan->span, FTDM_SPAN_PWR_SAVING)) { + snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "%s", "Channel is alarmed\n"); + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_WARNING, "Cannot open channel when is alarmed\n"); + goto done; + } + + if (globals.cpu_monitor.alarm && + globals.cpu_monitor.alarm_action_flags & FTDM_CPU_ALARM_ACTION_REJECT) { + snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "%s", "CPU usage alarm is on - refusing to open channel\n"); + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_WARNING, "CPU usage alarm is on - refusing to open channel\n"); + ftdmchan->caller_data.hangup_cause = FTDM_CAUSE_SWITCH_CONGESTION; + goto done; + } } if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_READY)) { @@ -1827,15 +1837,6 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_open_chan(ftdm_channel_t *ftdmchan) goto done; } - if (globals.cpu_monitor.alarm && - globals.cpu_monitor.alarm_action_flags & FTDM_CPU_ALARM_ACTION_REJECT) { - snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "%s", "CPU usage alarm is on - refusing to open channel\n"); - ftdm_log_chan_msg(ftdmchan, FTDM_LOG_WARNING, "CPU usage alarm is on - refusing to open channel\n"); - ftdmchan->caller_data.hangup_cause = FTDM_CAUSE_SWITCH_CONGESTION; - goto done; - } - - status = ftdmchan->fio->open(ftdmchan); if (status == FTDM_SUCCESS) { ftdm_set_flag(ftdmchan, FTDM_CHANNEL_OPEN | FTDM_CHANNEL_INUSE); @@ -2094,10 +2095,10 @@ FT_DECLARE(ftdm_status_t) _ftdm_channel_call_answer(const char *file, const char goto done; } -#if 0 - /* DAVIDY - We will fail RFC's if we do that, but some modules apart from ftmod_sangoma_isdn +#ifndef FREETDM_SKIP_SIG_STATES + /* We will fail RFC's if we not skip states, but some modules apart from ftmod_sangoma_isdn * expect the call to always to go PROGRESS and PROGRESS MEDIA state before going to UP, so - * remove this only in netborder branch for now */ + * remove this only in netborder branch for now while we update the sig modules */ if (ftdmchan->state < FTDM_CHANNEL_STATE_PROGRESS) { ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_PROGRESS, 1); @@ -2341,6 +2342,8 @@ FT_DECLARE(ftdm_status_t) _ftdm_channel_call_place(const char *file, const char UNREFERENCED_PARAMETER(line); #endif + ftdm_wait_for_flag_cleared(ftdmchan, FTDM_CHANNEL_STATE_CHANGE, 100); + ftdm_channel_unlock(ftdmchan); return status; @@ -2889,16 +2892,17 @@ done: FT_DECLARE(ftdm_status_t) ftdm_channel_wait(ftdm_channel_t *ftdmchan, ftdm_wait_flag_t *flags, int32_t to) { - assert(ftdmchan != NULL); - assert(ftdmchan->fio != NULL); + ftdm_status_t status = FTDM_FAIL; + ftdm_assert_return(ftdmchan != NULL, FTDM_FAIL, "Null channel\n"); + ftdm_assert_return(ftdmchan->fio != NULL, FTDM_FAIL, "Null io interface\n"); + ftdm_assert_return(ftdmchan->fio->wait != NULL, FTDM_NOTIMPL, "wait method not implemented\n"); - if (!ftdmchan->fio->wait) { - snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "method not implemented"); - return FTDM_FAIL; + status = ftdmchan->fio->wait(ftdmchan, flags, to); + if (status == FTDM_TIMEOUT) { + /* make sure the flags are cleared on timeout */ + *flags = 0; } - - return ftdmchan->fio->wait(ftdmchan, flags, to); - + return status; } /*******************************/ diff --git a/libs/freetdm/src/ftmod/ftmod_analog/ftmod_analog.2010.vcxproj b/libs/freetdm/src/ftmod/ftmod_analog/ftmod_analog.2010.vcxproj new file mode 100644 index 0000000000..81cb93fa44 --- /dev/null +++ b/libs/freetdm/src/ftmod/ftmod_analog/ftmod_analog.2010.vcxproj @@ -0,0 +1,198 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + ftmod_analog + {37C94798-6E33-4B4F-8EE0-C72A7DC91157} + ftmod_analog + Win32Proj + + + + DynamicLibrary + Unicode + true + + + DynamicLibrary + Unicode + + + DynamicLibrary + Unicode + true + + + DynamicLibrary + Unicode + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + $(SolutionDir)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\ + true + $(SolutionDir)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\ + false + $(SolutionDir)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\ + true + $(SolutionDir)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\ + false + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\include;..\..\isdn\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;_USRDLL;FTMOD_ANALOG_EXPORTS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + + Level4 + true + EditAndContinue + 4100;%(DisableSpecificWarnings) + + + true + Windows + MachineX86 + + + + + MaxSpeed + true + ..\..\include;..\..\isdn\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;_USRDLL;FTMOD_ANALOG_EXPORTS;%(PreprocessorDefinitions) + MultiThreadedDLL + true + + + Level4 + true + ProgramDatabase + 4100;%(DisableSpecificWarnings) + + + true + Windows + true + true + MachineX86 + + + + + X64 + + + Disabled + ..\..\include;..\..\isdn\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;_USRDLL;FTMOD_ANALOG_EXPORTS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + + Level4 + false + ProgramDatabase + 4100;%(DisableSpecificWarnings) + + + true + Windows + MachineX64 + + + + + X64 + + + MaxSpeed + true + ..\..\include;..\..\isdn\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;_USRDLL;FTMOD_ANALOG_EXPORTS;%(PreprocessorDefinitions) + MultiThreadedDLL + true + + + Level4 + true + ProgramDatabase + 4100;%(DisableSpecificWarnings) + + + true + Windows + true + true + MachineX64 + + + + + + + + + + + {93b8812c-3ec4-4f78-8970-ffbfc99e167d} + false + + + + + + \ No newline at end of file diff --git a/libs/freetdm/src/ftmod/ftmod_analog/ftmod_analog.2010.vcxproj.filters b/libs/freetdm/src/ftmod/ftmod_analog/ftmod_analog.2010.vcxproj.filters new file mode 100644 index 0000000000..b6fed5927a --- /dev/null +++ b/libs/freetdm/src/ftmod/ftmod_analog/ftmod_analog.2010.vcxproj.filters @@ -0,0 +1,23 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + + + Source Files + + + + + Header Files + + + \ No newline at end of file diff --git a/libs/freetdm/src/ftmod/ftmod_analog/ozmod_analog.2005.vcproj b/libs/freetdm/src/ftmod/ftmod_analog/ozmod_analog.2005.vcproj deleted file mode 100644 index 7a1cf53b20..0000000000 --- a/libs/freetdm/src/ftmod/ftmod_analog/ozmod_analog.2005.vcproj +++ /dev/null @@ -1,202 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/libs/freetdm/src/ftmod/ftmod_analog_em/ftmod_analog_em.2010.vcxproj b/libs/freetdm/src/ftmod/ftmod_analog_em/ftmod_analog_em.2010.vcxproj new file mode 100644 index 0000000000..44792df89f --- /dev/null +++ b/libs/freetdm/src/ftmod/ftmod_analog_em/ftmod_analog_em.2010.vcxproj @@ -0,0 +1,198 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + ftmod_analog_em + {B3F49375-2834-4937-9D8C-4AC2EC911010} + ftmod_analog_em + Win32Proj + + + + DynamicLibrary + Unicode + true + + + DynamicLibrary + Unicode + + + DynamicLibrary + Unicode + true + + + DynamicLibrary + Unicode + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + $(SolutionDir)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\ + true + $(SolutionDir)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\ + false + $(SolutionDir)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\ + true + $(SolutionDir)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\ + false + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\include;..\..\isdn\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;_USRDLL;FTMOD_ANALOG_EM_EXPORTS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + + Level4 + true + EditAndContinue + 4100;%(DisableSpecificWarnings) + + + true + Windows + MachineX86 + + + + + MaxSpeed + true + ..\..\include;..\..\isdn\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;_USRDLL;FTMOD_ANALOG_EM_EXPORTS;%(PreprocessorDefinitions) + MultiThreadedDLL + true + + + Level4 + true + ProgramDatabase + 4100;%(DisableSpecificWarnings) + + + true + Windows + true + true + MachineX86 + + + + + X64 + + + Disabled + ..\..\include;..\..\isdn\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;_USRDLL;FTMOD_ANALOG_EM_EXPORTS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + + Level4 + false + ProgramDatabase + 4100;%(DisableSpecificWarnings) + + + true + Windows + MachineX64 + + + + + X64 + + + MaxSpeed + true + ..\..\include;..\..\isdn\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;_USRDLL;FTMOD_ANALOG_EM_EXPORTS;%(PreprocessorDefinitions) + MultiThreadedDLL + true + + + Level4 + true + ProgramDatabase + 4100;%(DisableSpecificWarnings) + + + true + Windows + true + true + MachineX64 + + + + + + + + + + + {93b8812c-3ec4-4f78-8970-ffbfc99e167d} + false + + + + + + \ No newline at end of file diff --git a/libs/freetdm/src/ftmod/ftmod_analog_em/ftmod_analog_em.2010.vcxproj.filters b/libs/freetdm/src/ftmod/ftmod_analog_em/ftmod_analog_em.2010.vcxproj.filters new file mode 100644 index 0000000000..3326f9fd16 --- /dev/null +++ b/libs/freetdm/src/ftmod/ftmod_analog_em/ftmod_analog_em.2010.vcxproj.filters @@ -0,0 +1,23 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + + + Source Files + + + + + Header Files + + + \ No newline at end of file diff --git a/libs/freetdm/src/ftmod/ftmod_analog_em/ozmod_analog_em.2005.vcproj b/libs/freetdm/src/ftmod/ftmod_analog_em/ozmod_analog_em.2005.vcproj deleted file mode 100644 index 9ecbadc232..0000000000 --- a/libs/freetdm/src/ftmod/ftmod_analog_em/ozmod_analog_em.2005.vcproj +++ /dev/null @@ -1,202 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/libs/freetdm/src/ftmod/ftmod_isdn/ftmod_isdn.2010.vcxproj b/libs/freetdm/src/ftmod/ftmod_isdn/ftmod_isdn.2010.vcxproj new file mode 100644 index 0000000000..bd2e2fe4f0 --- /dev/null +++ b/libs/freetdm/src/ftmod/ftmod_isdn/ftmod_isdn.2010.vcxproj @@ -0,0 +1,223 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + ftmod_isdn + {729344A5-D5E9-434D-8EE8-AF8C6C795D15} + ftmod_isdn + Win32Proj + + + + DynamicLibrary + Unicode + true + + + DynamicLibrary + Unicode + + + DynamicLibrary + Unicode + true + + + DynamicLibrary + Unicode + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + true + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + false + $(SolutionDir)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\ + true + $(SolutionDir)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\ + false + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\isdn\include;..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;_USRDLL;FTMOD_ISDN_EXPORTS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + + Level4 + true + EditAndContinue + + + true + Windows + MachineX86 + + + + + MaxSpeed + true + ..\..\isdn\include;..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;_USRDLL;FTMOD_ISDN_EXPORTS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreadedDLL + true + + + Level4 + true + ProgramDatabase + + + true + Windows + true + true + MachineX86 + + + + + X64 + + + Disabled + ..\..\isdn\include;..\..\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;_USRDLL;FTMOD_ISDN_EXPORTS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + + Level4 + true + ProgramDatabase + + + true + Windows + MachineX64 + + + + + X64 + + + MaxSpeed + true + ..\..\isdn\include;..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;_USRDLL;FTMOD_ISDN_EXPORTS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreadedDLL + true + + + Level4 + true + ProgramDatabase + + + true + Windows + true + true + MachineX64 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {93b8812c-3ec4-4f78-8970-ffbfc99e167d} + false + + + + + + \ No newline at end of file diff --git a/libs/freetdm/src/ftmod/ftmod_isdn/ftmod_isdn.2010.vcxproj.filters b/libs/freetdm/src/ftmod/ftmod_isdn/ftmod_isdn.2010.vcxproj.filters new file mode 100644 index 0000000000..30824888fc --- /dev/null +++ b/libs/freetdm/src/ftmod/ftmod_isdn/ftmod_isdn.2010.vcxproj.filters @@ -0,0 +1,110 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + \ No newline at end of file diff --git a/libs/freetdm/src/ftmod/ftmod_libpri/ftmod_libpri.c b/libs/freetdm/src/ftmod/ftmod_libpri/ftmod_libpri.c index 669e85218a..68f0e9e5a4 100644 --- a/libs/freetdm/src/ftmod/ftmod_libpri/ftmod_libpri.c +++ b/libs/freetdm/src/ftmod/ftmod_libpri/ftmod_libpri.c @@ -462,7 +462,7 @@ static ftdm_state_map_t isdn_state_map = { ZSD_INBOUND, ZSM_UNACCEPTABLE, {FTDM_CHANNEL_STATE_RING, FTDM_END}, - {FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_PROGRESS, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_CHANNEL_STATE_UP, FTDM_END} + {FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_RINGING, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_CHANNEL_STATE_UP, FTDM_END} }, { ZSD_INBOUND, @@ -479,7 +479,7 @@ static ftdm_state_map_t isdn_state_map = { { ZSD_INBOUND, ZSM_UNACCEPTABLE, - {FTDM_CHANNEL_STATE_PROGRESS, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_END}, + {FTDM_CHANNEL_STATE_RINGING, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_END}, {FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_CHANNEL_STATE_CANCEL, FTDM_CHANNEL_STATE_UP, FTDM_END}, }, @@ -495,6 +495,7 @@ static ftdm_state_map_t isdn_state_map = { /** * \brief Handler for channel state change * \param ftdmchan Channel to handle + * \note This function MUST be called with the channel locked */ static __inline__ void state_advance(ftdm_channel_t *chan) { @@ -536,6 +537,8 @@ static __inline__ void state_advance(ftdm_channel_t *chan) break; case FTDM_CHANNEL_STATE_PROGRESS: + /* RINGING is an alias for PROGRESS state in inbound calls ATM */ + case FTDM_CHANNEL_STATE_RINGING: { if (ftdm_test_flag(chan, FTDM_CHANNEL_OUTBOUND)) { sig.event_id = FTDM_SIGEVENT_PROGRESS; @@ -727,15 +730,13 @@ static __inline__ void check_state(ftdm_span_t *span) for (j = 1; j <= ftdm_span_get_chan_count(span); j++) { ftdm_channel_t *chan = ftdm_span_get_channel(span, j); - if (ftdm_test_flag(chan, FTDM_CHANNEL_STATE_CHANGE)) { - ftdm_channel_lock(chan); - + ftdm_channel_lock(chan); + while (ftdm_test_flag(chan, FTDM_CHANNEL_STATE_CHANGE)) { ftdm_clear_flag(chan, FTDM_CHANNEL_STATE_CHANGE); state_advance(chan); ftdm_channel_complete_state(chan); - - ftdm_channel_unlock(chan); } + ftdm_channel_unlock(chan); } } } @@ -991,7 +992,16 @@ static int on_ring(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_event if (!chan) { ftdm_log(FTDM_LOG_ERROR, "-- Unable to get channel %d:%d\n", ftdm_span_get_id(span), pevent->ring.channel); - goto done; + return ret; + } + + ftdm_channel_lock(chan); + + if (chan->call_data) { + /* we could drop the incoming call, but most likely the pointer is just a ghost of the past, + * this check is just to detect potentially unreleased pointers */ + ftdm_log_chan(chan, FTDM_LOG_ERROR, "channel already has call %p!\n", chan->call_data); + chan->call_data = NULL; } if (ftdm_channel_get_state(chan) != FTDM_CHANNEL_STATE_DOWN || ftdm_test_flag(chan, FTDM_CHANNEL_INUSE)) { @@ -1051,9 +1061,10 @@ static int on_ring(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_event /* hurr, this is valid as along as nobody releases the call */ chan->call_data = pevent->ring.call; - ftdm_set_state_locked(chan, FTDM_CHANNEL_STATE_RING); + ftdm_set_state(chan, FTDM_CHANNEL_STATE_RING); done: + ftdm_channel_unlock(chan); return ret; } diff --git a/libs/freetdm/src/ftmod/ftmod_pika/ftmod_pika.2010.vcxproj b/libs/freetdm/src/ftmod/ftmod_pika/ftmod_pika.2010.vcxproj new file mode 100644 index 0000000000..c4004bda21 --- /dev/null +++ b/libs/freetdm/src/ftmod/ftmod_pika/ftmod_pika.2010.vcxproj @@ -0,0 +1,198 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + ftmod_pika + {E886B4D5-AB4F-4092-B8F4-3B06E1E462EF} + ftmod_pika + Win32Proj + + + + DynamicLibrary + Unicode + true + + + DynamicLibrary + Unicode + + + DynamicLibrary + Unicode + true + + + DynamicLibrary + Unicode + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + true + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + false + $(SolutionDir)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\ + true + $(SolutionDir)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\ + false + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\isdn\include;..\..\include;..\..\..\pika\aoh\inc;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;_USRDLL;FTMOD_PIKA_EXPORTS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + + Level3 + EditAndContinue + + + pikahmpapi.lib;%(AdditionalDependencies) + ..\..\..\pika\aoh\lib;%(AdditionalLibraryDirectories) + true + Windows + MachineX86 + + + + + MaxSpeed + true + ..\..\isdn\include;..\..\include;..\..\..\pika\aoh\inc;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;_USRDLL;FTMOD_PIKA_EXPORTS;%(PreprocessorDefinitions) + MultiThreadedDLL + true + + + Level3 + ProgramDatabase + + + pikahmpapi.lib;%(AdditionalDependencies) + ..\..\..\pika\aoh\lib;%(AdditionalLibraryDirectories) + true + Windows + true + true + MachineX86 + + + + + X64 + + + Disabled + ..\..\isdn\include;..\..\include;..\..\..\pika\aoh\inc;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;_USRDLL;FTMOD_PIKA_EXPORTS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + + Level3 + ProgramDatabase + + + pikahmpapi.lib;%(AdditionalDependencies) + ..\..\..\pika\aoh\lib;%(AdditionalLibraryDirectories) + true + Windows + MachineX64 + + + + + X64 + + + MaxSpeed + true + ..\..\isdn\include;..\..\include;..\..\..\pika\aoh\inc;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;_USRDLL;FTMOD_PIKA_EXPORTS;%(PreprocessorDefinitions) + MultiThreadedDLL + true + + + Level3 + ProgramDatabase + + + pikahmpapi.lib;%(AdditionalDependencies) + ..\..\..\pika\aoh\lib;%(AdditionalLibraryDirectories) + true + Windows + true + true + MachineX64 + + + + + + + + + + + {93b8812c-3ec4-4f78-8970-ffbfc99e167d} + false + + + + + + \ No newline at end of file diff --git a/libs/freetdm/src/ftmod/ftmod_pika/ftmod_pika.2010.vcxproj.filters b/libs/freetdm/src/ftmod/ftmod_pika/ftmod_pika.2010.vcxproj.filters new file mode 100644 index 0000000000..4d4cec4668 --- /dev/null +++ b/libs/freetdm/src/ftmod/ftmod_pika/ftmod_pika.2010.vcxproj.filters @@ -0,0 +1,23 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + + + Source Files + + + + + Header Files + + + \ No newline at end of file diff --git a/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.2010.vcxproj b/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.2010.vcxproj new file mode 100644 index 0000000000..f66f5afc0d --- /dev/null +++ b/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.2010.vcxproj @@ -0,0 +1,95 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + ftmod_r2 + {08C3EA27-A51D-47F8-B47D-B189C649CF30} + Win32Proj + + + + DynamicLibrary + + + DynamicLibrary + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + true + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + true + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\include;c:\Program Files\openr2\include\openr2;C:\Program Files\openr2\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;_USRDLL;FTMOD_R2_EXPORTS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + + Level3 + EditAndContinue + + + freetdm.lib;openr2.lib;%(AdditionalDependencies) + C:\Program Files\openr2\lib;$(OutDir);%(AdditionalLibraryDirectories) + true + Windows + MachineX86 + + + + + ..\..\include;C:\Program Files\openr2\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;_USRDLL;FTMOD_R2_EXPORTS;%(PreprocessorDefinitions) + MultiThreadedDLL + + + Level3 + ProgramDatabase + + + true + Windows + true + true + MachineX86 + + + + + + + + + \ No newline at end of file diff --git a/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.2010.vcxproj.filters b/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.2010.vcxproj.filters new file mode 100644 index 0000000000..9c91228e09 --- /dev/null +++ b/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.2010.vcxproj.filters @@ -0,0 +1,22 @@ + + + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + + + Source Files + + + \ No newline at end of file diff --git a/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c b/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c index f089846fae..5160005dc1 100644 --- a/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c +++ b/libs/freetdm/src/ftmod/ftmod_r2/ftmod_r2.c @@ -56,19 +56,14 @@ typedef enum { FTDM_R2_RUNNING = (1 << 0), } ftdm_r2_flag_t; -typedef enum { - FTDM_R2_WAITING_ACK = (1 << 0), -} ftdm_r2_call_flag_t; - /* private call information stored in ftdmchan->call_data void* ptr */ #define R2CALL(ftdmchan) ((ftdm_r2_call_t*)((ftdmchan)->call_data)) typedef struct ftdm_r2_call_t { openr2_chan_t *r2chan; - ftdm_r2_call_flag_t flags; int accepted:1; int answer_pending:1; int disconnect_rcvd:1; - int ftdm_started:1; + int ftdm_call_started:1; int protocol_error:1; ftdm_channel_state_t chanstate; ftdm_size_t dnis_index; @@ -123,11 +118,13 @@ typedef struct ftdm_r2_data_s { /* whether accept the call when offered, or wait until the user decides to accept */ int accept_on_offer:1; /* max time spent in ms doing real work in a single loop */ - int jobmax; - /* total working loops */ - unsigned long loops; + int32_t jobmax; + /* Total number of loops performed so far */ + uint64_t total_loops; + /* number of loops per 10ms increment from 0-9ms, 10-19ms .. 100ms and above */ + uint64_t loops[11]; /* LWP */ - unsigned long monitor_thread_id; + uint32_t monitor_thread_id; } ftdm_r2_data_t; /* one element per span will be stored in g_mod_data_hash global var to keep track of them @@ -150,7 +147,14 @@ static ftdm_hash_t *g_mod_data_hash; static ftdm_io_interface_t g_ftdm_r2_interface; static int ftdm_r2_state_advance(ftdm_channel_t *ftdmchan); +static void ftdm_r2_state_advance_all(ftdm_channel_t *ftdmchan); +/* whether R2 call accept process is pending */ +#define IS_ACCEPTING_PENDING(ftdmchan) \ + ( (!ftdm_test_flag((ftdmchan), FTDM_CHANNEL_OUTBOUND)) && !R2CALL((ftdmchan))->accepted && \ + ((ftdmchan)->state == FTDM_CHANNEL_STATE_PROGRESS || \ + (ftdmchan)->state == FTDM_CHANNEL_STATE_PROGRESS_MEDIA || \ + (ftdmchan)->state == FTDM_CHANNEL_STATE_UP) ) /* functions not available on windows */ #ifdef WIN32 @@ -312,9 +316,9 @@ static openr2_call_disconnect_cause_t ftdm_r2_ftdm_cause_to_openr2_cause(ftdm_ch static void ft_r2_clean_call(ftdm_r2_call_t *call) { - openr2_chan_t *r2chan = call->r2chan; - memset(call, 0, sizeof(*call)); - call->r2chan = r2chan; + openr2_chan_t *r2chan = call->r2chan; + memset(call, 0, sizeof(*call)); + call->r2chan = r2chan; } static void ft_r2_accept_call(ftdm_channel_t *ftdmchan) @@ -354,30 +358,26 @@ static FIO_CHANNEL_OUTGOING_CALL_FUNCTION(r2_outgoing_call) } ft_r2_clean_call(ftdmchan->call_data); - R2CALL(ftdmchan)->ftdm_started = 1; + R2CALL(ftdmchan)->ftdm_call_started = 1; R2CALL(ftdmchan)->chanstate = FTDM_CHANNEL_STATE_DOWN; - ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DIALING); + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DIALING); callstatus = openr2_chan_make_call(R2CALL(ftdmchan)->r2chan, ftdmchan->caller_data.cid_num.digits, ftdmchan->caller_data.dnis.digits, OR2_CALLING_PARTY_CATEGORY_NATIONAL_SUBSCRIBER); - if (callstatus) { - ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT, "Failed to make call in R2 channel, openr2_chan_make_call failed\n"); - return FTDM_FAIL; - } + if (callstatus) { + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT, "Failed to make call in R2 channel, openr2_chan_make_call failed\n"); + return FTDM_FAIL; + } if (ftdmchan->state != FTDM_CHANNEL_STATE_DIALING) { ftdm_log_chan(ftdmchan, FTDM_LOG_WARNING, "Collision after call attempt, try another channel, new state = %s\n", ftdm_channel_state2str(ftdmchan->state)); - ftdm_clear_flag(R2CALL(ftdmchan), FTDM_R2_WAITING_ACK); return FTDM_BREAK; } - - /* non-threaded implementation, we're done here */ - ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "R2 call placed in non-threaded mode\n"); - return FTDM_SUCCESS; + return FTDM_SUCCESS; } static ftdm_status_t ftdm_r2_start(ftdm_span_t *span) @@ -444,20 +444,47 @@ static void ftdm_r2_on_call_offered(openr2_chan_t *r2chan, const char *ani, cons { ftdm_channel_t *ftdmchan = openr2_chan_get_client_data(r2chan); - ftdm_log_chan(ftdmchan, FTDM_LOG_NOTICE, "Call offered with ANI = %s, DNIS = %s, Priority = (%d)\n", ani, dnis, category); - ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_RING); + ftdm_log_chan(ftdmchan, FTDM_LOG_NOTICE, "Call offered with ANI = %s, DNIS = %s, Category = (%d)\n", ani, dnis, category); + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_RING); +} + +/* + * Accepting a call in R2 is a lengthy process due to MF tones, + * when the user sends PROGRESS indication (implicitly moving the + * ftdm channel to PROGRESS state) the R2 processing loop + * does not clear FTDM_CHANNEL_STATE_CHANGE immediately as it does + * for all the other states, instead has to wait for on_call_accepted + * callback from openr2, which means the MF has ended and the progress + * indication is done, in order to clear the flag. However, if + * a protocol error or call disconnection (which is indicated using CAS bits) + * occurrs while accepting, we must clear the pending flag, this function + * takes care of that + * */ +static void clear_accept_pending(ftdm_channel_t *fchan) +{ + if (IS_ACCEPTING_PENDING(fchan)) { + ftdm_clear_flag(fchan, FTDM_CHANNEL_STATE_CHANGE); + ftdm_channel_complete_state(fchan); + } else if (ftdm_test_flag(fchan, FTDM_CHANNEL_STATE_CHANGE)) { + ftdm_log_chan(fchan, FTDM_LOG_CRIT, "State change flag set in state %s, last state = %s\n", + ftdm_channel_state2str(fchan->state), ftdm_channel_state2str(fchan->last_state)); + ftdm_clear_flag(fchan, FTDM_CHANNEL_STATE_CHANGE); + ftdm_channel_complete_state(fchan); + } } static void ftdm_r2_on_call_accepted(openr2_chan_t *r2chan, openr2_call_mode_t mode) { ftdm_channel_t *ftdmchan = openr2_chan_get_client_data(r2chan); ftdm_log_chan_msg(ftdmchan, FTDM_LOG_NOTICE, "Call accepted\n"); + + clear_accept_pending(ftdmchan); + /* at this point the MF signaling has ended and there is no point on keep reading */ openr2_chan_disable_read(r2chan); R2CALL(ftdmchan)->accepted = 1; + if (OR2_DIR_BACKWARD == openr2_chan_get_direction(r2chan)) { - ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE); - ftdm_channel_complete_state(ftdmchan); if (R2CALL(ftdmchan)->answer_pending) { ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Answer was pending, answering now.\n"); ft_r2_answer_call(ftdmchan); @@ -465,7 +492,7 @@ static void ftdm_r2_on_call_accepted(openr2_chan_t *r2chan, openr2_call_mode_t m return; } } else { - ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_PROGRESS_MEDIA); + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_PROGRESS_MEDIA); } } @@ -475,47 +502,30 @@ static void ftdm_r2_on_call_answered(openr2_chan_t *r2chan) ftdm_log_chan_msg(ftdmchan, FTDM_LOG_NOTICE, "Call answered\n"); /* notify the upper layer of progress in the outbound call */ if (OR2_DIR_FORWARD == openr2_chan_get_direction(r2chan)) { - ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_UP); + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_UP); } } /* may be called in the signaling or media thread depending on whether the hangup is product of MF or CAS signaling */ static void ftdm_r2_on_call_disconnect(openr2_chan_t *r2chan, openr2_call_disconnect_cause_t cause) { - ftdm_sigmsg_t sigev; - ftdm_r2_data_t *r2data; ftdm_channel_t *ftdmchan = openr2_chan_get_client_data(r2chan); ftdm_log_chan_msg(ftdmchan, FTDM_LOG_NOTICE, "Call disconnected\n"); - ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Got openr2 disconnection, clearing call\n"); + clear_accept_pending(ftdmchan); R2CALL(ftdmchan)->disconnect_rcvd = 1; if (ftdmchan->state == FTDM_CHANNEL_STATE_HANGUP) { ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Call had been disconnected already by the user\n"); - /* just ack the hangup to go down */ + /* just ack the hangup to trigger the on_call_end callback and go down */ openr2_chan_disconnect_call(r2chan, OR2_CAUSE_NORMAL_CLEARING); return; } - /* if the call has not been started yet we must go to HANGUP right here */ - if (!R2CALL(ftdmchan)->ftdm_started) { - ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_HANGUP); - return; - } - ftdmchan->caller_data.hangup_cause = ftdm_r2_cause_to_ftdm_cause(ftdmchan, cause); - - /* notify the user of the call terminating */ - memset(&sigev, 0, sizeof(sigev)); - sigev.chan_id = ftdmchan->chan_id; - sigev.span_id = ftdmchan->span_id; - sigev.channel = ftdmchan; - sigev.event_id = FTDM_SIGEVENT_STOP; - r2data = ftdmchan->span->signal_data; - - ftdm_span_send_signal(ftdmchan->span, &sigev); + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING); } static void ftdm_r2_on_call_end(openr2_chan_t *r2chan) @@ -527,7 +537,7 @@ static void ftdm_r2_on_call_end(openr2_chan_t *r2chan) ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DOWN); /* in some circumstances openr2 can call on_call_init right after this, so let's advance the state right here */ - ftdm_r2_state_advance(ftdmchan); + ftdm_r2_state_advance_all(ftdmchan); } static void ftdm_r2_on_call_read(openr2_chan_t *r2chan, const unsigned char *buf, int buflen) @@ -551,8 +561,6 @@ static void ftdm_r2_on_os_error(openr2_chan_t *r2chan, int errorcode) static void ftdm_r2_on_protocol_error(openr2_chan_t *r2chan, openr2_protocol_error_t reason) { - ftdm_sigmsg_t sigev; - ftdm_r2_data_t *r2data; ftdm_channel_t *ftdmchan = openr2_chan_get_client_data(r2chan); if (ftdmchan->state == FTDM_CHANNEL_STATE_DOWN) { @@ -561,25 +569,19 @@ static void ftdm_r2_on_protocol_error(openr2_chan_t *r2chan, openr2_protocol_err ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "Protocol error\n"); + clear_accept_pending(ftdmchan); + R2CALL(ftdmchan)->disconnect_rcvd = 1; R2CALL(ftdmchan)->protocol_error = 1; - if (!R2CALL(ftdmchan)->ftdm_started) { - ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_HANGUP); + if (ftdmchan->state == FTDM_CHANNEL_STATE_HANGUP) { + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "The user already hung up, finishing call in protocol error\n"); + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DOWN); return; } ftdmchan->caller_data.hangup_cause = FTDM_CAUSE_PROTOCOL_ERROR; - - /* FIXME: go to terminating and notify the user from the terminating handler instead of notifying here */ - memset(&sigev, 0, sizeof(sigev)); - sigev.chan_id = ftdmchan->chan_id; - sigev.span_id = ftdmchan->span_id; - sigev.channel = ftdmchan; - sigev.event_id = FTDM_SIGEVENT_STOP; - r2data = ftdmchan->span->signal_data; - - ftdm_span_send_signal(ftdmchan->span, &sigev); + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_TERMINATING); } static void ftdm_r2_on_line_blocked(openr2_chan_t *r2chan) @@ -638,14 +640,13 @@ static void ftdm_r2_on_chan_log(openr2_chan_t *r2chan, const char *file, const c openr2_log_level_t level, const char *fmt, va_list ap) { ftdm_channel_t *ftdmchan = openr2_chan_get_client_data(r2chan); -#define CHAN_TAG "Chan " - char logmsg[512]; - char completemsg[sizeof(logmsg) + sizeof(CHAN_TAG) - 1]; + char logmsg[1024]; + char completemsg[sizeof(logmsg)]; vsnprintf(logmsg, sizeof(logmsg), fmt, ap); - snprintf(completemsg, sizeof(completemsg), CHAN_TAG "%d:%d [%s] %s", - ftdmchan->span_id, ftdmchan->chan_id, ftdm_channel_state2str(ftdmchan->state), logmsg); + snprintf(completemsg, sizeof(completemsg), "[s%dc%d] [%d:%d] [%s] %s", + ftdmchan->span_id, ftdmchan->chan_id, ftdmchan->physical_span_id, ftdmchan->physical_chan_id, + ftdm_channel_state2str(ftdmchan->state), logmsg); ftdm_r2_write_log(level, file, function, line, completemsg); -#undef CHAN_TAG } static int ftdm_r2_on_dnis_digit_received(openr2_chan_t *r2chan, char digit) @@ -889,27 +890,147 @@ static openr2_io_interface_t ftdm_r2_io_iface = { /* .get_oob_event */ ftdm_r2_io_get_oob_event /* never called */ }; -static FIO_SIG_CONFIGURE_FUNCTION(ftdm_r2_configure_span) - //ftdm_status_t (ftdm_span_t *span, fio_signal_cb_t sig_cb, va_list ap) +/* resolve a loglevel string, such as "debug,notice,warning", to an openr2 log level integer */ +static openr2_log_level_t ftdm_r2_loglevel_from_string(const char *level) +{ + openr2_log_level_t tmplevel; + openr2_log_level_t newlevel = 0; + char *clevel = NULL; + char *logval = NULL; + + logval = ftdm_malloc(strlen(level)+1); /* alloca man page scared me, so better to use good ol' malloc */ + if (!logval) { + ftdm_log(FTDM_LOG_WARNING, "Ignoring R2 logging parameter: '%s', failed to alloc memory\n", level); + return newlevel; + } + strcpy(logval, level); + while (logval) { + clevel = strsep(&logval, ","); + if (-1 == (tmplevel = openr2_log_get_level(clevel))) { + ftdm_log(FTDM_LOG_WARNING, "Ignoring invalid R2 logging level: '%s'\n", clevel); + continue; + } + newlevel |= tmplevel; + } + ftdm_safe_free(logval); + return newlevel; +} + +static ftdm_state_map_t r2_state_map = { + { + { + ZSD_INBOUND, + ZSM_UNACCEPTABLE, + {FTDM_CHANNEL_STATE_DOWN, FTDM_END}, + {FTDM_CHANNEL_STATE_COLLECT, FTDM_END} + }, + { + ZSD_INBOUND, + ZSM_UNACCEPTABLE, + {FTDM_CHANNEL_STATE_COLLECT, FTDM_END}, + {FTDM_CHANNEL_STATE_RING, FTDM_CHANNEL_STATE_TERMINATING, FTDM_END} + }, + { + ZSD_INBOUND, + ZSM_UNACCEPTABLE, + {FTDM_CHANNEL_STATE_RING, FTDM_END}, + {FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_PROGRESS, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_CHANNEL_STATE_UP, FTDM_END} + }, + { + ZSD_INBOUND, + ZSM_UNACCEPTABLE, + {FTDM_CHANNEL_STATE_HANGUP, FTDM_END}, + {FTDM_CHANNEL_STATE_DOWN, FTDM_END}, + }, + { + ZSD_INBOUND, + ZSM_UNACCEPTABLE, + {FTDM_CHANNEL_STATE_TERMINATING, FTDM_END}, + {FTDM_CHANNEL_STATE_HANGUP, FTDM_END}, + }, + { + ZSD_INBOUND, + ZSM_UNACCEPTABLE, + {FTDM_CHANNEL_STATE_PROGRESS, FTDM_END}, + {FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_CHANNEL_STATE_UP, FTDM_END}, + }, + { + ZSD_INBOUND, + ZSM_UNACCEPTABLE, + {FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_END}, + {FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_UP, FTDM_END}, + }, + { + ZSD_INBOUND, + ZSM_UNACCEPTABLE, + {FTDM_CHANNEL_STATE_UP, FTDM_END}, + {FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_END}, + }, + + /* Outbound states */ + + { + ZSD_OUTBOUND, + ZSM_UNACCEPTABLE, + {FTDM_CHANNEL_STATE_DOWN, FTDM_END}, + {FTDM_CHANNEL_STATE_DIALING, FTDM_END} + }, + + { + ZSD_OUTBOUND, + ZSM_UNACCEPTABLE, + {FTDM_CHANNEL_STATE_DIALING, FTDM_END}, + {FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_END} + }, + + { + ZSD_OUTBOUND, + ZSM_UNACCEPTABLE, + {FTDM_CHANNEL_STATE_HANGUP, FTDM_END}, + {FTDM_CHANNEL_STATE_DOWN, FTDM_END} + }, + + { + ZSD_OUTBOUND, + ZSM_UNACCEPTABLE, + {FTDM_CHANNEL_STATE_TERMINATING, FTDM_END}, + {FTDM_CHANNEL_STATE_HANGUP, FTDM_END} + }, + + { + ZSD_OUTBOUND, + ZSM_UNACCEPTABLE, + {FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_END}, + {FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_UP, FTDM_END} + }, + + { + ZSD_OUTBOUND, + ZSM_UNACCEPTABLE, + {FTDM_CHANNEL_STATE_UP, FTDM_END}, + {FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_END} + }, + } +}; + +static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_r2_configure_span_signaling) { unsigned int i = 0; int conf_failure = 0; - char *var = NULL; - char *val = NULL; + const char *var = NULL, *val = NULL; + const char *log_level = "notice,warning,error"; /* default loglevel, if none is read from conf */ ftdm_r2_data_t *r2data = NULL; ftdm_r2_span_pvt_t *spanpvt = NULL; ftdm_r2_call_t *r2call = NULL; openr2_chan_t *r2chan = NULL; - openr2_log_level_t tmplevel; - char *clevel = NULL; - char *logval = NULL; + unsigned paramindex = 0; ft_r2_conf_t r2conf = { /* .variant */ OR2_VAR_ITU, /* .category */ OR2_CALLING_PARTY_CATEGORY_NATIONAL_SUBSCRIBER, /* .loglevel */ OR2_LOG_ERROR | OR2_LOG_WARNING, - /* .logdir */ NULL, + /* .logdir */ (char *)"/usr/local/freeswitch/log/", /* FIXME: get PREFIX variable */ /* .advanced_protocol_file */ NULL, /* .max_ani */ 10, /* .max_dnis */ 4, @@ -920,7 +1041,7 @@ static FIO_SIG_CONFIGURE_FUNCTION(ftdm_r2_configure_span) /* .get_ani_first */ -1, /* .call_files */ 0, /* .mf_files */ 0, - /* .double_answer */ 0, + /* .double_answer */ -1, /* .charge_calls */ -1, /* .forced_release */ -1, /* .allow_collect_calls */ -1 @@ -933,10 +1054,12 @@ static FIO_SIG_CONFIGURE_FUNCTION(ftdm_r2_configure_span) return FTDM_FAIL; } - while ((var = va_arg(ap, char *))) { + for (; ftdm_parameters[paramindex].var; paramindex++) { + var = ftdm_parameters[paramindex].var; + val = ftdm_parameters[paramindex].val; ftdm_log(FTDM_LOG_DEBUG, "Reading R2 parameter %s for span %d\n", var, span->span_id); if (!strcasecmp(var, "variant")) { - if (!(val = va_arg(ap, char *))) { + if (!val) { break; } if (ftdm_strlen_zero_buf(val)) { @@ -951,7 +1074,7 @@ static FIO_SIG_CONFIGURE_FUNCTION(ftdm_r2_configure_span) } ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d for variant %s\n", span->span_id, val); } else if (!strcasecmp(var, "category")) { - if (!(val = va_arg(ap, char *))) { + if (!val) { break; } if (ftdm_strlen_zero_buf(val)) { @@ -966,87 +1089,72 @@ static FIO_SIG_CONFIGURE_FUNCTION(ftdm_r2_configure_span) } ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d with default category %s\n", span->span_id, val); } else if (!strcasecmp(var, "logdir")) { - if (!(val = va_arg(ap, char *))) { + if (!val) { break; } if (ftdm_strlen_zero_buf(val)) { ftdm_log(FTDM_LOG_NOTICE, "Ignoring empty R2 logdir parameter\n"); continue; } - r2conf.logdir = val; + r2conf.logdir = (char *)val; ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d with logdir %s\n", span->span_id, val); } else if (!strcasecmp(var, "logging")) { - if (!(val = va_arg(ap, char *))) { + if (!val) { break; } if (ftdm_strlen_zero_buf(val)) { ftdm_log(FTDM_LOG_NOTICE, "Ignoring empty R2 logging parameter\n"); continue; } - logval = ftdm_malloc(strlen(val)+1); /* alloca man page scared me, so better to use good ol' malloc */ - if (!logval) { - ftdm_log(FTDM_LOG_WARNING, "Ignoring R2 logging parameter: '%s', failed to alloc memory\n", val); - continue; - } - strcpy(logval, val); - while (logval) { - clevel = strsep(&logval, ","); - if (-1 == (tmplevel = openr2_log_get_level(clevel))) { - ftdm_log(FTDM_LOG_WARNING, "Ignoring invalid R2 logging level: '%s'\n", clevel); - continue; - } - r2conf.loglevel |= tmplevel; - ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d with loglevel %s\n", span->span_id, clevel); - } - ftdm_safe_free(logval); + log_level = val; } else if (!strcasecmp(var, "advanced_protocol_file")) { - if (!(val = va_arg(ap, char *))) { + if (!val) { break; } if (ftdm_strlen_zero_buf(val)) { ftdm_log(FTDM_LOG_NOTICE, "Ignoring empty R2 advanced_protocol_file parameter\n"); continue; } - r2conf.advanced_protocol_file = val; + r2conf.advanced_protocol_file = (char *)val; ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d with advanced protocol file %s\n", span->span_id, val); } else if (!strcasecmp(var, "allow_collect_calls")) { - r2conf.allow_collect_calls = va_arg(ap, int); + r2conf.allow_collect_calls = ftdm_true(val); ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d with allow collect calls max ani = %d\n", span->span_id, r2conf.allow_collect_calls); } else if (!strcasecmp(var, "double_answer")) { - r2conf.double_answer = va_arg(ap, int); + r2conf.double_answer = ftdm_true(val); ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d with double answer = %d\n", span->span_id, r2conf.double_answer); } else if (!strcasecmp(var, "immediate_accept")) { - r2conf.immediate_accept = va_arg(ap, int); + r2conf.immediate_accept = ftdm_true(val); ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d with immediate accept = %d\n", span->span_id, r2conf.immediate_accept); } else if (!strcasecmp(var, "skip_category")) { - r2conf.skip_category = va_arg(ap, int); + r2conf.skip_category = ftdm_true(val); ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d with skip category = %d\n", span->span_id, r2conf.skip_category); } else if (!strcasecmp(var, "forced_release")) { - r2conf.forced_release = va_arg(ap, int); + r2conf.forced_release = ftdm_true(val); ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d with forced release = %d\n", span->span_id, r2conf.forced_release); } else if (!strcasecmp(var, "charge_calls")) { - r2conf.charge_calls = va_arg(ap, int); + r2conf.charge_calls = ftdm_true(val); ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d with charge calls = %d\n", span->span_id, r2conf.charge_calls); } else if (!strcasecmp(var, "get_ani_first")) { - r2conf.get_ani_first = va_arg(ap, int); + r2conf.get_ani_first = ftdm_true(val); ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d with get ani first = %d\n", span->span_id, r2conf.get_ani_first); } else if (!strcasecmp(var, "call_files")) { - r2conf.call_files = va_arg(ap, int); + r2conf.call_files = ftdm_true(val); ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d with call files = %d\n", span->span_id, r2conf.call_files); } else if (!strcasecmp(var, "mf_files")) { - r2conf.mf_files = va_arg(ap, int); + r2conf.mf_files = ftdm_true(val); ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d with mf files = %d\n", span->span_id, r2conf.mf_files); } else if (!strcasecmp(var, "mfback_timeout")) { - r2conf.mfback_timeout = va_arg(ap, int); + r2conf.mfback_timeout = atoi(val); ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d with MF backward timeout = %dms\n", span->span_id, r2conf.mfback_timeout); } else if (!strcasecmp(var, "metering_pulse_timeout")) { - r2conf.metering_pulse_timeout = va_arg(ap, int); + r2conf.metering_pulse_timeout = atoi(val); ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d with metering pulse timeout = %dms\n", span->span_id, r2conf.metering_pulse_timeout); } else if (!strcasecmp(var, "max_ani")) { - r2conf.max_ani = va_arg(ap, int); + r2conf.max_ani = atoi(val); ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d with max ani = %d\n", span->span_id, r2conf.max_ani); } else if (!strcasecmp(var, "max_dnis")) { - r2conf.max_dnis = va_arg(ap, int); + r2conf.max_dnis = atoi(val); ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d with max dnis = %d\n", span->span_id, r2conf.max_dnis); } else { snprintf(span->last_error, sizeof(span->last_error), "Unknown R2 parameter [%s]", var); @@ -1059,6 +1167,10 @@ static FIO_SIG_CONFIGURE_FUNCTION(ftdm_r2_configure_span) return FTDM_FAIL; } + /* set span log level */ + r2conf.loglevel = ftdm_r2_loglevel_from_string(log_level); + ftdm_log(FTDM_LOG_DEBUG, "Configuring R2 span %d with loglevel %s\n", span->span_id, log_level); + r2data = ftdm_malloc(sizeof(*r2data)); if (!r2data) { snprintf(span->last_error, sizeof(span->last_error), "Failed to allocate R2 data."); @@ -1143,6 +1255,8 @@ static FIO_SIG_CONFIGURE_FUNCTION(ftdm_r2_configure_span) span->signal_data = r2data; span->outgoing_call = r2_outgoing_call; + span->state_map = &r2_state_map; + /* use signals queue */ ftdm_set_flag(span, FTDM_SPAN_USE_SIGNALS_QUEUE); @@ -1187,12 +1301,9 @@ static int ftdm_r2_state_advance(ftdm_channel_t *ftdmchan) ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Executing state handler for %s\n", ftdm_channel_state2str(ftdmchan->state)); R2CALL(ftdmchan)->chanstate = ftdmchan->state; - if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND) && !R2CALL(ftdmchan)->accepted && - (ftdmchan->state == FTDM_CHANNEL_STATE_PROGRESS || - ftdmchan->state == FTDM_CHANNEL_STATE_PROGRESS_MEDIA || - ftdmchan->state == FTDM_CHANNEL_STATE_UP) ) { + if (IS_ACCEPTING_PENDING(ftdmchan)) { /* - Moving to PROGRESS, PROGRESS_MEDIA or UP means that we must accept the call, and accepting + Moving to PROGRESS, PROGRESS_MEDIA or UP means that we must accept the call first, and accepting the call in R2 means sending a tone, then waiting for the acknowledge from the other end, since all of that requires sending and detecting tones, it takes a few milliseconds (I'd say around 100) which means during that time the user should not try to perform any operations like answer, hangup or anything @@ -1243,7 +1354,7 @@ static int ftdm_r2_state_advance(ftdm_channel_t *ftdmchan) ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_CANCEL); break; } - R2CALL(ftdmchan)->ftdm_started = 1; + R2CALL(ftdmchan)->ftdm_call_started = 1; break; @@ -1258,10 +1369,11 @@ static int ftdm_r2_state_advance(ftdm_channel_t *ftdmchan) } } else { ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Notifying progress\n"); + sigev.event_id = FTDM_SIGEVENT_PROCEED; + ftdm_span_send_signal(ftdmchan->span, &sigev); + sigev.event_id = FTDM_SIGEVENT_PROGRESS_MEDIA; - if (ftdm_span_send_signal(ftdmchan->span, &sigev) != FTDM_SUCCESS) { - ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_HANGUP); - } + ftdm_span_send_signal(ftdmchan->span, &sigev); } } break; @@ -1282,31 +1394,44 @@ static int ftdm_r2_state_advance(ftdm_channel_t *ftdmchan) } else { ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Notifying of call answered\n"); sigev.event_id = FTDM_SIGEVENT_UP; - if (ftdm_span_send_signal(ftdmchan->span, &sigev) != FTDM_SUCCESS) { - ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_HANGUP); - } + ftdm_span_send_signal(ftdmchan->span, &sigev); } } break; /* just got hangup */ - case FTDM_CHANNEL_STATE_HANGUP: + case FTDM_CHANNEL_STATE_HANGUP: { - openr2_call_disconnect_cause_t disconnect_cause = ftdm_r2_ftdm_cause_to_openr2_cause(ftdmchan); - ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Clearing call, cause = %s\n", openr2_proto_get_disconnect_string(disconnect_cause)); if (!R2CALL(ftdmchan)->disconnect_rcvd) { + openr2_call_disconnect_cause_t disconnect_cause = ftdm_r2_ftdm_cause_to_openr2_cause(ftdmchan); + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Clearing call, cause = %s\n", openr2_proto_get_disconnect_string(disconnect_cause)); /* this will disconnect the call, but need to wait for the call end before moving to DOWN */ openr2_chan_disconnect_call(r2chan, disconnect_cause); } else if (!R2CALL(ftdmchan)->protocol_error) { /* just ack the hangup, on_call_end will be called by openr2 right after */ - openr2_chan_disconnect_call(r2chan, disconnect_cause); + openr2_chan_disconnect_call(r2chan, OR2_CAUSE_NORMAL_CLEARING); } else { - ftdm_log_chan_msg(ftdmchan, FTDM_LOG_WARNING, "Clearing call due to protocol error\n"); + ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "Clearing call due to protocol error\n"); ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DOWN); } } break; + case FTDM_CHANNEL_STATE_TERMINATING: + { + /* if the call has not been started yet we must go to HANGUP right here */ + if (!R2CALL(ftdmchan)->ftdm_call_started) { + ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_HANGUP); + } else { + openr2_call_disconnect_cause_t disconnect_cause = ftdm_r2_ftdm_cause_to_openr2_cause(ftdmchan); + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Clearing call, cause = %s\n", openr2_proto_get_disconnect_string(disconnect_cause)); + /* notify the user of the call terminating and we wait for the user to move us to hangup */ + sigev.event_id = FTDM_SIGEVENT_STOP; + ftdm_span_send_signal(ftdmchan->span, &sigev); + } + } + break; + /* just got hangup from the freetdm side due to abnormal failure */ case FTDM_CHANNEL_STATE_CANCEL: { @@ -1345,10 +1470,23 @@ static int ftdm_r2_state_advance(ftdm_channel_t *ftdmchan) return ret; } +/* the channel must be locked when calling this function */ +static void ftdm_r2_state_advance_all(ftdm_channel_t *ftdmchan) +{ + /* because we do not always acknowledge the state change (clearing the FTDM_CHANNEL_STATE_CHANGE flag) due to the accept + * procedure described below, we need the chanstate member to NOT process some states twice, so is valid entering this + * function with the FTDM_CHANNEL_STATE_CHANGE flag set but with a state that was already processed and is just waiting + * to complete (the processing is media-bound) + * */ + while (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE) + && (R2CALL(ftdmchan)->chanstate != ftdmchan->state)) { + ftdm_r2_state_advance(ftdmchan); + } +} + static void *ftdm_r2_run(ftdm_thread_t *me, void *obj) { openr2_chan_t *r2chan; - ftdm_r2_call_t *r2call = NULL; ftdm_channel_t *ftdmchan = NULL; ftdm_status_t status; ftdm_span_t *span = (ftdm_span_t *) obj; @@ -1356,8 +1494,10 @@ static void *ftdm_r2_run(ftdm_thread_t *me, void *obj) int waitms = 20; unsigned int i; int res, ms; + int index = 0; struct timeval start, end; - short *poll_events = ftdm_malloc(sizeof(short)*span->chan_count); + ftdm_iterator_t *chaniter = NULL; + short *poll_events = ftdm_malloc(sizeof(short) * span->chan_count); #ifdef __linux__ r2data->monitor_thread_id = syscall(SYS_gettid); @@ -1369,28 +1509,39 @@ static void *ftdm_r2_run(ftdm_thread_t *me, void *obj) r2chan = R2CALL(span->channels[i])->r2chan; openr2_chan_set_idle(r2chan); openr2_chan_process_cas_signaling(r2chan); + + ftdmchan = openr2_chan_get_client_data(r2chan); + //ftdm_channel_set_feature(ftdmchan, FTDM_CHANNEL_FEATURE_IO_STATS); } memset(&start, 0, sizeof(start)); memset(&end, 0, sizeof(end)); + chaniter = ftdm_span_get_chan_iterator(span, NULL); while (ftdm_running() && ftdm_test_flag(r2data, FTDM_R2_RUNNING)) { - r2data->loops++; res = gettimeofday(&end, NULL); if (start.tv_sec) { ms = ((end.tv_sec - start.tv_sec) * 1000) + ((( 1000000 + end.tv_usec - start.tv_usec) / 1000) - 1000); + if (ms < 0) { + ms = 0; + } if (ms > r2data->jobmax) { r2data->jobmax = ms; } + index = (ms / 10); + index = (index > 10) ? 10 : index; + r2data->loops[index]++; + r2data->total_loops++; } #ifndef WIN32 /* figure out what event to poll each channel for. POLLPRI when the channel is down, * POLLPRI|POLLIN|POLLOUT otherwise */ memset(poll_events, 0, sizeof(short)*span->chan_count); - for (i = 0; i < span->chan_count; i++) { - r2chan = R2CALL(span->channels[(i+1)])->r2chan; - ftdmchan = openr2_chan_get_client_data(r2chan); + chaniter = ftdm_span_get_chan_iterator(span, chaniter); + for (i = 0; chaniter; chaniter = ftdm_iterator_next(chaniter), i++) { + ftdmchan = ftdm_iterator_current(chaniter); + r2chan = R2CALL(ftdmchan)->r2chan; poll_events[i] = POLLPRI; if (openr2_chan_get_read_enabled(r2chan)) { poll_events[i] |= POLLIN; @@ -1412,29 +1563,35 @@ static void *ftdm_r2_run(ftdm_thread_t *me, void *obj) continue; } - /* XXX - * when ftdm_span_poll_event() returns FTDM_SUCCESS, means there are events pending on the span. - * is it possible to know on which channels those events are pending, without traversing the span? - * XXX */ - for (i = 1; i <= span->chan_count; i++) { - r2chan = R2CALL(span->channels[i])->r2chan; - ftdmchan = openr2_chan_get_client_data(r2chan); - r2call = R2CALL(ftdmchan); + /* this main loop takes care of MF and CAS signaling during call setup and tear down + * for every single channel in the span, do not perform blocking operations here! */ + chaniter = ftdm_span_get_chan_iterator(span, chaniter); + for ( ; chaniter; chaniter = ftdm_iterator_next(chaniter)) { + ftdmchan = ftdm_iterator_current(chaniter); ftdm_mutex_lock(ftdmchan->mutex); - ftdm_r2_state_advance(ftdmchan); + + ftdm_r2_state_advance_all(ftdmchan); + + r2chan = R2CALL(ftdmchan)->r2chan; openr2_chan_process_signaling(r2chan); - ftdm_r2_state_advance(ftdmchan); + + ftdm_r2_state_advance_all(ftdmchan); + ftdm_mutex_unlock(ftdmchan->mutex); } + /* deliver the actual events to the user now without any channel locking */ ftdm_span_trigger_signals(span); } - - for (i = 1; i <= span->chan_count; i++) { - r2chan = R2CALL(span->channels[i])->r2chan; + + chaniter = ftdm_span_get_chan_iterator(span, chaniter); + for ( ; chaniter; chaniter = ftdm_iterator_next(chaniter)) { + ftdmchan = ftdm_iterator_current(chaniter); + r2chan = R2CALL(ftdmchan)->r2chan; openr2_chan_set_blocked(r2chan); } + ftdm_iterator_free(chaniter); ftdm_safe_free(poll_events); ftdm_clear_flag(r2data, FTDM_R2_RUNNING); @@ -1576,7 +1733,7 @@ static FIO_API_FUNCTION(ftdm_r2_api) goto done; } if (!(r2data = span->signal_data)) { - stream->write_function(stream, "-ERR invalid span. No R2 singal data in span.\n"); + stream->write_function(stream, "-ERR invalid span. No R2 signal data in span.\n"); goto done; } r2context = r2data->r2context; @@ -1587,19 +1744,17 @@ static FIO_API_FUNCTION(ftdm_r2_api) "Max DNIS: %d\n" "ANI First: %s\n" "Immediate Accept: %s\n" - "Side: %s\n" + "Job Thread: %lu\n" "Job Max ms: %d\n" - "Job Loops: %lu\n" - "Monitor Thread: %lu\n", + "Job Loops: %lu\n", openr2_proto_get_variant_string(r2variant), openr2_context_get_max_ani(r2context), openr2_context_get_max_dnis(r2context), openr2_context_get_ani_first(r2context) ? "Yes" : "No", openr2_context_get_immediate_accept(r2context) ? "Yes" : "No", - "no side", + r2data->monitor_thread_id, r2data->jobmax, - r2data->loops, - r2data->monitor_thread_id); + r2data->total_loops); stream->write_function(stream, "\n"); stream->write_function(stream, "%4s %-12.12s %-12.12s\n", "Channel", "Tx CAS", "Rx CAS"); for (i = 1; i <= span->chan_count; i++) { @@ -1618,6 +1773,39 @@ static FIO_API_FUNCTION(ftdm_r2_api) } } + if (!strcasecmp(argv[0], "loopstats")) { + int range; + float pct; + span_id = atoi(argv[1]); + + if (ftdm_span_find_by_name(argv[1], &span) == FTDM_SUCCESS || ftdm_span_find(span_id, &span) == FTDM_SUCCESS) { + if (span->start != ftdm_r2_start) { + stream->write_function(stream, "-ERR not an R2 span.\n"); + goto done; + } + if (!(r2data = span->signal_data)) { + stream->write_function(stream, "-ERR invalid span. No R2 signal data in span.\n"); + goto done; + } + range = 0; + for (i = 0; i < ftdm_array_len(r2data->loops); i++) { + pct = 100*(float)r2data->loops[i]/r2data->total_loops; + if ((i + 1) == ftdm_array_len(r2data->loops)) { + stream->write_function(stream, ">= %dms: %llu - %.03lf%%\n", range, r2data->loops[i], pct); + } else { + stream->write_function(stream, "%d-%dms: %llu - %.03lf%%\n", range, range + 9, r2data->loops[i], pct); + } + range += 10; + } + stream->write_function(stream, "\n"); + stream->write_function(stream, "+OK.\n"); + goto done; + } else { + stream->write_function(stream, "-ERR invalid span.\n"); + goto done; + } + } + } if (argc == 1) { @@ -1707,12 +1895,13 @@ static FIO_SIG_UNLOAD_FUNCTION(ftdm_r2_destroy) } EX_DECLARE_DATA ftdm_module_t ftdm_module = { - "r2", - ftdm_r2_io_init, - NULL, - ftdm_r2_init, - ftdm_r2_configure_span, - ftdm_r2_destroy + /* .name */ "r2", + /* .io_load */ ftdm_r2_io_init, + /* .io_unload */ NULL, + /* .sig_load */ ftdm_r2_init, + /* .sig_configure */ NULL, + /* .sig_unload */ ftdm_r2_destroy, + /* .configure_span_signaling */ ftdm_r2_configure_span_signaling }; diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_boost/ftmod_sangoma_boost.2010.vcxproj b/libs/freetdm/src/ftmod/ftmod_sangoma_boost/ftmod_sangoma_boost.2010.vcxproj new file mode 100644 index 0000000000..1dd09211e2 --- /dev/null +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_boost/ftmod_sangoma_boost.2010.vcxproj @@ -0,0 +1,206 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + ftmod_sangoma_boost + {D021EF2A-460D-4827-A0F7-41FDECF46F1B} + ftmod_sangoma_boost + Win32Proj + + + + DynamicLibrary + Unicode + true + + + DynamicLibrary + Unicode + + + DynamicLibrary + Unicode + true + + + DynamicLibrary + Unicode + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + true + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + false + $(SolutionDir)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\ + true + $(SolutionDir)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\ + false + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\include;..\..\isdn\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;_USRDLL;FTMOD_SANGOMA_BOOST_EXPORTS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + + Level4 + true + EditAndContinue + 4100;%(DisableSpecificWarnings) + + + freetdm.lib;%(AdditionalDependencies) + $(OutDir);%(AdditionalLibraryDirectories) + true + Windows + MachineX86 + + + + + MaxSpeed + true + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;_USRDLL;FTMOD_SANGOMA_BOOST_EXPORTS;%(PreprocessorDefinitions) + MultiThreadedDLL + true + + + Level4 + true + ProgramDatabase + 4100;%(DisableSpecificWarnings) + + + true + Windows + true + true + MachineX86 + + + + + X64 + + + Disabled + ..\..\include;..\..\isdn\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;_USRDLL;FTMOD_SANGOMA_BOOST_EXPORTS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + + Level4 + true + ProgramDatabase + 4100;%(DisableSpecificWarnings) + + + freetdm.lib;%(AdditionalDependencies) + $(OutDir);%(AdditionalLibraryDirectories) + true + Windows + MachineX64 + + + + + X64 + + + MaxSpeed + true + ..\..\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;_USRDLL;FTMOD_SANGOMA_BOOST_EXPORTS;%(PreprocessorDefinitions) + MultiThreadedDLL + true + + + Level4 + true + ProgramDatabase + 4100;%(DisableSpecificWarnings) + + + true + Windows + true + true + MachineX64 + + + + + + + + + + + + + + + {93b8812c-3ec4-4f78-8970-ffbfc99e167d} + false + + + + + + \ No newline at end of file diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_boost/ftmod_sangoma_boost.2010.vcxproj.filters b/libs/freetdm/src/ftmod/ftmod_sangoma_boost/ftmod_sangoma_boost.2010.vcxproj.filters new file mode 100644 index 0000000000..2aeed155cd --- /dev/null +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_boost/ftmod_sangoma_boost.2010.vcxproj.filters @@ -0,0 +1,35 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + \ No newline at end of file diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.2010.vcxproj b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.2010.vcxproj new file mode 100644 index 0000000000..b4d234cc7d --- /dev/null +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.2010.vcxproj @@ -0,0 +1,121 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + ftmod_sangoma_isdn + {B2AF4EA6-0CD7-4529-9EB5-5AF43DB90395} + ftmod_sangoma_isdn + Win32Proj + + + + DynamicLibrary + true + + + DynamicLibrary + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + true + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + true + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + C:\Program Files\libsng_isdn\include;C:\Program Files\libsng_isdn\include\sng_isdn;../../include;C:\Program Files\Sangoma\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + EnableFastChecks + + + Level3 + EditAndContinue + + + freetdm.lib;libsng_isdn.lib;%(AdditionalDependencies) + $(OutDir);C:\Program Files\libsng_isdn\lib;C:\Program Files\Sangoma\api\lib\x86;%(AdditionalLibraryDirectories) + true + Console + false + + + MachineX86 + + + + + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + + Level3 + ProgramDatabase + + + true + Windows + true + true + MachineX86 + + + + + + + + + + + + + + + + + + + + + {93b8812c-3ec4-4f78-8970-ffbfc99e167d} + false + + + + + + \ No newline at end of file diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.2010.vcxproj.filters b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.2010.vcxproj.filters new file mode 100644 index 0000000000..5f592fa9ef --- /dev/null +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.2010.vcxproj.filters @@ -0,0 +1,57 @@ + + + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + \ No newline at end of file diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.h b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.h index 8027dd391c..b80d5b5577 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.h +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.h @@ -65,6 +65,31 @@ /* TODO: rename all *_cc_* to *_an_* */ +#define SNGISDN_ENUM_NAMES(_NAME, _STRINGS) static const char * _NAME [] = { _STRINGS , NULL }; +#define SNGISDN_STR2ENUM_P(_FUNC1, _FUNC2, _TYPE) _TYPE _FUNC1 (const char *name); const char * _FUNC2 (_TYPE type); +#define SNGISDN_STR2ENUM(_FUNC1, _FUNC2, _TYPE, _STRINGS, _MAX) \ + _TYPE _FUNC1 (const char *name) \ +{ \ + int i; \ + _TYPE t = _MAX ; \ + \ + for (i = 0; i < _MAX ; i++) { \ + if (!strcasecmp(name, _STRINGS[i])) { \ + t = (_TYPE) i; \ + break; \ +} \ +} \ + \ + return t; \ +} \ + const char * _FUNC2 (_TYPE type) \ +{ \ + if (type > _MAX) { \ + type = _MAX; \ +} \ + return _STRINGS[(int)type]; \ +} \ + typedef enum { @@ -139,7 +164,45 @@ typedef enum { SNGISDN_EVENT_RST_IND, } ftdm_sngisdn_event_id_t; +typedef enum { + /* Call is not end-to-end ISDN */ + SNGISDN_PROGIND_DESCR_NETE_ISDN, + /* Destination address is non-ISDN */ + SNGISDN_PROGIND_DESCR_DEST_NISDN, + /* Origination address is non-ISDN */ + SNGISDN_PROGIND_DESCR_ORIG_NISDN, + /* Call has returned to the ISDN */ + SNGISDN_PROGIND_DESCR_RET_ISDN, + /* Interworking as occured and has resulted in a telecommunication service change */ + SNGISDN_PROGIND_DESCR_SERV_CHANGE, + /* In-band information or an appropriate pattern is now available */ + SNGISDN_PROGIND_DESCR_IB_AVAIL, + /* Invalid */ + SNGISDN_PROGIND_DESCR_INVALID, +} ftdm_sngisdn_progind_descr_t; +#define SNGISDN_PROGIND_DESCR_STRINGS "not-end-to-end-isdn", "destination-is-non-isdn", "origination-is-non-isdn", "call-returned-to-isdn", "service-change", "inband-info-available", "invalid" +SNGISDN_STR2ENUM_P(ftdm_str2ftdm_sngisdn_progind_descr, ftdm_sngisdn_progind_descr2str, ftdm_sngisdn_progind_descr_t); +typedef enum { + /* User */ + SNGISDN_PROGIND_LOC_USER, + /* Private network serving the local user */ + SNGISDN_PROGIND_LOC_PRIV_NET_LOCAL_USR, + /* Public network serving the local user */ + SNGISDN_PROGIND_LOC_PUB_NET_LOCAL_USR, + /* Transit network */ + SNGISDN_PROGIND_LOC_TRANSIT_NET, + /* Public network serving remote user */ + SNGISDN_PROGIND_LOC_PUB_NET_REMOTE_USR, + /* Private network serving remote user */ + SNGISDN_PROGIND_LOC_PRIV_NET_REMOTE_USR, + /* Network beyond the interworking point */ + SNGISDN_PROGIND_LOC_NET_BEYOND_INTRW, + /* Invalid */ + SNGISDN_PROGIND_LOC_INVALID, +} ftdm_sngisdn_progind_loc_t; +#define SNGISDN_PROGIND_LOC_STRINGS "user", "private-net-local-user", "public-net-local-user", "transit-network", "public-net-remote-user", "private-net-remote-user", "beyond-interworking", "invalid" +SNGISDN_STR2ENUM_P(ftdm_str2ftdm_sngisdn_progind_loc, ftdm_sngisdn_progind_loc2str, ftdm_sngisdn_progind_loc_t); typedef struct ftdm_sngisdn_prog_ind { ftdm_sngisdn_progind_loc_t loc; /* location */ @@ -198,7 +261,7 @@ typedef struct sngisdn_span_data { uint8_t num_local_numbers; uint8_t ignore_cause_value; uint8_t timer_t3; - uint8_t restart_opt; + uint8_t restart_opt; char* local_numbers[SNGISDN_NUM_LOCAL_NUMBERS]; ftdm_sched_t *sched; ftdm_queue_t *event_queue; diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_cfg.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_cfg.c index b7e6e26fd5..cce10cc1dd 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_cfg.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_cfg.c @@ -204,6 +204,7 @@ ftdm_status_t ftmod_isdn_parse_cfg(ftdm_conf_parameter_t *ftdm_parameters, ftdm_ signal_data->facility_ie_decode = SNGISDN_OPT_DEFAULT; signal_data->ignore_cause_value = SNGISDN_OPT_DEFAULT; signal_data->timer_t3 = 8; + signal_data->restart_opt = SNGISDN_OPT_DEFAULT; signal_data->link_id = span->span_id; span->default_caller_data.bearer_capability = IN_ITC_SPEECH; diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_cfg.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_cfg.c index 6c75fb3a81..de10a9fac0 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_cfg.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_cfg.c @@ -686,7 +686,16 @@ ftdm_status_t sngisdn_stack_cfg_q931_dlsap(ftdm_span_t *span) cfg.t.cfg.s.inDLSAP.statEnqOpt = FALSE; cfg.t.cfg.s.inDLSAP.rstOpt = FALSE; } - + + /* Override the restart options if user selected that option */ + if (signal_data->restart_opt != SNGISDN_OPT_DEFAULT) { + if (signal_data->restart_opt == SNGISDN_OPT_TRUE) { + cfg.t.cfg.s.inDLSAP.rstOpt = TRUE; + } else { + cfg.t.cfg.s.inDLSAP.rstOpt = FALSE; + } + } + for (i = 0; i < IN_MAXBCHNL; i++) { cfg.t.cfg.s.inDLSAP.bProf[i].profNmb = 0; 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 d1c7063279..08b14a08ce 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 @@ -607,32 +607,32 @@ void sngisdn_snd_data(ftdm_channel_t *dchan, uint8_t *data, ftdm_size_t len) memcpy(&l1_frame.data, data, len); - if (ftdm_test_flag(&(dchan->iostats.stats.rx), FTDM_IOSTATS_ERROR_CRC)) { + if (ftdm_test_flag(&(dchan->iostats.rx), FTDM_IOSTATS_ERROR_CRC)) { l1_frame.flags |= SNG_L1FRAME_ERROR_CRC; } - if (ftdm_test_flag(&(dchan->iostats.stats.rx), FTDM_IOSTATS_ERROR_FRAME)) { + if (ftdm_test_flag(&(dchan->iostats.rx), FTDM_IOSTATS_ERROR_FRAME)) { l1_frame.flags |= SNG_L1FRAME_ERROR_FRAME; } - if (ftdm_test_flag(&(dchan->iostats.stats.rx), FTDM_IOSTATS_ERROR_ABORT)) { + if (ftdm_test_flag(&(dchan->iostats.rx), FTDM_IOSTATS_ERROR_ABORT)) { l1_frame.flags |= SNG_L1FRAME_ERROR_ABORT; } - if (ftdm_test_flag(&(dchan->iostats.stats.rx), FTDM_IOSTATS_ERROR_FIFO)) { + if (ftdm_test_flag(&(dchan->iostats.rx), FTDM_IOSTATS_ERROR_FIFO)) { l1_frame.flags |= SNG_L1FRAME_ERROR_FIFO; } - if (ftdm_test_flag(&(dchan->iostats.stats.rx), FTDM_IOSTATS_ERROR_DMA)) { + if (ftdm_test_flag(&(dchan->iostats.rx), FTDM_IOSTATS_ERROR_DMA)) { l1_frame.flags |= SNG_L1FRAME_ERROR_DMA; } - if (ftdm_test_flag(&(dchan->iostats.stats.rx), FTDM_IOSTATS_ERROR_QUEUE_THRES)) { + if (ftdm_test_flag(&(dchan->iostats.rx), FTDM_IOSTATS_ERROR_QUEUE_THRES)) { /* Should we trigger congestion here? */ l1_frame.flags |= SNG_L1FRAME_QUEUE_THRES; } - if (ftdm_test_flag(&(dchan->iostats.stats.rx), FTDM_IOSTATS_ERROR_QUEUE_FULL)) { + if (ftdm_test_flag(&(dchan->iostats.rx), FTDM_IOSTATS_ERROR_QUEUE_FULL)) { /* Should we trigger congestion here? */ l1_frame.flags |= SNG_L1FRAME_QUEUE_FULL; } diff --git a/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.2010.vcxproj b/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.2010.vcxproj new file mode 100644 index 0000000000..b165ac82d3 --- /dev/null +++ b/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.2010.vcxproj @@ -0,0 +1,201 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + ftmod_wanpipe + {1A145EE9-BBD8-45E5-98CD-EB4BE99E1DCD} + ftmod_wanpipe + Win32Proj + + + + DynamicLibrary + MultiByte + true + + + DynamicLibrary + MultiByte + + + DynamicLibrary + MultiByte + true + + + DynamicLibrary + MultiByte + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + true + $(SolutionDir)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\ + true + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + false + $(SolutionDir)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\ + false + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ../../include;C:\Program Files\Sangoma\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + + Level3 + EditAndContinue + + + freetdm.lib;libsangoma.lib;%(AdditionalDependencies) + $(OutDir);C:\Program Files\Sangoma\api\lib\x86;%(AdditionalLibraryDirectories) + true + Console + false + + + MachineX86 + + + + + X64 + + + Disabled + ../../include;C:\Program Files\Sangoma\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + + Level3 + ProgramDatabase + + + freetdm.lib;libsangoma.lib;%(AdditionalDependencies) + $(OutDir);C:\Program Files\Sangoma\api\lib\x64;%(AdditionalLibraryDirectories) + true + Console + false + + + MachineX64 + + + + + ../../include;C:\Program Files\Sangoma\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreadedDLL + + + Level3 + ProgramDatabase + + + freetdm.lib;libsangoma.lib;%(AdditionalDependencies) + $(OutDir);C:\Program Files\Sangoma\api\lib\x86;%(AdditionalLibraryDirectories) + true + Console + true + true + false + + + MachineX86 + + + + + X64 + + + ../../include;C:\Program Files\Sangoma\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreadedDLL + + + Level3 + ProgramDatabase + + + freetdm.lib;libsangoma.lib;%(AdditionalDependencies) + $(OutDir);C:\Program Files\Sangoma\api\lib\x64;%(AdditionalLibraryDirectories) + true + Console + true + true + false + + + MachineX64 + + + + + + + + {93b8812c-3ec4-4f78-8970-ffbfc99e167d} + false + + + + + + \ No newline at end of file diff --git a/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.2010.vcxproj.filters b/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.2010.vcxproj.filters new file mode 100644 index 0000000000..15a8bc3d35 --- /dev/null +++ b/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.2010.vcxproj.filters @@ -0,0 +1,18 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + + + Source Files + + + \ No newline at end of file diff --git a/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c b/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c index c55d42e8b0..72a57280d6 100644 --- a/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c +++ b/libs/freetdm/src/ftmod/ftmod_wanpipe/ftmod_wanpipe.c @@ -123,6 +123,10 @@ static __inline__ int tdmv_api_wait_socket(ftdm_channel_t *ftdmchan, int timeout uint32_t outflags = 0; sangoma_wait_obj_t *sangoma_wait_obj = ftdmchan->io_data; + if (timeout == -1) { + timeout = SANGOMA_WAIT_INFINITE; + } + err = sangoma_waitfor(sangoma_wait_obj, inflags, &outflags, timeout); *flags = 0; if (err == SANG_STATUS_SUCCESS) { @@ -515,7 +519,10 @@ static FIO_OPEN_FUNCTION(wanpipe_open) wanpipe_tdm_api_t tdm_api; memset(&tdm_api,0,sizeof(tdm_api)); + sangoma_tdm_flush_bufs(ftdmchan->sockfd, &tdm_api); + sangoma_flush_stats(ftdmchan->sockfd, &tdm_api); + memset(&ftdmchan->iostats, 0, sizeof(ftdmchan->iostats)); if (ftdmchan->type == FTDM_CHAN_TYPE_DQ921 || ftdmchan->type == FTDM_CHAN_TYPE_DQ931) { ftdmchan->native_codec = ftdmchan->effective_codec = FTDM_CODEC_NONE; @@ -752,6 +759,7 @@ static FIO_COMMAND_FUNCTION(wanpipe_command) case FTDM_COMMAND_FLUSH_IOSTATS: { err = sangoma_flush_stats(ftdmchan->sockfd, &tdm_api); + memset(&ftdmchan->iostats, 0, sizeof(ftdmchan->iostats)); } break; case FTDM_COMMAND_SET_RX_QUEUE_SIZE: @@ -779,44 +787,103 @@ static FIO_COMMAND_FUNCTION(wanpipe_command) return FTDM_SUCCESS; } +static void wanpipe_write_stats(ftdm_channel_t *ftdmchan, wp_tdm_api_tx_hdr_t *tx_stats) +{ + ftdmchan->iostats.tx.errors = tx_stats->wp_api_tx_hdr_errors; + ftdmchan->iostats.tx.queue_size = tx_stats->wp_api_tx_hdr_max_queue_length; + ftdmchan->iostats.tx.queue_len = tx_stats->wp_api_tx_hdr_number_of_frames_in_queue; + + /* we don't test for 80% full in tx since is typically full for voice channels, should we test tx 80% full for D-channels? */ + if (ftdmchan->iostats.tx.queue_len >= ftdmchan->iostats.tx.queue_size) { + ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "Tx Queue Full (%d/%d)\n", + ftdmchan->iostats.tx.queue_len, ftdmchan->iostats.tx.queue_size); + ftdm_set_flag(&(ftdmchan->iostats.tx), FTDM_IOSTATS_ERROR_QUEUE_FULL); + } else if (ftdm_test_flag(&(ftdmchan->iostats.tx), FTDM_IOSTATS_ERROR_QUEUE_FULL)){ + ftdm_log_chan(ftdmchan, FTDM_LOG_NOTICE, "Tx Queue no longer full (%d/%d)\n", + ftdmchan->iostats.tx.queue_len, ftdmchan->iostats.tx.queue_size); + ftdm_clear_flag(&(ftdmchan->iostats.tx), FTDM_IOSTATS_ERROR_QUEUE_FULL); + } + + if (ftdmchan->iostats.tx.idle_packets < tx_stats->wp_api_tx_hdr_number_of_frames_in_queue) { + ftdmchan->iostats.tx.idle_packets = tx_stats->wp_api_tx_hdr_tx_idle_packets; + /* HDLC channels do not always transmit, so its ok for drivers to fill with idle */ + if (FTDM_IS_VOICE_CHANNEL(ftdmchan)) { + ftdm_log_chan(ftdmchan, FTDM_LOG_WARNING, "Tx idle: %d\n", ftdmchan->iostats.tx.idle_packets); + } + } + + if (!ftdmchan->iostats.tx.packets) { + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "First packet write stats: Tx queue len: %d, Tx queue size: %d, Tx idle: %d\n", + ftdmchan->iostats.tx.queue_len, + ftdmchan->iostats.tx.queue_size, + ftdmchan->iostats.tx.idle_packets); + } + + ftdmchan->iostats.tx.packets++; +} + static void wanpipe_read_stats(ftdm_channel_t *ftdmchan, wp_tdm_api_rx_hdr_t *rx_stats) { - ftdmchan->iostats.stats.rx.flags = 0; - - ftdmchan->iostats.stats.rx.errors = rx_stats->wp_api_rx_hdr_errors; - ftdmchan->iostats.stats.rx.rx_queue_size = rx_stats->wp_api_rx_hdr_max_queue_length; - ftdmchan->iostats.stats.rx.rx_queue_len = rx_stats->wp_api_rx_hdr_number_of_frames_in_queue; + ftdmchan->iostats.rx.errors = rx_stats->wp_api_rx_hdr_errors; + ftdmchan->iostats.rx.queue_size = rx_stats->wp_api_rx_hdr_max_queue_length; + ftdmchan->iostats.rx.queue_len = rx_stats->wp_api_rx_hdr_number_of_frames_in_queue; - if (rx_stats->wp_api_rx_hdr_error_map & (1<iostats.stats.rx), FTDM_IOSTATS_ERROR_ABORT); - } - if (rx_stats->wp_api_rx_hdr_error_map & (1<iostats.stats.rx), FTDM_IOSTATS_ERROR_DMA); - } - if (rx_stats->wp_api_rx_hdr_error_map & (1<iostats.stats.rx), FTDM_IOSTATS_ERROR_FIFO); - } - if (rx_stats->wp_api_rx_hdr_error_map & (1<iostats.stats.rx), FTDM_IOSTATS_ERROR_CRC); - } - if (rx_stats->wp_api_rx_hdr_error_map & (1<iostats.stats.rx), FTDM_IOSTATS_ERROR_FRAME); + if ((rx_stats->wp_api_rx_hdr_error_map & (1 << WP_ABORT_ERROR_BIT))) { + ftdm_set_flag(&(ftdmchan->iostats.rx), FTDM_IOSTATS_ERROR_ABORT); + } else { + ftdm_clear_flag(&(ftdmchan->iostats.rx), FTDM_IOSTATS_ERROR_ABORT); } - if (ftdmchan->iostats.stats.rx.rx_queue_len >= (0.8*ftdmchan->iostats.stats.rx.rx_queue_size)) { - ftdm_log_chan(ftdmchan, FTDM_LOG_WARNING, "Rx Queue length exceeded threshold (%d/%d)\n", - ftdmchan->iostats.stats.rx.rx_queue_len, ftdmchan->iostats.stats.rx.rx_queue_size); - - ftdm_set_flag(&(ftdmchan->iostats.stats.rx), FTDM_IOSTATS_ERROR_QUEUE_THRES); + if ((rx_stats->wp_api_rx_hdr_error_map & (1 << WP_DMA_ERROR_BIT))) { + ftdm_set_flag(&(ftdmchan->iostats.rx), FTDM_IOSTATS_ERROR_DMA); + } else { + ftdm_clear_flag(&(ftdmchan->iostats.rx), FTDM_IOSTATS_ERROR_DMA); + } + + if ((rx_stats->wp_api_rx_hdr_error_map & (1 << WP_FIFO_ERROR_BIT))) { + ftdm_set_flag(&(ftdmchan->iostats.rx), FTDM_IOSTATS_ERROR_FIFO); + } else { + ftdm_clear_flag(&(ftdmchan->iostats.rx), FTDM_IOSTATS_ERROR_FIFO); + } + + if ((rx_stats->wp_api_rx_hdr_error_map & (1 << WP_CRC_ERROR_BIT))) { + ftdm_set_flag(&(ftdmchan->iostats.rx), FTDM_IOSTATS_ERROR_CRC); + } else { + ftdm_clear_flag(&(ftdmchan->iostats.rx), FTDM_IOSTATS_ERROR_CRC); + } + + if ((rx_stats->wp_api_rx_hdr_error_map & (1 << WP_FRAME_ERROR_BIT))) { + ftdm_set_flag(&(ftdmchan->iostats.rx), FTDM_IOSTATS_ERROR_FRAME); + } else { + ftdm_clear_flag(&(ftdmchan->iostats.rx), FTDM_IOSTATS_ERROR_FRAME); + } + + if (ftdmchan->iostats.rx.queue_len >= (0.8 * ftdmchan->iostats.rx.queue_size)) { + ftdm_log_chan(ftdmchan, FTDM_LOG_WARNING, "Rx Queue length exceeded 80% threshold (%d/%d)\n", + ftdmchan->iostats.rx.queue_len, ftdmchan->iostats.rx.queue_size); + ftdm_set_flag(&(ftdmchan->iostats.rx), FTDM_IOSTATS_ERROR_QUEUE_THRES); + } else if (ftdm_test_flag(&(ftdmchan->iostats.rx), FTDM_IOSTATS_ERROR_QUEUE_THRES)){ + ftdm_log_chan(ftdmchan, FTDM_LOG_NOTICE, "Rx Queue length reduced 80% threshold (%d/%d)\n", + ftdmchan->iostats.rx.queue_len, ftdmchan->iostats.rx.queue_size); + ftdm_clear_flag(&(ftdmchan->iostats.rx), FTDM_IOSTATS_ERROR_QUEUE_THRES); } - if (ftdmchan->iostats.stats.rx.rx_queue_len >= ftdmchan->iostats.stats.rx.rx_queue_size) { + if (ftdmchan->iostats.rx.queue_len >= ftdmchan->iostats.rx.queue_size) { ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "Rx Queue Full (%d/%d)\n", - ftdmchan->iostats.stats.rx.rx_queue_len, ftdmchan->iostats.stats.rx.rx_queue_size); - - ftdm_set_flag(&(ftdmchan->iostats.stats.rx), FTDM_IOSTATS_ERROR_QUEUE_FULL); + ftdmchan->iostats.rx.queue_len, ftdmchan->iostats.rx.queue_size); + ftdm_set_flag(&(ftdmchan->iostats.rx), FTDM_IOSTATS_ERROR_QUEUE_FULL); + } else if (ftdm_test_flag(&(ftdmchan->iostats.rx), FTDM_IOSTATS_ERROR_QUEUE_FULL)){ + ftdm_log_chan(ftdmchan, FTDM_LOG_NOTICE, "Rx Queue no longer full (%d/%d)\n", + ftdmchan->iostats.rx.queue_len, ftdmchan->iostats.rx.queue_size); + ftdm_clear_flag(&(ftdmchan->iostats.rx), FTDM_IOSTATS_ERROR_QUEUE_FULL); } - return; + + if (!ftdmchan->iostats.rx.packets) { + ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "First packet read stats: Rx queue len: %d, Rx queue size: %d\n", + ftdmchan->iostats.rx.queue_len, ftdmchan->iostats.rx.queue_size); + } + + ftdmchan->iostats.rx.packets++; } /** @@ -877,6 +944,9 @@ static FIO_WRITE_FUNCTION(wanpipe_write) /* should we be checking if bsent == *datalen here? */ if (bsent > 0) { *datalen = bsent; + if (ftdm_channel_test_feature(ftdmchan, FTDM_CHANNEL_FEATURE_IO_STATS)) { + wanpipe_write_stats(ftdmchan, &hdrframe); + } return FTDM_SUCCESS; } diff --git a/libs/freetdm/src/ftmod/ftmod_wanpipe/ozmod_wanpipe.2005.vcproj b/libs/freetdm/src/ftmod/ftmod_wanpipe/ozmod_wanpipe.2005.vcproj deleted file mode 100644 index abebf30427..0000000000 --- a/libs/freetdm/src/ftmod/ftmod_wanpipe/ozmod_wanpipe.2005.vcproj +++ /dev/null @@ -1,196 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/libs/freetdm/src/ftmod/ftmod_wanpipe/wanpipe_tdm_api_iface.h b/libs/freetdm/src/ftmod/ftmod_wanpipe/wanpipe_tdm_api_iface.h deleted file mode 100644 index 3801ff9c8c..0000000000 --- a/libs/freetdm/src/ftmod/ftmod_wanpipe/wanpipe_tdm_api_iface.h +++ /dev/null @@ -1,351 +0,0 @@ -/***************************************************************************** -* wanpipe_tdm_api_iface.h -* -* WANPIPE(tm) AFT TE1 Hardware Support -* -* Authors: Nenad Corbic -* -* Copyright (c) 2007 - 08, Sangoma Technologies -* 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 nor the -* names of its contributors may be used to endorse or promote products -* derived from this software without specific prior written permission. -* -* THIS SOFTWARE IS PROVIDED BY ``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 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. - -* ============================================================================ -* Oct 04, 2005 Nenad Corbic Initial version. -* -* Jul 25, 2006 David Rokhvarg Ported to Windows. -*****************************************************************************/ - -#ifndef __WANPIPE_TDM_API_IFACE_H_ -#define __WANPIPE_TDM_API_IFACE_H_ - - -#if defined(__WINDOWS__) -typedef HANDLE sng_fd_t; -#else -typedef int sng_fd_t; -#endif - -/* Indicate to library that new features exist */ -#define WP_TDM_FEATURE_DTMF_EVENTS 1 -#define WP_TDM_FEATURE_FE_ALARM 1 -#define WP_TDM_FEATURE_EVENTS 1 -#define WP_TDM_FEATURE_LINK_STATUS 1 - -enum wanpipe_tdm_api_cmds { - - SIOC_WP_TDM_GET_USR_MTU_MRU, /* 0x00 */ - - SIOC_WP_TDM_SET_USR_PERIOD, /* 0x01 */ - SIOC_WP_TDM_GET_USR_PERIOD, /* 0x02 */ - - SIOC_WP_TDM_SET_HW_MTU_MRU, /* 0x03 */ - SIOC_WP_TDM_GET_HW_MTU_MRU, /* 0x04 */ - - SIOC_WP_TDM_SET_CODEC, /* 0x05 */ - SIOC_WP_TDM_GET_CODEC, /* 0x06 */ - - SIOC_WP_TDM_SET_POWER_LEVEL, /* 0x07 */ - SIOC_WP_TDM_GET_POWER_LEVEL, /* 0x08 */ - - SIOC_WP_TDM_TOGGLE_RX, /* 0x09 */ - SIOC_WP_TDM_TOGGLE_TX, /* 0x0A */ - - SIOC_WP_TDM_GET_HW_CODING, /* 0x0B */ - SIOC_WP_TDM_SET_HW_CODING, /* 0x0C */ - - SIOC_WP_TDM_GET_FULL_CFG, /* 0x0D */ - - SIOC_WP_TDM_SET_EC_TAP, /* 0x0E */ - SIOC_WP_TDM_GET_EC_TAP, /* 0x0F */ - - SIOC_WP_TDM_ENABLE_RBS_EVENTS, /* 0x10 */ - SIOC_WP_TDM_DISABLE_RBS_EVENTS, /* 0x11 */ - SIOC_WP_TDM_WRITE_RBS_BITS, /* 0x12 */ - - SIOC_WP_TDM_GET_STATS, /* 0x13 */ - SIOC_WP_TDM_FLUSH_BUFFERS, /* 0x14 */ - - SIOC_WP_TDM_READ_EVENT, /* 0x15 */ - - SIOC_WP_TDM_SET_EVENT, /* 0x16 */ - - SIOC_WP_TDM_SET_RX_GAINS, /* 0x17 */ - SIOC_WP_TDM_SET_TX_GAINS, /* 0x18 */ - SIOC_WP_TDM_CLEAR_RX_GAINS, /* 0x19 */ - SIOC_WP_TDM_CLEAR_TX_GAINS, /* 0x1A */ - - SIOC_WP_TDM_GET_FE_ALARMS, /* 0x1B */ - - SIOC_WP_TDM_ENABLE_HWEC, /* 0x1C */ - SIOC_WP_TDM_DISABLE_HWEC, /* 0x1D */ - - SIOC_WP_TDM_SET_FE_STATUS, /* 0x1E */ - SIOC_WP_TDM_GET_FE_STATUS, /* 0x1F */ - - SIOC_WP_TDM_GET_HW_DTMF, /* 0x20 */ - - SIOC_WP_TDM_NOTSUPP /* */ - -}; - -#define SIOC_WP_TDM_GET_LINK_STATUS SIOC_WP_TDM_GET_FE_STATUS - -enum wanpipe_tdm_api_events { - WP_TDMAPI_EVENT_NONE, - WP_TDMAPI_EVENT_RBS, - WP_TDMAPI_EVENT_ALARM, - WP_TDMAPI_EVENT_DTMF, - WP_TDMAPI_EVENT_RM_DTMF, - WP_TDMAPI_EVENT_RXHOOK, - WP_TDMAPI_EVENT_RING, - WP_TDMAPI_EVENT_RING_DETECT, - WP_TDMAPI_EVENT_RING_TRIP_DETECT, - WP_TDMAPI_EVENT_TONE, - WP_TDMAPI_EVENT_TXSIG_KEWL, - WP_TDMAPI_EVENT_TXSIG_START, - WP_TDMAPI_EVENT_TXSIG_OFFHOOK, - WP_TDMAPI_EVENT_TXSIG_ONHOOK, - WP_TDMAPI_EVENT_ONHOOKTRANSFER, - WP_TDMAPI_EVENT_SETPOLARITY, - WP_TDMAPI_EVENT_BRI_CHAN_LOOPBACK, - WP_TDMAPI_EVENT_LINK_STATUS -}; - -#define WP_TDMAPI_EVENT_FE_ALARM WP_TDMAPI_EVENT_ALARM - - -#define WP_TDMAPI_EVENT_ENABLE 0x01 -#define WP_TDMAPI_EVENT_DISABLE 0x02 -#define WP_TDMAPI_EVENT_MODE_DECODE(mode) \ - ((mode) == WP_TDMAPI_EVENT_ENABLE) ? "Enable" : \ - ((mode) == WP_TDMAPI_EVENT_DISABLE) ? "Disable" : \ - "(Unknown mode)" - -#define WPTDM_A_BIT WAN_RBS_SIG_A -#define WPTDM_B_BIT WAN_RBS_SIG_B -#define WPTDM_C_BIT WAN_RBS_SIG_C -#define WPTDM_D_BIT WAN_RBS_SIG_D - -#define WP_TDMAPI_EVENT_RXHOOK_OFF 0x01 -#define WP_TDMAPI_EVENT_RXHOOK_ON 0x02 -#define WP_TDMAPI_EVENT_RXHOOK_DECODE(state) \ - ((state) == WP_TDMAPI_EVENT_RXHOOK_OFF) ? "Off-hook" : \ - ((state) == WP_TDMAPI_EVENT_RXHOOK_ON) ? "On-hook" : \ - "(Unknown state)" - -#define WP_TDMAPI_EVENT_RING_PRESENT 0x01 -#define WP_TDMAPI_EVENT_RING_STOP 0x02 -#define WP_TDMAPI_EVENT_RING_DECODE(state) \ - ((state) == WP_TDMAPI_EVENT_RING_PRESENT) ? "Ring Present" : \ - ((state) == WP_TDMAPI_EVENT_RING_STOP) ? "Ring Stop" : \ - "(Unknown state)" - -#define WP_TDMAPI_EVENT_RING_TRIP_PRESENT 0x01 -#define WP_TDMAPI_EVENT_RING_TRIP_STOP 0x02 -#define WP_TDMAPI_EVENT_RING_TRIP_DECODE(state) \ - ((state) == WP_TDMAPI_EVENT_RING_TRIP_PRESENT) ? "Ring Present" : \ - ((state) == WP_TDMAPI_EVENT_RING_TRIP_STOP) ? "Ring Stop" : \ - "(Unknown state)" -/*Link Status */ -#define WP_TDMAPI_EVENT_LINK_STATUS_CONNECTED 0x01 -#define WP_TDMAPI_EVENT_LINK_STATUS_DISCONNECTED 0x02 -#define WP_TDMAPI_EVENT_LINK_STATUS_DECODE(status) \ - ((status) == WP_TDMAPI_EVENT_LINK_STATUS_CONNECTED) ? "Connected" : \ - ((status) == WP_TDMAPI_EVENT_LINK_STATUS_DISCONNECTED) ? "Disconnected" : \ - "Unknown" -#define WP_TDMAPI_EVENT_TONE_DIAL 0x01 -#define WP_TDMAPI_EVENT_TONE_BUSY 0x02 -#define WP_TDMAPI_EVENT_TONE_RING 0x03 -#define WP_TDMAPI_EVENT_TONE_CONGESTION 0x04 - -/* BRI channels list */ -#define WAN_BRI_BCHAN1 0x01 -#define WAN_BRI_BCHAN2 0x02 -#define WAN_BRI_DCHAN 0x03 - - -typedef struct { - - u_int8_t type; - u_int8_t mode; - u_int32_t time_stamp; - u_int8_t channel; - u_int32_t chan_map; - u_int8_t span; - union { - struct { - u_int8_t alarm; - } te1_alarm; - struct { - u_int8_t rbs_bits; - } te1_rbs; - struct { - u_int8_t state; - u_int8_t sig; - } rm_hook; - struct { - u_int8_t state; - } rm_ring; - struct { - u_int8_t type; - } rm_tone; - struct { - u_int8_t digit; /* DTMF: digit */ - u_int8_t port; /* DTMF: SOUT/ROUT */ - u_int8_t type; /* DTMF: PRESET/STOP */ - } dtmf; - struct { - u_int16_t polarity; - u_int16_t ohttimer; - } rm_common; - struct{ - u_int16_t status; - } linkstatus; - } wp_tdm_api_event_u; -#define wp_tdm_api_event_type type -#define wp_tdm_api_event_mode mode -#define wp_tdm_api_event_alarm wp_tdm_api_event_u.te1_alarm.alarm -#define wp_tdm_api_event_alarm wp_tdm_api_event_u.te1_alarm.alarm -#define wp_tdm_api_event_rbs_bits wp_tdm_api_event_u.te1_rbs.rbs_bits -#define wp_tdm_api_event_hook_state wp_tdm_api_event_u.rm_hook.state -#define wp_tdm_api_event_hook_sig wp_tdm_api_event_u.rm_hook.sig -#define wp_tdm_api_event_ring_state wp_tdm_api_event_u.rm_ring.state -#define wp_tdm_api_event_tone_type wp_tdm_api_event_u.rm_tone.type -#define wp_tdm_api_event_dtmf_digit wp_tdm_api_event_u.dtmf.digit -#define wp_tdm_api_event_dtmf_type wp_tdm_api_event_u.dtmf.type -#define wp_tdm_api_event_dtmf_port wp_tdm_api_event_u.dtmf.port -#define wp_tdm_api_event_ohttimer wp_tdm_api_event_u.rm_common.ohttimer -#define wp_tdm_api_event_polarity wp_tdm_api_event_u.rm_common.polarity -#define wp_tdm_api_event_link_status wp_tdm_api_event_u.linkstatus.status -} wp_tdm_api_event_t; - -typedef struct { - union { - unsigned char reserved[16]; - }wp_rx_hdr_u; -} wp_tdm_api_rx_hdr_t; - -typedef struct { - wp_tdm_api_rx_hdr_t hdr; - unsigned char data[1]; -} wp_tdm_api_rx_element_t; - -typedef struct { - union { - struct { - unsigned char _rbs_rx_bits; - unsigned int _time_stamp; - }wp_tx; - unsigned char reserved[16]; - }wp_tx_hdr_u; -#define wp_api_time_stamp wp_tx_hdr_u.wp_tx._time_stamp -} wp_tdm_api_tx_hdr_t; - -typedef struct { - wp_tdm_api_tx_hdr_t hdr; - unsigned char data[1]; -} wp_tdm_api_tx_element_t; - - - -typedef struct wp_tdm_chan_stats -{ - unsigned int rx_packets; /* total packets received */ - unsigned int tx_packets; /* total packets transmitted */ - unsigned int rx_bytes; /* total bytes received */ - unsigned int tx_bytes; /* total bytes transmitted */ - unsigned int rx_errors; /* bad packets received */ - unsigned int tx_errors; /* packet transmit problems */ - unsigned int rx_dropped; /* no space in linux buffers */ - unsigned int tx_dropped; /* no space available in linux */ - unsigned int multicast; /* multicast packets received */ -#if !defined(__WINDOWS__) - unsigned int collisions; -#endif - /* detailed rx_errors: */ - unsigned int rx_length_errors; - unsigned int rx_over_errors; /* receiver ring buff overflow */ - unsigned int rx_crc_errors; /* recved pkt with crc error */ - unsigned int rx_frame_errors; /* recv'd frame alignment error */ -#if !defined(__WINDOWS__) - unsigned int rx_fifo_errors; /* recv'r fifo overrun */ -#endif - unsigned int rx_missed_errors; /* receiver missed packet */ - - /* detailed tx_errors */ -#if !defined(__WINDOWS__) - unsigned int tx_aborted_errors; - unsigned int tx_carrier_errors; -#endif - unsigned int tx_fifo_errors; - unsigned int tx_heartbeat_errors; - unsigned int tx_window_errors; - -}wp_tdm_chan_stats_t; - - - -typedef struct wanpipe_tdm_api_cmd{ - unsigned int cmd; - unsigned int hw_tdm_coding; /* Set/Get HW TDM coding: uLaw muLaw */ - unsigned int hw_mtu_mru; /* Set/Get HW TDM MTU/MRU */ - unsigned int usr_period; /* Set/Get User Period in ms */ - unsigned int tdm_codec; /* Set/Get TDM Codec: SLinear */ - unsigned int power_level; /* Set/Get Power level treshold */ - unsigned int rx_disable; /* Enable/Disable Rx */ - unsigned int tx_disable; /* Enable/Disable Tx */ - unsigned int usr_mtu_mru; /* Set/Get User TDM MTU/MRU */ - unsigned int ec_tap; /* Echo Cancellation Tap */ - unsigned int rbs_poll; /* Enable/Disable RBS Polling */ - unsigned int rbs_rx_bits; /* Rx RBS Bits */ - unsigned int rbs_tx_bits; /* Tx RBS Bits */ - unsigned int hdlc; /* HDLC based device */ - unsigned int idle_flag; /* IDLE flag to Tx */ - unsigned int fe_alarms; /* FE Alarms detected */ - wp_tdm_chan_stats_t stats; /* TDM Statistics */ - /* Do NOT add anything above this! Important for binary backward compatibility. */ - wp_tdm_api_event_t event; /* TDM Event */ - unsigned int data_len; - void *data; - unsigned char fe_status; /* FE status - Connected or Disconnected */ - unsigned int hw_dtmf; /* HW DTMF enabled */ -}wanpipe_tdm_api_cmd_t; - -typedef struct wanpipe_tdm_api_event{ - int (*wp_rbs_event)(sng_fd_t fd, unsigned char rbs_bits); - int (*wp_dtmf_event)(sng_fd_t fd, unsigned char dtmf, unsigned char type, unsigned char port); - int (*wp_rxhook_event)(sng_fd_t fd, unsigned char hook_state); - int (*wp_ring_detect_event)(sng_fd_t fd, unsigned char ring_state); - int (*wp_ring_trip_detect_event)(sng_fd_t fd, unsigned char ring_state); - int (*wp_fe_alarm_event)(sng_fd_t fd, unsigned char fe_alarm_event); - int (*wp_link_status_event)(sng_fd_t fd, unsigned char link_status_event); -}wanpipe_tdm_api_event_t; - -typedef struct wanpipe_tdm_api{ - wanpipe_tdm_api_cmd_t wp_tdm_cmd; - wanpipe_tdm_api_event_t wp_tdm_event; -}wanpipe_tdm_api_t; - - -#endif diff --git a/libs/freetdm/src/include/freetdm.h b/libs/freetdm/src/include/freetdm.h index 5ae14abb31..57c590faf2 100644 --- a/libs/freetdm/src/include/freetdm.h +++ b/libs/freetdm/src/include/freetdm.h @@ -915,7 +915,7 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_remove_from_group(ftdm_group_t* group, ft * from a different thread or even the same. It is recommended to * handle events from the same span in a single thread. * - * \param span The channel to retrieve the event from + * \param ftdmchan The channel to retrieve the event from * \param event Pointer to store the pointer to the event * * \retval FTDM_SUCCESS success (at least one event available) diff --git a/libs/freetdm/src/include/private/ftdm_core.h b/libs/freetdm/src/include/private/ftdm_core.h index 06f899c8c9..7683ec7145 100644 --- a/libs/freetdm/src/include/private/ftdm_core.h +++ b/libs/freetdm/src/include/private/ftdm_core.h @@ -368,30 +368,32 @@ typedef struct { } ftdm_channel_history_entry_t; typedef enum { - FTDM_IOSTATS_ERROR_CRC = (1<<0), - FTDM_IOSTATS_ERROR_FRAME = (1<<1), - FTDM_IOSTATS_ERROR_ABORT = (1<<2), - FTDM_IOSTATS_ERROR_FIFO = (1<<3), - FTDM_IOSTATS_ERROR_DMA = (1<<4), - FTDM_IOSTATS_ERROR_QUEUE_THRES = (1<<5), /* Queue reached high threshold */ - FTDM_IOSTATS_ERROR_QUEUE_FULL = (1<<6), /* Queue is full */ + FTDM_IOSTATS_ERROR_CRC = (1 << 0), + FTDM_IOSTATS_ERROR_FRAME = (1 << 1), + FTDM_IOSTATS_ERROR_ABORT = (1 << 2), + FTDM_IOSTATS_ERROR_FIFO = (1 << 3), + FTDM_IOSTATS_ERROR_DMA = (1 << 4), + FTDM_IOSTATS_ERROR_QUEUE_THRES = (1 << 5), /* Queue reached high threshold */ + FTDM_IOSTATS_ERROR_QUEUE_FULL = (1 << 6), /* Queue is full */ } ftdm_iostats_error_type_t; typedef struct { - union { - struct { - uint32_t errors; - uint16_t flags; - uint8_t rx_queue_size; /* max queue size configured */ - uint8_t rx_queue_len; /* Current number of elements in queue */ - } rx; - struct { - uint32_t errors; - uint16_t flags; - uint8_t tx_queue_size; /* max queue size configured */ - uint8_t tx_queue_len; /* Current number of elements in queue */ - } tx; - } stats; + struct { + uint32_t errors; + uint16_t flags; + uint8_t queue_size; /* max queue size configured */ + uint8_t queue_len; /* Current number of elements in queue */ + uint64_t packets; + } rx; + + struct { + uint32_t errors; + uint16_t flags; + uint8_t idle_packets; + uint8_t queue_size; /* max queue size configured */ + uint8_t queue_len; /* Current number of elements in queue */ + uint64_t packets; + } tx; } ftdm_channel_iostats_t; /* 2^8 table size, one for each byte (sample) value */ diff --git a/libs/freetdm/src/testsangomaboost.c b/libs/freetdm/src/testsangomaboost.c index 38eac3c190..85b5332635 100644 --- a/libs/freetdm/src/testsangomaboost.c +++ b/libs/freetdm/src/testsangomaboost.c @@ -45,10 +45,14 @@ #include -#include "freetdm.h" #include #include #include +#ifdef __linux__ +#define __USE_BSD +#include +#endif +#include "freetdm.h" /* arbitrary limit for max calls in this sample program */ @@ -338,9 +342,9 @@ int main(int argc, char *argv[]) exit(-1); } - if (!strcasecmp(argv[2], "cpe")) { + if (!strcmp(argv[2], "cpe")) { sigtype = "pri_cpe"; - } else if (!strcasecmp(argv[2], "net")) { + } else if (!strcmp(argv[2], "net")) { sigtype = "pri_net"; } else { fprintf(stderr, "Valid signaling types are cpe and net only\n"); diff --git a/libs/libsndfile/M4/lt~obsolete.m4 b/libs/libsndfile/M4/lt~obsolete.m4 deleted file mode 100644 index c573da90c5..0000000000 --- a/libs/libsndfile/M4/lt~obsolete.m4 +++ /dev/null @@ -1,98 +0,0 @@ -# lt~obsolete.m4 -- aclocal satisfying obsolete definitions. -*-Autoconf-*- -# -# Copyright (C) 2004, 2005, 2007, 2009 Free Software Foundation, Inc. -# Written by Scott James Remnant, 2004. -# -# This file is free software; the Free Software Foundation gives -# unlimited permission to copy and/or distribute it, with or without -# modifications, as long as this notice is preserved. - -# serial 5 lt~obsolete.m4 - -# These exist entirely to fool aclocal when bootstrapping libtool. -# -# In the past libtool.m4 has provided macros via AC_DEFUN (or AU_DEFUN) -# which have later been changed to m4_define as they aren't part of the -# exported API, or moved to Autoconf or Automake where they belong. -# -# The trouble is, aclocal is a bit thick. It'll see the old AC_DEFUN -# in /usr/share/aclocal/libtool.m4 and remember it, then when it sees us -# using a macro with the same name in our local m4/libtool.m4 it'll -# pull the old libtool.m4 in (it doesn't see our shiny new m4_define -# and doesn't know about Autoconf macros at all.) -# -# So we provide this file, which has a silly filename so it's always -# included after everything else. This provides aclocal with the -# AC_DEFUNs it wants, but when m4 processes it, it doesn't do anything -# because those macros already exist, or will be overwritten later. -# We use AC_DEFUN over AU_DEFUN for compatibility with aclocal-1.6. -# -# Anytime we withdraw an AC_DEFUN or AU_DEFUN, remember to add it here. -# Yes, that means every name once taken will need to remain here until -# we give up compatibility with versions before 1.7, at which point -# we need to keep only those names which we still refer to. - -# This is to help aclocal find these macros, as it can't see m4_define. -AC_DEFUN([LTOBSOLETE_VERSION], [m4_if([1])]) - -m4_ifndef([AC_LIBTOOL_LINKER_OPTION], [AC_DEFUN([AC_LIBTOOL_LINKER_OPTION])]) -m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP])]) -m4_ifndef([_LT_AC_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH])]) -m4_ifndef([_LT_AC_SHELL_INIT], [AC_DEFUN([_LT_AC_SHELL_INIT])]) -m4_ifndef([_LT_AC_SYS_LIBPATH_AIX], [AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX])]) -m4_ifndef([_LT_PROG_LTMAIN], [AC_DEFUN([_LT_PROG_LTMAIN])]) -m4_ifndef([_LT_AC_TAGVAR], [AC_DEFUN([_LT_AC_TAGVAR])]) -m4_ifndef([AC_LTDL_ENABLE_INSTALL], [AC_DEFUN([AC_LTDL_ENABLE_INSTALL])]) -m4_ifndef([AC_LTDL_PREOPEN], [AC_DEFUN([AC_LTDL_PREOPEN])]) -m4_ifndef([_LT_AC_SYS_COMPILER], [AC_DEFUN([_LT_AC_SYS_COMPILER])]) -m4_ifndef([_LT_AC_LOCK], [AC_DEFUN([_LT_AC_LOCK])]) -m4_ifndef([AC_LIBTOOL_SYS_OLD_ARCHIVE], [AC_DEFUN([AC_LIBTOOL_SYS_OLD_ARCHIVE])]) -m4_ifndef([_LT_AC_TRY_DLOPEN_SELF], [AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF])]) -m4_ifndef([AC_LIBTOOL_PROG_CC_C_O], [AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O])]) -m4_ifndef([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], [AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS])]) -m4_ifndef([AC_LIBTOOL_OBJDIR], [AC_DEFUN([AC_LIBTOOL_OBJDIR])]) -m4_ifndef([AC_LTDL_OBJDIR], [AC_DEFUN([AC_LTDL_OBJDIR])]) -m4_ifndef([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], [AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH])]) -m4_ifndef([AC_LIBTOOL_SYS_LIB_STRIP], [AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP])]) -m4_ifndef([AC_PATH_MAGIC], [AC_DEFUN([AC_PATH_MAGIC])]) -m4_ifndef([AC_PROG_LD_GNU], [AC_DEFUN([AC_PROG_LD_GNU])]) -m4_ifndef([AC_PROG_LD_RELOAD_FLAG], [AC_DEFUN([AC_PROG_LD_RELOAD_FLAG])]) -m4_ifndef([AC_DEPLIBS_CHECK_METHOD], [AC_DEFUN([AC_DEPLIBS_CHECK_METHOD])]) -m4_ifndef([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI])]) -m4_ifndef([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], [AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE])]) -m4_ifndef([AC_LIBTOOL_PROG_COMPILER_PIC], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC])]) -m4_ifndef([AC_LIBTOOL_PROG_LD_SHLIBS], [AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS])]) -m4_ifndef([AC_LIBTOOL_POSTDEP_PREDEP], [AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP])]) -m4_ifndef([LT_AC_PROG_EGREP], [AC_DEFUN([LT_AC_PROG_EGREP])]) -m4_ifndef([LT_AC_PROG_SED], [AC_DEFUN([LT_AC_PROG_SED])]) -m4_ifndef([_LT_CC_BASENAME], [AC_DEFUN([_LT_CC_BASENAME])]) -m4_ifndef([_LT_COMPILER_BOILERPLATE], [AC_DEFUN([_LT_COMPILER_BOILERPLATE])]) -m4_ifndef([_LT_LINKER_BOILERPLATE], [AC_DEFUN([_LT_LINKER_BOILERPLATE])]) -m4_ifndef([_AC_PROG_LIBTOOL], [AC_DEFUN([_AC_PROG_LIBTOOL])]) -m4_ifndef([AC_LIBTOOL_SETUP], [AC_DEFUN([AC_LIBTOOL_SETUP])]) -m4_ifndef([_LT_AC_CHECK_DLFCN], [AC_DEFUN([_LT_AC_CHECK_DLFCN])]) -m4_ifndef([AC_LIBTOOL_SYS_DYNAMIC_LINKER], [AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER])]) -m4_ifndef([_LT_AC_TAGCONFIG], [AC_DEFUN([_LT_AC_TAGCONFIG])]) -m4_ifndef([AC_DISABLE_FAST_INSTALL], [AC_DEFUN([AC_DISABLE_FAST_INSTALL])]) -m4_ifndef([_LT_AC_LANG_CXX], [AC_DEFUN([_LT_AC_LANG_CXX])]) -m4_ifndef([_LT_AC_LANG_F77], [AC_DEFUN([_LT_AC_LANG_F77])]) -m4_ifndef([_LT_AC_LANG_GCJ], [AC_DEFUN([_LT_AC_LANG_GCJ])]) -m4_ifndef([AC_LIBTOOL_LANG_C_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG])]) -m4_ifndef([_LT_AC_LANG_C_CONFIG], [AC_DEFUN([_LT_AC_LANG_C_CONFIG])]) -m4_ifndef([AC_LIBTOOL_LANG_CXX_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG])]) -m4_ifndef([_LT_AC_LANG_CXX_CONFIG], [AC_DEFUN([_LT_AC_LANG_CXX_CONFIG])]) -m4_ifndef([AC_LIBTOOL_LANG_F77_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG])]) -m4_ifndef([_LT_AC_LANG_F77_CONFIG], [AC_DEFUN([_LT_AC_LANG_F77_CONFIG])]) -m4_ifndef([AC_LIBTOOL_LANG_GCJ_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG])]) -m4_ifndef([_LT_AC_LANG_GCJ_CONFIG], [AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG])]) -m4_ifndef([AC_LIBTOOL_LANG_RC_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG])]) -m4_ifndef([_LT_AC_LANG_RC_CONFIG], [AC_DEFUN([_LT_AC_LANG_RC_CONFIG])]) -m4_ifndef([AC_LIBTOOL_CONFIG], [AC_DEFUN([AC_LIBTOOL_CONFIG])]) -m4_ifndef([_LT_AC_FILE_LTDLL_C], [AC_DEFUN([_LT_AC_FILE_LTDLL_C])]) -m4_ifndef([_LT_REQUIRED_DARWIN_CHECKS], [AC_DEFUN([_LT_REQUIRED_DARWIN_CHECKS])]) -m4_ifndef([_LT_AC_PROG_CXXCPP], [AC_DEFUN([_LT_AC_PROG_CXXCPP])]) -m4_ifndef([_LT_PREPARE_SED_QUOTE_VARS], [AC_DEFUN([_LT_PREPARE_SED_QUOTE_VARS])]) -m4_ifndef([_LT_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_PROG_ECHO_BACKSLASH])]) -m4_ifndef([_LT_PROG_F77], [AC_DEFUN([_LT_PROG_F77])]) -m4_ifndef([_LT_PROG_FC], [AC_DEFUN([_LT_PROG_FC])]) -m4_ifndef([_LT_PROG_CXX], [AC_DEFUN([_LT_PROG_CXX])]) diff --git a/libs/unimrcp/modules/mrcp-sofiasip/mrcpsofiasip.2010.vcxproj b/libs/unimrcp/modules/mrcp-sofiasip/mrcpsofiasip.2010.vcxproj index c6aaba5cd6..b3931497c7 100644 --- a/libs/unimrcp/modules/mrcp-sofiasip/mrcpsofiasip.2010.vcxproj +++ b/libs/unimrcp/modules/mrcp-sofiasip/mrcpsofiasip.2010.vcxproj @@ -127,6 +127,11 @@ + + + {70a49bc2-7500-41d0-b75d-edcc5be987a0} + + diff --git a/scripts/perl/add_user b/scripts/perl/add_user new file mode 100755 index 0000000000..d16ebb5efe --- /dev/null +++ b/scripts/perl/add_user @@ -0,0 +1,306 @@ +#!/usr/bin/perl +# +# add_user +# +# Add one or more users to the XML directory +# +# + +use strict; +use warnings; +use Getopt::Long; +use Data::Dumper; + +## Useful items +my $path_sep; +my $config_path; +my @dir_elem; +my $user_template = &get_user_template; +my $new_user_count = 0; + +## Command line args +my $users; +my $domain; +my $dirpath; +my $help; + +## Misc items somewhat related to cmd line args +my $start; +my $end; +my $user; + +## Check for Windows vs. *nix +if ( $^O =~ m/^win/i ) { + ## Detected Windows (probably) + $path_sep = "\\"; # single backslash (\) + use File::Spec::Win32; +} else { + $path_sep = '/'; # single slash (/) + use File::Spec; +} + +GetOptions( + 'h' => \$help, + 'help' => \$help, + 'domain=s' => \$domain, + 'users=s' => \$users, + 'confpath=s' => \$config_path, +); + +if ( $help ) { + usage(); + exit(0); +} + +if ( ! $domain ) { + $domain='default'; +} + +## Validate users if specified on command line +if ( $users ) { + ($start,$end) = split /-/,$users; + if ( ! $start && ! $end ) { + die "Please specify both a start and end range, separated by a hyphen:\n add_user --users=xxxx-yyyy\n"; + } + + unless ( $start =~ m/[1-9]\d+/ ) { + die "Start of range '$start' is not numeric or is too short\n"; + } + + unless ( $end =~ m/[1-9]\d+/ ) { + die "End of range '$end' is not numberic or is too short\n"; + } + + if ( $end <= $start ) { + die "End of range needs to be greater than start of range\n"; + } +} else { + ## Look for user id in $ARGV[0] + if ( ! $ARGV[0] ) { + die "You must specify user id as a command line argument to add user, or use the --users option.\n"; + } + unless ( $ARGV[0] =~ m/^[1-9]\d+$/ ) { + die "User id must be numeric, be at least 2 digits long, and cannot begin with the digit zero.\n" + } + $user = $ARGV[0]; +} + +if ( ! $config_path ) { + $config_path = '/usr/local/freeswitch/conf'; +} + +## Check to make sure the directories in question exists +unless ( -d $config_path ) { + die "Configuration path '$config_path' does not exist.\n"; +} + +my $directory_path = $config_path . $path_sep . 'directory'; +unless ( -d $directory_path ) { + die "Directory path '$directory_path' does not exist.\n"; +} + +## Now check domain pathname and test existence +if ( ! $domain ) { + $domain = 'default'; +} + +## Full directory path includes the domain name +my $full_dir_path = $directory_path . $path_sep . $domain; +unless ( -d $full_dir_path ) { + die "Full path to directory and domain '$full_dir_path' does not exist. \n"; +} + +unless ( -w $full_dir_path ) { + die "This user does not have write access to '$full_dir_path'.\n"; +} +print "\n"; + +## Regexp assemble items to show user what a PCRE might look like for his new users +my $ra_present; +my $ra_new; +my $ra_all; +eval { require Regexp::Assemble; }; +if ( ! $@ ) { + ## If Regexp::Assemble is available flag it for later building regexes + $ra_present = 'true'; + $ra_new = Regexp::Assemble->new( # new user regex + reduce => 1, + flags => 0, +); + $ra_all = Regexp::Assemble->new( # all users regex w/ new users thrown in + reduce => 1, + flags => 0, +); +} + +## If we're this far then we can read in the existing users and put them in a hash +## Later we can check hash to avoid adding duplicate users +my %current_users; +my @CURRENT_USER_FILES = glob($full_dir_path . $path_sep . '*.xml'); +foreach ( @CURRENT_USER_FILES ) { + #print "User: $_\n"; + open(FILEIN,'<',$_); + while() { + next unless m/user id|number-alias/; + m/user id="(\d+)"/; + my $user_id = $1; + if ( ! $user_id ) { + m/alias="(\d+)"/; + $user_id = $1; + } + + next unless $user_id; + $current_users{$user_id}++; + + if ( $ra_present && $user_id =~ m/^\d+$/ ) { + #print "Adding $user_id to \$re_all...\n"; + $ra_all->add($user_id)->anchor_line_begin->anchor_line_end; + } + last; + } + close(FILEIN); +} + +#print Dumper(%current_users) . "\n"; +if ( $start && $end ) { + ## Add range of users + foreach $user ($start .. $end) { + &add_user($user); + } +} else { + ## Add single user + &add_user($user); +} + +print "\nOperation complete. "; +if ( $new_user_count == 0 ) { + print "No users added.\n"; + exit(0); +} else { + printf "%d user%s added.\n", $new_user_count, $new_user_count==1 ? "" : "s"; + print "Be sure to reloadxml.\n\n"; +} + +if ( $ra_present ) { + print "Regular expression information:\n\n"; + ## Regexp::Assemble adds some stuff we really don't need + ## These lines just make the regexp pattern a bit more readable + my $tmp = $ra_new->as_string; + $tmp =~ s/\?://g; + $tmp =~ s/^\(\?\-xism:\^/^(/; + $tmp =~ s/\$\)$/)\$/; + $tmp =~ s/\\d/[0-9]/g; # [0-9] is sometimes easier to read than \d + print " Sample regex for all new users: " . $tmp . "\n"; + $tmp = $ra_all->as_string; + $tmp =~ s/\?://g; + $tmp =~ s/^\(\?\-xism:\^/^(/; + $tmp =~ s/\$\)$/)\$/; + $tmp =~ s/\\d/[0-9]/g; # [0-9] is sometimes easier to read than \d + print "Sample regex for all new AND current users: " . $tmp . "\n\n"; + print "In the default configuration you can modify the expression in the condition for 'Local_Extension'.\n"; + print "" +} else { + print "If CPAN module Regexp::Assemble were installed this program would be able to suggest a regex for your new users.\n" +} + +exit(0); + +sub add_user { + my $user_id = shift; + if ( exists( $current_users{$user_id} ) ) { + warn "User id $user_id already exists, skipping...\n"; + } else { + my $new_user = $user_template; + $new_user =~ s/__USERID__/$user_id/g; + #print "Adding user id '$user_id' with this XML:\n"; + #print $new_user . "\n"; + + ## Attempt to create the user file + my $user_file_name = $full_dir_path . $path_sep . $user_id . '.xml'; + + ## Does it already exist? + if ( -f $user_file_name ) { + warn "$user_file_name exists, skipping...\n"; + } + my $fh; + open($fh,'>',$user_file_name); + if ( ! $fh ) { + warn "Unable to open '$user_file_name' - $!\n"; + warn "Skipping...\n"; + next; + } + + print $fh $new_user; + close($fh); + print "Added $user_id in file $user_file_name \n"; + $new_user_count++; + if ( $ra_present ) { + $ra_new->add($user_id)->anchor_line_begin->anchor_line_end; + $ra_all->add($user_id)->anchor_line_begin->anchor_line_end; + } + } + +} + +sub get_user_template { + my $templ = < + + + + + + + + + + + + + + + + + + +ENDUSERTEMPLATE + + return $templ; +} + +sub usage { + print < [--domain=] [--confpath=] + add_user --users=- [--domain=] [--confpath=] + +In its simplest form, add_user will simply add the user_id specified at the command line. +By default, users are added to the "default" domain. Use the --domain option to specify +a different domain for the user(s) that are added. + +To specify a range of user IDs use the --users option. Separate the beginning and +end of the range with a hyphen (-) character. + +By default add_user will look for the XML directory in its default location of +/usr/local/freeswitch/conf/directory. Use the --confpath (configuration path) +option to specify an alternate directory location. + + + NOTES: + +add_user assumes +User IDs must be numeric and cannot begin with zero. +User IDs must be at least two digits long and have no specific length limit. +If a user ID exists it will be skipped. +If a domain specified does not exist no users will be created. + +ENDUSAGE + +} diff --git a/src/include/private/switch_core_pvt.h b/src/include/private/switch_core_pvt.h index 3df9001b0c..13410a00ae 100644 --- a/src/include/private/switch_core_pvt.h +++ b/src/include/private/switch_core_pvt.h @@ -135,6 +135,7 @@ struct switch_core_session { switch_mutex_t *frame_read_mutex; switch_thread_rwlock_t *rwlock; + switch_thread_rwlock_t *io_rwlock; void *streams[SWITCH_MAX_STREAMS]; int stream_count; diff --git a/src/include/switch_channel.h b/src/include/switch_channel.h index a1f13edd85..d6bce5e8bf 100644 --- a/src/include/switch_channel.h +++ b/src/include/switch_channel.h @@ -179,8 +179,8 @@ SWITCH_DECLARE(void) switch_channel_uninit(switch_channel_t *channel); SWITCH_DECLARE(void) switch_channel_set_caller_profile(switch_channel_t *channel, switch_caller_profile_t *caller_profile); /*! - \brief Retrive the given channel's caller profile - \param channel channel to retrive the profile from + \brief Retrieve the given channel's caller profile + \param channel channel to retrieve the profile from \return the requested profile */ SWITCH_DECLARE(switch_caller_profile_t *) switch_channel_get_caller_profile(switch_channel_t *channel); @@ -195,8 +195,8 @@ SWITCH_DECLARE(void) switch_channel_set_originator_caller_profile(switch_channel SWITCH_DECLARE(void) switch_channel_set_hunt_caller_profile(switch_channel_t *channel, switch_caller_profile_t *caller_profile); /*! - \brief Retrive the given channel's originator caller profile - \param channel channel to retrive the profile from + \brief Retrieve the given channel's originator caller profile + \param channel channel to retrieve the profile from \return the requested profile */ SWITCH_DECLARE(switch_caller_profile_t *) switch_channel_get_originator_caller_profile(switch_channel_t *channel); @@ -209,8 +209,8 @@ SWITCH_DECLARE(switch_caller_profile_t *) switch_channel_get_originator_caller_p SWITCH_DECLARE(void) switch_channel_set_originatee_caller_profile(switch_channel_t *channel, switch_caller_profile_t *caller_profile); /*! - \brief Retrive the given channel's originatee caller profile - \param channel channel to retrive the profile from + \brief Retrieve the given channel's originatee caller profile + \param channel channel to retrieve the profile from \return the requested profile */ SWITCH_DECLARE(switch_caller_profile_t *) switch_channel_get_originatee_caller_profile(switch_channel_t *channel); @@ -223,16 +223,16 @@ SWITCH_DECLARE(switch_caller_profile_t *) switch_channel_get_originatee_caller_p SWITCH_DECLARE(void) switch_channel_set_origination_caller_profile(switch_channel_t *channel, switch_caller_profile_t *caller_profile); /*! - \brief Retrive the given channel's origination caller profile - \param channel channel to retrive the profile from + \brief Retrieve the given channel's origination caller profile + \param channel channel to retrieve the profile from \return the requested profile */ SWITCH_DECLARE(switch_caller_profile_t *) switch_channel_get_origination_caller_profile(switch_channel_t *channel); /*! - \brief Retrive the given channel's unique id - \param channel channel to retrive the unique id from + \brief Retrieve the given channel's unique id + \param channel channel to retrieve the unique id from \return the unique id */ SWITCH_DECLARE(char *) switch_channel_get_uuid(switch_channel_t *channel); @@ -241,7 +241,7 @@ SWITCH_DECLARE(char *) switch_channel_get_uuid(switch_channel_t *channel); \brief Set a variable on a given channel \param channel channel to set variable on \param varname the name of the variable - \param value the vaule of the variable + \param value the value of the variable \returns SWITCH_STATUS_SUCCESS if successful */ diff --git a/src/include/switch_core.h b/src/include/switch_core.h index 3f636d00c4..840a06c204 100644 --- a/src/include/switch_core.h +++ b/src/include/switch_core.h @@ -354,6 +354,11 @@ SWITCH_DECLARE(switch_status_t) switch_core_destroy(void); ///\ingroup core1 ///\{ + +SWITCH_DECLARE(switch_status_t) switch_core_session_io_read_lock(switch_core_session_t *session); +SWITCH_DECLARE(switch_status_t) switch_core_session_io_write_lock(switch_core_session_t *session); +SWITCH_DECLARE(switch_status_t) switch_core_session_io_rwunlock(switch_core_session_t *session); + #ifdef SWITCH_DEBUG_RWLOCKS SWITCH_DECLARE(switch_status_t) switch_core_session_perform_read_lock(_In_ switch_core_session_t *session, const char *file, const char *func, int line); #endif @@ -882,6 +887,8 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_exec(_In_ switch_core_sessio SWITCH_DECLARE(switch_status_t) switch_core_session_execute_application_get_flags(_In_ switch_core_session_t *session, _In_ const char *app, _In_opt_z_ const char *arg, _Out_opt_ int32_t *flags); +SWITCH_DECLARE(switch_status_t) switch_core_session_execute_application_async(switch_core_session_t *session, const char *app, const char *arg); + SWITCH_DECLARE(switch_status_t) switch_core_session_get_app_flags(const char *app, int32_t *flags); /*! @@ -1024,6 +1031,11 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_queue_event(_In_ switch_core */ SWITCH_DECLARE(uint32_t) switch_core_session_event_count(_In_ switch_core_session_t *session); +/* + Number of parsable messages waiting on the session. + */ +SWITCH_DECLARE(uint32_t) switch_core_session_messages_waiting(switch_core_session_t *session); + /*! \brief DE-Queue an event on a given session \param session the session to de-queue the message on diff --git a/src/include/switch_ivr.h b/src/include/switch_ivr.h index 249ac63a58..d277bd030f 100644 --- a/src/include/switch_ivr.h +++ b/src/include/switch_ivr.h @@ -874,6 +874,11 @@ SWITCH_DECLARE(void) switch_ivr_dmachine_set_input_timeout_ms(switch_ivr_dmachin 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); + +SWITCH_DECLARE(switch_status_t) switch_ivr_get_file_handle(switch_core_session_t *session, switch_file_handle_t **fh); +SWITCH_DECLARE(switch_status_t) switch_ivr_release_file_handle(switch_core_session_t *session, switch_file_handle_t **fh); +SWITCH_DECLARE(switch_status_t) switch_ivr_process_fh(switch_core_session_t *session, const char *cmd, switch_file_handle_t *fhp); + /** @} */ SWITCH_END_EXTERN_C diff --git a/src/mod/.gitignore b/src/mod/.gitignore index 47cdbafa70..b6e7842a50 100644 --- a/src/mod/.gitignore +++ b/src/mod/.gitignore @@ -7,6 +7,7 @@ /applications/mod_spandsp/mod_spandsp.log /applications/mod_commands/Makefile /applications/mod_conference/Makefile +/applications/mod_db/Makefile /applications/mod_dptools/Makefile /applications/mod_enum/Makefile /applications/mod_enum/Makefile.in diff --git a/src/mod/applications/mod_callcenter/mod_callcenter.c b/src/mod/applications/mod_callcenter/mod_callcenter.c index 1b0ba1331a..ca92b17fa4 100644 --- a/src/mod/applications/mod_callcenter/mod_callcenter.c +++ b/src/mod/applications/mod_callcenter/mod_callcenter.c @@ -1346,6 +1346,7 @@ static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *threa switch_time_t t_agent_called = 0; switch_time_t t_agent_answered = 0; switch_time_t t_member_called = atoi(h->member_joined_epoch); + switch_event_t *event = NULL; switch_mutex_lock(globals.mutex); globals.threads++; @@ -1360,6 +1361,21 @@ static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *threa switch_safe_free(sql); goto done; } + + /* Proceed contact the agent to offer the member */ + if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CALLCENTER_EVENT) == SWITCH_STATUS_SUCCESS) { + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Queue", h->queue_name); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Action", "agent-offering"); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Agent", h->agent_name); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Agent-Type", h->agent_type); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Agent-System", h->agent_system); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Caller-UUID", h->member_uuid); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Caller-CID-Name", h->member_caller_name); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Caller-CID-Number", h->member_caller_number); + switch_event_fire(&event); + } + + /* CallBack Mode */ if (!strcasecmp(h->agent_type, CC_AGENT_TYPE_CALLBACK)) { switch_event_create(&ovars, SWITCH_EVENT_REQUEST_PARAMS); switch_event_add_header(ovars, SWITCH_STACK_BOTTOM, "cc_queue", "%s", h->queue_name); @@ -1375,6 +1391,7 @@ static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *threa switch_safe_free(dialstr); switch_event_destroy(&ovars); + /* UUID Standby Mode */ } else if (!strcasecmp(h->agent_type, CC_AGENT_TYPE_UUID_STANDBY)) { agent_session = switch_core_session_locate(h->agent_uuid); if (agent_session) { @@ -1400,14 +1417,17 @@ static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *threa cc_agent_update("status", cc_agent_status2str(CC_AGENT_STATUS_LOGGED_OUT), h->agent_name); cc_agent_update("uuid", "", h->agent_name); } + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Invalid agent type '%s' for agent '%s', aborting member offering", h->agent_type, h->agent_name); + status = SWITCH_CAUSE_USER_NOT_REGISTERED; } + /* Originate/Bridge is not finished, processing the return value */ if (status == SWITCH_STATUS_SUCCESS) { /* Agent Answered */ const char *agent_uuid = switch_core_session_get_uuid(agent_session); switch_channel_t *member_channel = switch_core_session_get_channel(member_session); switch_channel_t *agent_channel = switch_core_session_get_channel(agent_session); - switch_event_t *event; switch_channel_set_variable(agent_channel, "cc_member_pre_answer_uuid", NULL); diff --git a/src/mod/applications/mod_commands/mod_commands.c b/src/mod/applications/mod_commands/mod_commands.c index ba4b6d310d..c7edfd5420 100644 --- a/src/mod/applications/mod_commands/mod_commands.c +++ b/src/mod/applications/mod_commands/mod_commands.c @@ -3968,6 +3968,47 @@ SWITCH_STANDARD_API(uuid_getvar_function) return SWITCH_STATUS_SUCCESS; } + +#define FILEMAN_SYNTAX " :" +SWITCH_STANDARD_API(uuid_fileman_function) +{ + switch_core_session_t *psession = NULL; + char *mycmd = NULL, *argv[4] = { 0 }; + int argc = 0; + + if (!zstr(cmd) && (mycmd = strdup(cmd))) { + argc = switch_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0]))); + if (argc >= 2 && !zstr(argv[0])) { + char *uuid = argv[0]; + char *cmd = argv[1]; + + if ((psession = switch_core_session_locate(uuid))) { + switch_channel_t *channel; + switch_file_handle_t *fh = NULL; + + channel = switch_core_session_get_channel(psession); + + if (switch_ivr_get_file_handle(psession, &fh) == SWITCH_STATUS_SUCCESS) { + switch_ivr_process_fh(psession, cmd, fh); + switch_ivr_release_file_handle(psession, &fh); + } + + switch_core_session_rwunlock(psession); + + } else { + stream->write_function(stream, "-ERR No Such Channel!\n"); + } + goto done; + } + } + + stream->write_function(stream, "-USAGE: %s\n", GETVAR_SYNTAX); + + done: + switch_safe_free(mycmd); + return SWITCH_STATUS_SUCCESS; +} + #define UUID_SEND_DTMF_SYNTAX " " SWITCH_STANDARD_API(uuid_send_dtmf_function) { @@ -4674,6 +4715,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_commands_load) SWITCH_ADD_API(commands_api_interface, "uuid_display", "change display", uuid_display_function, DISPLAY_SYNTAX); SWITCH_ADD_API(commands_api_interface, "uuid_dump", "uuid_dump", uuid_dump_function, DUMP_SYNTAX); SWITCH_ADD_API(commands_api_interface, "uuid_exists", "see if a uuid exists", uuid_exists_function, EXISTS_SYNTAX); + SWITCH_ADD_API(commands_api_interface, "uuid_fileman", "uuid_fileman", uuid_fileman_function, FILEMAN_SYNTAX); SWITCH_ADD_API(commands_api_interface, "uuid_flush_dtmf", "Flush dtmf on a given uuid", uuid_flush_dtmf_function, ""); SWITCH_ADD_API(commands_api_interface, "uuid_getvar", "uuid_getvar", uuid_getvar_function, GETVAR_SYNTAX); SWITCH_ADD_API(commands_api_interface, "uuid_hold", "hold", uuid_hold_function, HOLD_SYNTAX); @@ -4785,6 +4827,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_commands_load) switch_console_set_complete("add uuid_display ::console::list_uuid"); switch_console_set_complete("add uuid_dump ::console::list_uuid"); switch_console_set_complete("add uuid_exists ::console::list_uuid"); + switch_console_set_complete("add uuid_fileman ::console::list_uuid"); switch_console_set_complete("add uuid_flush_dtmf ::console::list_uuid"); switch_console_set_complete("add uuid_getvar ::console::list_uuid"); switch_console_set_complete("add uuid_hold ::console::list_uuid"); diff --git a/src/mod/applications/mod_hash/mod_hash.c b/src/mod/applications/mod_hash/mod_hash.c index 29a056104f..2609b6cb87 100644 --- a/src/mod/applications/mod_hash/mod_hash.c +++ b/src/mod/applications/mod_hash/mod_hash.c @@ -130,7 +130,7 @@ SWITCH_LIMIT_INCR(limit_incr_hash) { switch_channel_t *channel = switch_core_session_get_channel(session); char *hashkey = NULL; - switch_bool_t status = SWITCH_STATUS_SUCCESS; + switch_status_t status = SWITCH_STATUS_SUCCESS; limit_hash_item_t *item = NULL; time_t now = switch_epoch_time_now(NULL); limit_hash_private_t *pvt = NULL; diff --git a/src/mod/asr_tts/mod_cepstral/WinReadme.txt b/src/mod/asr_tts/mod_cepstral/WinReadme.txt new file mode 100644 index 0000000000..56b4e79a39 --- /dev/null +++ b/src/mod/asr_tts/mod_cepstral/WinReadme.txt @@ -0,0 +1,4 @@ +The Cepstral SDK for Windows should be placed in c:\dev\cepstral +ex. C:\dev\cepstral\sdk\include +This SDK can be obtained from http://cepstral.com/ +If you want a prebuilt version you may download one from http://files.freeswitch.org/windows/installer/ \ No newline at end of file diff --git a/src/mod/asr_tts/mod_cepstral/mod_cepstral.2010.vcxproj b/src/mod/asr_tts/mod_cepstral/mod_cepstral.2010.vcxproj index 2bc46efdca..b7e42eb850 100644 --- a/src/mod/asr_tts/mod_cepstral/mod_cepstral.2010.vcxproj +++ b/src/mod/asr_tts/mod_cepstral/mod_cepstral.2010.vcxproj @@ -66,13 +66,13 @@ - C:\Program Files\Cepstral\sdk\include;%(AdditionalIncludeDirectories) + C:\dev\cepstral\sdk\include;%(AdditionalIncludeDirectories) swift.lib;%(AdditionalDependencies) - C:\Program Files\Cepstral\sdk\lib\winnt;C:\Program Files\Cepstral\sdk\lib\windows;%(AdditionalLibraryDirectories) + C:\dev\cepstral\sdk\lib\lib-windows;%(AdditionalLibraryDirectories) false @@ -83,13 +83,13 @@ X64 - C:\Program Files\Cepstral\sdk\include;%(AdditionalIncludeDirectories) + C:\dev\cepstral\sdk\include;%(AdditionalIncludeDirectories) swift.lib;%(AdditionalDependencies) - C:\Program Files\Cepstral\sdk\lib\winnt;C:\Program Files\Cepstral\sdk\lib\windows;%(AdditionalLibraryDirectories) + C:\dev\cepstral\sdk\lib\lib-windows_x64;%(AdditionalLibraryDirectories) false @@ -98,13 +98,13 @@ - C:\Program Files\Cepstral\sdk\include;%(AdditionalIncludeDirectories) + C:\dev\cepstral\sdk\include;%(AdditionalIncludeDirectories) swift.lib;%(AdditionalDependencies) - C:\Program Files\Cepstral\sdk\lib\winnt;C:\Program Files\Cepstral\sdk\lib\windows;%(AdditionalLibraryDirectories) + C:\dev\cepstral\sdk\lib\lib-windows;%(AdditionalLibraryDirectories) false @@ -115,13 +115,13 @@ X64 - C:\Program Files\Cepstral\sdk\include;%(AdditionalIncludeDirectories) + C:\dev\cepstral\sdk\include;%(AdditionalIncludeDirectories) swift.lib;%(AdditionalDependencies) - C:\Program Files\Cepstral\sdk\lib\winnt;C:\Program Files\Cepstral\sdk\lib\windows;%(AdditionalLibraryDirectories) + C:\dev\cepstral\sdk\lib\lib-windows_x64;%(AdditionalLibraryDirectories) false @@ -132,9 +132,8 @@ - + {202d7a4e-760d-4d0e-afa1-d7459ced30ff} - false diff --git a/src/mod/codecs/mod_celt/mod_celt.vcxproj b/src/mod/codecs/mod_celt/mod_celt.vcxproj index 01c55d4217..ee8a70ca3f 100644 --- a/src/mod/codecs/mod_celt/mod_celt.vcxproj +++ b/src/mod/codecs/mod_celt/mod_celt.vcxproj @@ -62,10 +62,6 @@ <_ProjectFileVersion>10.0.30319.1 - $(Platform)\$(Configuration)\ - $(Platform)\$(Configuration)\ - $(Platform)\$(Configuration)\ - $(Platform)\$(Configuration)\ diff --git a/src/mod/endpoints/mod_dingaling/mod_dingaling.c b/src/mod/endpoints/mod_dingaling/mod_dingaling.c index 7558e1b1b8..75329a0848 100644 --- a/src/mod/endpoints/mod_dingaling/mod_dingaling.c +++ b/src/mod/endpoints/mod_dingaling/mod_dingaling.c @@ -514,13 +514,19 @@ static switch_status_t chat_send(const char *proto, const char *from, const char from = hint; } else { char *p; - ffrom = switch_mprintf("%s+%s", proto, from); - from = ffrom; + + if (!(profile->user_flags & LDL_FLAG_COMPONENT)) { + from = ffrom = strdup(profile->login); + } else { + from = ffrom = switch_mprintf("%s+%s", proto, from); + } + if ((p = strchr(from, '/'))) { *p = '\0'; } } ldl_handle_send_msg(profile->handle, (char *) from, (char *) to, NULL, switch_str_nil(body)); + switch_safe_free(ffrom); } else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid Profile %s\n", f_host ? f_host : "NULL"); return SWITCH_STATUS_FALSE; @@ -602,7 +608,7 @@ static void ipchanged_event_handler(switch_event_t *event) for (hi = switch_hash_first(NULL, globals.profile_hash); hi; hi = switch_hash_next(hi)) { switch_hash_this(hi, NULL, NULL, &val); profile = (mdl_profile_t *) val; - if (old_ip4 && !strcmp(profile->extip, old_ip4)) { + if (old_ip4 && profile->extip && !strcmp(profile->extip, old_ip4)) { tmp = profile->extip; profile->extip = strdup(new_ip4); switch_safe_free(tmp); diff --git a/src/mod/endpoints/mod_gsmopen/gsmopen.h b/src/mod/endpoints/mod_gsmopen/gsmopen.h index fd94bccc2a..05ef1641bf 100644 --- a/src/mod/endpoints/mod_gsmopen/gsmopen.h +++ b/src/mod/endpoints/mod_gsmopen/gsmopen.h @@ -158,7 +158,7 @@ typedef enum { #define WARNINGA(...) switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "rev "GSMOPEN_SVN_VERSION "[%p|%-7lx][WARNINGA %-5d][%-10s][%2d,%2d,%2d] " __VA_ARGS__ ); #define NOTICA(...) switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "rev "GSMOPEN_SVN_VERSION "[%p|%-7lx][NOTICA %-5d][%-10s][%2d,%2d,%2d] " __VA_ARGS__ ); -#define GSMOPEN_P_LOG NULL, (unsigned long)55, __LINE__, tech_pvt ? tech_pvt->name ? tech_pvt->name : "none" : "none", -1, tech_pvt ? tech_pvt->interface_state : -1, tech_pvt ? tech_pvt->phone_callflow : -1 +#define GSMOPEN_P_LOG (void *)NULL, (unsigned long)55, __LINE__, tech_pvt ? tech_pvt->name ? tech_pvt->name : "none" : "none", -1, tech_pvt ? tech_pvt->interface_state : -1, tech_pvt ? tech_pvt->phone_callflow : -1 /*********************************/ #define GSMOPEN_CAUSE_NORMAL 1 diff --git a/src/mod/endpoints/mod_gsmopen/gsmopen_protocol.cpp b/src/mod/endpoints/mod_gsmopen/gsmopen_protocol.cpp index e4bb6b9200..76d32ac3f0 100644 --- a/src/mod/endpoints/mod_gsmopen/gsmopen_protocol.cpp +++ b/src/mod/endpoints/mod_gsmopen/gsmopen_protocol.cpp @@ -3294,12 +3294,18 @@ int alsa_write(private_t * tech_pvt, short *data, int datalen) time_t now_timestamp; /* size_t frames = 0; */ snd_pcm_state_t state; - snd_pcm_sframes_t delayp1; - snd_pcm_sframes_t delayp2; + snd_pcm_sframes_t delayp1=0; + snd_pcm_sframes_t delayp2=0; if(tech_pvt->no_sound==1){ return res; } + + + memset(sizbuf, 255, sizeof(sizbuf)); + memset(sizbuf2, 255, sizeof(sizbuf)); + memset(silencebuf, 255, sizeof(sizbuf)); + //ERRORA("data=%p, datalen=%d\n", GSMOPEN_P_LOG, (void *)data, datalen); /* We have to digest the frame in 160-byte portions */ if (datalen > sizeof(sizbuf) - sizpos) { @@ -3307,8 +3313,11 @@ int alsa_write(private_t * tech_pvt, short *data, int datalen) res = -1; } else { memcpy(sizbuf + sizpos, data, datalen); + memset(data, 255, datalen); len += datalen; pos = 0; + + #ifdef ALSA_MONITOR alsa_monitor_write(sizbuf, len); #endif @@ -3456,6 +3465,7 @@ int alsa_write(private_t * tech_pvt, short *data, int datalen) if (res == -ESTRPIPE) { ERRORA("You've got some big problems\n", GSMOPEN_P_LOG); } else if (res == -EAGAIN) { + DEBUGA_GSMOPEN("Momentarily busy\n", GSMOPEN_P_LOG); res = 0; } else if (res < 0) { ERRORA("Error %d on audio write: \"%s\"\n", GSMOPEN_P_LOG, res, snd_strerror(res)); @@ -3572,9 +3582,11 @@ int alsa_read(private_t * tech_pvt, short *data, int datalen) return r; } else if (r == -EAGAIN) { - DEBUGA_GSMOPEN("ALSA read -EAGAIN, the soundcard is not ready to be read by gsmopen\n", GSMOPEN_P_LOG); + int count=0; while (r == -EAGAIN) { - gsmopen_sleep(1000); + gsmopen_sleep(10000); + DEBUGA_GSMOPEN("%d ALSA read -EAGAIN, the soundcard is not ready to be read by gsmopen\n", GSMOPEN_P_LOG, count); + count++; if (tech_pvt->alsa_capture_is_mono) { r = snd_pcm_readi(tech_pvt->alsac, buf + readpos, left); diff --git a/src/mod/endpoints/mod_gsmopen/mod_gsmopen.cpp b/src/mod/endpoints/mod_gsmopen/mod_gsmopen.cpp index cb440d3bcb..7e20b7c25e 100644 --- a/src/mod/endpoints/mod_gsmopen/mod_gsmopen.cpp +++ b/src/mod/endpoints/mod_gsmopen/mod_gsmopen.cpp @@ -1904,14 +1904,25 @@ static switch_status_t load_config(int reload_type) if (globals.GSMOPEN_INTERFACES[interface_id].controldevprotocol != PROTOCOL_NO_SERIAL) { res = gsmopen_serial_config(&globals.GSMOPEN_INTERFACES[interface_id]); if (res) { - ERRORA("gsmopen_serial_config failed\n", GSMOPEN_P_LOG); - ERRORA("STARTING interface_id=%d FAILED\n", GSMOPEN_P_LOG, interface_id); - //return SWITCH_STATUS_FALSE; - globals.GSMOPEN_INTERFACES[interface_id].running=0; - alarm_event(&globals.GSMOPEN_INTERFACES[interface_id], ALARM_FAILED_INTERFACE, "gsmopen_serial_config failed"); - globals.GSMOPEN_INTERFACES[interface_id].active=0; - globals.GSMOPEN_INTERFACES[interface_id].name[0]='\0'; - continue; + int count = 0; + ERRORA("gsmopen_serial_config failed, let's try again\n", GSMOPEN_P_LOG); + while(res && count < 5){ + switch_sleep(100000); //0.1 seconds + res = gsmopen_serial_config(&globals.GSMOPEN_INTERFACES[interface_id]); + count++; + if (res) { + ERRORA("%d: gsmopen_serial_config failed, let's try again\n", GSMOPEN_P_LOG, count); + } + } + if (res) { + ERRORA("STARTING interface_id=%d FAILED\n", GSMOPEN_P_LOG, interface_id); + //return SWITCH_STATUS_FALSE; + globals.GSMOPEN_INTERFACES[interface_id].running=0; + alarm_event(&globals.GSMOPEN_INTERFACES[interface_id], ALARM_FAILED_INTERFACE, "gsmopen_serial_config failed"); + globals.GSMOPEN_INTERFACES[interface_id].active=0; + globals.GSMOPEN_INTERFACES[interface_id].name[0]='\0'; + continue; + } } } diff --git a/src/mod/endpoints/mod_skypopen/osscuse/98-osscuse.rules b/src/mod/endpoints/mod_skypopen/osscuse/98-osscuse.rules new file mode 100644 index 0000000000..c1430fd5c0 --- /dev/null +++ b/src/mod/endpoints/mod_skypopen/osscuse/98-osscuse.rules @@ -0,0 +1,7 @@ +# Since these devices are not part of 'sound' subsystem the group is forced +# to audio by name +# /dev/cuse can stay mode 0660 root:root since osspd is run as root +# and drops privileges to user level when opened by user +KERNEL=="dsp", GROUP="audio" +KERNEL=="mixer", GROUP="audio" +KERNEL=="adsp", GROUP="audio" diff --git a/src/mod/endpoints/mod_skypopen/osscuse/LICENSE b/src/mod/endpoints/mod_skypopen/osscuse/LICENSE new file mode 100644 index 0000000000..d511905c16 --- /dev/null +++ b/src/mod/endpoints/mod_skypopen/osscuse/LICENSE @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/src/mod/endpoints/mod_skypopen/osscuse/Makefile b/src/mod/endpoints/mod_skypopen/osscuse/Makefile new file mode 100644 index 0000000000..a42d37a8a3 --- /dev/null +++ b/src/mod/endpoints/mod_skypopen/osscuse/Makefile @@ -0,0 +1,69 @@ +# These can be overridden if needed +# DESTDIR is completely respected +CC := gcc +AR := ar +CFLAGS := -Wall $(CFLAGS) +XLDFLAGS := $(LDFLAGS) +LDFLAGS := -L. -lossp $(LDFLAGS) +prefix := /usr/local +DESTDIR := +UDEVDIR := /etc/udev/rules.d + +ifeq "$(origin OSSPD_CFLAGS)" "undefined" +OSSPD_CFLAGS := $(shell pkg-config --cflags fuse) +endif + +ifeq "$(origin OSSPD_LDFLAGS)" "undefined" +OSSPD_LDFLAGS := $(shell pkg-config --libs fuse) +endif + +ifeq "$(origin OSSP_PADSP_CFLAGS)" "undefined" +OSSP_PADSP_CFLAGS := $(shell pkg-config --cflags libpulse) +endif + +ifeq "$(origin OSSP_PADSP_LDFLAGS)" "undefined" +OSSP_PADSP_LDFLAGS := $(shell pkg-config --libs libpulse) +endif + +ifeq "$(origin OSSP_ALSAP_CFLAGS)" "undefined" +OSSP_ALSAP_CFLAGS := $(shell pkg-config --libs alsa) +endif + +ifeq "$(origin OSSP_ALSAP_LDFLAGS)" "undefined" +OSSP_ALSAP_LDFLAGS := $(shell pkg-config --libs alsa) +endif + +headers := ossp.h ossp-util.h ossp-slave.h + +#all: osspd ossp-padsp ossp-alsap +all: osspd ossp-alsap + +install: + mkdir -p $(DESTDIR)$(prefix)/sbin + install -m755 osspd ossp-padsp ossp-alsap $(DESTDIR)$(prefix)/sbin + mkdir -p $(DESTDIR)$(UDEVDIR) + install -m644 98-osscuse.rules $(DESTDIR)$(UDEVDIR) + +libossp.a: ossp.c ossp.h ossp-util.c ossp-util.h ossp-slave.c ossp-slave.h + $(CC) $(CFLAGS) -c -o ossp.o ossp.c + $(CC) $(CFLAGS) -c -o ossp-util.o ossp-util.c + $(CC) $(CFLAGS) -c -o ossp-slave.o ossp-slave.c + $(AR) rc $@ ossp.o ossp-util.o ossp-slave.o + +osspd: osspd.c libossp.a $(headers) + $(CC) $(CFLAGS) $(OSSPD_CFLAGS) -o $@ $< $(OSSPD_LDFLAGS) $(LDFLAGS) + +ossp-padsp: ossp-padsp.c libossp.a $(headers) + $(CC) $(CFLAGS) $(OSSP_PADSP_CFLAGS) -o $@ $< $(OSSP_PADSP_LDFLAGS) $(LDFLAGS) + +ossp-alsap: ossp-alsap.c libossp.a $(headers) + $(CC) $(CFLAGS) $(OSSP_ALSAP_CFLAGS) -o $@ $< $(OSSP_ALSAP_LDFLAGS) $(LDFLAGS) + +osstest: osstest.c + $(CC) $(CFLAGS) -o $@ $< $(XLDFLAGS) + +test: osstest + @./osstest + +clean: + rm -f *.o *.a osspd ossp-padsp ossp-alsap osstest diff --git a/src/mod/endpoints/mod_skypopen/osscuse/README b/src/mod/endpoints/mod_skypopen/osscuse/README new file mode 100644 index 0000000000..6b716c76e4 --- /dev/null +++ b/src/mod/endpoints/mod_skypopen/osscuse/README @@ -0,0 +1,119 @@ + + OSS Proxy - emulate OSS device using CUSE + + Copyright (C) 2008-2009 SUSE Linux Products GmbH + Copyright (C) 2008-2009 Tejun Heo + +1. What is it? +-------------- + +Well, first, OSS refers to Open Sound System. If it still doesn't +ring a bell, think /dev/dsp, /dev/adsp and /dev/mixer. + +Currently, Linux supports two audio programming interface - ALSA and +OSS. The latter one is deprecated and has been that way for a long +time but there still are applications which still use them including +UML (usermode Linux) host sound support. + +ALSA contains OSS emulation but sadly the emulation is behind +multiplexing layer (which is in userland) which means that if your +sound card doesn't support multiple audio streams, only either one of +ALSA or OSS interface would be usable at any given moment. + +There have been also attempts to emulate OSS in userland using dynamic +library preloading - aoss and more recently padsp. This works for +many applications but it's just not easy to emulate everything using +the technique. Things like polling, signals, forking, privilege +changes make it very difficult to emulate things reliably. + +OSS Proxy uses CUSE (extension of FUSE allowing character devices to +be implemented in userspace) to implement OSS interface - /dev/dsp, +/dev/adsp and /dev/mixer. From the POV of the applications, these +devices are proper character devices and behave exactly the same way +so it can be made quite versatile. + + +2. Hmmm... So, how does the whole thing work? +--------------------------------------------- + +The OSS Proxy daemon - osspd - should be started first. Note that +osspd will fail to start if sound device number regions are already +occupied. You'll need to turn off OSS or its emulation[1]. + +On startup, osspd creates /dev/dsp, /dev/adsp and /dev/mixer using +CUSE. When an application access one of the devices, all IOs are +redirected to osspd via CUSE. Upon receiving a new DSP open request, +osspd creates a slave process which drops the root privilege and +assumes the opening process's credentials. After handshaking, osspd +forwards all relevant IOs to the slave which is responsible for +actually playing the sound. + +Currently there's only one slave implemented - ossp-padsp, which as +the name suggests forwards (again) the sound to pulseaudio. To sum +up, the whole pipe looks like the following. + + App <-> /dev/dsp <-> CUSE <-> osspd <-> ossp-padsp <-> pulseaudio + +Which is a lot of forwarding, but on modern machines, it won't be too +noticeable. + + +3. What works? +-------------- + +Well, MIDI part isn't implemented and I doubt it will be in any near +future but except that everything should work. Playing, recording, +5.1ch, A-V syncing, all should work. If not, it's a bug, so please +report. + +The mixer behaves a bit differently tho. In the original OSS, +/dev/mixer is the hardware mixer, so adjusting volumes there affects +all audio streams. When using ossp, each process group gets its own +mixer and the mixer always contains only two knobs - PCM and IGAIN. +Combined with per-stream volume control of pulseaudio, this scheme +works quite well for applications with embedded volume control +although it makes standalone OSS mixer programs virtually useless[2]. + + +4. How do I use it? +------------------- + +First you need CUSE support in kernel which might land on 2.6.28 with +sufficient luck[3] and then you also need libfuse which supports +CUSE[4]. Once you have both, it should be easy. First build it by +running `make'. You can set OSSPD_CFLAGS, OSSPD_LDFLAGS, +OSSP_PADSP_CFLAGS and OSSP_PADSP_LDFLAGS if you have stuff at +non-default locations. + +After build completes, there will be two executables - `osspd' and +`ossp-padsp'. Just copy them to where other system executables live. +Specific location doesn't matter as long as both files end up in the +same directory. + +Execute `osspd'. It will create the device files and you're all set. +`osspd' uses syslog with LOG_DAEMON facility, so if something doesn't +work take a look at what osspd complains about. + + +[1] As of this writing, turning on any sound support makes the + soundcore module claim OSS device regions. Patch to make it claim + OSS device regions only when OSS support or emulation is enabled + is scheduled for 2.6.28. Even with the patch, soundcore will + claim OSS device regions if OSS support or ALSA OSS emulation is + enabled. Make sure they're turned off. + +[2] If you have a strong reason to use standalone OSS mixer program, + you can play some shell tricks to put it into the same process + group as the target audio application. e.g. To use aumix with + mpg123 - `(mpg123 asdf.mp3 > /dev/null 2>&1 & aumix)', but + seriously, just use PA or ALSA one. + +[3] For the time being, here's the git tree with all the necessary + changes. This tree is base on top of 2.6.27-rc3. + + http://git.kernel.org/?p=linux/kernel/git/tj/misc.git;a=shortlog;h=cuse + git://git.kernel.org/pub/scm/linux/kernel/git/tj/misc.git cuse + +[4] And libfuse with the modifications can be found at... + + http://userweb.kernel.org/~tj/ossp/fuse-cuse.tar.gz diff --git a/src/mod/endpoints/mod_skypopen/osscuse/ossp-alsap.c b/src/mod/endpoints/mod_skypopen/osscuse/ossp-alsap.c new file mode 100644 index 0000000000..607e05ca84 --- /dev/null +++ b/src/mod/endpoints/mod_skypopen/osscuse/ossp-alsap.c @@ -0,0 +1,613 @@ +/* + * ossp-alsap - ossp DSP slave which forwards to alsa + * + * Copyright (C) 2009 Maarten Lankhorst + * + * This file is released under the GPLv2. + * + * Why an alsa plugin as well? Just to show how much + * the alsa userspace api sucks ;-) + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "ossp-slave.h" + +enum { + AFMT_FLOAT = 0x00004000, + AFMT_S32_LE = 0x00001000, + AFMT_S32_BE = 0x00002000, +}; + +static size_t page_size; + +/* alsa structures */ +static snd_pcm_t *pcm[2]; +static snd_pcm_hw_params_t *hw_params; +static snd_pcm_sw_params_t *sw_params; +static int block; + +static unsigned int byte_counter[2]; +static snd_pcm_uframes_t mmap_pos[2]; +static int stream_corked[2]; +static int stream_notify; + +static struct format { + snd_pcm_format_t format; + snd_pcm_sframes_t rate; + int channels; +} hw_format = { SND_PCM_FORMAT_U8, 8000, 1 }; + +#if 0 +/* future mmap stuff */ +static size_t mmap_raw_size, mmap_size; +static int mmap_fd[2] = { -1, -1 }; +static void *mmap_map[2]; +static uint64_t mmap_idx[2]; /* mmap pointer */ +static uint64_t mmap_last_idx[2]; /* last idx for get_ptr */ +static struct ring_buf mmap_stg[2]; /* staging ring buffer */ +static size_t mmap_lead[2]; /* lead bytes */ +static int mmap_sync[2]; /* sync with backend stream */ +#endif + +static snd_pcm_format_t fmt_oss_to_alsa(int fmt) +{ + switch (fmt) { + case AFMT_U8: return SND_PCM_FORMAT_U8; + case AFMT_A_LAW: return SND_PCM_FORMAT_A_LAW; + case AFMT_MU_LAW: return SND_PCM_FORMAT_MU_LAW; + case AFMT_S16_LE: return SND_PCM_FORMAT_S16_LE; + case AFMT_S16_BE: return SND_PCM_FORMAT_S16_BE; + case AFMT_FLOAT: return SND_PCM_FORMAT_FLOAT; + case AFMT_S32_LE: return SND_PCM_FORMAT_S32_LE; + case AFMT_S32_BE: return SND_PCM_FORMAT_S32_BE; + default: return SND_PCM_FORMAT_U8; + } +} + +static int fmt_alsa_to_oss(snd_pcm_format_t fmt) +{ + switch (fmt) { + case SND_PCM_FORMAT_U8: return AFMT_U8; + case SND_PCM_FORMAT_A_LAW: return AFMT_A_LAW; + case SND_PCM_FORMAT_MU_LAW: return AFMT_MU_LAW; + case SND_PCM_FORMAT_S16_LE: return AFMT_S16_LE; + case SND_PCM_FORMAT_S16_BE: return AFMT_S16_BE; + case SND_PCM_FORMAT_FLOAT: return AFMT_FLOAT; + case SND_PCM_FORMAT_S32_LE: return AFMT_S32_LE; + case SND_PCM_FORMAT_S32_BE: return AFMT_S32_BE; + default: return AFMT_U8; + } +} + +static void flush_streams(int drain) +{ + /* FIXME: snd_pcm_drain appears to be able to deadlock, + * always drop or check state? */ + if (drain) { + if (pcm[PLAY]) + snd_pcm_drain(pcm[PLAY]); + if (pcm[REC]) + snd_pcm_drain(pcm[REC]); + } else { + if (pcm[PLAY]) + snd_pcm_drop(pcm[PLAY]); + if (pcm[REC]) + snd_pcm_drop(pcm[REC]); + } + + /* XXX: Really needed? */ +#if 0 + if (pcm[PLAY]) { + snd_pcm_close(pcm[PLAY]); + snd_pcm_open(&pcm[PLAY], "default", + SND_PCM_STREAM_PLAYBACK, block); + } + if (pcm[REC]) { + snd_pcm_close(pcm[REC]); + snd_pcm_open(&pcm[REC], "default", + SND_PCM_STREAM_CAPTURE, block); + } +#endif +} + +static void kill_streams(void) +{ + flush_streams(0); +} + +static int trigger_streams(int play, int rec) +{ + int ret = 0; + + if (pcm[PLAY] && play >= 0) { + ret = snd_pcm_sw_params_set_start_threshold(pcm[PLAY], sw_params, + play ? 1 : -1); + if (ret >= 0) + snd_pcm_sw_params(pcm[PLAY], sw_params); + } + if (ret >= 0 && pcm[REC] && rec >= 0) { + ret = snd_pcm_sw_params_set_start_threshold(pcm[REC], sw_params, + rec ? 1 : -1); + if (ret >= 0) + snd_pcm_sw_params(pcm[REC], sw_params); + } + + return ret; +} + +static ssize_t alsap_mixer(enum ossp_opcode opcode, + void *carg, void *din, size_t din_sz, + void *rarg, void *dout, size_t *dout_szp, int tfd) +{ +return -EBUSY; +} + +static int set_hw_params(snd_pcm_t *pcm) +{ + int ret; + unsigned rate; + + ret = snd_pcm_hw_params_any(pcm, hw_params); + if (ret >= 0) + ret = snd_pcm_hw_params_set_access(pcm, hw_params, + SND_PCM_ACCESS_RW_INTERLEAVED); + rate = hw_format.rate; + if (ret >= 0) + ret = snd_pcm_hw_params_set_rate_minmax(pcm, hw_params, + &rate, NULL, + &rate, NULL); + if (ret >= 0) + ret = snd_pcm_hw_params_set_format(pcm, hw_params, hw_format.format); + if (ret >= 0) + ret = snd_pcm_hw_params_set_channels(pcm, hw_params, + hw_format.channels); + if (ret >= 0) + ret = snd_pcm_hw_params(pcm, hw_params); + if (ret >= 0) + ret = snd_pcm_sw_params_current(pcm, sw_params); + if (ret >= 0) + ret = snd_pcm_sw_params(pcm, sw_params); + return ret; +} + +static ssize_t alsap_open(enum ossp_opcode opcode, + void *carg, void *din, size_t din_sz, + void *rarg, void *dout, size_t *dout_szp, int tfd) +{ + struct ossp_dsp_open_arg *arg = carg; + int ret; + block = arg->flags & O_NONBLOCK ? SND_PCM_NONBLOCK : 0; + int access; +// block |= SND_PCM_ASYNC; + /* Woop dee dooo.. I love handling things in SIGIO (PAIN!!) + * Probably needed for MMAP + */ + + if (!hw_params) + ret = snd_pcm_hw_params_malloc(&hw_params); + if (ret < 0) + return ret; + + if (!sw_params) + ret = snd_pcm_sw_params_malloc(&sw_params); + if (ret < 0) + return ret; + + if (pcm[PLAY]) + snd_pcm_close(pcm[PLAY]); + if (pcm[REC]) + snd_pcm_close(pcm[REC]); + pcm[REC] = pcm[PLAY] = NULL; + + access = arg->flags & O_ACCMODE; + if (access == O_WRONLY || access == O_RDWR) { + ret = snd_pcm_open(&pcm[PLAY], "default", + SND_PCM_STREAM_PLAYBACK, block); + if (ret >= 0) + ret = set_hw_params(pcm[PLAY]); + } + + if (ret >= 0 && (access == O_RDONLY || access == O_RDWR)) { + ret = snd_pcm_open(&pcm[REC], "default", + SND_PCM_STREAM_CAPTURE, block); + if (ret >= 0) + ret = set_hw_params(pcm[REC]); + } + + if (ret < 0) { + if (pcm[PLAY]) + snd_pcm_close(pcm[PLAY]); + if (pcm[REC]) + snd_pcm_close(pcm[REC]); + pcm[REC] = pcm[PLAY] = NULL; + return ret; + } + return 0; +} + +#define GIOVANNI +#ifdef GIOVANNI + +#define GIOVA_SLEEP 40000 +#define GIOVA_BLK 3840 +static ssize_t alsap_write(enum ossp_opcode opcode, + void *carg, void *din, size_t din_sz, + void *rarg, void *dout, size_t *dout_szp, int tfd) +{ + usleep((GIOVA_SLEEP/GIOVA_BLK)* din_sz); + return din_sz; +} +static ssize_t alsap_read(enum ossp_opcode opcode, + void *carg, void *din, size_t din_sz, + void *rarg, void *dout, size_t *dout_szp, int tfd) +{ + usleep((GIOVA_SLEEP/GIOVA_BLK)* *dout_szp); + return *dout_szp; +} +#else// GIOVANNI +static ssize_t alsap_write(enum ossp_opcode opcode, + void *carg, void *din, size_t din_sz, + void *rarg, void *dout, size_t *dout_szp, int tfd) +{ +// struct ossp_dsp_rw_arg *arg = carg; + int ret, insize; + + insize = snd_pcm_bytes_to_frames(pcm[PLAY], din_sz); + + if (snd_pcm_state(pcm[PLAY]) == SND_PCM_STATE_SETUP) + snd_pcm_prepare(pcm[PLAY]); + +// snd_pcm_start(pcm[PLAY]); + ret = snd_pcm_writei(pcm[PLAY], din, insize); + if (ret < 0) + ret = snd_pcm_recover(pcm[PLAY], ret, 1); + + if (ret >= 0) + return snd_pcm_frames_to_bytes(pcm[PLAY], ret); + else + return ret; +} + +static ssize_t alsap_read(enum ossp_opcode opcode, + void *carg, void *din, size_t din_sz, + void *rarg, void *dout, size_t *dout_szp, int tfd) +{ +// struct ossp_dsp_rw_arg *arg = carg; + int ret, outsize; + + outsize = snd_pcm_bytes_to_frames(pcm[REC], *dout_szp); + + if (snd_pcm_state(pcm[REC]) == SND_PCM_STATE_SETUP) + snd_pcm_prepare(pcm[REC]); + + ret = snd_pcm_readi(pcm[REC], dout, outsize); + if (ret < 0) + ret = snd_pcm_recover(pcm[REC], ret, 1); + if (ret >= 0) + *dout_szp = ret = snd_pcm_frames_to_bytes(pcm[REC], ret); + else + *dout_szp = 0; + + return ret; +} +#endif// GIOVANNI + +static ssize_t alsap_poll(enum ossp_opcode opcode, + void *carg, void *din, size_t din_sz, + void *rarg, void *dout, size_t *dout_szp, int tfd) +{ + unsigned revents = 0; + + stream_notify |= *(int *)carg; + + if (pcm[PLAY]) + revents |= POLLOUT; + if (pcm[REC]) + revents |= POLLIN; + + *(unsigned *)rarg = revents; + return 0; +} + + +static ssize_t alsap_flush(enum ossp_opcode opcode, + void *carg, void *din, size_t din_sz, + void *rarg, void *dout, size_t *dout_szp, int tfd) +{ + flush_streams(opcode == OSSP_DSP_SYNC); + return 0; +} + +static ssize_t alsap_post(enum ossp_opcode opcode, + void *carg, void *din, size_t din_sz, + void *rarg, void *dout, size_t *dout_szp, int tfd) +{ + int ret; + + ret = trigger_streams(1, 1); + if (ret >= 0 && pcm[PLAY]) + ret = snd_pcm_start(pcm[PLAY]); + if (pcm[REC]) + ret = snd_pcm_start(pcm[REC]); + return ret; +} + +static ssize_t alsap_get_param(enum ossp_opcode opcode, + void *carg, void *din, size_t din_sz, + void *rarg, void *dout, size_t *dout_szp, + int tfd) +{ + int v = 0; + + switch (opcode) { + case OSSP_DSP_GET_RATE: + return hw_format.rate; + + case OSSP_DSP_GET_CHANNELS: + return hw_format.channels; + + case OSSP_DSP_GET_FORMAT: { + v = fmt_alsa_to_oss(hw_format.format); + break; + } + + case OSSP_DSP_GET_BLKSIZE: { + snd_pcm_uframes_t psize; + snd_pcm_hw_params_get_period_size(hw_params, &psize, NULL); + v = psize; + break; + } + + case OSSP_DSP_GET_FORMATS: + v = AFMT_U8 | AFMT_A_LAW | AFMT_MU_LAW | AFMT_S16_LE | + AFMT_S16_BE | AFMT_FLOAT | AFMT_S32_LE | AFMT_S32_BE; + break; + + case OSSP_DSP_GET_TRIGGER: + if (!stream_corked[PLAY]) + v |= PCM_ENABLE_OUTPUT; + if (!stream_corked[REC]) + v |= PCM_ENABLE_INPUT; + break; + + default: + assert(0); + } + + *(int *)rarg = v; + + return 0; +} + +static ssize_t alsap_set_param(enum ossp_opcode opcode, + void *carg, void *din, size_t din_sz, + void *rarg, void *dout, size_t *dout_szp, + int tfd) +{ + int v = *(int *)carg; + int ret = 0; + + /* kill the streams before changing parameters */ + kill_streams(); + + switch (opcode) { + case OSSP_DSP_SET_RATE: { + hw_format.rate = v; + break; + } + + case OSSP_DSP_SET_CHANNELS: { + hw_format.channels = v; + break; + } + + case OSSP_DSP_SET_FORMAT: { + snd_pcm_format_t format = fmt_oss_to_alsa(v); + hw_format.format = format; + break; + } + + case OSSP_DSP_SET_SUBDIVISION: + if (!v) + v = 1; +#if 0 + if (!v) { + v = user_subdivision ?: 1; + break; + } + user_frag_size = 0; + user_subdivision = v; + break; + + case OSSP_DSP_SET_FRAGMENT: + user_subdivision = 0; + user_frag_size = 1 << (v & 0xffff); + user_max_frags = (v >> 16) & 0xffff; + if (user_frag_size < 4) + user_frag_size = 4; + if (user_max_frags < 2) + user_max_frags = 2; +#else + case OSSP_DSP_SET_FRAGMENT: +#endif + break; + default: + assert(0); + } + + if (pcm[PLAY]) + ret = set_hw_params(pcm[PLAY]); + if (ret >= 0 && pcm[REC]) + ret = set_hw_params(pcm[REC]); + + if (rarg) + *(int *)rarg = v; + return 0; +} + +static ssize_t alsap_set_trigger(enum ossp_opcode opcode, + void *carg, void *din, size_t din_sz, + void *rarg, void *dout, size_t *dout_szp, + int fd) +{ + int enable = *(int *)carg; + + stream_corked[PLAY] = !!(enable & PCM_ENABLE_OUTPUT); + stream_corked[REC] = !!(enable & PCM_ENABLE_INPUT); + + return trigger_streams(enable & PCM_ENABLE_OUTPUT, + enable & PCM_ENABLE_INPUT); +} + +static ssize_t alsap_get_space(enum ossp_opcode opcode, + void *carg, void *din, size_t din_sz, + void *rarg, void *dout, size_t *dout_szp, int tfd) +{ + int dir = (opcode == OSSP_DSP_GET_OSPACE) ? PLAY : REC; + int underrun = 0; + struct audio_buf_info info = { }; + unsigned long bufsize; + snd_pcm_uframes_t avail, fragsize; + snd_pcm_state_t state; + + if (!pcm[dir]) + return -EINVAL; + + state = snd_pcm_state(pcm[dir]); + if (state == SND_PCM_STATE_XRUN) { + snd_pcm_recover(pcm[dir], -EPIPE, 0); + underrun = 1; + } else if (state == SND_PCM_STATE_SUSPENDED) { + snd_pcm_recover(pcm[dir], -ESTRPIPE, 0); + underrun = 1; + } + + snd_pcm_hw_params_current(pcm[dir], hw_params); + snd_pcm_hw_params_get_period_size(hw_params, &fragsize, NULL); + snd_pcm_hw_params_get_buffer_size(hw_params, &bufsize); + info.fragsize = snd_pcm_frames_to_bytes(pcm[dir], fragsize); + info.fragstotal = bufsize / fragsize; + if (!underrun) { + avail = snd_pcm_avail_update(pcm[dir]); + info.fragments = avail / fragsize; + } else + info.fragments = info.fragstotal; + + info.bytes = info.fragsize * info.fragments; + + *(struct audio_buf_info *)rarg = info; + return 0; +} + +static ssize_t alsap_get_ptr(enum ossp_opcode opcode, + void *carg, void *din, size_t din_sz, + void *rarg, void *dout, size_t *dout_szp, int tfd) +{ + int dir = (opcode == OSSP_DSP_GET_OPTR) ? PLAY : REC; + struct count_info info = { }; + + if (!pcm[dir]) + return -EIO; + + snd_pcm_hw_params_current(pcm[dir], hw_params); + info.bytes = byte_counter[dir]; + snd_pcm_hw_params_get_periods(hw_params, (unsigned int *)&info.blocks, NULL); + info.ptr = mmap_pos[dir]; + + *(struct count_info *)rarg = info; + return 0; +} + +static ssize_t alsap_get_odelay(enum ossp_opcode opcode, + void *carg, void *din, size_t din_sz, + void *rarg, void *dout, size_t *dout_szp, + int fd) +{ + snd_pcm_sframes_t delay; + + if (!pcm[PLAY]) + return -EIO; + + if (snd_pcm_delay(pcm[PLAY], &delay) < 0) + return -EIO; + + *(int *)rarg = snd_pcm_frames_to_bytes(pcm[PLAY], delay); + return 0; +} + +static ossp_action_fn_t action_fn_tbl[OSSP_NR_OPCODES] = { + [OSSP_MIXER] = alsap_mixer, + [OSSP_DSP_OPEN] = alsap_open, + [OSSP_DSP_READ] = alsap_read, + [OSSP_DSP_WRITE] = alsap_write, + [OSSP_DSP_POLL] = alsap_poll, +#if 0 + [OSSP_DSP_MMAP] = alsap_mmap, + [OSSP_DSP_MUNMAP] = alsap_munmap, +#endif + [OSSP_DSP_RESET] = alsap_flush, + [OSSP_DSP_SYNC] = alsap_flush, + [OSSP_DSP_POST] = alsap_post, + [OSSP_DSP_GET_RATE] = alsap_get_param, + [OSSP_DSP_GET_CHANNELS] = alsap_get_param, + [OSSP_DSP_GET_FORMAT] = alsap_get_param, + [OSSP_DSP_GET_BLKSIZE] = alsap_get_param, + [OSSP_DSP_GET_FORMATS] = alsap_get_param, + [OSSP_DSP_SET_RATE] = alsap_set_param, + [OSSP_DSP_SET_CHANNELS] = alsap_set_param, + [OSSP_DSP_SET_FORMAT] = alsap_set_param, + [OSSP_DSP_SET_SUBDIVISION] = alsap_set_param, + [OSSP_DSP_SET_FRAGMENT] = alsap_set_param, + [OSSP_DSP_GET_TRIGGER] = alsap_get_param, + [OSSP_DSP_SET_TRIGGER] = alsap_set_trigger, + [OSSP_DSP_GET_OSPACE] = alsap_get_space, + [OSSP_DSP_GET_ISPACE] = alsap_get_space, + [OSSP_DSP_GET_OPTR] = alsap_get_ptr, + [OSSP_DSP_GET_IPTR] = alsap_get_ptr, + [OSSP_DSP_GET_ODELAY] = alsap_get_odelay, +}; + +static int action_pre(void) +{ + return 0; +} + +static void action_post(void) +{ +} + +int main(int argc, char **argv) +{ + int rc; + + ossp_slave_init(argc, argv); + + page_size = sysconf(_SC_PAGE_SIZE); + + /* Okay, now we're open for business */ + rc = 0; + do { + rc = ossp_slave_process_command(ossp_cmd_fd, action_fn_tbl, + action_pre, action_post); + } while (rc > 0); + + return rc ? 1 : 0; +} diff --git a/src/mod/endpoints/mod_skypopen/osscuse/ossp-slave.c b/src/mod/endpoints/mod_skypopen/osscuse/ossp-slave.c new file mode 100644 index 0000000000..4c5cb2d129 --- /dev/null +++ b/src/mod/endpoints/mod_skypopen/osscuse/ossp-slave.c @@ -0,0 +1,250 @@ +/* + * ossp-slave - OSS Proxy: Common codes for slaves + * + * Copyright (C) 2008-2010 SUSE Linux Products GmbH + * Copyright (C) 2008-2010 Tejun Heo + * + * This file is released under the GPLv2. + */ + +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ossp-slave.h" + +static const char *usage = +"usage: ossp-SLAVE [options]\n" +"\n" +"proxies commands from osspd to pulseaudio\n" +"\n" +"options:\n" +" -u UID uid to use\n" +" -g GID gid to use\n" +" -c CMD_FD fd to receive commands from osspd\n" +" -n NOTIFY_FD fd to send async notifications to osspd\n" +" -m MMAP_FD fd to use for mmap\n" +" -o MMAP_OFFSET mmap offset\n" +" -s MMAP_SIZE mmap size\n" +" -l LOG_LEVEL set log level\n" +" -t enable log timestamps\n"; + +char ossp_user_name[OSSP_USER_NAME_LEN]; +int ossp_cmd_fd = -1, ossp_notify_fd = -1; +void *ossp_mmap_addr[2]; + +void ossp_slave_init(int argc, char **argv) +{ + int have_uid = 0, have_gid = 0; + uid_t uid; + gid_t gid; + int mmap_fd = -1; + off_t mmap_off = 0; + size_t mmap_size = 0; + int opt; + struct passwd *pw, pw_buf; + struct sigaction sa; + char pw_sbuf[sysconf(_SC_GETPW_R_SIZE_MAX)]; + + while ((opt = getopt(argc, argv, "u:g:c:n:m:o:s:l:t")) != -1) { + switch (opt) { + case 'u': + have_uid = 1; + uid = strtol(optarg, NULL, 0); + break; + case 'g': + have_gid = 1; + gid = strtol(optarg, NULL, 0); + break; + case 'c': + ossp_cmd_fd = strtol(optarg, NULL, 0); + break; + case 'n': + ossp_notify_fd = strtol(optarg, NULL, 0); + break; + case 'm': + mmap_fd = strtol(optarg, NULL, 0); + break; + case 'o': + mmap_off = strtoull(optarg, NULL, 0); + break; + case 's': + mmap_size = strtoul(optarg, NULL, 0); + break; + case 'l': + ossp_log_level = strtol(optarg, NULL, 0); + break; + case 't': + ossp_log_timestamp = 1; + break; + } + } + + if (!have_uid || !have_gid || ossp_cmd_fd < 0 || ossp_notify_fd < 0) { + fprintf(stderr, usage); + _exit(1); + } + + snprintf(ossp_user_name, sizeof(ossp_user_name), "uid%d", uid); + if (getpwuid_r(uid, &pw_buf, pw_sbuf, sizeof(pw_sbuf), &pw) == 0) + snprintf(ossp_user_name, sizeof(ossp_user_name), "%s", + pw->pw_name); + + snprintf(ossp_log_name, sizeof(ossp_log_name), "ossp-padsp[%s:%d]", + ossp_user_name, getpid()); + + if (mmap_fd >= 0) { + void *p; + + if (!mmap_off || !mmap_size) { + fprintf(stderr, usage); + _exit(1); + } + + p = mmap(NULL, mmap_size, PROT_READ | PROT_WRITE, MAP_SHARED, + mmap_fd, mmap_off); + if (p == MAP_FAILED) + fatal_e(-errno, "mmap failed"); + + ossp_mmap_addr[PLAY] = p; + ossp_mmap_addr[REC] = p + mmap_size / 2; + close(mmap_fd); + } + + /* mmap done, drop privileges */ + if (setresgid(gid, gid, gid) || setresuid(uid, uid, uid)) + fatal_e(-errno, "failed to drop privileges"); + + /* block SIGPIPE */ + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = SIG_IGN; + if (sigaction(SIGPIPE, &sa, NULL)) + fatal_e(-errno, "failed to ignore SIGPIPE"); +} + +int ossp_slave_process_command(int cmd_fd, + ossp_action_fn_t const *action_fn_tbl, + int (*action_pre_fn)(void), + void (*action_post_fn)(void)) +{ + static struct sized_buf carg_sbuf = { }, rarg_sbuf = { }; + static struct sized_buf din_sbuf = { }, dout_sbuf = { }; + struct ossp_cmd cmd; + int fd = -1; + char cmsg_buf[CMSG_SPACE(sizeof(fd))]; + struct iovec iov = { &cmd, sizeof(cmd) }; + struct msghdr msg = { .msg_iov = &iov, .msg_iovlen = 1, + .msg_control = cmsg_buf, + .msg_controllen = sizeof(cmsg_buf) }; + struct cmsghdr *cmsg; + size_t carg_size, din_size, rarg_size, dout_size; + char *carg = NULL, *din = NULL, *rarg = NULL, *dout = NULL; + struct ossp_reply reply = { .magic = OSSP_REPLY_MAGIC }; + ssize_t ret; + + ret = recvmsg(cmd_fd, &msg, 0); + if (ret == 0) + return 0; + if (ret < 0) { + ret = -errno; + err_e(ret, "failed to read command channel"); + return ret; + } + + if (ret != sizeof(cmd)) { + err("command struct size mismatch (%zu, should be %zu)", + ret, sizeof(cmd)); + return -EINVAL; + } + + if (cmd.magic != OSSP_CMD_MAGIC) { + err("illegal command magic 0x%x", cmd.magic); + return -EINVAL; + } + + for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; + cmsg = CMSG_NXTHDR(&msg, cmsg)) { + if (cmsg->cmsg_level == SOL_SOCKET && + cmsg->cmsg_type == SCM_RIGHTS) + fd = *(int *)CMSG_DATA(cmsg); + else { + err("unknown cmsg %d:%d received (opcode %d)", + cmsg->cmsg_level, cmsg->cmsg_type, cmd.opcode); + return -EINVAL; + } + } + + if (cmd.opcode >= OSSP_NR_OPCODES) { + err("unknown opcode %d", cmd.opcode); + return -EINVAL; + } + + carg_size = ossp_arg_sizes[cmd.opcode].carg_size; + din_size = cmd.din_size; + rarg_size = ossp_arg_sizes[cmd.opcode].rarg_size; + dout_size = cmd.dout_size; + + if ((fd >= 0) != ossp_arg_sizes[cmd.opcode].has_fd) { + err("fd=%d unexpected for opcode %d", fd, cmd.opcode); + return -EINVAL; + } + + if (ensure_sbuf_size(&carg_sbuf, carg_size) || + ensure_sbuf_size(&din_sbuf, din_size) || + ensure_sbuf_size(&rarg_sbuf, rarg_size) || + ensure_sbuf_size(&dout_sbuf, dout_size)) { + err("failed to allocate command buffers"); + return -ENOMEM; + } + + if (carg_size) { + carg = carg_sbuf.buf; + ret = read_fill(cmd_fd, carg, carg_size); + if (ret < 0) + return ret; + } + if (din_size) { + din = din_sbuf.buf; + ret = read_fill(cmd_fd, din, din_size); + if (ret < 0) + return ret; + } + if (rarg_size) + rarg = rarg_sbuf.buf; + if (dout_size) + dout = dout_sbuf.buf; + + ret = -EINVAL; + if (action_fn_tbl[cmd.opcode]) { + ret = action_pre_fn(); + if (ret == 0) { + ret = action_fn_tbl[cmd.opcode](cmd.opcode, carg, + din, din_size, rarg, + dout, &dout_size, fd); + action_post_fn(); + } + } + + reply.result = ret; + if (ret >= 0) + reply.dout_size = dout_size; + else { + rarg_size = 0; + dout_size = 0; + } + + if (write_fill(cmd_fd, &reply, sizeof(reply)) < 0 || + write_fill(cmd_fd, rarg, rarg_size) < 0 || + write_fill(cmd_fd, dout, dout_size) < 0) + return -EIO; + + return 1; +} diff --git a/src/mod/endpoints/mod_skypopen/osscuse/ossp-slave.h b/src/mod/endpoints/mod_skypopen/osscuse/ossp-slave.h new file mode 100644 index 0000000000..10c22cdb02 --- /dev/null +++ b/src/mod/endpoints/mod_skypopen/osscuse/ossp-slave.h @@ -0,0 +1,28 @@ +/* + * ossp-slave - OSS Proxy: Common codes for slaves + * + * Copyright (C) 2008-2010 SUSE Linux Products GmbH + * Copyright (C) 2008-2010 Tejun Heo + * + * This file is released under the GPLv2. + */ + +#ifndef _OSSP_SLAVE_H +#define _OSSP_SLAVE_H + +#include "ossp.h" +#include "ossp-util.h" + +#define OSSP_USER_NAME_LEN 128 + +extern char ossp_user_name[OSSP_USER_NAME_LEN]; +extern int ossp_cmd_fd, ossp_notify_fd; +extern void *ossp_mmap_addr[2]; + +void ossp_slave_init(int argc, char **argv); +int ossp_slave_process_command(int cmd_fd, + ossp_action_fn_t const *action_fn_tbl, + int (*action_pre_fn)(void), + void (*action_post_fn)(void)); + +#endif /* _OSSP_SLAVE_H */ diff --git a/src/mod/endpoints/mod_skypopen/osscuse/ossp-util.c b/src/mod/endpoints/mod_skypopen/osscuse/ossp-util.c new file mode 100644 index 0000000000..325cefd5fd --- /dev/null +++ b/src/mod/endpoints/mod_skypopen/osscuse/ossp-util.c @@ -0,0 +1,369 @@ +/* + * ossp-util - OSS Proxy: Common utilities + * + * Copyright (C) 2008-2010 SUSE Linux Products GmbH + * Copyright (C) 2008-2010 Tejun Heo + * + * This file is released under the GPLv2. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ossp-util.h" + +#define BIT(nr) (1UL << (nr)) +#define BIT_MASK(nr) (1UL << ((nr) % BITS_PER_LONG)) +#define BIT_WORD(nr) ((nr) / BITS_PER_LONG) +#define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long)) +#define BITOP_WORD(nr) ((nr) / BITS_PER_LONG) + +char ossp_log_name[OSSP_LOG_NAME_LEN]; +int ossp_log_level = OSSP_LOG_DFL; +int ossp_log_timestamp; + +static const char *severity_strs[] = { + [OSSP_LOG_CRIT] = "CRIT", + [OSSP_LOG_ERR] = " ERR", + [OSSP_LOG_WARN] = "WARN", + [OSSP_LOG_INFO] = NULL, + [OSSP_LOG_DBG0] = "DBG0", + [OSSP_LOG_DBG1] = "DBG1", +}; + +static int severity_map[] = { + [OSSP_LOG_CRIT] = LOG_ERR, + [OSSP_LOG_ERR] = LOG_ERR, + [OSSP_LOG_WARN] = LOG_WARNING, + [OSSP_LOG_INFO] = LOG_INFO, + [OSSP_LOG_DBG0] = LOG_DEBUG, + [OSSP_LOG_DBG1] = LOG_DEBUG, +}; + +void log_msg(int severity, const char *fmt, ...) +{ + static int syslog_opened = 0; + char buf[1024]; + size_t len = sizeof(buf), off = 0; + va_list ap; + + if (severity > abs(ossp_log_level)) + return; + + if (ossp_log_level < 0 && !syslog_opened) + openlog(ossp_log_name, 0, LOG_DAEMON); + + assert(severity >= 0 && severity < ARRAY_SIZE(severity_strs)); + + if (ossp_log_timestamp) { + static uint64_t start; + uint64_t now; + struct timeval tv; + gettimeofday(&tv, NULL); + now = tv.tv_sec * 1000 + tv.tv_usec / 1000; + if (!start) + start = now; + + off += snprintf(buf + off, len - off, "<%08"PRIu64"> ", + now - start); + } + + if (ossp_log_level > 0) { + char sev_buf[16] = ""; + if (severity_strs[severity]) + snprintf(sev_buf, sizeof(sev_buf), " %s", + severity_strs[severity]); + off += snprintf(buf + off, len - off, "%s%s: ", + ossp_log_name, sev_buf); + } else if (severity_strs[severity]) + off += snprintf(buf + off, len - off, "%s ", + severity_strs[severity]); + + va_start(ap, fmt); + off += vsnprintf(buf + off, len - off, fmt, ap); + va_end(ap); + + off += snprintf(buf + off, len - off, "\n"); + + if (ossp_log_level > 0) + fputs(buf, stderr); + else + syslog(severity_map[severity], "%s", buf); +} + +int read_fill(int fd, void *buf, size_t size) +{ + while (size) { + ssize_t ret; + int rc; + + ret = read(fd, buf, size); + if (ret <= 0) { + if (ret == 0) + rc = -EIO; + else + rc = -errno; + err_e(rc, "failed to read_fill %zu bytes from fd %d", + size, fd); + return rc; + } + buf += ret; + size -= ret; + } + return 0; +} + +int write_fill(int fd, const void *buf, size_t size) +{ + while (size) { + ssize_t ret; + int rc; + + ret = write(fd, buf, size); + if (ret <= 0) { + if (ret == 0) + rc = -EIO; + else + rc = -errno; + err_e(rc, "failed to write_fill %zu bytes to fd %d", + size, fd); + return rc; + } + buf += ret; + size -= ret; + } + return 0; +} + +void ring_fill(struct ring_buf *ring, const void *buf, size_t size) +{ + size_t tail; + + assert(ring_space(ring) >= size); + + tail = (ring->head + ring->size - ring->bytes) % ring->size; + + if (ring->head >= tail) { + size_t todo = min(size, ring->size - ring->head); + + memcpy(ring->buf + ring->head, buf, todo); + ring->head = (ring->head + todo) % ring->size; + ring->bytes += todo; + buf += todo; + size -= todo; + } + + assert(ring->size - ring->head >= size); + memcpy(ring->buf + ring->head, buf, size); + ring->head += size; + ring->bytes += size; +} + +void *ring_data(struct ring_buf *ring, size_t *sizep) +{ + size_t tail; + + if (!ring->bytes) + return NULL; + + tail = (ring->head + ring->size - ring->bytes) % ring->size; + + *sizep = min(ring->bytes, ring->size - tail); + return ring->buf + tail; +} + +int ring_resize(struct ring_buf *ring, size_t new_size) +{ + struct ring_buf new_ring = { .size = new_size }; + void *p; + size_t size; + + if (ring_bytes(ring) > new_size) + return -ENOSPC; + + new_ring.buf = calloc(1, new_size); + if (new_size && !new_ring.buf) + return -ENOMEM; + + while ((p = ring_data(ring, &size))) { + ring_fill(&new_ring, p, size); + ring_consume(ring, size); + } + + free(ring->buf); + *ring = new_ring; + return 0; +} + +int ensure_sbuf_size(struct sized_buf *sbuf, size_t size) +{ + char *new_buf; + + if (sbuf->size >= size) + return 0; + + new_buf = realloc(sbuf->buf, size); + if (size && !new_buf) + return -ENOMEM; + + sbuf->buf = new_buf; + sbuf->size = size; + return 0; +} + +static unsigned long __ffs(unsigned long word) +{ + int num = 0; + + if (BITS_PER_LONG == 64) { + if ((word & 0xffffffff) == 0) { + num += 32; + word >>= 32; + } + } + + if ((word & 0xffff) == 0) { + num += 16; + word >>= 16; + } + if ((word & 0xff) == 0) { + num += 8; + word >>= 8; + } + if ((word & 0xf) == 0) { + num += 4; + word >>= 4; + } + if ((word & 0x3) == 0) { + num += 2; + word >>= 2; + } + if ((word & 0x1) == 0) + num += 1; + return num; +} + +#define ffz(x) __ffs(~(x)) + +unsigned long find_next_zero_bit(const unsigned long *addr, unsigned long size, + unsigned long offset) +{ + const unsigned long *p = addr + BITOP_WORD(offset); + unsigned long result = offset & ~(BITS_PER_LONG-1); + unsigned long tmp; + + if (offset >= size) + return size; + size -= result; + offset %= BITS_PER_LONG; + if (offset) { + tmp = *(p++); + tmp |= ~0UL >> (BITS_PER_LONG - offset); + if (size < BITS_PER_LONG) + goto found_first; + if (~tmp) + goto found_middle; + size -= BITS_PER_LONG; + result += BITS_PER_LONG; + } + while (size & ~(BITS_PER_LONG-1)) { + if (~(tmp = *(p++))) + goto found_middle; + result += BITS_PER_LONG; + size -= BITS_PER_LONG; + } + if (!size) + return result; + tmp = *p; + +found_first: + tmp |= ~0UL << size; + if (tmp == ~0UL) /* Are any bits zero? */ + return result + size; /* Nope. */ +found_middle: + return result + ffz(tmp); +} + +void __set_bit(int nr, volatile unsigned long *addr) +{ + unsigned long mask = BIT_MASK(nr); + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + + *p |= mask; +} + +void __clear_bit(int nr, volatile unsigned long *addr) +{ + unsigned long mask = BIT_MASK(nr); + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + + *p &= ~mask; +} + +int get_proc_self_info(pid_t pid, pid_t *ppid_r, + char *cmd_buf, size_t cmd_buf_sz) + +{ + char path[64], buf[4096]; + int fd = -1; + char *cmd_start, *cmd_end, *ppid_start, *end; + ssize_t ret; + pid_t ppid; + int i, rc; + + snprintf(path, sizeof(path), "/proc/%ld/stat", (long)pid); + fd = open(path, O_RDONLY); + if (fd < 0) { + rc = -errno; + goto out; + } + + ret = read(fd, buf, sizeof(buf)); + if (ret < 0) + goto out; + if (ret == sizeof(buf)) { + rc = -EOVERFLOW; + goto out; + } + buf[ret] = '\0'; + + rc = -EINVAL; + cmd_start = strchr(buf, '('); + cmd_end = strrchr(buf, ')'); + if (!cmd_start || !cmd_end) + goto out; + cmd_start++; + + ppid_start = cmd_end; + for (i = 0; i < 3; i++) { + ppid_start = strchr(ppid_start, ' '); + if (!ppid_start) + goto out; + ppid_start++; + } + + ppid = strtoul(ppid_start, &end, 10); + if (end == ppid_start || *end != ' ') + goto out; + + if (ppid_r) + *ppid_r = ppid; + if (cmd_buf) { + size_t len = min_t(size_t, cmd_end - cmd_start, cmd_buf_sz - 1); + memcpy(cmd_buf, cmd_start, len); + cmd_buf[len] = '\0'; + } + + rc = 0; + out: + close(fd); + + return rc; +} diff --git a/src/mod/endpoints/mod_skypopen/osscuse/ossp-util.h b/src/mod/endpoints/mod_skypopen/osscuse/ossp-util.h new file mode 100644 index 0000000000..f48d02257a --- /dev/null +++ b/src/mod/endpoints/mod_skypopen/osscuse/ossp-util.h @@ -0,0 +1,609 @@ +/* + * ossp-util - OSS Proxy: Common utilities + * + * Copyright (C) 2008-2010 SUSE Linux Products GmbH + * Copyright (C) 2008-2010 Tejun Heo + * + * This file is released under the GPLv2. + */ + +#ifndef _OSSP_UTIL_H +#define _OSSP_UTIL_H + +#include +#include +#include +#include +#include +#include +#include "ossp.h" + +#define OSSP_LOG_NAME_LEN 128 + +enum { + OSSP_LOG_CRIT = 1, + OSSP_LOG_ERR, + OSSP_LOG_WARN, + OSSP_LOG_INFO, + OSSP_LOG_DFL = OSSP_LOG_INFO, /* default log level */ + OSSP_LOG_DBG0, + OSSP_LOG_DBG1, + OSSP_LOG_MAX = OSSP_LOG_DBG1, +}; + +extern char ossp_log_name[OSSP_LOG_NAME_LEN]; +extern int ossp_log_level; +extern int ossp_log_timestamp; + +#define BITS_PER_BYTE 8 +#define BITS_PER_LONG (BITS_PER_BYTE * sizeof(long)) +#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d)) +#define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long)) + +/* ARRAY_SIZE and min/max macros stolen from linux/kernel.h */ +#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) + +#define min(x, y) ({ \ + typeof(x) _min1 = (x); \ + typeof(y) _min2 = (y); \ + (void) (&_min1 == &_min2); \ + _min1 < _min2 ? _min1 : _min2; }) + +#define max(x, y) ({ \ + typeof(x) _max1 = (x); \ + typeof(y) _max2 = (y); \ + (void) (&_max1 == &_max2); \ + _max1 > _max2 ? _max1 : _max2; }) + +#define min_t(type, x, y) ({ \ + type __min1 = (x); \ + type __min2 = (y); \ + __min1 < __min2 ? __min1: __min2; }) + +#define max_t(type, x, y) ({ \ + type __max1 = (x); \ + type __max2 = (y); \ + __max1 > __max2 ? __max1: __max2; }) + +void log_msg(int severity, const char *fmt, ...) + __attribute__ ((format (printf, 2, 3))); + +#define fatal(fmt, args...) do { \ + log_msg(OSSP_LOG_CRIT, fmt , ##args); \ + _exit(1); \ +} while (0) +#define err(fmt, args...) log_msg(OSSP_LOG_ERR, fmt , ##args) +#define warn(fmt, args...) log_msg(OSSP_LOG_WARN, fmt , ##args) +#define info(fmt, args...) log_msg(OSSP_LOG_INFO, fmt , ##args) +#define dbg0(fmt, args...) log_msg(OSSP_LOG_DBG0, fmt , ##args) +#define dbg1(fmt, args...) log_msg(OSSP_LOG_DBG1, fmt , ##args) + +#define fatal_e(e, fmt, args...) \ + fatal(fmt" (%s)" , ##args, strerror(-(e))) +#define err_e(e, fmt, args...) \ + err(fmt" (%s)" , ##args, strerror(-(e))) +#define warn_e(e, fmt, args...) \ + warn(fmt" (%s)" , ##args, strerror(-(e))) +#define info_e(e, fmt, args...) \ + info(fmt" (%s)" , ##args, strerror(-(e))) +#define dbg0_e(e, fmt, args...) \ + dbg0(fmt" (%s)" , ##args, strerror(-(e))) +#define dbg1_e(e, fmt, args...) \ + dbg1(fmt" (%s)" , ##args, strerror(-(e))) + +struct ring_buf { + char *buf; + size_t size; + size_t head; + size_t bytes; +}; + +static inline size_t ring_size(struct ring_buf *ring) +{ + return ring->size; +} + +static inline size_t ring_bytes(struct ring_buf *ring) +{ + return ring->bytes; +} + +static inline size_t ring_space(struct ring_buf *ring) +{ + return ring->size - ring->bytes; +} + +static inline void ring_consume(struct ring_buf *ring, size_t size) +{ + assert(ring->bytes >= size); + ring->bytes -= size; +} + +static inline void ring_manual_init(struct ring_buf *ring, void *buf, + size_t size, size_t head, size_t bytes) +{ + ring->buf = buf; + ring->size = size; + ring->head = head; + ring->bytes = bytes; +} + +void ring_fill(struct ring_buf *ring, const void *buf, size_t size); +void *ring_data(struct ring_buf *ring, size_t *sizep); +int ring_resize(struct ring_buf *ring, size_t new_size); + +struct sized_buf { + char *buf; + size_t size; +}; + +int ensure_sbuf_size(struct sized_buf *sbuf, size_t size); + +int read_fill(int fd, void *buf, size_t size); +int write_fill(int fd, const void *buf, size_t size); + +/* + * Bitops lifted from linux asm-generic implementation. + */ +unsigned long find_next_zero_bit(const unsigned long *addr, unsigned + long size, unsigned long offset); +#define find_first_zero_bit(addr, size) find_next_zero_bit((addr), (size), 0) +extern void __set_bit(int nr, volatile unsigned long *addr); +extern void __clear_bit(int nr, volatile unsigned long *addr); + +typedef ssize_t (*ossp_action_fn_t)(enum ossp_opcode opcode, + void *carg, void *din, size_t din_sz, + void *rarg, void *dout, size_t *dout_szp, + int fd); + +int get_proc_self_info(pid_t tid, pid_t *pgrp, + char *cmd_buf, size_t cmd_buf_sz); + +/* + * Doubly linked list handling code shamelessly stolen from the Linux + * kernel 2.6.26 include/linux/list.h. + */ + +/** + * container_of - cast a member of a structure out to the containing structure + * @ptr: the pointer to the member. + * @type: the type of the container struct this is embedded in. + * @member: the name of the member within the struct. + * + */ +#define container_of(ptr, type, member) ({ \ + const typeof( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - offsetof(type,member) );}) + +#define LIST_POISON1 ((void *) 0x00100100) +#define LIST_POISON2 ((void *) 0x00200200) + +/* + * Simple doubly linked list implementation. + * + * Some of the internal functions ("__xxx") are useful when + * manipulating whole lists rather than single entries, as + * sometimes we already know the next/prev entries and we can + * generate better code by using them directly rather than + * using the generic single-entry routines. + */ + +struct list_head { + struct list_head *next, *prev; +}; + +#define LIST_HEAD_INIT(name) { &(name), &(name) } + +#define LIST_HEAD(name) \ + struct list_head name = LIST_HEAD_INIT(name) + +static inline void INIT_LIST_HEAD(struct list_head *list) +{ + list->next = list; + list->prev = list; +} + +/* + * Insert a new entry between two known consecutive entries. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +static inline void __list_add(struct list_head *new, + struct list_head *prev, + struct list_head *next) +{ + next->prev = new; + new->next = next; + new->prev = prev; + prev->next = new; +} + +/** + * list_add - add a new entry + * @new: new entry to be added + * @head: list head to add it after + * + * Insert a new entry after the specified head. + * This is good for implementing stacks. + */ +static inline void list_add(struct list_head *new, struct list_head *head) +{ + __list_add(new, head, head->next); +} + +/** + * list_add_tail - add a new entry + * @new: new entry to be added + * @head: list head to add it before + * + * Insert a new entry before the specified head. + * This is useful for implementing queues. + */ +static inline void list_add_tail(struct list_head *new, struct list_head *head) +{ + __list_add(new, head->prev, head); +} + +/* + * Delete a list entry by making the prev/next entries + * point to each other. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +static inline void __list_del(struct list_head * prev, struct list_head * next) +{ + next->prev = prev; + prev->next = next; +} + +/** + * list_del - deletes entry from list. + * @entry: the element to delete from the list. + * Note: list_empty() on entry does not return true after this, the entry is + * in an undefined state. + */ +static inline void list_del(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); + entry->next = LIST_POISON1; + entry->prev = LIST_POISON2; +} + +/** + * list_replace - replace old entry by new one + * @old : the element to be replaced + * @new : the new element to insert + * + * If @old was empty, it will be overwritten. + */ +static inline void list_replace(struct list_head *old, + struct list_head *new) +{ + new->next = old->next; + new->next->prev = new; + new->prev = old->prev; + new->prev->next = new; +} + +static inline void list_replace_init(struct list_head *old, + struct list_head *new) +{ + list_replace(old, new); + INIT_LIST_HEAD(old); +} + +/** + * list_del_init - deletes entry from list and reinitialize it. + * @entry: the element to delete from the list. + */ +static inline void list_del_init(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); + INIT_LIST_HEAD(entry); +} + +/** + * list_move - delete from one list and add as another's head + * @list: the entry to move + * @head: the head that will precede our entry + */ +static inline void list_move(struct list_head *list, struct list_head *head) +{ + __list_del(list->prev, list->next); + list_add(list, head); +} + +/** + * list_move_tail - delete from one list and add as another's tail + * @list: the entry to move + * @head: the head that will follow our entry + */ +static inline void list_move_tail(struct list_head *list, + struct list_head *head) +{ + __list_del(list->prev, list->next); + list_add_tail(list, head); +} + +/** + * list_is_last - tests whether @list is the last entry in list @head + * @list: the entry to test + * @head: the head of the list + */ +static inline int list_is_last(const struct list_head *list, + const struct list_head *head) +{ + return list->next == head; +} + +/** + * list_empty - tests whether a list is empty + * @head: the list to test. + */ +static inline int list_empty(const struct list_head *head) +{ + return head->next == head; +} + +/** + * list_empty_careful - tests whether a list is empty and not being modified + * @head: the list to test + * + * Description: + * tests whether a list is empty _and_ checks that no other CPU might be + * in the process of modifying either member (next or prev) + * + * NOTE: using list_empty_careful() without synchronization + * can only be safe if the only activity that can happen + * to the list entry is list_del_init(). Eg. it cannot be used + * if another CPU could re-list_add() it. + */ +static inline int list_empty_careful(const struct list_head *head) +{ + struct list_head *next = head->next; + return (next == head) && (next == head->prev); +} + +/** + * list_is_singular - tests whether a list has just one entry. + * @head: the list to test. + */ +static inline int list_is_singular(const struct list_head *head) +{ + return !list_empty(head) && (head->next == head->prev); +} + +static inline void __list_splice(const struct list_head *list, + struct list_head *head) +{ + struct list_head *first = list->next; + struct list_head *last = list->prev; + struct list_head *at = head->next; + + first->prev = head; + head->next = first; + + last->next = at; + at->prev = last; +} + +/** + * list_splice - join two lists + * @list: the new list to add. + * @head: the place to add it in the first list. + */ +static inline void list_splice(const struct list_head *list, + struct list_head *head) +{ + if (!list_empty(list)) + __list_splice(list, head); +} + +/** + * list_splice_init - join two lists and reinitialise the emptied list. + * @list: the new list to add. + * @head: the place to add it in the first list. + * + * The list at @list is reinitialised + */ +static inline void list_splice_init(struct list_head *list, + struct list_head *head) +{ + if (!list_empty(list)) { + __list_splice(list, head); + INIT_LIST_HEAD(list); + } +} + +/** + * list_entry - get the struct for this entry + * @ptr: the &struct list_head pointer. + * @type: the type of the struct this is embedded in. + * @member: the name of the list_struct within the struct. + */ +#define list_entry(ptr, type, member) \ + container_of(ptr, type, member) + +/** + * list_first_entry - get the first element from a list + * @ptr: the list head to take the element from. + * @type: the type of the struct this is embedded in. + * @member: the name of the list_struct within the struct. + * + * Note, that list is expected to be not empty. + */ +#define list_first_entry(ptr, type, member) \ + list_entry((ptr)->next, type, member) + +/** + * list_for_each - iterate over a list + * @pos: the &struct list_head to use as a loop cursor. + * @head: the head for your list. + */ +#define list_for_each(pos, head) \ + for (pos = (head)->next; pos != (head); pos = pos->next) + +/** + * list_for_each_prev - iterate over a list backwards + * @pos: the &struct list_head to use as a loop cursor. + * @head: the head for your list. + */ +#define list_for_each_prev(pos, head) \ + for (pos = (head)->prev; pos != (head); pos = pos->prev) + +/** + * list_for_each_safe - iterate over a list safe against removal of list entry + * @pos: the &struct list_head to use as a loop cursor. + * @n: another &struct list_head to use as temporary storage + * @head: the head for your list. + */ +#define list_for_each_safe(pos, n, head) \ + for (pos = (head)->next, n = pos->next; pos != (head); \ + pos = n, n = pos->next) + +/** + * list_for_each_prev_safe - iterate over a list backwards safe against removal of list entry + * @pos: the &struct list_head to use as a loop cursor. + * @n: another &struct list_head to use as temporary storage + * @head: the head for your list. + */ +#define list_for_each_prev_safe(pos, n, head) \ + for (pos = (head)->prev, n = pos->prev; \ + pos != (head); pos = n, n = pos->prev) + +/** + * list_for_each_entry - iterate over list of given type + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry(pos, head, member) \ + for (pos = list_entry((head)->next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = list_entry(pos->member.next, typeof(*pos), member)) + +/** + * list_for_each_entry_reverse - iterate backwards over list of given type. + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry_reverse(pos, head, member) \ + for (pos = list_entry((head)->prev, typeof(*pos), member); \ + &pos->member != (head); \ + pos = list_entry(pos->member.prev, typeof(*pos), member)) + +/** + * list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue() + * @pos: the type * to use as a start point + * @head: the head of the list + * @member: the name of the list_struct within the struct. + * + * Prepares a pos entry for use as a start point in list_for_each_entry_continue(). + */ +#define list_prepare_entry(pos, head, member) \ + ((pos) ? : list_entry(head, typeof(*pos), member)) + +/** + * list_for_each_entry_continue - continue iteration over list of given type + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * Continue to iterate over list of given type, continuing after + * the current position. + */ +#define list_for_each_entry_continue(pos, head, member) \ + for (pos = list_entry(pos->member.next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = list_entry(pos->member.next, typeof(*pos), member)) + +/** + * list_for_each_entry_continue_reverse - iterate backwards from the given point + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * Start to iterate over list of given type backwards, continuing after + * the current position. + */ +#define list_for_each_entry_continue_reverse(pos, head, member) \ + for (pos = list_entry(pos->member.prev, typeof(*pos), member); \ + &pos->member != (head); \ + pos = list_entry(pos->member.prev, typeof(*pos), member)) + +/** + * list_for_each_entry_from - iterate over list of given type from the current point + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * Iterate over list of given type, continuing from current position. + */ +#define list_for_each_entry_from(pos, head, member) \ + for (; &pos->member != (head); \ + pos = list_entry(pos->member.next, typeof(*pos), member)) + +/** + * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry + * @pos: the type * to use as a loop cursor. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry_safe(pos, n, head, member) \ + for (pos = list_entry((head)->next, typeof(*pos), member), \ + n = list_entry(pos->member.next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = n, n = list_entry(n->member.next, typeof(*n), member)) + +/** + * list_for_each_entry_safe_continue + * @pos: the type * to use as a loop cursor. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * Iterate over list of given type, continuing after current point, + * safe against removal of list entry. + */ +#define list_for_each_entry_safe_continue(pos, n, head, member) \ + for (pos = list_entry(pos->member.next, typeof(*pos), member), \ + n = list_entry(pos->member.next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = n, n = list_entry(n->member.next, typeof(*n), member)) + +/** + * list_for_each_entry_safe_from + * @pos: the type * to use as a loop cursor. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * Iterate over list of given type from current point, safe against + * removal of list entry. + */ +#define list_for_each_entry_safe_from(pos, n, head, member) \ + for (n = list_entry(pos->member.next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = n, n = list_entry(n->member.next, typeof(*n), member)) + +/** + * list_for_each_entry_safe_reverse + * @pos: the type * to use as a loop cursor. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + * + * Iterate backwards over list of given type, safe against removal + * of list entry. + */ +#define list_for_each_entry_safe_reverse(pos, n, head, member) \ + for (pos = list_entry((head)->prev, typeof(*pos), member), \ + n = list_entry(pos->member.prev, typeof(*pos), member); \ + &pos->member != (head); \ + pos = n, n = list_entry(n->member.prev, typeof(*n), member)) + +#endif /*_OSSP_UTIL_H*/ diff --git a/src/mod/endpoints/mod_skypopen/osscuse/ossp.c b/src/mod/endpoints/mod_skypopen/osscuse/ossp.c new file mode 100644 index 0000000000..96f98fa37a --- /dev/null +++ b/src/mod/endpoints/mod_skypopen/osscuse/ossp.c @@ -0,0 +1,83 @@ +/* + * ossp - OSS Proxy: emulate OSS device using CUSE + * + * Copyright (C) 2008-2010 SUSE Linux Products GmbH + * Copyright (C) 2008-2010 Tejun Heo + * + * This file is released under the GPLv2. + */ + +#include "ossp.h" + +const struct ossp_arg_size ossp_arg_sizes[OSSP_NR_OPCODES] = { + [OSSP_MIXER] = { sizeof(struct ossp_mixer_arg), + sizeof(struct ossp_mixer_arg), 0 }, + + [OSSP_DSP_OPEN] = { sizeof(struct ossp_dsp_open_arg), 0, 0 }, + [OSSP_DSP_READ] = { sizeof(struct ossp_dsp_rw_arg), 0, 0 }, + [OSSP_DSP_WRITE] = { sizeof(struct ossp_dsp_rw_arg), 0, 0 }, + [OSSP_DSP_POLL] = { sizeof(int), sizeof(unsigned), 0 }, + [OSSP_DSP_MMAP] = { sizeof(struct ossp_dsp_mmap_arg), 0, 0 }, + [OSSP_DSP_MUNMAP] = { sizeof(int), 0, 0 }, + + [OSSP_DSP_RESET] = { 0, 0, 0 }, + [OSSP_DSP_SYNC] = { 0, 0, 0 }, + [OSSP_DSP_POST] = { 0, 0, 0 }, + [OSSP_DSP_GET_RATE] = { 0, sizeof(int), 0 }, + [OSSP_DSP_GET_CHANNELS] = { 0, sizeof(int), 0 }, + [OSSP_DSP_GET_FORMAT] = { 0, sizeof(int), 0 }, + [OSSP_DSP_GET_BLKSIZE] = { 0, sizeof(int), 0 }, + [OSSP_DSP_GET_FORMATS] = { 0, sizeof(int), 0 }, + [OSSP_DSP_SET_RATE] = { sizeof(int), sizeof(int), 0 }, + [OSSP_DSP_SET_CHANNELS] = { sizeof(int), sizeof(int), 0 }, + [OSSP_DSP_SET_FORMAT] = { sizeof(int), sizeof(int), 0 }, + [OSSP_DSP_SET_SUBDIVISION] = { sizeof(int), sizeof(int), 0 }, + [OSSP_DSP_SET_FRAGMENT] = { sizeof(int), 0, 0 }, + [OSSP_DSP_GET_TRIGGER] = { 0, sizeof(int), 0 }, + [OSSP_DSP_SET_TRIGGER] = { sizeof(int), 0, 0 }, + [OSSP_DSP_GET_OSPACE] = { 0, sizeof(struct audio_buf_info), 0 }, + [OSSP_DSP_GET_ISPACE] = { 0, sizeof(struct audio_buf_info), 0 }, + [OSSP_DSP_GET_OPTR] = { 0, sizeof(struct count_info), 0 }, + [OSSP_DSP_GET_IPTR] = { 0, sizeof(struct count_info), 0 }, + [OSSP_DSP_GET_ODELAY] = { 0, sizeof(int), 0 }, +}; + +const char *ossp_cmd_str[OSSP_NR_OPCODES] = { + [OSSP_MIXER] = "MIXER", + + [OSSP_DSP_OPEN] = "OPEN", + [OSSP_DSP_READ] = "READ", + [OSSP_DSP_WRITE] = "WRITE", + [OSSP_DSP_POLL] = "POLL", + [OSSP_DSP_MMAP] = "MMAP", + [OSSP_DSP_MUNMAP] = "MUNMAP", + + [OSSP_DSP_RESET] = "RESET", + [OSSP_DSP_SYNC] = "SYNC", + [OSSP_DSP_POST] = "POST", + + [OSSP_DSP_GET_RATE] = "GET_RATE", + [OSSP_DSP_GET_CHANNELS] = "GET_CHANNELS", + [OSSP_DSP_GET_FORMAT] = "GET_FORMAT", + [OSSP_DSP_GET_BLKSIZE] = "GET_BLKSIZE", + [OSSP_DSP_GET_FORMATS] = "GET_FORMATS", + [OSSP_DSP_SET_RATE] = "SET_RATE", + [OSSP_DSP_SET_CHANNELS] = "SET_CHANNELS", + [OSSP_DSP_SET_FORMAT] = "SET_FORMAT", + [OSSP_DSP_SET_SUBDIVISION] = "SET_BUSDIVISION", + + [OSSP_DSP_SET_FRAGMENT] = "SET_FRAGMENT", + [OSSP_DSP_GET_TRIGGER] = "GET_TRIGGER", + [OSSP_DSP_SET_TRIGGER] = "SET_TRIGGER", + [OSSP_DSP_GET_OSPACE] = "GET_OSPACE", + [OSSP_DSP_GET_ISPACE] = "GET_ISPACE", + [OSSP_DSP_GET_OPTR] = "GET_OPTR", + [OSSP_DSP_GET_IPTR] = "GET_IPTR", + [OSSP_DSP_GET_ODELAY] = "GET_ODELAY", +}; + +const char *ossp_notify_str[OSSP_NR_NOTIFY_OPCODES] = { + [OSSP_NOTIFY_POLL] = "POLL", + [OSSP_NOTIFY_OBITUARY] = "OBITUARY", + [OSSP_NOTIFY_VOLCHG] = "VOLCHG", +}; diff --git a/src/mod/endpoints/mod_skypopen/osscuse/ossp.h b/src/mod/endpoints/mod_skypopen/osscuse/ossp.h new file mode 100644 index 0000000000..9d03e63adf --- /dev/null +++ b/src/mod/endpoints/mod_skypopen/osscuse/ossp.h @@ -0,0 +1,117 @@ +/* + * ossp - OSS Proxy: emulate OSS device using CUSE + * + * Copyright (C) 2008-2010 SUSE Linux Products GmbH + * Copyright (C) 2008-2010 Tejun Heo + * + * This file is released under the GPLv2. + */ + +#ifndef _OSSP_H +#define _OSSP_H + +#include +#include +#include + +#define OSSP_VERSION "1.3.2" +#define OSSP_CMD_MAGIC 0xdeadbeef +#define OSSP_REPLY_MAGIC 0xbeefdead +#define OSSP_NOTIFY_MAGIC 0xbebebebe + +#define PLAY 0 +#define REC 1 +#define LEFT 0 +#define RIGHT 1 + +enum ossp_opcode { + OSSP_MIXER, + + OSSP_DSP_OPEN, + OSSP_DSP_READ, + OSSP_DSP_WRITE, + OSSP_DSP_POLL, + OSSP_DSP_MMAP, + OSSP_DSP_MUNMAP, + + OSSP_DSP_RESET, + OSSP_DSP_SYNC, + OSSP_DSP_POST, + + OSSP_DSP_GET_RATE, + OSSP_DSP_GET_CHANNELS, + OSSP_DSP_GET_FORMAT, + OSSP_DSP_GET_BLKSIZE, + OSSP_DSP_GET_FORMATS, + OSSP_DSP_SET_RATE, + OSSP_DSP_SET_CHANNELS, + OSSP_DSP_SET_FORMAT, + OSSP_DSP_SET_SUBDIVISION, + + OSSP_DSP_SET_FRAGMENT, + OSSP_DSP_GET_TRIGGER, + OSSP_DSP_SET_TRIGGER, + OSSP_DSP_GET_OSPACE, + OSSP_DSP_GET_ISPACE, + OSSP_DSP_GET_OPTR, + OSSP_DSP_GET_IPTR, + OSSP_DSP_GET_ODELAY, + + OSSP_NR_OPCODES, +}; + +enum ossp_notify_opcode { + OSSP_NOTIFY_POLL, + OSSP_NOTIFY_OBITUARY, + OSSP_NOTIFY_VOLCHG, + + OSSP_NR_NOTIFY_OPCODES, +}; + +struct ossp_mixer_arg { + int vol[2][2]; +}; + +struct ossp_dsp_open_arg { + int flags; + pid_t opener_pid; +}; + +struct ossp_dsp_rw_arg { + unsigned nonblock:1; +}; + +struct ossp_dsp_mmap_arg { + int dir; + size_t size; +}; + +struct ossp_cmd { + unsigned magic; + enum ossp_opcode opcode; + size_t din_size; + size_t dout_size; +}; + +struct ossp_reply { + unsigned magic; + int result; + size_t dout_size; /* <= cmd.data_in_size */ +}; + +struct ossp_notify { + unsigned magic; + enum ossp_notify_opcode opcode; +}; + +struct ossp_arg_size { + ssize_t carg_size; + ssize_t rarg_size; + unsigned has_fd:1; +}; + +extern const struct ossp_arg_size ossp_arg_sizes[OSSP_NR_OPCODES]; +extern const char *ossp_cmd_str[OSSP_NR_OPCODES]; +extern const char *ossp_notify_str[OSSP_NR_NOTIFY_OPCODES]; + +#endif /* _OSSP_H */ diff --git a/src/mod/endpoints/mod_skypopen/osscuse/osspd.c b/src/mod/endpoints/mod_skypopen/osscuse/osspd.c new file mode 100644 index 0000000000..dc9f36a09b --- /dev/null +++ b/src/mod/endpoints/mod_skypopen/osscuse/osspd.c @@ -0,0 +1,2374 @@ +/* + * osspd - OSS Proxy Daemon: emulate OSS device using CUSE + * + * Copyright (C) 2008-2010 SUSE Linux Products GmbH + * Copyright (C) 2008-2010 Tejun Heo + * + * This file is released under the GPLv2. + */ +#undef GIOVANNI + +#define FUSE_USE_VERSION 28 +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ossp.h" +#include "ossp-util.h" + +/* + * MMAP support needs to be updated to the new fuse MMAP API. Disable + * it for the time being. + */ +#warning mmap support disabled for now +/* #define OSSP_MMAP */ + +#define DFL_MIXER_NAME "mixer" +#define DFL_DSP_NAME "dsp" +#define DFL_ADSP_NAME "adsp" +#define STRFMT "S[%u/%d]" +#define STRID(os) os->id, os->pid + +#define dbg1_os(os, fmt, args...) dbg1(STRFMT" "fmt, STRID(os) , ##args) +#define dbg0_os(os, fmt, args...) dbg0(STRFMT" "fmt, STRID(os) , ##args) +#define warn_os(os, fmt, args...) warn(STRFMT" "fmt, STRID(os) , ##args) +#define err_os(os, fmt, args...) err(STRFMT" "fmt, STRID(os) , ##args) +#define warn_ose(os, err, fmt, args...) \ + warn_e(err, STRFMT" "fmt, STRID(os) , ##args) +#define err_ose(os, err, fmt, args...) \ + err_e(err, STRFMT" "fmt, STRID(os) , ##args) + +enum { + SNDRV_OSS_VERSION = ((3<<16)|(8<<8)|(1<<4)|(0)), /* 3.8.1a */ + DFL_MIXER_MAJOR = 14, + DFL_MIXER_MINOR = 0, + DFL_DSP_MAJOR = 14, + DFL_DSP_MINOR = 3, + DFL_ADSP_MAJOR = 14, + DFL_ADSP_MINOR = 12, + DFL_MAX_STREAMS = 128, + MIXER_PUT_DELAY = 600, /* 10 mins */ + /* DSPS_MMAP_SIZE / 2 must be multiple of SHMLBA */ + DSPS_MMAP_SIZE = 2 * (512 << 10), /* 512k for each dir */ +}; + +struct ossp_uid_cnt { + struct list_head link; + uid_t uid; + unsigned nr_os; +}; + +struct ossp_mixer { + pid_t pgrp; + struct list_head link; + struct list_head delayed_put_link; + unsigned refcnt; + /* the following two fields are protected by mixer_mutex */ + int vol[2][2]; + int modify_counter; + time_t put_expires; +}; + +struct ossp_mixer_cmd { + struct ossp_mixer *mixer; + struct ossp_mixer_arg set; + int out_dir; + int rvol; +}; + +#define for_each_vol(i, j) \ + for (i = 0, j = 0; i < 2; j += i << 1, j++, i = j >> 1, j &= 1) + +struct ossp_stream { + unsigned id; /* stream ID */ + struct list_head link; + struct list_head pgrp_link; + struct list_head notify_link; + unsigned refcnt; + pthread_mutex_t cmd_mutex; + pthread_mutex_t mmap_mutex; + struct fuse_pollhandle *ph; + + /* stream owner info */ + pid_t pid; + pid_t pgrp; + uid_t uid; + gid_t gid; + + /* slave info */ + pid_t slave_pid; + int cmd_fd; + int notify_tx; + int notify_rx; + + /* the following dead flag is set asynchronously, keep it separate. */ + int dead; + + /* stream mixer state, protected by mixer_mutex */ + int mixer_pending; + int vol[2][2]; + int vol_set[2][2]; + + off_t mmap_off; + size_t mmap_size; + + struct ossp_uid_cnt *ucnt; + struct fuse_session *se; /* associated fuse session */ + struct ossp_mixer *mixer; +}; + +struct ossp_dsp_stream { + struct ossp_stream os; + unsigned rw; + unsigned mmapped; + int nonblock; +}; + +#define os_to_dsps(_os) container_of(_os, struct ossp_dsp_stream, os) + +static unsigned max_streams; +static unsigned umax_streams; +static unsigned hashtbl_size; +static char dsp_slave_path[PATH_MAX]; + +static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t mixer_mutex = PTHREAD_MUTEX_INITIALIZER; +static unsigned long *os_id_bitmap; +static unsigned nr_mixers; +static struct list_head *mixer_tbl; /* indexed by PGRP */ +static struct list_head *os_tbl; /* indexed by ID */ +static struct list_head *os_pgrp_tbl; /* indexed by PGRP */ +static struct list_head *os_notify_tbl; /* indexed by notify fd */ +static LIST_HEAD(uid_cnt_list); +static int notify_epfd; /* epoll used to monitor notify fds */ +static pthread_t notify_poller_thread; +static pthread_t slave_reaper_thread; +static pthread_t mixer_delayed_put_thread; +static pthread_t cuse_mixer_thread; +static pthread_t cuse_adsp_thread; +static pthread_cond_t notify_poller_kill_wait = PTHREAD_COND_INITIALIZER; +static pthread_cond_t slave_reaper_wait = PTHREAD_COND_INITIALIZER; +static LIST_HEAD(slave_corpse_list); +static LIST_HEAD(mixer_delayed_put_head); /* delayed reference */ +static pthread_cond_t mixer_delayed_put_cond = PTHREAD_COND_INITIALIZER; + +static int init_wait_fd = -1; +static int exit_on_idle; +static struct fuse_session *mixer_se; +static struct fuse_session *dsp_se; +static struct fuse_session *adsp_se; + +static void put_os(struct ossp_stream *os); + + +/*************************************************************************** + * Accessors + */ + +static struct list_head *mixer_tbl_head(pid_t pid) +{ + return &mixer_tbl[pid % hashtbl_size]; +} + +static struct list_head *os_tbl_head(uint64_t id) +{ + return &os_tbl[id % hashtbl_size]; +} + +static struct list_head *os_pgrp_tbl_head(pid_t pgrp) +{ + return &os_pgrp_tbl[pgrp % hashtbl_size]; +} + +static struct list_head *os_notify_tbl_head(int notify_rx) +{ + return &os_notify_tbl[notify_rx % hashtbl_size]; +} + +static struct ossp_mixer *find_mixer_locked(pid_t pgrp) +{ + struct ossp_mixer *mixer; + + list_for_each_entry(mixer, mixer_tbl_head(pgrp), link) + if (mixer->pgrp == pgrp) + return mixer; + return NULL; +} + +static struct ossp_mixer *find_mixer(pid_t pgrp) +{ + struct ossp_mixer *mixer; + + pthread_mutex_lock(&mutex); + mixer = find_mixer_locked(pgrp); + pthread_mutex_unlock(&mutex); + return mixer; +} + +static struct ossp_stream *find_os(unsigned id) +{ + struct ossp_stream *os, *found = NULL; + + pthread_mutex_lock(&mutex); + list_for_each_entry(os, os_tbl_head(id), link) + if (os->id == id) { + found = os; + break; + } + pthread_mutex_unlock(&mutex); + return found; +} + +static struct ossp_stream *find_os_by_notify_rx(int notify_rx) +{ + struct ossp_stream *os, *found = NULL; + + pthread_mutex_lock(&mutex); + list_for_each_entry(os, os_notify_tbl_head(notify_rx), notify_link) + if (os->notify_rx == notify_rx) { + found = os; + break; + } + pthread_mutex_unlock(&mutex); + return found; +} + + +/*************************************************************************** + * Command and ioctl helpers + */ + +static ssize_t exec_cmd_intern(struct ossp_stream *os, enum ossp_opcode opcode, + const void *carg, size_t carg_size, const void *din, size_t din_size, + void *rarg, size_t rarg_size, void *dout, size_t *dout_sizep, int fd) +{ + size_t dout_size = dout_sizep ? *dout_sizep : 0; + struct ossp_cmd cmd = { .magic = OSSP_CMD_MAGIC, .opcode = opcode, + .din_size = din_size, + .dout_size = dout_size }; + struct iovec iov = { &cmd, sizeof(cmd) }; + struct msghdr msg = { .msg_iov = &iov, .msg_iovlen = 1 }; + struct ossp_reply reply = { }; + char cmsg_buf[CMSG_SPACE(sizeof(fd))]; + char reason[512]; + int rc; + + if (os->dead) + return -EIO; + + //dbg1_os(os, "opcode %s=%d carg=%zu din=%zu rarg=%zu dout=%zu", + //ossp_cmd_str[opcode], opcode, carg_size, din_size, rarg_size, + //dout_size); +#ifndef GIOVANNI +memset(dout, 255, dout_size); +memset(din, 255, din_size); + +#define GIOVA_BLK 3840 +#define GIOVA_SLEEP 40000 +switch(opcode){ + + case 1: //OPEN + reply.result = 0; + break; + case 2: //READ + usleep((GIOVA_SLEEP/GIOVA_BLK)* *dout_sizep); + reply.result = *dout_sizep; + break; + case 3: //WRITE + usleep((GIOVA_SLEEP/GIOVA_BLK)* din_size); + reply.result = din_size; + break; + case 9: //POST + reply.result = -32; + break; + case 13: //GET_BLKSIZE + reply.result = 0; + *(int *)rarg = GIOVA_BLK; + break; + case 14: //GET_FORMATS + reply.result = 0; + *(int *)rarg = 28731; + break; + case 15: //SET_RATE + reply.result = 0; + *(int *)rarg = *(int *) carg; + break; + case 16: //SET_CHANNELS + reply.result = 0; + *(int *)rarg = *(int *) carg; + break; + case 17: //SET_FORMAT + reply.result = 0; + *(int *)rarg = *(int *) carg; + break; + case 19: //SET_FRAGMENT + reply.result = 0; + break; + default: + reply.result = 0; + break; +} +#endif // GIOVANNI + +#ifdef GIOVANNI + if (fd >= 0) { + struct cmsghdr *cmsg; + + msg.msg_control = cmsg_buf; + msg.msg_controllen = sizeof(cmsg_buf); + cmsg = CMSG_FIRSTHDR(&msg); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + cmsg->cmsg_len = CMSG_LEN(sizeof(fd)); + *(int *)CMSG_DATA(cmsg) = fd; + msg.msg_controllen = cmsg->cmsg_len; + } + + if (sendmsg(os->cmd_fd, &msg, 0) <= 0) { + rc = -errno; + snprintf(reason, sizeof(reason), "command sendmsg failed: %s", + strerror(-rc)); + goto fail; + } + + if ((rc = write_fill(os->cmd_fd, carg, carg_size)) < 0 || + (rc = write_fill(os->cmd_fd, din, din_size)) < 0) { + snprintf(reason, sizeof(reason), + "can't tranfer command argument and/or data: %s", + strerror(-rc)); + goto fail; + } + if ((rc = read_fill(os->cmd_fd, &reply, sizeof(reply))) < 0) { + snprintf(reason, sizeof(reason), "can't read reply: %s", + strerror(-rc)); + goto fail; + } + + if (reply.magic != OSSP_REPLY_MAGIC) { + snprintf(reason, sizeof(reason), + "reply magic mismatch %x != %x", + reply.magic, OSSP_REPLY_MAGIC); + rc = -EINVAL; + goto fail; + } + + if (reply.result < 0) + goto out_unlock; + + if (reply.dout_size > dout_size) { + snprintf(reason, sizeof(reason), + "data out size overflow %zu > %zu", + reply.dout_size, dout_size); + rc = -EINVAL; + goto fail; + } + + dout_size = reply.dout_size; + if (dout_sizep) + *dout_sizep = dout_size; + + if ((rc = read_fill(os->cmd_fd, rarg, rarg_size)) < 0 || + (rc = read_fill(os->cmd_fd, dout, dout_size)) < 0) { + snprintf(reason, sizeof(reason), "can't read data out: %s", + strerror(-rc)); + goto fail; + } + +#endif // GIOVANNI + +out_unlock: + //dbg1_os(os, " completed, result=%d dout=%zu", + //reply.result, dout_size); + +//if(rarg) + //dbg1_os(os, " 2 %s=%d completed, result=%d dout=%zu carg=%d rarg=%d", ossp_cmd_str[opcode], opcode, + //reply.result, dout_size, carg ? *(int *) carg : 666, *(int *)rarg); + return reply.result; + +fail: + warn_os(os, "communication with slave failed (%s)", reason); + os->dead = 1; + return rc; +} + +static ssize_t exec_cmd(struct ossp_stream *os, enum ossp_opcode opcode, + const void *carg, size_t carg_size, const void *din, size_t din_size, + void *rarg, size_t rarg_size, void *dout, size_t *dout_sizep, int fd) +{ + int is_mixer; + int i, j; + ssize_t ret, mret; + + /* mixer command is handled exlicitly below */ + is_mixer = opcode == OSSP_MIXER; + if (is_mixer) { + ret = -pthread_mutex_trylock(&os->cmd_mutex); + if (ret) + return ret; + } else { + pthread_mutex_lock(&os->cmd_mutex); + + ret = exec_cmd_intern(os, opcode, carg, carg_size, + din, din_size, rarg, rarg_size, + dout, dout_sizep, fd); + } + + /* lazy mixer handling */ + pthread_mutex_lock(&mixer_mutex); + + if (os->mixer_pending) { + struct ossp_mixer_arg marg; + repeat_mixer: + /* we have mixer command pending */ + memcpy(marg.vol, os->vol_set, sizeof(os->vol_set)); + memset(os->vol_set, -1, sizeof(os->vol_set)); + + pthread_mutex_unlock(&mixer_mutex); + mret = exec_cmd_intern(os, OSSP_MIXER, &marg, sizeof(marg), + NULL, 0, &marg, sizeof(marg), NULL, NULL, + -1); + pthread_mutex_lock(&mixer_mutex); + + /* was there mixer set request while executing mixer command? */ + for_each_vol(i, j) + if (os->vol_set[i][j] >= 0) + goto repeat_mixer; + + /* update internal mixer state */ + if (mret == 0) { + for_each_vol(i, j) { + if (marg.vol[i][j] >= 0) { + if (os->vol[i][j] != marg.vol[i][j]) + os->mixer->modify_counter++; + os->vol[i][j] = marg.vol[i][j]; + } + } + } + os->mixer_pending = 0; + } + + pthread_mutex_unlock(&os->cmd_mutex); + + /* + * mixer mutex must be released after cmd_mutex so that + * exec_mixer_cmd() can guarantee that mixer_pending flags + * will be handled immediately or when the currently + * in-progress command completes. + */ + pthread_mutex_unlock(&mixer_mutex); + + return is_mixer ? mret : ret; +} + +static ssize_t exec_simple_cmd(struct ossp_stream *os, + enum ossp_opcode opcode, void *carg, void *rarg) +{ + return exec_cmd(os, opcode, + carg, ossp_arg_sizes[opcode].carg_size, NULL, 0, + rarg, ossp_arg_sizes[opcode].rarg_size, NULL, NULL, -1); +} + +static int ioctl_prep_uarg(fuse_req_t req, void *in, size_t in_sz, void *out, + size_t out_sz, void *uarg, const void *in_buf, + size_t in_bufsz, size_t out_bufsz) +{ + struct iovec in_iov = { }, out_iov = { }; + int retry = 0; + + if (in) { + if (!in_bufsz) { + in_iov.iov_base = uarg; + in_iov.iov_len = in_sz; + retry = 1; + } else { + assert(in_bufsz == in_sz); + memcpy(in, in_buf, in_sz); + } + } + + if (out) { + if (!out_bufsz) { + out_iov.iov_base = uarg; + out_iov.iov_len = out_sz; + retry = 1; + } else + assert(out_bufsz == out_sz); + } + + if (retry) + fuse_reply_ioctl_retry(req, &in_iov, 1, &out_iov, 1); + + return retry; +} + +#define PREP_UARG(inp, outp) do { \ + if (ioctl_prep_uarg(req, (inp), sizeof(*(inp)), \ + (outp), sizeof(*(outp)), uarg, \ + in_buf, in_bufsz, out_bufsz)) \ + return; \ +} while (0) + +#define IOCTL_RETURN(result, outp) do { \ + if ((outp) != NULL) \ + fuse_reply_ioctl(req, result, (outp), sizeof(*(outp))); \ + else \ + fuse_reply_ioctl(req, result, NULL, 0); \ + return; \ +} while (0) + + +/*************************************************************************** + * Mixer implementation + */ + +static void put_mixer_real(struct ossp_mixer *mixer) +{ + if (!--mixer->refcnt) { + dbg0("DESTROY mixer(%d)", mixer->pgrp); + list_del_init(&mixer->link); + list_del_init(&mixer->delayed_put_link); + free(mixer); + nr_mixers--; + + /* + * If exit_on_idle, mixer for pgrp0 is touched during + * init and each stream has mixer attached. As mixers + * are destroyed after they have been idle for + * MIXER_PUT_DELAY seconds, we can use it for idle + * detection. Note that this might race with + * concurrent open. The race is inherent. + */ + if (exit_on_idle && !nr_mixers) { + info("idle, exiting"); + exit(0); + } + } +} + +static struct ossp_mixer *get_mixer(pid_t pgrp) +{ + struct ossp_mixer *mixer; + + pthread_mutex_lock(&mutex); + + /* is there a matching one? */ + mixer = find_mixer_locked(pgrp); + if (mixer) { + if (list_empty(&mixer->delayed_put_link)) + mixer->refcnt++; + else + list_del_init(&mixer->delayed_put_link); + goto out_unlock; + } + + /* reap delayed put list if there are too many mixers */ + while (nr_mixers > 2 * max_streams && + !list_empty(&mixer_delayed_put_head)) { + struct ossp_mixer *mixer = + list_first_entry(&mixer_delayed_put_head, + struct ossp_mixer, delayed_put_link); + + assert(mixer->refcnt == 1); + put_mixer_real(mixer); + } + + /* create a new one */ + mixer = calloc(1, sizeof(*mixer)); + if (!mixer) { + warn("failed to allocate mixer for %d", pgrp); + mixer = NULL; + goto out_unlock; + } + + mixer->pgrp = pgrp; + INIT_LIST_HEAD(&mixer->link); + INIT_LIST_HEAD(&mixer->delayed_put_link); + mixer->refcnt = 1; + memset(mixer->vol, -1, sizeof(mixer->vol)); + + list_add(&mixer->link, mixer_tbl_head(pgrp)); + nr_mixers++; + dbg0("CREATE mixer(%d)", pgrp); + +out_unlock: + pthread_mutex_unlock(&mutex); + return mixer; +} + +static void put_mixer(struct ossp_mixer *mixer) +{ + pthread_mutex_lock(&mutex); + + if (mixer) { + if (mixer->refcnt == 1) { + struct timespec ts; + + clock_gettime(CLOCK_REALTIME, &ts); + mixer->put_expires = ts.tv_sec + MIXER_PUT_DELAY; + list_add_tail(&mixer->delayed_put_link, + &mixer_delayed_put_head); + pthread_cond_signal(&mixer_delayed_put_cond); + } else + put_mixer_real(mixer); + } + + pthread_mutex_unlock(&mutex); +} + +static void *mixer_delayed_put_worker(void *arg) +{ + struct ossp_mixer *mixer; + struct timespec ts; + time_t now; + + pthread_mutex_lock(&mutex); +again: + clock_gettime(CLOCK_REALTIME, &ts); + now = ts.tv_sec; + + mixer = NULL; + while (!list_empty(&mixer_delayed_put_head)) { + mixer = list_first_entry(&mixer_delayed_put_head, + struct ossp_mixer, delayed_put_link); + + if (now <= mixer->put_expires) + break; + + assert(mixer->refcnt == 1); + put_mixer_real(mixer); + mixer = NULL; + } + + if (mixer) { + ts.tv_sec = mixer->put_expires + 1; + pthread_cond_timedwait(&mixer_delayed_put_cond, &mutex, &ts); + } else + pthread_cond_wait(&mixer_delayed_put_cond, &mutex); + + goto again; +} + +static void init_mixer_cmd(struct ossp_mixer_cmd *mxcmd, + struct ossp_mixer *mixer) +{ + memset(mxcmd, 0, sizeof(*mxcmd)); + memset(&mxcmd->set.vol, -1, sizeof(mxcmd->set.vol)); + mxcmd->mixer = mixer; + mxcmd->out_dir = -1; +} + +static int exec_mixer_cmd(struct ossp_mixer_cmd *mxcmd, struct ossp_stream *os) +{ + int i, j, rc; + + /* + * Set pending flags before trying to execute mixer command. + * Combined with lock release order in exec_cmd(), this + * guarantees that the mixer command will be executed + * immediately or when the current command completes. + */ + pthread_mutex_lock(&mixer_mutex); + os->mixer_pending = 1; + for_each_vol(i, j) + if (mxcmd->set.vol[i][j] >= 0) + os->vol_set[i][j] = mxcmd->set.vol[i][j]; + pthread_mutex_unlock(&mixer_mutex); + + rc = exec_simple_cmd(os, OSSP_MIXER, NULL, NULL); + if (rc >= 0) { + dbg0_os(os, "volume set=%d/%d:%d/%d get=%d/%d:%d/%d", + mxcmd->set.vol[PLAY][LEFT], mxcmd->set.vol[PLAY][RIGHT], + mxcmd->set.vol[REC][LEFT], mxcmd->set.vol[REC][RIGHT], + os->vol[PLAY][LEFT], os->vol[PLAY][RIGHT], + os->vol[REC][LEFT], os->vol[REC][RIGHT]); + } else if (rc != -EBUSY) + warn_ose(os, rc, "mixer command failed"); + + return rc; +} + +static void finish_mixer_cmd(struct ossp_mixer_cmd *mxcmd) +{ + struct ossp_mixer *mixer = mxcmd->mixer; + struct ossp_stream *os; + int dir = mxcmd->out_dir; + int vol[2][2] = { }; + int cnt[2][2] = { }; + int i, j; + + pthread_mutex_lock(&mixer_mutex); + + /* get volume of all streams attached to this mixer */ + pthread_mutex_lock(&mutex); + list_for_each_entry(os, os_pgrp_tbl_head(mixer->pgrp), pgrp_link) { + if (os->pgrp != mixer->pgrp) + continue; + for_each_vol(i, j) { + if (os->vol[i][j] < 0) + continue; + vol[i][j] += os->vol[i][j]; + cnt[i][j]++; + } + } + pthread_mutex_unlock(&mutex); + + /* calculate the summary volume values */ + for_each_vol(i, j) { + if (mxcmd->set.vol[i][j] >= 0) + vol[i][j] = mxcmd->set.vol[i][j]; + else if (cnt[i][j]) + vol[i][j] = vol[i][j] / cnt[i][j]; + else if (mixer->vol[i][j] >= 0) + vol[i][j] = mixer->vol[i][j]; + else + vol[i][j] = 100; + + vol[i][j] = min(max(0, vol[i][j]), 100); + } + + if (dir >= 0) + mxcmd->rvol = vol[dir][LEFT] | (vol[dir][RIGHT] << 8); + + pthread_mutex_unlock(&mixer_mutex); +} + +static void mixer_simple_ioctl(fuse_req_t req, struct ossp_mixer *mixer, + unsigned cmd, void *uarg, const void *in_buf, + size_t in_bufsz, size_t out_bufsz, + int *not_minep) +{ + const char *id = "OSS Proxy", *name = "Mixer"; + int i; + + switch (cmd) { + case SOUND_MIXER_INFO: { + struct mixer_info info = { }; + + PREP_UARG(NULL, &info); + strncpy(info.id, id, sizeof(info.id) - 1); + strncpy(info.name, name, sizeof(info.name) - 1); + info.modify_counter = mixer->modify_counter; + IOCTL_RETURN(0, &info); + } + + case SOUND_OLD_MIXER_INFO: { + struct _old_mixer_info info = { }; + + PREP_UARG(NULL, &info); + strncpy(info.id, id, sizeof(info.id) - 1); + strncpy(info.name, name, sizeof(info.name) - 1); + IOCTL_RETURN(0, &info); + } + + case OSS_GETVERSION: + i = SNDRV_OSS_VERSION; + goto puti; + case SOUND_MIXER_READ_DEVMASK: + case SOUND_MIXER_READ_STEREODEVS: + i = SOUND_MASK_PCM | SOUND_MASK_IGAIN; + goto puti; + case SOUND_MIXER_READ_CAPS: + i = SOUND_CAP_EXCL_INPUT; + goto puti; + case SOUND_MIXER_READ_RECMASK: + case SOUND_MIXER_READ_RECSRC: + i = SOUND_MASK_IGAIN; + goto puti; + puti: + PREP_UARG(NULL, &i); + IOCTL_RETURN(0, &i); + + case SOUND_MIXER_WRITE_RECSRC: + IOCTL_RETURN(0, NULL); + + default: + *not_minep = 1; + return; + } + assert(0); +} + +static void mixer_do_ioctl(fuse_req_t req, struct ossp_mixer *mixer, + unsigned cmd, void *uarg, const void *in_buf, + size_t in_bufsz, size_t out_bufsz) +{ + struct ossp_mixer_cmd mxcmd; + struct ossp_stream *os, **osa; + int not_mine = 0; + int slot = cmd & 0xff, dir; + int nr_os; + int i, rc; + + mixer_simple_ioctl(req, mixer, cmd, uarg, in_buf, in_bufsz, out_bufsz, + ¬_mine); + if (!not_mine) + return; + + rc = -ENXIO; + if (!(cmd & (SIOC_IN | SIOC_OUT))) + goto err; + + /* + * Okay, it's not one of the easy ones. Build mxcmd for + * actual volume control. + */ + if (cmd & SIOC_IN) + PREP_UARG(&i, &i); + else + PREP_UARG(NULL, &i); + + switch (slot) { + case SOUND_MIXER_PCM: + dir = PLAY; + break; + case SOUND_MIXER_IGAIN: + dir = REC; + break; + default: + i = 0; + IOCTL_RETURN(0, &i); + } + + init_mixer_cmd(&mxcmd, mixer); + + if (cmd & SIOC_IN) { + unsigned l, r; + + rc = -EINVAL; + l = i & 0xff; + r = (i >> 8) & 0xff; + if (l > 100 || r > 100) + goto err; + + mixer->vol[dir][LEFT] = mxcmd.set.vol[dir][LEFT] = l; + mixer->vol[dir][RIGHT] = mxcmd.set.vol[dir][RIGHT] = r; + } + mxcmd.out_dir = dir; + + /* + * Apply volume conrol + */ + /* acquire target streams */ + pthread_mutex_lock(&mutex); + osa = calloc(max_streams, sizeof(osa[0])); + if (!osa) { + pthread_mutex_unlock(&mutex); + rc = -ENOMEM; + goto err; + } + + nr_os = 0; + list_for_each_entry(os, os_pgrp_tbl_head(mixer->pgrp), pgrp_link) { + if (os->pgrp == mixer->pgrp) { + osa[nr_os++] = os; + os->refcnt++; + } + } + + pthread_mutex_unlock(&mutex); + + /* execute mxcmd for each stream and put it */ + for (i = 0; i < nr_os; i++) { + exec_mixer_cmd(&mxcmd, osa[i]); + put_os(osa[i]); + } + + finish_mixer_cmd(&mxcmd); + free(osa); + + IOCTL_RETURN(0, out_bufsz ? &mxcmd.rvol : NULL); + +err: + fuse_reply_err(req, -rc); +} + +static void mixer_open(fuse_req_t req, struct fuse_file_info *fi) +{ + pid_t pid = fuse_req_ctx(req)->pid, pgrp; + struct ossp_mixer *mixer; + int rc; + + rc = get_proc_self_info(pid, &pgrp, NULL, 0); + if (rc) { + err_e(rc, "get_proc_self_info(%d) failed", pid); + fuse_reply_err(req, -rc); + return; + } + + mixer = get_mixer(pgrp); + fi->fh = pgrp; + + if (mixer) + fuse_reply_open(req, fi); + else + fuse_reply_err(req, ENOMEM); +} + +static void mixer_ioctl(fuse_req_t req, int signed_cmd, void *uarg, + struct fuse_file_info *fi, unsigned int flags, + const void *in_buf, size_t in_bufsz, size_t out_bufsz) +{ + struct ossp_mixer *mixer; + + mixer = find_mixer(fi->fh); + if (!mixer) { + fuse_reply_err(req, EBADF); + return; + } + + mixer_do_ioctl(req, mixer, signed_cmd, uarg, in_buf, in_bufsz, + out_bufsz); +} + +static void mixer_release(fuse_req_t req, struct fuse_file_info *fi) +{ + struct ossp_mixer *mixer; + + mixer = find_mixer(fi->fh); + if (mixer) { + put_mixer(mixer); + fuse_reply_err(req, 0); + } else + fuse_reply_err(req, EBADF); +} + + +/*************************************************************************** + * Stream implementation + */ + +static int alloc_os(size_t stream_size, size_t mmap_size, pid_t pid, uid_t pgrp, + uid_t uid, gid_t gid, int cmd_sock, + const int *notify, struct fuse_session *se, + struct ossp_stream **osp) +{ + struct ossp_uid_cnt *tmp_ucnt, *ucnt = NULL; + struct ossp_stream *os; + int rc; + + assert(stream_size >= sizeof(struct ossp_stream)); + os = calloc(1, stream_size); + if (!os) + return -ENOMEM; + + INIT_LIST_HEAD(&os->link); + INIT_LIST_HEAD(&os->pgrp_link); + INIT_LIST_HEAD(&os->notify_link); + os->refcnt = 1; + + rc = -pthread_mutex_init(&os->cmd_mutex, NULL); + if (rc) + goto err_free; + + rc = -pthread_mutex_init(&os->mmap_mutex, NULL); + if (rc) + goto err_destroy_cmd_mutex; + + pthread_mutex_lock(&mutex); + + list_for_each_entry(tmp_ucnt, &uid_cnt_list, link) + if (tmp_ucnt->uid == uid) { + ucnt = tmp_ucnt; + break; + } + if (!ucnt) { + rc = -ENOMEM; + ucnt = calloc(1, sizeof(*ucnt)); + if (!ucnt) + goto err_unlock; + ucnt->uid = uid; + list_add(&ucnt->link, &uid_cnt_list); + } + + rc = -EBUSY; + if (ucnt->nr_os + 1 > umax_streams) + goto err_unlock; + + /* everything looks fine, allocate id and init stream */ + rc = -EBUSY; + os->id = find_next_zero_bit(os_id_bitmap, max_streams, 0); + if (os->id >= max_streams) + goto err_unlock; + __set_bit(os->id, os_id_bitmap); + + os->cmd_fd = cmd_sock; + os->notify_tx = notify[1]; + os->notify_rx = notify[0]; + os->pid = pid; + os->pgrp = pgrp; + os->uid = uid; + os->gid = gid; + if (mmap_size) { + os->mmap_off = os->id * mmap_size; + os->mmap_size = mmap_size; + } + os->ucnt = ucnt; + os->se = se; + + memset(os->vol, -1, sizeof(os->vol)); + memset(os->vol_set, -1, sizeof(os->vol)); + + list_add(&os->link, os_tbl_head(os->id)); + list_add(&os->pgrp_link, os_pgrp_tbl_head(os->pgrp)); + + ucnt->nr_os++; + *osp = os; + pthread_mutex_unlock(&mutex); + return 0; + +err_unlock: + pthread_mutex_unlock(&mutex); + pthread_mutex_destroy(&os->mmap_mutex); +err_destroy_cmd_mutex: + pthread_mutex_destroy(&os->cmd_mutex); +err_free: + free(os); + return rc; +} + +static void shutdown_notification(struct ossp_stream *os) +{ + struct ossp_notify obituary = { .magic = OSSP_NOTIFY_MAGIC, + .opcode = OSSP_NOTIFY_OBITUARY }; + ssize_t ret; + + /* + * Shutdown notification for this stream. We politely ask + * notify_poller to shut the receive side down to avoid racing + * with it. + */ + while (os->notify_rx >= 0) { + ret = write(os->notify_tx, &obituary, sizeof(obituary)); + if (ret <= 0) { + if (ret == 0) + warn_os(os, "unexpected EOF on notify_tx"); + else if (errno != EPIPE) + warn_ose(os, -errno, + "unexpected error on notify_tx"); + close(os->notify_rx); + os->notify_rx = -1; + break; + } + + if (ret != sizeof(obituary)) + warn_os(os, "short transfer on notify_tx"); + pthread_cond_wait(¬ify_poller_kill_wait, &mutex); + } +} + +static void put_os(struct ossp_stream *os) +{ + if (!os) + return; + + pthread_mutex_lock(&mutex); + + assert(os->refcnt); + if (--os->refcnt) { + pthread_mutex_unlock(&mutex); + return; + } + + os->dead = 1; + shutdown_notification(os); + + dbg0_os(os, "DESTROY"); + + list_del_init(&os->link); + list_del_init(&os->pgrp_link); + list_del_init(&os->notify_link); + os->ucnt->nr_os--; + + pthread_mutex_unlock(&mutex); + + close(os->cmd_fd); + close(os->notify_tx); + put_mixer(os->mixer); + pthread_mutex_destroy(&os->cmd_mutex); + pthread_mutex_destroy(&os->mmap_mutex); + + pthread_mutex_lock(&mutex); + dbg1_os(os, "stream dead, requesting reaping"); + list_add_tail(&os->link, &slave_corpse_list); + pthread_cond_signal(&slave_reaper_wait); + pthread_mutex_unlock(&mutex); +} + +static void set_extra_env(pid_t pid) +{ + char procenviron[32]; + const int step = 1024; + char *data = malloc(step + 1); + int ofs = 0; + int fd; + int ret; + + if (!data) + return; + + sprintf(procenviron, "/proc/%d/environ", pid); + fd = open(procenviron, O_RDONLY); + if (fd < 0) + return; + + /* + * There should really be a 'read whole file to a newly allocated + * buffer' function. + */ + while ((ret = read(fd, data + ofs, step)) > 0) { + char *newdata; + ofs += ret; + newdata = realloc(data, ofs + step + 1); + if (!newdata) { + ret = -1; + break; + } + data = newdata; + } + if (ret == 0) { + char *ptr = data; + /* Append the extra 0 for end condition */ + data[ofs] = 0; + + while ((ret = strlen(ptr)) > 0) { + /* + * Copy all PULSE variables and DISPLAY so that + * ssh -X remotehost 'mplayer -ao oss' will work + */ + if (!strncmp(ptr, "DISPLAY=", 8) || + !strncmp(ptr, "PULSE_", 6)) + putenv(ptr); + ptr += ret + 1; + } + } + + free(data); + close(fd); +} + +#ifndef GIOVANNI +int contapid = 13000; +#endif// GIOVANNI + +static int create_os(const char *slave_path, + size_t stream_size, size_t mmap_size, + pid_t pid, pid_t pgrp, uid_t uid, gid_t gid, + struct fuse_session *se, struct ossp_stream **osp) +{ + static pthread_mutex_t create_mutex = PTHREAD_MUTEX_INITIALIZER; + int cmd_sock[2] = { -1, -1 }; + int notify_sock[2] = { -1, -1 }; + struct ossp_stream *os = NULL; + struct epoll_event ev = { }; + int i, rc; + + /* + * Only one thread can be creating a stream. This is to avoid + * leaking unwanted fds into slaves. + */ + pthread_mutex_lock(&create_mutex); + + /* prepare communication channels */ + if (socketpair(AF_UNIX, SOCK_STREAM, 0, cmd_sock) || + socketpair(AF_UNIX, SOCK_STREAM, 0, notify_sock)) { + rc = -errno; + warn_e(rc, "failed to create slave command channel"); + goto close_all; + } + + if (fcntl(notify_sock[0], F_SETFL, O_NONBLOCK) < 0) { + rc = -errno; + warn_e(rc, "failed to set NONBLOCK on notify sock"); + goto close_all; + } + + /* + * Alloc stream which will be responsible for all server side + * resources from now on. + */ + rc = alloc_os(stream_size, mmap_size, pid, pgrp, uid, gid, cmd_sock[0], + notify_sock, se, &os); + if (rc) { + warn_e(rc, "failed to allocate stream for %d", pid); + goto close_all; + } + + rc = -ENOMEM; + os->mixer = get_mixer(pgrp); + if (!os->mixer) + goto put_os; + + /* + * Register notification. If successful, notify_poller has + * custody of notify_rx fd. + */ + pthread_mutex_lock(&mutex); + list_add(&os->notify_link, os_notify_tbl_head(os->notify_rx)); + pthread_mutex_unlock(&mutex); + +#ifndef GIOVANNI + os->slave_pid = contapid; + contapid++; + if(contapid > 30000) + contapid=13000; +#endif //GIOVANNI + +//#ifdef GIOVANNI + ev.events = EPOLLIN; + ev.data.fd = notify_sock[0]; + if (epoll_ctl(notify_epfd, EPOLL_CTL_ADD, notify_sock[0], &ev)) { + /* + * Without poller watching this notify sock, poller + * shutdown sequence in shutdown_notification() can't + * be used. Kill notification rx manually. + */ + rc = -errno; + warn_ose(os, rc, "failed to add notify epoll"); + close(os->notify_rx); + os->notify_rx = -1; + goto put_os; + } + + /* start slave */ + os->slave_pid = fork(); + if (os->slave_pid < 0) { + rc = -errno; + warn_ose(os, rc, "failed to fork slave"); + goto put_os; + } + + if (os->slave_pid == 0) { + /* child */ + char id_str[2][16], fd_str[3][16]; + char mmap_off_str[32], mmap_size_str[32]; + char log_str[16], slave_path_copy[PATH_MAX]; + char *argv[] = { slave_path_copy, "-u", id_str[0], + "-g", id_str[1], "-c", fd_str[0], + "-n", fd_str[1], "-m", fd_str[2], + "-o", mmap_off_str, "-s", mmap_size_str, + "-l", log_str, NULL, NULL }; + struct passwd *pwd; + + /* drop stuff we don't need */ + if (close(cmd_sock[0]) || close(notify_sock[0])) + fatal_e(-errno, "failed to close server pipe fds"); + +#ifdef OSSP_MMAP + if (!mmap_size) + close(fuse_mmap_fd(se)); +#endif + + clearenv(); + pwd = getpwuid(os->uid); + if (pwd) { + setenv("LOGNAME", pwd->pw_name, 1); + setenv("USER", pwd->pw_name, 1); + setenv("HOME", pwd->pw_dir, 1); + } + /* Set extra environment variables from the caller */ + set_extra_env(pid); + + /* prep and exec */ + slave_path_copy[sizeof(slave_path_copy) - 1] = '\0'; + strncpy(slave_path_copy, slave_path, sizeof(slave_path_copy) - 1); + if (slave_path_copy[sizeof(slave_path_copy) - 1] != '\0') { + rc = -errno; + err_ose(os, rc, "slave path too long"); + goto child_fail; + } + + snprintf(id_str[0], sizeof(id_str[0]), "%d", os->uid); + snprintf(id_str[1], sizeof(id_str[0]), "%d", os->gid); + snprintf(fd_str[0], sizeof(fd_str[0]), "%d", cmd_sock[1]); + snprintf(fd_str[1], sizeof(fd_str[1]), "%d", notify_sock[1]); + snprintf(fd_str[2], sizeof(fd_str[2]), "%d", +#ifdef OSSP_MMAP + mmap_size ? fuse_mmap_fd(se) : +#endif + -1); + snprintf(mmap_off_str, sizeof(mmap_off_str), "0x%llx", + (unsigned long long)os->mmap_off); + snprintf(mmap_size_str, sizeof(mmap_size_str), "0x%zx", + mmap_size); + snprintf(log_str, sizeof(log_str), "%d", ossp_log_level); + if (ossp_log_timestamp) + argv[ARRAY_SIZE(argv) - 2] = "-t"; + + execv(slave_path, argv); + rc = -errno; + err_ose(os, rc, "execv failed for <%d>", pid); + child_fail: + _exit(1); + } +//#endif //GIOVANNI + + /* turn on CLOEXEC on all server side fds */ + if (fcntl(os->cmd_fd, F_SETFD, FD_CLOEXEC) < 0 || + fcntl(os->notify_tx, F_SETFD, FD_CLOEXEC) < 0 || + fcntl(os->notify_rx, F_SETFD, FD_CLOEXEC) < 0) { + rc = -errno; + err_ose(os, rc, "failed to set CLOEXEC on server side fds"); + goto put_os; + } + + dbg0_os(os, "CREATE slave=%d %s", os->slave_pid, slave_path); + dbg0_os(os, " client=%d cmd=%d:%d notify=%d:%d mmap=%d:0x%llx:%zu", + pid, cmd_sock[0], cmd_sock[1], notify_sock[0], notify_sock[1], +#ifdef OSSP_MMAP + os->mmap_size ? fuse_mmap_fd(se) : +#endif + -1, + (unsigned long long)os->mmap_off, os->mmap_size); + + *osp = os; + rc = 0; + goto close_client_fds; + +put_os: + put_os(os); +close_client_fds: + close(cmd_sock[1]); + pthread_mutex_unlock(&create_mutex); + return rc; + +close_all: + for (i = 0; i < 2; i++) { + close(cmd_sock[i]); + close(notify_sock[i]); + } + pthread_mutex_unlock(&create_mutex); + return rc; +} + +static void dsp_open_common(fuse_req_t req, struct fuse_file_info *fi, + struct fuse_session *se) +{ + const struct fuse_ctx *fuse_ctx = fuse_req_ctx(req); + struct ossp_dsp_open_arg arg = { }; + struct ossp_stream *os = NULL; + struct ossp_mixer *mixer; + struct ossp_dsp_stream *dsps; + struct ossp_mixer_cmd mxcmd; + pid_t pgrp; + ssize_t ret; + + ret = get_proc_self_info(fuse_ctx->pid, &pgrp, NULL, 0); + if (ret) { + err_e(ret, "get_proc_self_info(%d) failed", fuse_ctx->pid); + goto err; + } + + ret = create_os(dsp_slave_path, sizeof(*dsps), DSPS_MMAP_SIZE, + fuse_ctx->pid, pgrp, fuse_ctx->uid, fuse_ctx->gid, + se, &os); + if (ret) + goto err; + dsps = os_to_dsps(os); + mixer = os->mixer; + + switch (fi->flags & O_ACCMODE) { + case O_WRONLY: + dsps->rw |= 1 << PLAY; + break; + case O_RDONLY: + dsps->rw |= 1 << REC; + break; + case O_RDWR: + dsps->rw |= (1 << PLAY) | (1 << REC); + break; + default: + assert(0); + } + + arg.flags = fi->flags; + arg.opener_pid = os->pid; + ret = exec_simple_cmd(&dsps->os, OSSP_DSP_OPEN, &arg, NULL); + if (ret < 0) { + put_os(os); + goto err; + } + + memcpy(os->vol, mixer->vol, sizeof(os->vol)); + if (os->vol[PLAY][0] >= 0 || os->vol[REC][0] >= 0) { + init_mixer_cmd(&mxcmd, mixer); + memcpy(mxcmd.set.vol, os->vol, sizeof(os->vol)); + exec_mixer_cmd(&mxcmd, os); + finish_mixer_cmd(&mxcmd); + } + + fi->direct_io = 1; + fi->nonseekable = 1; + fi->fh = os->id; + + fuse_reply_open(req, fi); + return; + +err: + fuse_reply_err(req, -ret); +} + +static void dsp_open(fuse_req_t req, struct fuse_file_info *fi) +{ + dsp_open_common(req, fi, dsp_se); +} + +static void adsp_open(fuse_req_t req, struct fuse_file_info *fi) +{ + dsp_open_common(req, fi, adsp_se); +} + +static void dsp_release(fuse_req_t req, struct fuse_file_info *fi) +{ + struct ossp_stream *os; + + os = find_os(fi->fh); + if (os) { + put_os(os); + fuse_reply_err(req, 0); + } else + fuse_reply_err(req, EBADF); +} + +static void dsp_read(fuse_req_t req, size_t size, off_t off, + struct fuse_file_info *fi) +{ + struct ossp_dsp_rw_arg arg = { }; + struct ossp_stream *os; + struct ossp_dsp_stream *dsps; + void *buf = NULL; + ssize_t ret; + + ret = -EBADF; + os = find_os(fi->fh); + if (!os) + goto out; + dsps = os_to_dsps(os); + + ret = -EINVAL; + if (!(dsps->rw & (1 << REC))) + goto out; + + ret = -ENXIO; + if (dsps->mmapped) + goto out; + + ret = -ENOMEM; + buf = malloc(size); + if (!buf) + goto out; + + arg.nonblock = (fi->flags & O_NONBLOCK) || dsps->nonblock; + + ret = exec_cmd(os, OSSP_DSP_READ, &arg, sizeof(arg), + NULL, 0, NULL, 0, buf, &size, -1); +out: + if (ret >= 0) + fuse_reply_buf(req, buf, size); + else + fuse_reply_err(req, -ret); + + free(buf); +} + +static void dsp_write(fuse_req_t req, const char *buf, size_t size, off_t off, + struct fuse_file_info *fi) +{ + struct ossp_dsp_rw_arg arg = { }; + struct ossp_stream *os; + struct ossp_dsp_stream *dsps; + ssize_t ret; + + ret = -EBADF; + os = find_os(fi->fh); + if (!os) + goto out; + dsps = os_to_dsps(os); + + ret = -EINVAL; + if (!(dsps->rw & (1 << PLAY))) + goto out; + + ret = -ENXIO; + if (dsps->mmapped) + goto out; + + arg.nonblock = (fi->flags & O_NONBLOCK) || dsps->nonblock; + + ret = exec_cmd(os, OSSP_DSP_WRITE, &arg, sizeof(arg), + buf, size, NULL, 0, NULL, NULL, -1); +out: + if (ret >= 0) + fuse_reply_write(req, ret); + else + fuse_reply_err(req, -ret); +} + +static void dsp_poll(fuse_req_t req, struct fuse_file_info *fi, + struct fuse_pollhandle *ph) +{ + int notify = ph != NULL; + unsigned revents = 0; + struct ossp_stream *os; + ssize_t ret; + + ret = -EBADF; + os = find_os(fi->fh); + if (!os) + goto out; + + if (ph) { + pthread_mutex_lock(&mutex); + if (os->ph) + fuse_pollhandle_destroy(os->ph); + os->ph = ph; + pthread_mutex_unlock(&mutex); + } + + ret = exec_simple_cmd(os, OSSP_DSP_POLL, ¬ify, &revents); +out: + if (ret >= 0) + fuse_reply_poll(req, revents); + else + fuse_reply_err(req, -ret); +} + +static void dsp_ioctl(fuse_req_t req, int signed_cmd, void *uarg, + struct fuse_file_info *fi, unsigned int flags, + const void *in_buf, size_t in_bufsz, size_t out_bufsz) +{ + /* some ioctl constants are long and has the highest bit set */ + unsigned cmd = signed_cmd; + struct ossp_stream *os; + struct ossp_dsp_stream *dsps; + enum ossp_opcode op; + ssize_t ret; + int i; + + ret = -EBADF; + os = find_os(fi->fh); + if (!os) + goto err; + dsps = os_to_dsps(os); + + /* mixer commands are allowed on DSP devices */ + if (((cmd >> 8) & 0xff) == 'M') { + mixer_do_ioctl(req, os->mixer, cmd, uarg, in_buf, in_bufsz, + out_bufsz); + return; + } + + /* and the rest */ + switch (cmd) { + case OSS_GETVERSION: + i = SNDRV_OSS_VERSION; + PREP_UARG(NULL, &i); + IOCTL_RETURN(0, &i); + + case SNDCTL_DSP_GETCAPS: + i = DSP_CAP_DUPLEX | DSP_CAP_REALTIME | DSP_CAP_TRIGGER | +#ifdef OSSP_MMAP + DSP_CAP_MMAP | +#endif + DSP_CAP_MULTI; + PREP_UARG(NULL, &i); + IOCTL_RETURN(0, &i); + + case SNDCTL_DSP_NONBLOCK: + dsps->nonblock = 1; + ret = 0; + IOCTL_RETURN(0, NULL); + + case SNDCTL_DSP_RESET: op = OSSP_DSP_RESET; goto nd; + case SNDCTL_DSP_SYNC: op = OSSP_DSP_SYNC; goto nd; + case SNDCTL_DSP_POST: op = OSSP_DSP_POST; goto nd; + nd: + ret = exec_simple_cmd(&dsps->os, op, NULL, NULL); + if (ret) + goto err; + IOCTL_RETURN(0, NULL); + + case SOUND_PCM_READ_RATE: op = OSSP_DSP_GET_RATE; goto ri; + case SOUND_PCM_READ_BITS: op = OSSP_DSP_GET_FORMAT; goto ri; + case SOUND_PCM_READ_CHANNELS: op = OSSP_DSP_GET_CHANNELS; goto ri; + case SNDCTL_DSP_GETBLKSIZE: op = OSSP_DSP_GET_BLKSIZE; goto ri; + case SNDCTL_DSP_GETFMTS: op = OSSP_DSP_GET_FORMATS; goto ri; + case SNDCTL_DSP_GETTRIGGER: op = OSSP_DSP_GET_TRIGGER; goto ri; + ri: + PREP_UARG(NULL, &i); + ret = exec_simple_cmd(&dsps->os, op, NULL, &i); + if (ret) + goto err; + IOCTL_RETURN(0, &i); + + case SNDCTL_DSP_SPEED: op = OSSP_DSP_SET_RATE; goto wi; + case SNDCTL_DSP_SETFMT: op = OSSP_DSP_SET_FORMAT; goto wi; + case SNDCTL_DSP_CHANNELS: op = OSSP_DSP_SET_CHANNELS; goto wi; + case SNDCTL_DSP_SUBDIVIDE: op = OSSP_DSP_SET_SUBDIVISION; goto wi; + wi: + PREP_UARG(&i, &i); + ret = exec_simple_cmd(&dsps->os, op, &i, &i); + if (ret) + goto err; + IOCTL_RETURN(0, &i); + + case SNDCTL_DSP_STEREO: + PREP_UARG(NULL, &i); + i = 2; + ret = exec_simple_cmd(&dsps->os, OSSP_DSP_SET_CHANNELS, &i, &i); + i--; + if (ret) + goto err; + IOCTL_RETURN(0, &i); + + case SNDCTL_DSP_SETFRAGMENT: + PREP_UARG(&i, NULL); + ret = exec_simple_cmd(&dsps->os, + OSSP_DSP_SET_FRAGMENT, &i, NULL); + if (ret) + goto err; + IOCTL_RETURN(0, NULL); + + case SNDCTL_DSP_SETTRIGGER: + PREP_UARG(&i, NULL); + ret = exec_simple_cmd(&dsps->os, + OSSP_DSP_SET_TRIGGER, &i, NULL); + if (ret) + goto err; + IOCTL_RETURN(0, NULL); + + case SNDCTL_DSP_GETOSPACE: + case SNDCTL_DSP_GETISPACE: { + struct audio_buf_info info; + + ret = -EINVAL; + if (cmd == SNDCTL_DSP_GETOSPACE) { + if (!(dsps->rw & (1 << PLAY))) + goto err; + op = OSSP_DSP_GET_OSPACE; + } else { + if (!(dsps->rw & (1 << REC))) + goto err; + op = OSSP_DSP_GET_ISPACE; + } + + PREP_UARG(NULL, &info); + ret = exec_simple_cmd(&dsps->os, op, NULL, &info); + if (ret) + goto err; + IOCTL_RETURN(0, &info); + } + + case SNDCTL_DSP_GETOPTR: + case SNDCTL_DSP_GETIPTR: { + struct count_info info; + + op = cmd == SNDCTL_DSP_GETOPTR ? OSSP_DSP_GET_OPTR + : OSSP_DSP_GET_IPTR; + PREP_UARG(NULL, &info); + ret = exec_simple_cmd(&dsps->os, op, NULL, &info); + if (ret) + goto err; + IOCTL_RETURN(0, &info); + } + + case SNDCTL_DSP_GETODELAY: + PREP_UARG(NULL, &i); + i = 0; + ret = exec_simple_cmd(&dsps->os, OSSP_DSP_GET_ODELAY, NULL, &i); + IOCTL_RETURN(ret, &i); /* always copy out result, 0 on err */ + + case SOUND_PCM_WRITE_FILTER: + case SOUND_PCM_READ_FILTER: + ret = -EIO; + goto err; + + case SNDCTL_DSP_MAPINBUF: + case SNDCTL_DSP_MAPOUTBUF: + ret = -EINVAL; + goto err; + + case SNDCTL_DSP_SETSYNCRO: + case SNDCTL_DSP_SETDUPLEX: + case SNDCTL_DSP_PROFILE: + IOCTL_RETURN(0, NULL); + + default: + warn_os(os, "unknown ioctl 0x%x", cmd); + ret = -EINVAL; + goto err; + } + assert(0); /* control shouldn't reach here */ +err: + fuse_reply_err(req, -ret); +} + +#ifdef OSSP_MMAP +static int dsp_mmap_dir(int prot) +{ + if (!(prot & PROT_WRITE)) + return REC; + return PLAY; +} + +static void dsp_mmap(fuse_req_t req, void *addr, size_t len, int prot, + int flags, off_t offset, struct fuse_file_info *fi, + uint64_t mh) +{ + int dir = dsp_mmap_dir(prot); + struct ossp_dsp_mmap_arg arg = { }; + struct ossp_stream *os; + struct ossp_dsp_stream *dsps; + ssize_t ret; + + os = find_os(fi->fh); + if (!os) { + fuse_reply_err(req, EBADF); + return; + } + dsps = os_to_dsps(os); + + if (!os->mmap_off || len > os->mmap_size / 2) { + fuse_reply_err(req, EINVAL); + return; + } + + pthread_mutex_lock(&os->mmap_mutex); + + ret = -EBUSY; + if (dsps->mmapped & (1 << dir)) + goto out_unlock; + + arg.dir = dir; + arg.size = len; + + ret = exec_simple_cmd(os, OSSP_DSP_MMAP, &arg, NULL); + if (ret == 0) + dsps->mmapped |= 1 << dir; + +out_unlock: + pthread_mutex_unlock(&os->mmap_mutex); + + if (ret == 0) + fuse_reply_mmap(req, os->mmap_off + dir * os->mmap_size / 2, 0); + else + fuse_reply_err(req, -ret); +} + +static void dsp_munmap(fuse_req_t req, size_t len, struct fuse_file_info *fi, + off_t offset, uint64_t mh) +{ + struct ossp_stream *os; + struct ossp_dsp_stream *dsps; + int dir, rc; + + os = find_os(fi->fh); + if (!os) + goto out; + dsps = os_to_dsps(os); + + pthread_mutex_lock(&os->mmap_mutex); + + for (dir = 0; dir < 2; dir++) + if (offset == os->mmap_off + dir * os->mmap_size / 2) + break; + if (dir == 2 || len > os->mmap_size / 2) { + warn_os(os, "invalid munmap request " + "offset=%llu len=%zu mmapped=0x%x", + (unsigned long long)offset, len, dsps->mmapped); + goto out_unlock; + } + + rc = exec_simple_cmd(os, OSSP_DSP_MUNMAP, &dir, NULL); + if (rc) + warn_ose(os, rc, "MUNMAP failed for dir=%d", dir); + + dsps->mmapped &= ~(1 << dir); + +out_unlock: + pthread_mutex_unlock(&os->mmap_mutex); +out: + fuse_reply_none(req); +} +#endif + + +/*************************************************************************** + * Notify poller + */ + +static void *notify_poller(void *arg) +{ + struct epoll_event events[1024]; + int i, nfds; + +repeat: + nfds = epoll_wait(notify_epfd, events, ARRAY_SIZE(events), -1); + for (i = 0; i < nfds; i++) { + int do_notify = 0; + struct ossp_stream *os; + struct ossp_notify notify; + ssize_t ret; + + os = find_os_by_notify_rx(events[i].data.fd); + if (!os) { + err("can't find stream for notify_rx fd %d", + events[i].data.fd); + epoll_ctl(notify_epfd, EPOLL_CTL_DEL, events[i].data.fd, + NULL); + /* we don't know what's going on, don't close the fd */ + continue; + } + + while ((ret = read(os->notify_rx, + ¬ify, sizeof(notify))) > 0) { + if (os->dead) + continue; + if (ret != sizeof(notify)) { + warn_os(os, "short read on notify_rx (%zu, " + "expected %zu), killing the stream", + ret, sizeof(notify)); + os->dead = 1; + break; + } + if (notify.magic != OSSP_NOTIFY_MAGIC) { + warn_os(os, "invalid magic on notification, " + "killing the stream"); + os->dead = 1; + break; + } + + if (notify.opcode >= OSSP_NR_NOTIFY_OPCODES) + goto unknown; + + dbg1_os(os, "NOTIFY %s", ossp_notify_str[notify.opcode]); + + switch (notify.opcode) { + case OSSP_NOTIFY_POLL: + do_notify = 1; + break; + case OSSP_NOTIFY_OBITUARY: + os->dead = 1; + break; + case OSSP_NOTIFY_VOLCHG: + pthread_mutex_lock(&mixer_mutex); + os->mixer->modify_counter++; + pthread_mutex_unlock(&mixer_mutex); + break; + default: + unknown: + warn_os(os, "unknown notification %d", + notify.opcode); + } + } + if (ret == 0) + os->dead = 1; + else if (ret < 0 && errno != EAGAIN) { + warn_ose(os, -errno, "read fail on notify fd"); + os->dead = 1; + } + + if (!do_notify && !os->dead) + continue; + + pthread_mutex_lock(&mutex); + + if (os->ph) { + fuse_lowlevel_notify_poll(os->ph); + fuse_pollhandle_destroy(os->ph); + os->ph = NULL; + } + + if (os->dead) { + dbg0_os(os, "removing %d from notify poll list", + os->notify_rx); + epoll_ctl(notify_epfd, EPOLL_CTL_DEL, os->notify_rx, + NULL); + close(os->notify_rx); + os->notify_rx = -1; + pthread_cond_broadcast(¬ify_poller_kill_wait); + } + + pthread_mutex_unlock(&mutex); + } + goto repeat; +} + + +/*************************************************************************** + * Slave corpse reaper + */ + +static void *slave_reaper(void *arg) +{ + struct ossp_stream *os; + int status; + pid_t pid; + + pthread_mutex_lock(&mutex); +repeat: + while (list_empty(&slave_corpse_list)) + pthread_cond_wait(&slave_reaper_wait, &mutex); + + os = list_first_entry(&slave_corpse_list, struct ossp_stream, link); + list_del_init(&os->link); + + pthread_mutex_unlock(&mutex); + + do { + pid = waitpid(os->slave_pid, &status, 0); + } while (pid < 0 && errno == EINTR); + + if (pid < 0) { + if (errno == ECHILD) + warn_ose(os, -errno, "slave %d already gone?", + os->slave_pid); + else + fatal_e(-errno, "waitpid(%d) failed", os->slave_pid); + } + + pthread_mutex_lock(&mutex); + + dbg1_os(os, "slave %d reaped", os->slave_pid); + __clear_bit(os->id, os_id_bitmap); + free(os); + + goto repeat; +} + + +/*************************************************************************** + * Stuff to bind and start everything + */ + +static void ossp_daemonize(void) +{ + int fd, pfd[2]; + pid_t pid; + ssize_t ret; + int err; + + fd = open("/dev/null", O_RDWR); + if (fd >= 0) { + dup2(fd, 0); + dup2(fd, 1); + dup2(fd, 2); + if (fd > 2) + close(fd); + } + + if (pipe(pfd)) + fatal_e(-errno, "failed to create pipe for init wait"); + + if (fcntl(pfd[0], F_SETFD, FD_CLOEXEC) < 0 || + fcntl(pfd[1], F_SETFD, FD_CLOEXEC) < 0) + fatal_e(-errno, "failed to set CLOEXEC on init wait pipe"); + + pid = fork(); + if (pid < 0) + fatal_e(-errno, "failed to fork for daemon"); + + if (pid == 0) { + close(pfd[0]); + init_wait_fd = pfd[1]; + + /* be evil, my child */ + chdir("/"); + setsid(); + return; + } + + /* wait for init completion and pass over success indication */ + close(pfd[1]); + + do { + ret = read(pfd[0], &err, sizeof(err)); + } while (ret < 0 && errno == EINTR); + + if (ret == sizeof(err) && err == 0) + exit(0); + + fatal("daemon init failed ret=%zd err=%d", ret, err); + exit(1); +} + +static void ossp_init_done(void *userdata) +{ + /* init complete, notify parent if it's waiting */ + if (init_wait_fd >= 0) { + ssize_t ret; + int err = 0; + + ret = write(init_wait_fd, &err, sizeof(err)); + if (ret != sizeof(err)) + fatal_e(-errno, "failed to notify init completion, " + "ret=%zd", ret); + close(init_wait_fd); + init_wait_fd = -1; + } +} + +static const struct cuse_lowlevel_ops mixer_ops = { + .open = mixer_open, + .release = mixer_release, + .ioctl = mixer_ioctl, +}; + +static const struct cuse_lowlevel_ops dsp_ops = { + .init_done = ossp_init_done, + .open = dsp_open, + .release = dsp_release, + .read = dsp_read, + .write = dsp_write, + .poll = dsp_poll, + .ioctl = dsp_ioctl, +#ifdef OSSP_MMAP + .mmap = dsp_mmap, + .munmap = dsp_munmap, +#endif +}; + +static const struct cuse_lowlevel_ops adsp_ops = { + .open = adsp_open, + .release = dsp_release, + .read = dsp_read, + .write = dsp_write, + .poll = dsp_poll, + .ioctl = dsp_ioctl, +#ifdef OSSP_MMAP + .mmap = dsp_mmap, + .munmap = dsp_munmap, +#endif +}; + +static const char *usage = +"usage: osspd [options]\n" +"\n" +"options:\n" +" --help print this help message\n" +" --dsp=NAME DSP device name (default dsp)\n" +" --dsp-maj=MAJ DSP device major number (default 14)\n" +" --dsp-min=MIN DSP device minor number (default 3)\n" +" --adsp=NAME Aux DSP device name (default adsp, blank to disable)\n" +" --adsp-maj=MAJ Aux DSP device major number (default 14)\n" +" --adsp-min=MIN Aux DSP device minor number (default 12)\n" +" --mixer=NAME mixer device name (default mixer, blank to disable)\n" +" --mixer-maj=MAJ mixer device major number (default 14)\n" +" --mixer-min=MIN mixer device minor number (default 0)\n" +" --max=MAX maximum number of open streams (default 256)\n" +" --umax=MAX maximum number of open streams per UID (default --max)\n" +" --exit-on-idle exit if idle\n" +" --dsp-slave=PATH DSP slave (default ossp-padsp in the same dir)\n" +" --log=LEVEL log level (0..6)\n" +" --timestamp timestamp log messages\n" +" -v increase verbosity, can be specified multiple times\n" +" -f Run in foreground (don't daemonize)\n" +"\n"; + +struct ossp_param { + char *dsp_name; + unsigned dsp_major; + unsigned dsp_minor; + char *adsp_name; + unsigned adsp_major; + unsigned adsp_minor; + char *mixer_name; + unsigned mixer_major; + unsigned mixer_minor; + unsigned max_streams; + unsigned umax_streams; + char *dsp_slave_path; + unsigned log_level; + int exit_on_idle; + int timestamp; + int fg; + int help; +}; + +#define OSSP_OPT(t, p) { t, offsetof(struct ossp_param, p), 1 } + +static const struct fuse_opt ossp_opts[] = { + OSSP_OPT("--dsp=%s", dsp_name), + OSSP_OPT("--dsp-maj=%u", dsp_major), + OSSP_OPT("--dsp-min=%u", dsp_minor), + OSSP_OPT("--adsp=%s", adsp_name), + OSSP_OPT("--adsp-maj=%u", adsp_major), + OSSP_OPT("--adsp-min=%u", adsp_minor), + OSSP_OPT("--mixer=%s", mixer_name), + OSSP_OPT("--mixer-maj=%u", mixer_major), + OSSP_OPT("--mixer-min=%u", mixer_minor), + OSSP_OPT("--max=%u", max_streams), + OSSP_OPT("--umax=%u", umax_streams), + OSSP_OPT("--exit-on-idle", exit_on_idle), + OSSP_OPT("--dsp-slave=%s", dsp_slave_path), + OSSP_OPT("--timestamp", timestamp), + OSSP_OPT("--log=%u", log_level), + OSSP_OPT("-f", fg), + FUSE_OPT_KEY("-h", 0), + FUSE_OPT_KEY("--help", 0), + FUSE_OPT_KEY("-v", 1), + FUSE_OPT_END +}; + +static struct fuse_session *setup_ossp_cuse(const struct cuse_lowlevel_ops *ops, + const char *name, int major, + int minor, int argc, char **argv) +{ + char name_buf[128]; + const char *bufp = name_buf; + struct cuse_info ci = { .dev_major = major, .dev_minor = minor, + .dev_info_argc = 1, .dev_info_argv = &bufp, + .flags = CUSE_UNRESTRICTED_IOCTL }; + struct fuse_session *se; + int fd; + + snprintf(name_buf, sizeof(name_buf), "DEVNAME=%s", name); + + se = cuse_lowlevel_setup(argc, argv, &ci, ops, NULL, NULL); + if (!se) { + err("failed to setup %s CUSE", name); + return NULL; + } + + fd = fuse_chan_fd(fuse_session_next_chan(se, NULL)); + if ( +#ifdef OSSP_MMAP + fd != fuse_mmap_fd(se) && +#endif + fcntl(fd, F_SETFD, FD_CLOEXEC) < 0) { + err_e(-errno, "failed to set CLOEXEC on %s CUSE fd", name); + cuse_lowlevel_teardown(se); + return NULL; + } + + return se; +} + +static void *cuse_worker(void *arg) +{ + struct fuse_session *se = arg; + int rc; + + rc = fuse_session_loop_mt(se); + cuse_lowlevel_teardown(se); + + return (void *)(unsigned long)rc; +} + +static int process_arg(void *data, const char *arg, int key, + struct fuse_args *outargs) +{ + struct ossp_param *param = data; + + switch (key) { + case 0: + fprintf(stderr, usage); + param->help = 1; + return 0; + case 1: + param->log_level++; + return 0; + } + return 1; +} + +int main(int argc, char **argv) +{ + static struct ossp_param param = { + .dsp_name = DFL_DSP_NAME, + .dsp_major = DFL_DSP_MAJOR, .dsp_minor = DFL_DSP_MINOR, + .adsp_name = DFL_ADSP_NAME, + .adsp_major = DFL_ADSP_MAJOR, .adsp_minor = DFL_ADSP_MINOR, + .mixer_name = DFL_MIXER_NAME, + .mixer_major = DFL_MIXER_MAJOR, .mixer_minor = DFL_MIXER_MINOR, + .max_streams = DFL_MAX_STREAMS, + }; + struct fuse_args args = FUSE_ARGS_INIT(argc, argv); + char path_buf[PATH_MAX], *dir; + char adsp_buf[64] = "", mixer_buf[64] = ""; + struct sigaction sa; + struct stat stat_buf; + ssize_t ret; + unsigned u; + + snprintf(ossp_log_name, sizeof(ossp_log_name), "osspd"); + param.log_level = ossp_log_level; + + if (fuse_opt_parse(&args, ¶m, ossp_opts, process_arg)) + fatal("failed to parse arguments"); + + if (param.help) + return 0; + + max_streams = param.max_streams; + hashtbl_size = max_streams / 2 + 13; + + umax_streams = max_streams; + if (param.umax_streams) + umax_streams = param.umax_streams; + if (param.log_level > OSSP_LOG_MAX) + param.log_level = OSSP_LOG_MAX; + if (!param.fg) + param.log_level = -param.log_level; + ossp_log_level = param.log_level; + ossp_log_timestamp = param.timestamp; + + if (!param.fg) + ossp_daemonize(); + + /* daemonization already handled, prevent forking inside FUSE */ + fuse_opt_add_arg(&args, "-f"); + + info("OSS Proxy v%s (C) 2008-2010 by Tejun Heo ", + OSSP_VERSION); + + /* ignore stupid SIGPIPEs */ + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = SIG_IGN; + if (sigaction(SIGPIPE, &sa, NULL)) + fatal_e(-errno, "failed to ignore SIGPIPE"); + +//#ifdef GIOVANNI + /* determine slave path and check for availability */ + ret = readlink("/proc/self/exe", path_buf, PATH_MAX - 1); + if (ret < 0) + fatal_e(-errno, "failed to determine executable path"); + path_buf[ret] = '\0'; + dir = dirname(path_buf); + + if (param.dsp_slave_path) { + strncpy(dsp_slave_path, param.dsp_slave_path, PATH_MAX - 1); + dsp_slave_path[PATH_MAX - 1] = '\0'; + } else { + ret = snprintf(dsp_slave_path, PATH_MAX, "%s/%s", + dir, "ossp-padsp"); + if (ret >= PATH_MAX) + fatal("dsp slave pathname too long"); + } + + if (stat(dsp_slave_path, &stat_buf)) + fatal_e(-errno, "failed to stat %s", dsp_slave_path); + if (!S_ISREG(stat_buf.st_mode) || !(stat_buf.st_mode & 0444)) + fatal("%s is not executable", dsp_slave_path); + +//#endif// GIOVANNI + /* allocate tables */ + os_id_bitmap = calloc(BITS_TO_LONGS(max_streams), sizeof(long)); + mixer_tbl = calloc(hashtbl_size, sizeof(mixer_tbl[0])); + os_tbl = calloc(hashtbl_size, sizeof(os_tbl[0])); + os_pgrp_tbl = calloc(hashtbl_size, sizeof(os_pgrp_tbl[0])); + os_notify_tbl = calloc(hashtbl_size, sizeof(os_notify_tbl[0])); + if (!os_id_bitmap || !mixer_tbl || !os_tbl || !os_pgrp_tbl || + !os_notify_tbl) + fatal("failed to allocate stream hash tables"); + for (u = 0; u < hashtbl_size; u++) { + INIT_LIST_HEAD(&mixer_tbl[u]); + INIT_LIST_HEAD(&os_tbl[u]); + INIT_LIST_HEAD(&os_pgrp_tbl[u]); + INIT_LIST_HEAD(&os_notify_tbl[u]); + } + __set_bit(0, os_id_bitmap); /* don't use id 0 */ + + /* create mixer delayed reference worker */ + ret = -pthread_create(&mixer_delayed_put_thread, NULL, + mixer_delayed_put_worker, NULL); + if (ret) + fatal_e(ret, "failed to create mixer delayed put worker"); + + /* if exit_on_idle, touch mixer for pgrp0 */ + exit_on_idle = param.exit_on_idle; + if (exit_on_idle) { + struct ossp_mixer *mixer; + + mixer = get_mixer(0); + if (!mixer) + fatal("failed to touch idle mixer"); + put_mixer(mixer); + } + + /* create notify epoll and kick off watcher thread */ + notify_epfd = epoll_create(max_streams); + if (notify_epfd < 0) + fatal_e(-errno, "failed to create notify epoll"); + if (fcntl(notify_epfd, F_SETFD, FD_CLOEXEC) < 0) + fatal_e(-errno, "failed to set CLOEXEC on notify epfd"); + + ret = -pthread_create(¬ify_poller_thread, NULL, notify_poller, NULL); + if (ret) + fatal_e(ret, "failed to create notify poller thread"); + + /* create reaper for slave corpses */ + ret = -pthread_create(&slave_reaper_thread, NULL, slave_reaper, NULL); + if (ret) + fatal_e(ret, "failed to create slave reaper thread"); + +#ifdef GIOVANNI + /* we're set, let's setup fuse structures */ + if (strlen(param.mixer_name)) + mixer_se = setup_ossp_cuse(&mixer_ops, param.mixer_name, + param.mixer_major, param.mixer_minor, + args.argc, args.argv); + if (strlen(param.adsp_name)) + adsp_se = setup_ossp_cuse(&dsp_ops, param.adsp_name, + param.adsp_major, param.adsp_minor, + args.argc, args.argv); + +#endif// GIOVANNI + dsp_se = setup_ossp_cuse(&dsp_ops, param.dsp_name, + param.dsp_major, param.dsp_minor, + args.argc, args.argv); + if (!dsp_se) + fatal("can't create dsp, giving up"); + +#ifdef GIOVANNI + if (mixer_se) + snprintf(mixer_buf, sizeof(mixer_buf), ", %s (%d:%d)", + param.mixer_name, param.mixer_major, param.mixer_minor); + if (adsp_se) + snprintf(adsp_buf, sizeof(adsp_buf), ", %s (%d:%d)", + param.adsp_name, param.adsp_major, param.adsp_minor); + +#endif// GIOVANNI + info("Creating %s (%d:%d)%s%s", param.dsp_name, param.dsp_major, + param.dsp_minor, adsp_buf, mixer_buf); + +#ifdef GIOVANNI + /* start threads for mixer and adsp */ + if (mixer_se) { + ret = -pthread_create(&cuse_mixer_thread, NULL, + cuse_worker, mixer_se); + if (ret) + err_e(ret, "failed to create mixer worker"); + } + if (adsp_se) { + ret = -pthread_create(&cuse_adsp_thread, NULL, + cuse_worker, adsp_se); + if (ret) + err_e(ret, "failed to create adsp worker"); + } +#endif// GIOVANNI + + /* run CUSE for /dev/dsp in the main thread */ + ret = (ssize_t)cuse_worker(dsp_se); + if (ret < 0) + fatal("dsp worker failed"); + return 0; +} diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.c b/src/mod/endpoints/mod_sofia/mod_sofia.c index 3c8404dd6b..3bb926adf3 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.c +++ b/src/mod/endpoints/mod_sofia/mod_sofia.c @@ -3936,7 +3936,7 @@ static switch_call_cause_t sofia_outgoing_channel(switch_core_session_t *session dest_num = p + 5; } } -#endif + if (profile->pres_type) { char *sql; @@ -3957,6 +3957,7 @@ static switch_call_cause_t sofia_outgoing_channel(switch_core_session_t *session sofia_glue_actually_execute_sql(profile, sql, profile->ireg_mutex); switch_safe_free(sql); } +#endif caller_profile = switch_caller_profile_clone(nsession, outbound_profile); diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.h b/src/mod/endpoints/mod_sofia/mod_sofia.h index 750fb60c15..6970a7ab05 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.h +++ b/src/mod/endpoints/mod_sofia/mod_sofia.h @@ -224,6 +224,7 @@ typedef enum { PFLAG_IN_DIALOG_CHAT, PFLAG_DEL_SUBS_ON_REG, PFLAG_IGNORE_183NOSDP, + PFLAG_PRESENCE_PROBE_ON_REGISTER, /* No new flags below this line */ PFLAG_MAX } PFLAGS; @@ -957,6 +958,7 @@ void sofia_presence_event_thread_start(void); void sofia_reg_expire_call_id(sofia_profile_t *profile, const char *call_id, int reboot); switch_status_t sofia_glue_tech_choose_video_port(private_object_t *tech_pvt, int force); switch_status_t sofia_glue_tech_set_video_codec(private_object_t *tech_pvt, int force); +char *sofia_glue_get_register_host(const char *uri); const char *sofia_glue_strip_proto(const char *uri); switch_status_t reconfig_sofia(sofia_profile_t *profile); void sofia_glue_del_gateway(sofia_gateway_t *gp); diff --git a/src/mod/endpoints/mod_sofia/sofia.c b/src/mod/endpoints/mod_sofia/sofia.c index e749abdc01..e20d868548 100644 --- a/src/mod/endpoints/mod_sofia/sofia.c +++ b/src/mod/endpoints/mod_sofia/sofia.c @@ -2156,6 +2156,30 @@ static void parse_gateways(sofia_profile_t *profile, switch_xml_t gateways_tag) sipip = profile->sipip; } + gateway->extension = switch_core_strdup(gateway->pool, extension); + + + if (!strncasecmp(proxy, "sip:", 4)) { + gateway->register_proxy = switch_core_strdup(gateway->pool, proxy); + gateway->register_to = switch_core_sprintf(gateway->pool, "sip:%s@%s", username, proxy + 4); + } else { + gateway->register_proxy = switch_core_sprintf(gateway->pool, "sip:%s", proxy); + gateway->register_to = switch_core_sprintf(gateway->pool, "sip:%s@%s", username, proxy); + } + + /* This checks to make sure we provide the right contact on register for targets behind nat with us. */ + if (sofia_test_pflag(profile, PFLAG_AUTO_NAT)) { + char *register_host = NULL; + + register_host = sofia_glue_get_register_host(gateway->register_proxy); + + if (register_host && switch_is_lan_addr(register_host)) { + sipip = profile->sipip; + } + + switch_safe_free(register_host); + } + if (extension_in_contact) { format = strchr(sipip, ':') ? "" : ""; gateway->register_contact = switch_core_sprintf(gateway->pool, format, extension, @@ -2170,16 +2194,6 @@ static void parse_gateways(sofia_profile_t *profile, switch_xml_t gateways_tag) profile->tls_sip_port : profile->sip_port, params); } - gateway->extension = switch_core_strdup(gateway->pool, extension); - - if (!strncasecmp(proxy, "sip:", 4)) { - gateway->register_proxy = switch_core_strdup(gateway->pool, proxy); - gateway->register_to = switch_core_sprintf(gateway->pool, "sip:%s@%s", username, proxy + 4); - } else { - gateway->register_proxy = switch_core_sprintf(gateway->pool, "sip:%s", proxy); - gateway->register_to = switch_core_sprintf(gateway->pool, "sip:%s@%s", username, proxy); - } - gateway->expires_str = switch_core_strdup(gateway->pool, expire_seconds); if ((gateway->freq = atoi(gateway->expires_str)) < 5) { @@ -2391,6 +2405,12 @@ switch_status_t reconfig_sofia(sofia_profile_t *profile) } else { sofia_clear_pflag(profile, PFLAG_IGNORE_183NOSDP); } + } else if (!strcasecmp(var, "presence-probe-on-register")) { + if (switch_true(val)) { + sofia_set_pflag(profile, PFLAG_PRESENCE_PROBE_ON_REGISTER); + } else { + sofia_clear_pflag(profile, PFLAG_PRESENCE_PROBE_ON_REGISTER); + } } else if (!strcasecmp(var, "cid-in-1xx")) { if (switch_true(val)) { sofia_set_pflag(profile, PFLAG_CID_IN_1XX); @@ -3056,6 +3076,12 @@ switch_status_t config_sofia(int reload, char *profile_name) } else { sofia_clear_pflag(profile, PFLAG_IGNORE_183NOSDP); } + } else if (!strcasecmp(var, "presence-probe-on-register")) { + if (switch_true(val)) { + sofia_set_pflag(profile, PFLAG_PRESENCE_PROBE_ON_REGISTER); + } else { + sofia_clear_pflag(profile, PFLAG_PRESENCE_PROBE_ON_REGISTER); + } } else if (!strcasecmp(var, "cid-in-1xx")) { if (switch_true(val)) { sofia_set_pflag(profile, PFLAG_CID_IN_1XX); @@ -4406,7 +4432,6 @@ static void sofia_handle_sip_r_invite(switch_core_session_t *session, int status contact_host, astate, "outbound", user_agent, profile->name, mod_sofia_globals.hostname, switch_str_nil(full_contact), switch_str_nil(presence_id), switch_str_nil(presence_data), switch_str_nil(p)); - switch_assert(sql); sofia_glue_actually_execute_sql(profile, sql, profile->ireg_mutex); @@ -5959,7 +5984,9 @@ void sofia_handle_sip_i_info(nua_t *nua, sofia_profile_t *profile, nua_handle_t /* Barf if we didn't get our private */ assert(switch_core_session_get_private(session)); - if (!strncasecmp(sip->sip_content_type->c_type, "message", 7) && !strcasecmp(sip->sip_content_type->c_subtype, "update_display")) { + if (sip->sip_content_type && sip->sip_content_type->c_subtype && sip->sip_content_type->c_type && + !strncasecmp(sip->sip_content_type->c_type, "message", 7) && + !strcasecmp(sip->sip_content_type->c_subtype, "update_display")) { sofia_update_callee_id(session, profile, sip, SWITCH_TRUE); goto end; } @@ -6856,8 +6883,9 @@ void sofia_handle_sip_i_invite(nua_t *nua, sofia_profile_t *profile, nua_handle_ sql = switch_mprintf - ("select call_id from sip_dialogs where call_info='%q' and sip_from_user='%q' and sip_from_host='%q' and call_id is not null", - switch_str_nil(p), user, host); + ("select call_id from sip_dialogs where call_info='%q' and ((sip_from_user='%q' and sip_from_host='%q') or presence_id='%q@%q') " + "and call_id is not null", + switch_str_nil(p), user, host, user, host); if ((str = sofia_glue_execute_sql2str(profile, profile->ireg_mutex, sql, cid, sizeof(cid)))) { bnh = nua_handle_by_call_id(nua, str); diff --git a/src/mod/endpoints/mod_sofia/sofia_glue.c b/src/mod/endpoints/mod_sofia/sofia_glue.c index fa828607bd..57a2bfaa6a 100644 --- a/src/mod/endpoints/mod_sofia/sofia_glue.c +++ b/src/mod/endpoints/mod_sofia/sofia_glue.c @@ -5734,6 +5734,48 @@ char *sofia_glue_execute_sql2str(sofia_profile_t *profile, switch_mutex_t *mutex return ret; } +char *sofia_glue_get_register_host(const char *uri) +{ + char *register_host = NULL; + const char *s; + char *p = NULL; + + if (zstr(uri)) { + return NULL; + } + + if ((s = switch_stristr("sip:", uri))) { + s += 4; + } else if ((s = switch_stristr("sips:", uri))) { + s += 5; + } + + if (!s) { + return NULL; + } + + register_host = strdup(s); + + /* remove port for register_host for testing nat acl take into account + ipv6 addresses which are required to have brackets around the addr + */ + + if ((p = strchr(register_host, ']'))) { + if (*(p + 1) == ':') { + *(p + 1) = '\0'; + } + } else { + if ((p = strrchr(register_host, ':'))) { + *p = '\0'; + } + } + + /* register_proxy should always start with "sip:" or "sips:" */ + assert(register_host); + + return register_host; +} + const char *sofia_glue_strip_proto(const char *uri) { char *p; @@ -5983,7 +6025,6 @@ void sofia_glue_tech_simplify(private_object_t *tech_pvt) } } - void sofia_glue_build_vid_refresh_message(switch_core_session_t *session, const char *pl) { switch_core_session_message_t *msg; diff --git a/src/mod/endpoints/mod_sofia/sofia_presence.c b/src/mod/endpoints/mod_sofia/sofia_presence.c index dc02ca47ae..5c2517db61 100644 --- a/src/mod/endpoints/mod_sofia/sofia_presence.c +++ b/src/mod/endpoints/mod_sofia/sofia_presence.c @@ -567,7 +567,8 @@ static void actual_sofia_presence_event_handler(switch_event_t *event) } if (probe_euser && probe_host && (profile = sofia_glue_find_profile(probe_host))) { - sql = switch_mprintf("select status,rpid from sip_dialogs where sip_from_user='%q' and sip_from_host='%q'", probe_euser, probe_host); + sql = switch_mprintf("select status,rpid from sip_dialogs where ((sip_from_user='%q' and sip_from_host='%q') or presence_id='%q@%q')", + probe_euser, probe_host, probe_euser, probe_host); sofia_glue_execute_sql_callback(profile, profile->ireg_mutex, sql, sofia_presence_dialog_callback, &dh); h.profile = profile; @@ -591,9 +592,11 @@ static void actual_sofia_presence_event_handler(switch_event_t *event) "'%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_server_host or " - "sip_dialogs.sip_from_host = sip_registrations.sip_host) ) " + "sip_dialogs.presence_id = sip_registrations.sip_user || '@' || sip_registrations.sip_host " + + + "or (sip_dialogs.sip_from_user = sip_registrations.sip_user " + "and 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_server_host=sip_presence.sip_host and " @@ -601,7 +604,8 @@ static void actual_sofia_presence_event_handler(switch_event_t *event) "where sip_dialogs.presence_id='%q@%q' or (sip_registrations.sip_user='%q' and " "(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_euser, probe_host, probe_host, probe_host); + dh.status, dh.rpid, + probe_euser, probe_host, probe_euser, probe_host, probe_host, probe_host); switch_assert(sql); if (mod_sofia_globals.debug_presence > 0) { @@ -711,9 +715,10 @@ static void actual_sofia_presence_event_handler(switch_event_t *event) sql = switch_mprintf("update sip_dialogs set call_info='%q',call_info_state='%q' where hostname='%q' and uuid='%q'", call_info, call_info_state, mod_sofia_globals.hostname, uuid); } else { - sql = switch_mprintf("update sip_dialogs set call_info='%q', call_info_state='%q' where hostname='%q' and sip_dialogs.sip_from_user='%q' " - "and sip_dialogs.sip_from_host='%q' and call_info='%q'", - call_info, call_info_state, mod_sofia_globals.hostname, euser, host, call_info); + sql = switch_mprintf("update sip_dialogs set call_info='%q', call_info_state='%q' where hostname='%q' and " + "((sip_dialogs.sip_from_user='%q' and sip_dialogs.sip_from_host='%q') or presence_id='%q@%q') and call_info='%q'", + + call_info, call_info_state, mod_sofia_globals.hostname, euser, host, euser, host, call_info); } @@ -737,7 +742,8 @@ static void actual_sofia_presence_event_handler(switch_event_t *event) sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE); } - sql = switch_mprintf("select status,rpid from sip_dialogs where sip_from_user='%q' and sip_from_host='%q'", euser, host); + sql = switch_mprintf("select status,rpid from sip_dialogs where ((sip_from_user='%q' and sip_from_host='%q') or presence_id='%q@%q')", + euser, host, euser, host); sofia_glue_execute_sql_callback(profile, profile->ireg_mutex, sql, sofia_presence_dialog_callback, &dh); switch_safe_free(sql); @@ -753,17 +759,20 @@ static void actual_sofia_presence_event_handler(switch_event_t *event) "(sip_subscriptions.sub_to_user=sip_presence.sip_user and sip_subscriptions.sub_to_host=sip_presence.sip_host and " "sip_subscriptions.profile_name=sip_presence.profile_name) " "left join sip_dialogs on " + + "sip_dialogs.presence_id = sip_subscriptions.sub_to_user || '@' || sip_subscriptions.sub_to_host or " + "(sip_dialogs.sip_from_user = sip_subscriptions.sub_to_user " "and sip_dialogs.sip_from_host = sip_subscriptions.sub_to_host) " "where sip_subscriptions.expires > -1 and " - "(event='%q' or event='%q') and (sub_to_user='%q' or sip_dialogs.presence_id like '%q@%%') " + "(event='%q' or event='%q') and sub_to_user='%q' " "and (sub_to_host='%q' or presence_hosts like '%%%q%%') " "and (sip_subscriptions.profile_name = '%q' or sip_subscriptions.presence_hosts != sip_subscriptions.sub_to_host)", switch_str_nil(status), switch_str_nil(rpid), host, dh.status,dh.rpid, - event_type, alt_event_type, euser, euser, host, host, profile->name))) { + event_type, alt_event_type, euser, host, host, profile->name))) { struct presence_helper helper = { 0 }; @@ -1616,7 +1625,7 @@ static int sofia_presence_sub_callback(void *pArg, int argc, char **argv, char * } - /* commenting to test + if (helper->event){ const char *uuid = switch_event_get_header_nil(helper->event, "unique-id"); @@ -1625,7 +1634,7 @@ static int sofia_presence_sub_callback(void *pArg, int argc, char **argv, char * sofia_glue_execute_sql(profile, &sql, SWITCH_TRUE); } } - */ + nua_handle_bind(nh, &mod_sofia_globals.keep_private); @@ -1918,7 +1927,8 @@ static void sync_sla(sofia_profile_t *profile, const char *to_user, const char * switch_core_hash_init(&sh->hash, sh->pool); sql = switch_mprintf("select sip_from_user,sip_from_host,call_info,call_info_state,uuid from sip_dialogs " - "where hostname='%q' " "and sip_from_user='%q' and sip_from_host='%q' ", mod_sofia_globals.hostname, to_user, to_host); + "where hostname='%q' and ((sip_from_user='%q' and sip_from_host='%q') or presence_id='%q@%q')", + mod_sofia_globals.hostname, to_user, to_host, to_user, to_host); if (mod_sofia_globals.debug_sla > 1) { @@ -1954,7 +1964,8 @@ static void sync_sla(sofia_profile_t *profile, const char *to_user, const char * if (clear) { - sql = switch_mprintf("delete from sip_dialogs where sip_from_user='%q' and sip_from_host='%q' and call_info_state='seized'", to_user, to_host); + sql = switch_mprintf("delete from sip_dialogs where ((sip_from_user='%q' and sip_from_host='%q') or presence_id='%q@%q') " + "and call_info_state='seized'", to_user, to_host, to_user, to_host); if (mod_sofia_globals.debug_sla > 1) { @@ -2326,8 +2337,9 @@ void sofia_presence_handle_sip_i_subscribe(int status, switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "CANCEL LINE SEIZE\n"); } - sql = switch_mprintf("delete from sip_dialogs where sip_from_user='%q' and sip_from_host='%q' and call_info_state='seized'", - to_user, to_host); + sql = switch_mprintf("delete from sip_dialogs where ((sip_from_user='%q' and sip_from_host='%q') or presence_id='%q@%q') " + "and call_info_state='seized'", + to_user, to_host, to_user, to_host); if (mod_sofia_globals.debug_sla > 1) { @@ -2360,8 +2372,9 @@ void sofia_presence_handle_sip_i_subscribe(int status, - sql = switch_mprintf("delete from sip_dialogs where sip_from_user='%q' and sip_from_host='%q' and call_info_state='seized'", - to_user, to_host); + sql = switch_mprintf("delete from sip_dialogs where ((sip_from_user='%q' and sip_from_host='%q') or presence_id='%q@%q') " + "and call_info_state='seized'", + to_user, to_host, to_user, to_host); if (mod_sofia_globals.debug_sla > 1) { diff --git a/src/mod/endpoints/mod_sofia/sofia_reg.c b/src/mod/endpoints/mod_sofia/sofia_reg.c index 4bb879659c..e93bdaac08 100644 --- a/src/mod/endpoints/mod_sofia/sofia_reg.c +++ b/src/mod/endpoints/mod_sofia/sofia_reg.c @@ -142,16 +142,22 @@ void sofia_sub_check_gateway(sofia_profile_t *profile, time_t now) int ss_state = nua_callstate_authenticating; sub_state_t ostate = gw_sub_ptr->state; char *user_via = NULL; + char *register_host = NULL; if (!now) { gw_sub_ptr->state = ostate = SUB_STATE_UNSUBED; gw_sub_ptr->expires_str = "0"; } - if (sofia_glue_check_nat(gateway_ptr->profile, gateway_ptr->register_proxy)) { + register_host = sofia_glue_get_register_host(gateway_ptr->register_proxy); + + /* check for NAT and place a Via header if necessary (hostname or non-local IP) */ + if (register_host && sofia_glue_check_nat(gateway_ptr->profile, register_host)) { user_via = sofia_glue_create_external_via(NULL, gateway_ptr->profile, gateway_ptr->register_transport); } + switch_safe_free(register_host); + switch (ostate) { case SUB_STATE_NOSUB: break; @@ -189,7 +195,15 @@ void sofia_sub_check_gateway(sofia_profile_t *profile, time_t now) nua_handle_bind(gateway_ptr->nh, gateway_ptr->sofia_private); if (now) { - nua_subscribe(gateway_ptr->sub_nh, NUTAG_URL(gateway_ptr->register_url), TAG_IF(user_via, SIPTAG_VIA_STR(user_via)), SIPTAG_EVENT_STR(gw_sub_ptr->event), SIPTAG_ACCEPT_STR(gw_sub_ptr->content_type), SIPTAG_TO_STR(gateway_ptr->register_from), SIPTAG_FROM_STR(gateway_ptr->register_from), SIPTAG_CONTACT_STR(gateway_ptr->register_contact), SIPTAG_EXPIRES_STR(gw_sub_ptr->expires_str), // sofia stack bases its auto-refresh stuff on this + nua_subscribe(gateway_ptr->sub_nh, + NUTAG_URL(gateway_ptr->register_url), + TAG_IF(user_via, SIPTAG_VIA_STR(user_via)), + SIPTAG_EVENT_STR(gw_sub_ptr->event), + SIPTAG_ACCEPT_STR(gw_sub_ptr->content_type), + SIPTAG_TO_STR(gateway_ptr->register_from), + SIPTAG_FROM_STR(gateway_ptr->register_from), + SIPTAG_CONTACT_STR(gateway_ptr->register_contact), + SIPTAG_EXPIRES_STR(gw_sub_ptr->expires_str), /* sofia stack bases its auto-refresh stuff on this */ TAG_NULL()); gw_sub_ptr->retry = now + gw_sub_ptr->retry_seconds; } else { @@ -266,6 +280,7 @@ void sofia_reg_check_gateway(sofia_profile_t *profile, time_t now) for (gateway_ptr = profile->gateways; gateway_ptr; gateway_ptr = gateway_ptr->next) { reg_state_t ostate = gateway_ptr->state; char *user_via = NULL; + char *register_host = NULL; if (!now) { gateway_ptr->state = ostate = REG_STATE_UNREGED; @@ -277,10 +292,15 @@ void sofia_reg_check_gateway(sofia_profile_t *profile, time_t now) nua_handle_t *nh = nua_handle(profile->nua, NULL, NUTAG_URL(gateway_ptr->register_url), TAG_END()); sofia_private_t *pvt; - if (sofia_glue_check_nat(gateway_ptr->profile, gateway_ptr->register_proxy)) { + register_host = sofia_glue_get_register_host(gateway_ptr->register_proxy); + + /* check for NAT and place a Via header if necessary (hostname or non-local IP) */ + if (register_host && sofia_glue_check_nat(gateway_ptr->profile, register_host)) { user_via = sofia_glue_create_external_via(NULL, gateway_ptr->profile, gateway_ptr->register_transport); } + switch_safe_free(register_host); + pvt = malloc(sizeof(*pvt)); switch_assert(pvt); memset(pvt, 0, sizeof(*pvt)); @@ -335,10 +355,15 @@ void sofia_reg_check_gateway(sofia_profile_t *profile, time_t now) sofia_reg_new_handle(gateway_ptr, now ? 1 : 0); } - if (sofia_glue_check_nat(gateway_ptr->profile, gateway_ptr->register_proxy)) { + register_host = sofia_glue_get_register_host(gateway_ptr->register_proxy); + + /* check for NAT and place a Via header if necessary (hostname or non-local IP) */ + if (register_host && sofia_glue_check_nat(gateway_ptr->profile, register_host)) { user_via = sofia_glue_create_external_via(NULL, gateway_ptr->profile, gateway_ptr->register_transport); } + switch_safe_free(register_host); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Registering %s\n", gateway_ptr->name); if (now) { @@ -1114,19 +1139,23 @@ uint8_t sofia_reg_handle_register(nua_t *nua, sofia_profile_t *profile, nua_hand } if (auth_res != AUTH_OK && !stale) { + if (sofia_test_pflag(profile, PFLAG_LOG_AUTH_FAIL)) { + if (regtype == REG_REGISTER) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "SIP auth %s (REGISTER) on sofia profile '%s' " + "for [%s@%s] from ip %s\n", forbidden ? "failure" : "challenge", profile->name, to_user, to_host, network_ip); + } + } + if (profile->debug) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Send %s for [%s@%s] from ip '%s'\n", - forbidden ? "forbidden" : "challenge", to_user, to_host, network_ip); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Send %s for [%s@%s]\n", + forbidden ? "forbidden" : "challenge", to_user, to_host); } if (auth_res == AUTH_FORBIDDEN) { nua_respond(nh, SIP_403_FORBIDDEN, NUTAG_WITH_THIS(nua), TAG_END()); - + /* Log line added to support Fail2Ban */ if (sofia_test_pflag(profile, PFLAG_LOG_AUTH_FAIL)) { - if (regtype == REG_REGISTER) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "SIP auth failure (REGISTER) on sofia profile '%s' " - "for [%s@%s] from ip %s\n", profile->name, to_user, to_host, network_ip); - } else if (regtype == REG_INVITE) { + if (regtype == REG_INVITE) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "SIP auth failure (INVITE) on sofia profile '%s' " "for [%s@%s] from ip %s\n", profile->name, to_user, to_host, network_ip); } @@ -1416,27 +1445,27 @@ uint8_t sofia_reg_handle_register(nua_t *nua, sofia_profile_t *profile, nua_hand } } - -#if 0 - if (switch_event_create(&s_event, SWITCH_EVENT_PRESENCE_PROBE) == SWITCH_STATUS_SUCCESS) { - switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "proto", SOFIA_CHAT_PROTO); - switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "login", profile->name); - switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "from", "%s@%s", to_user, sub_host); - switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "to", "%s@%s", to_user, sub_host); - switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "event_type", "presence"); - switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "alt_event_type", "dialog"); - switch_event_fire(&s_event); + if (sofia_test_pflag(profile, PFLAG_PRESENCE_PROBE_ON_REGISTER)) { + if (switch_event_create(&s_event, SWITCH_EVENT_PRESENCE_PROBE) == SWITCH_STATUS_SUCCESS) { + switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "proto", SOFIA_CHAT_PROTO); + switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "login", profile->name); + switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "from", "%s@%s", to_user, sub_host); + switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "to", "%s@%s", to_user, sub_host); + switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "event_type", "presence"); + switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "alt_event_type", "dialog"); + switch_event_fire(&s_event); + } + } else { + if (switch_event_create(&s_event, SWITCH_EVENT_PRESENCE_IN) == SWITCH_STATUS_SUCCESS) { + switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "proto", SOFIA_CHAT_PROTO); + switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "login", profile->name); + switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "from", "%s@%s", to_user, sub_host); + switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "rpid", "unknown"); + switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "status", "Registered"); + switch_event_fire(&s_event); + } } -#else - if (switch_event_create(&s_event, SWITCH_EVENT_PRESENCE_IN) == SWITCH_STATUS_SUCCESS) { - switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "proto", SOFIA_CHAT_PROTO); - switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "login", profile->name); - switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "from", "%s@%s", to_user, sub_host); - switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "rpid", "unknown"); - switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "status", "Registered"); - switch_event_fire(&s_event); - } -#endif + } else { if (switch_event_create_subclass(&s_event, SWITCH_EVENT_CUSTOM, MY_EVENT_UNREGISTER) == SWITCH_STATUS_SUCCESS) { switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "profile-name", profile->name); diff --git a/src/mod/event_handlers/mod_event_socket/mod_event_socket.c b/src/mod/event_handlers/mod_event_socket/mod_event_socket.c index 941db22c84..ee7cfc9eaf 100644 --- a/src/mod/event_handlers/mod_event_socket/mod_event_socket.c +++ b/src/mod/event_handlers/mod_event_socket/mod_event_socket.c @@ -691,7 +691,7 @@ SWITCH_STANDARD_API(event_sink_function) switch_mutex_lock(listener->filter_mutex); if (!listener->filters) { - switch_event_create_plain(&listener->filters, SWITCH_EVENT_CHANNEL_DATA); + switch_event_create_plain(&listener->filters, SWITCH_EVENT_CLONE); } if (!strcasecmp(action, "delete")) { @@ -702,7 +702,7 @@ SWITCH_STANDARD_API(event_sink_function) if (!strcasecmp(header_val, "all")) { switch_event_destroy(&listener->filters); - switch_event_create_plain(&listener->filters, SWITCH_EVENT_CHANNEL_DATA); + switch_event_create_plain(&listener->filters, SWITCH_EVENT_CLONE); } else { switch_event_del_header(listener->filters, header_val); } @@ -1744,7 +1744,7 @@ static switch_status_t parse_command(listener_t *listener, switch_event_t **even switch_mutex_lock(listener->filter_mutex); if (!listener->filters) { - switch_event_create_plain(&listener->filters, SWITCH_EVENT_CHANNEL_DATA); + switch_event_create_plain(&listener->filters, SWITCH_EVENT_CLONE); } if (!strcasecmp(header_name, "delete") && header_val) { @@ -1754,7 +1754,7 @@ static switch_status_t parse_command(listener_t *listener, switch_event_t **even } if (!strcasecmp(header_name, "all")) { switch_event_destroy(&listener->filters); - switch_event_create_plain(&listener->filters, SWITCH_EVENT_CHANNEL_DATA); + switch_event_create_plain(&listener->filters, SWITCH_EVENT_CLONE); } else { switch_event_del_header_val(listener->filters, header_name, header_val); } diff --git a/src/mod/languages/mod_managed/freeswitch_wrap.cxx b/src/mod/languages/mod_managed/freeswitch_wrap.cxx index ca001f64b1..f4bf780086 100644 --- a/src/mod/languages/mod_managed/freeswitch_wrap.cxx +++ b/src/mod/languages/mod_managed/freeswitch_wrap.cxx @@ -6744,6 +6744,42 @@ SWIGEXPORT int SWIGSTDCALL CSharp_switch_core_destroy() { } +SWIGEXPORT int SWIGSTDCALL CSharp_switch_core_session_io_read_lock(void * jarg1) { + int jresult ; + switch_core_session_t *arg1 = (switch_core_session_t *) 0 ; + switch_status_t result; + + arg1 = (switch_core_session_t *)jarg1; + result = (switch_status_t)switch_core_session_io_read_lock(arg1); + jresult = result; + return jresult; +} + + +SWIGEXPORT int SWIGSTDCALL CSharp_switch_core_session_io_write_lock(void * jarg1) { + int jresult ; + switch_core_session_t *arg1 = (switch_core_session_t *) 0 ; + switch_status_t result; + + arg1 = (switch_core_session_t *)jarg1; + result = (switch_status_t)switch_core_session_io_write_lock(arg1); + jresult = result; + return jresult; +} + + +SWIGEXPORT int SWIGSTDCALL CSharp_switch_core_session_io_rwunlock(void * jarg1) { + int jresult ; + switch_core_session_t *arg1 = (switch_core_session_t *) 0 ; + switch_status_t result; + + arg1 = (switch_core_session_t *)jarg1; + result = (switch_status_t)switch_core_session_io_rwunlock(arg1); + jresult = result; + return jresult; +} + + SWIGEXPORT int SWIGSTDCALL CSharp_switch_core_session_read_lock(void * jarg1) { int jresult ; switch_core_session_t *arg1 = (switch_core_session_t *) 0 ; @@ -7626,6 +7662,22 @@ SWIGEXPORT int SWIGSTDCALL CSharp_switch_core_session_execute_application_get_fl } +SWIGEXPORT int SWIGSTDCALL CSharp_switch_core_session_execute_application_async(void * jarg1, char * jarg2, char * jarg3) { + int jresult ; + switch_core_session_t *arg1 = (switch_core_session_t *) 0 ; + char *arg2 = (char *) 0 ; + char *arg3 = (char *) 0 ; + switch_status_t result; + + arg1 = (switch_core_session_t *)jarg1; + arg2 = (char *)jarg2; + arg3 = (char *)jarg3; + result = (switch_status_t)switch_core_session_execute_application_async(arg1,(char const *)arg2,(char const *)arg3); + jresult = result; + return jresult; +} + + SWIGEXPORT int SWIGSTDCALL CSharp_switch_core_session_get_app_flags(char * jarg1, void * jarg2) { int jresult ; char *arg1 = (char *) 0 ; @@ -7856,6 +7908,18 @@ SWIGEXPORT unsigned long SWIGSTDCALL CSharp_switch_core_session_event_count(void } +SWIGEXPORT unsigned long SWIGSTDCALL CSharp_switch_core_session_messages_waiting(void * jarg1) { + unsigned long jresult ; + switch_core_session_t *arg1 = (switch_core_session_t *) 0 ; + uint32_t result; + + arg1 = (switch_core_session_t *)jarg1; + result = (uint32_t)switch_core_session_messages_waiting(arg1); + jresult = (unsigned long)result; + return jresult; +} + + SWIGEXPORT int SWIGSTDCALL CSharp_switch_core_session_dequeue_event(void * jarg1, void * jarg2, int jarg3) { int jresult ; switch_core_session_t *arg1 = (switch_core_session_t *) 0 ; @@ -28289,6 +28353,50 @@ SWIGEXPORT int SWIGSTDCALL CSharp_switch_ivr_dmachine_set_realm(void * jarg1, ch } +SWIGEXPORT int SWIGSTDCALL CSharp_switch_ivr_get_file_handle(void * jarg1, void * jarg2) { + int jresult ; + switch_core_session_t *arg1 = (switch_core_session_t *) 0 ; + switch_file_handle_t **arg2 = (switch_file_handle_t **) 0 ; + switch_status_t result; + + arg1 = (switch_core_session_t *)jarg1; + arg2 = (switch_file_handle_t **)jarg2; + result = (switch_status_t)switch_ivr_get_file_handle(arg1,arg2); + jresult = result; + return jresult; +} + + +SWIGEXPORT int SWIGSTDCALL CSharp_switch_ivr_release_file_handle(void * jarg1, void * jarg2) { + int jresult ; + switch_core_session_t *arg1 = (switch_core_session_t *) 0 ; + switch_file_handle_t **arg2 = (switch_file_handle_t **) 0 ; + switch_status_t result; + + arg1 = (switch_core_session_t *)jarg1; + arg2 = (switch_file_handle_t **)jarg2; + result = (switch_status_t)switch_ivr_release_file_handle(arg1,arg2); + jresult = result; + return jresult; +} + + +SWIGEXPORT int SWIGSTDCALL CSharp_switch_ivr_process_fh(void * jarg1, char * jarg2, void * jarg3) { + int jresult ; + switch_core_session_t *arg1 = (switch_core_session_t *) 0 ; + char *arg2 = (char *) 0 ; + switch_file_handle_t *arg3 = (switch_file_handle_t *) 0 ; + switch_status_t result; + + arg1 = (switch_core_session_t *)jarg1; + arg2 = (char *)jarg2; + arg3 = (switch_file_handle_t *)jarg3; + result = (switch_status_t)switch_ivr_process_fh(arg1,(char const *)arg2,arg3); + jresult = result; + return jresult; +} + + SWIGEXPORT int SWIGSTDCALL CSharp_SWITCH_RTP_MAX_BUF_LEN_get() { int jresult ; int result; diff --git a/src/mod/languages/mod_managed/managed/swig.cs b/src/mod/languages/mod_managed/managed/swig.cs index bd901911ed..10fd3c6bc6 100644 --- a/src/mod/languages/mod_managed/managed/swig.cs +++ b/src/mod/languages/mod_managed/managed/swig.cs @@ -1103,6 +1103,21 @@ public class freeswitch { return ret; } + public static switch_status_t switch_core_session_io_read_lock(SWIGTYPE_p_switch_core_session session) { + switch_status_t ret = (switch_status_t)freeswitchPINVOKE.switch_core_session_io_read_lock(SWIGTYPE_p_switch_core_session.getCPtr(session)); + return ret; + } + + public static switch_status_t switch_core_session_io_write_lock(SWIGTYPE_p_switch_core_session session) { + switch_status_t ret = (switch_status_t)freeswitchPINVOKE.switch_core_session_io_write_lock(SWIGTYPE_p_switch_core_session.getCPtr(session)); + return ret; + } + + public static switch_status_t switch_core_session_io_rwunlock(SWIGTYPE_p_switch_core_session session) { + switch_status_t ret = (switch_status_t)freeswitchPINVOKE.switch_core_session_io_rwunlock(SWIGTYPE_p_switch_core_session.getCPtr(session)); + return ret; + } + public static switch_status_t switch_core_session_read_lock(SWIGTYPE_p_switch_core_session session) { switch_status_t ret = (switch_status_t)freeswitchPINVOKE.switch_core_session_read_lock(SWIGTYPE_p_switch_core_session.getCPtr(session)); return ret; @@ -1439,6 +1454,11 @@ public class freeswitch { return ret; } + public static switch_status_t switch_core_session_execute_application_async(SWIGTYPE_p_switch_core_session session, string app, string arg) { + switch_status_t ret = (switch_status_t)freeswitchPINVOKE.switch_core_session_execute_application_async(SWIGTYPE_p_switch_core_session.getCPtr(session), app, arg); + return ret; + } + public static switch_status_t switch_core_session_get_app_flags(string app, SWIGTYPE_p_int flags) { switch_status_t ret = (switch_status_t)freeswitchPINVOKE.switch_core_session_get_app_flags(app, SWIGTYPE_p_int.getCPtr(flags)); return ret; @@ -1518,6 +1538,11 @@ public class freeswitch { return ret; } + public static uint switch_core_session_messages_waiting(SWIGTYPE_p_switch_core_session session) { + uint ret = freeswitchPINVOKE.switch_core_session_messages_waiting(SWIGTYPE_p_switch_core_session.getCPtr(session)); + return ret; + } + public static switch_status_t switch_core_session_dequeue_event(SWIGTYPE_p_switch_core_session session, SWIGTYPE_p_p_switch_event arg1, switch_bool_t force) { switch_status_t ret = (switch_status_t)freeswitchPINVOKE.switch_core_session_dequeue_event(SWIGTYPE_p_switch_core_session.getCPtr(session), SWIGTYPE_p_p_switch_event.getCPtr(arg1), (int)force); return ret; @@ -4461,6 +4486,21 @@ public class freeswitch { return ret; } + public static switch_status_t switch_ivr_get_file_handle(SWIGTYPE_p_switch_core_session session, SWIGTYPE_p_p_switch_file_handle fh) { + switch_status_t ret = (switch_status_t)freeswitchPINVOKE.switch_ivr_get_file_handle(SWIGTYPE_p_switch_core_session.getCPtr(session), SWIGTYPE_p_p_switch_file_handle.getCPtr(fh)); + return ret; + } + + public static switch_status_t switch_ivr_release_file_handle(SWIGTYPE_p_switch_core_session session, SWIGTYPE_p_p_switch_file_handle fh) { + switch_status_t ret = (switch_status_t)freeswitchPINVOKE.switch_ivr_release_file_handle(SWIGTYPE_p_switch_core_session.getCPtr(session), SWIGTYPE_p_p_switch_file_handle.getCPtr(fh)); + return ret; + } + + public static switch_status_t switch_ivr_process_fh(SWIGTYPE_p_switch_core_session session, string cmd, switch_file_handle fhp) { + switch_status_t ret = (switch_status_t)freeswitchPINVOKE.switch_ivr_process_fh(SWIGTYPE_p_switch_core_session.getCPtr(session), cmd, switch_file_handle.getCPtr(fhp)); + return ret; + } + public static switch_status_t switch_rtp_add_crypto_key(SWIGTYPE_p_switch_rtp rtp_session, switch_rtp_crypto_direction_t direction, uint index, switch_rtp_crypto_key_type_t type, SWIGTYPE_p_unsigned_char key, SWIGTYPE_p_switch_size_t keylen) { switch_status_t ret = (switch_status_t)freeswitchPINVOKE.switch_rtp_add_crypto_key(SWIGTYPE_p_switch_rtp.getCPtr(rtp_session), (int)direction, index, (int)type, SWIGTYPE_p_unsigned_char.getCPtr(key), SWIGTYPE_p_switch_size_t.getCPtr(keylen)); if (freeswitchPINVOKE.SWIGPendingException.Pending) throw freeswitchPINVOKE.SWIGPendingException.Retrieve(); @@ -7245,6 +7285,15 @@ class freeswitchPINVOKE { [DllImport("mod_managed", EntryPoint="CSharp_switch_core_destroy")] public static extern int switch_core_destroy(); + [DllImport("mod_managed", EntryPoint="CSharp_switch_core_session_io_read_lock")] + public static extern int switch_core_session_io_read_lock(HandleRef jarg1); + + [DllImport("mod_managed", EntryPoint="CSharp_switch_core_session_io_write_lock")] + public static extern int switch_core_session_io_write_lock(HandleRef jarg1); + + [DllImport("mod_managed", EntryPoint="CSharp_switch_core_session_io_rwunlock")] + public static extern int switch_core_session_io_rwunlock(HandleRef jarg1); + [DllImport("mod_managed", EntryPoint="CSharp_switch_core_session_read_lock")] public static extern int switch_core_session_read_lock(HandleRef jarg1); @@ -7449,6 +7498,9 @@ class freeswitchPINVOKE { [DllImport("mod_managed", EntryPoint="CSharp_switch_core_session_execute_application_get_flags")] public static extern int switch_core_session_execute_application_get_flags(HandleRef jarg1, string jarg2, string jarg3, HandleRef jarg4); + [DllImport("mod_managed", EntryPoint="CSharp_switch_core_session_execute_application_async")] + public static extern int switch_core_session_execute_application_async(HandleRef jarg1, string jarg2, string jarg3); + [DllImport("mod_managed", EntryPoint="CSharp_switch_core_session_get_app_flags")] public static extern int switch_core_session_get_app_flags(string jarg1, HandleRef jarg2); @@ -7497,6 +7549,9 @@ class freeswitchPINVOKE { [DllImport("mod_managed", EntryPoint="CSharp_switch_core_session_event_count")] public static extern uint switch_core_session_event_count(HandleRef jarg1); + [DllImport("mod_managed", EntryPoint="CSharp_switch_core_session_messages_waiting")] + public static extern uint switch_core_session_messages_waiting(HandleRef jarg1); + [DllImport("mod_managed", EntryPoint="CSharp_switch_core_session_dequeue_event")] public static extern int switch_core_session_dequeue_event(HandleRef jarg1, HandleRef jarg2, int jarg3); @@ -12228,6 +12283,15 @@ class freeswitchPINVOKE { [DllImport("mod_managed", EntryPoint="CSharp_switch_ivr_dmachine_set_realm")] public static extern int switch_ivr_dmachine_set_realm(HandleRef jarg1, string jarg2); + [DllImport("mod_managed", EntryPoint="CSharp_switch_ivr_get_file_handle")] + public static extern int switch_ivr_get_file_handle(HandleRef jarg1, HandleRef jarg2); + + [DllImport("mod_managed", EntryPoint="CSharp_switch_ivr_release_file_handle")] + public static extern int switch_ivr_release_file_handle(HandleRef jarg1, HandleRef jarg2); + + [DllImport("mod_managed", EntryPoint="CSharp_switch_ivr_process_fh")] + public static extern int switch_ivr_process_fh(HandleRef jarg1, string jarg2, HandleRef jarg3); + [DllImport("mod_managed", EntryPoint="CSharp_SWITCH_RTP_MAX_BUF_LEN_get")] public static extern int SWITCH_RTP_MAX_BUF_LEN_get(); @@ -17103,6 +17167,36 @@ namespace FreeSWITCH.Native { using System; using System.Runtime.InteropServices; +public class SWIGTYPE_p_p_switch_file_handle { + private HandleRef swigCPtr; + + internal SWIGTYPE_p_p_switch_file_handle(IntPtr cPtr, bool futureUse) { + swigCPtr = new HandleRef(this, cPtr); + } + + protected SWIGTYPE_p_p_switch_file_handle() { + swigCPtr = new HandleRef(null, IntPtr.Zero); + } + + internal static HandleRef getCPtr(SWIGTYPE_p_p_switch_file_handle obj) { + return (obj == null) ? new HandleRef(null, IntPtr.Zero) : obj.swigCPtr; + } +} + +} +/* ---------------------------------------------------------------------------- + * This file was automatically generated by SWIG (http://www.swig.org). + * Version 1.3.35 + * + * Do not make changes to this file unless you know what you are doing--modify + * the SWIG interface file instead. + * ----------------------------------------------------------------------------- */ + +namespace FreeSWITCH.Native { + +using System; +using System.Runtime.InteropServices; + public class SWIGTYPE_p_p_switch_frame { private HandleRef swigCPtr; diff --git a/src/mod/languages/mod_managed/mono28.patch b/src/mod/languages/mod_managed/mono28.patch new file mode 100644 index 0000000000..7ec60f596c --- /dev/null +++ b/src/mod/languages/mod_managed/mono28.patch @@ -0,0 +1,75 @@ +diff --git a/src/mod/languages/mod_managed/Makefile b/src/mod/languages/mod_managed/Makefile +index 0ac49b4..ec44ff5 100644 +--- a/src/mod/languages/mod_managed/Makefile ++++ b/src/mod/languages/mod_managed/Makefile +@@ -1,6 +1,6 @@ +-LOCAL_INSERT_CFLAGS= /usr/bin/pkg-config mono --cflags +-LOCAL_INSERT_LDFLAGS= /usr/bin/pkg-config mono --libs +-#MOD_CFLAGS=-D_REENTRANT -pthread -I/opt/mono-1.9/lib/pkgconfig/../../include/mono-1.0 -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -lmono ++LOCAL_INSERT_CFLAGS= /usr/bin/pkg-config mono-2 --cflags ++LOCAL_INSERT_LDFLAGS= /usr/bin/pkg-config mono-2 --libs ++#MOD_CFLAGS=-D_REENTRANT -pthread -I/usr/lib/mono -lmono + BASE=../../../.. + VERBOSE=1 + include $(BASE)/build/modmake.rules +diff --git a/src/mod/languages/mod_managed/freeswitch.i b/src/mod/languages/mod_managed/freeswitch.i +index ffbdf9b..117d58c 100644 +--- a/src/mod/languages/mod_managed/freeswitch.i ++++ b/src/mod/languages/mod_managed/freeswitch.i +@@ -8,7 +8,6 @@ + + /* Callback for returning strings to C# without leaking memory */ + #ifndef _MANAGED +-#include + #include + #include + #include +diff --git a/src/mod/languages/mod_managed/freeswitch_managed.h b/src/mod/languages/mod_managed/freeswitch_managed.h +index 1d0b6a7..13ffe5d 100644 +--- a/src/mod/languages/mod_managed/freeswitch_managed.h ++++ b/src/mod/languages/mod_managed/freeswitch_managed.h +@@ -40,7 +40,6 @@ typedef void (*hangupFunction) (void); + typedef char *(*inputFunction) (void *, switch_input_type_t); + + #ifndef _MANAGED +-#include + #include + #include + #include +@@ -73,7 +72,7 @@ extern mod_managed_globals globals; + #ifdef WIN32 + #define RESULT_FREE(x) CoTaskMemFree(x) + #else +-#define RESULT_FREE(x) g_free(x) ++#define RESULT_FREE(x) mono_free(x) + #endif + + SWITCH_END_EXTERN_C +diff --git a/src/mod/languages/mod_managed/mod_managed.cpp b/src/mod/languages/mod_managed/mod_managed.cpp +index ec2d866..87e831f 100644 +--- a/src/mod/languages/mod_managed/mod_managed.cpp ++++ b/src/mod/languages/mod_managed/mod_managed.cpp +@@ -208,18 +208,13 @@ switch_status_t loadRuntime() + } + + /* Already loaded? */ +- MonoAssemblyName name; +- name.name = MOD_MANAGED_ASM_NAME; +- name.major = MOD_MANAGED_ASM_V1; +- name.minor = MOD_MANAGED_ASM_V2; +- name.revision = MOD_MANAGED_ASM_V3; +- name.build = MOD_MANAGED_ASM_V4; +- name.culture = ""; +- name.hash_value = ""; +- ++ MonoAssemblyName *name = mono_assembly_name_new (MOD_MANAGED_ASM_NAME); ++ //Note also that it can't be allocated on the stack anymore and you'll need to create and destroy it with the following API: ++ //mono_assembly_name_free (name); ++ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Calling mono_assembly_loaded.\n"); + +- if (!(globals.mod_mono_asm = mono_assembly_loaded(&name))) { ++ if (!(globals.mod_mono_asm = mono_assembly_loaded(name))) { + /* Open the assembly */ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Calling mono_domain_assembly_open.\n"); + globals.mod_mono_asm = mono_domain_assembly_open(globals.domain, filename); 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 --- a/src/mod/languages/mod_perl/mod_perl_wrap.cpp +++ b/src/mod/languages/mod_perl/mod_perl_wrap.cpp @@ -9732,17 +9732,17 @@ XS(SWIG_init) { SWIG_TypeClientData(SWIGTYPE_p_IVRMenu, (void*) "freeswitch::IVRMenu"); SWIG_TypeClientData(SWIGTYPE_p_API, (void*) "freeswitch::API"); SWIG_TypeClientData(SWIGTYPE_p_input_callback_state, (void*) "freeswitch::input_callback_state_t"); - /*@SWIG:/usr/share/swig/1.3.35/perl5/perltypemaps.swg,64,%set_constant@*/ do { + /*@SWIG:/usr/local/share/swig/1.3.35/perl5/perltypemaps.swg,64,%set_constant@*/ do { SV *sv = get_sv((char*) SWIG_prefix "S_HUP", TRUE | 0x2 | GV_ADDMULTI); sv_setsv(sv, SWIG_From_int SWIG_PERL_CALL_ARGS_1(static_cast< int >(S_HUP))); SvREADONLY_on(sv); } while(0) /*@SWIG@*/; - /*@SWIG:/usr/share/swig/1.3.35/perl5/perltypemaps.swg,64,%set_constant@*/ do { + /*@SWIG:/usr/local/share/swig/1.3.35/perl5/perltypemaps.swg,64,%set_constant@*/ do { SV *sv = get_sv((char*) SWIG_prefix "S_FREE", TRUE | 0x2 | GV_ADDMULTI); sv_setsv(sv, SWIG_From_int SWIG_PERL_CALL_ARGS_1(static_cast< int >(S_FREE))); SvREADONLY_on(sv); } while(0) /*@SWIG@*/; - /*@SWIG:/usr/share/swig/1.3.35/perl5/perltypemaps.swg,64,%set_constant@*/ do { + /*@SWIG:/usr/local/share/swig/1.3.35/perl5/perltypemaps.swg,64,%set_constant@*/ do { SV *sv = get_sv((char*) SWIG_prefix "S_RDLOCK", TRUE | 0x2 | GV_ADDMULTI); sv_setsv(sv, SWIG_From_int SWIG_PERL_CALL_ARGS_1(static_cast< int >(S_RDLOCK))); SvREADONLY_on(sv); diff --git a/src/switch_channel.c b/src/switch_channel.c index c63a1aadb9..a9c87c5954 100644 --- a/src/switch_channel.c +++ b/src/switch_channel.c @@ -2518,7 +2518,12 @@ SWITCH_DECLARE(switch_status_t) switch_channel_perform_mark_ring_ready_value(swi if ((arg = strchr(app, ' '))) { *arg++ = '\0'; } - switch_core_session_execute_application(channel->session, app, arg); + + if (switch_core_session_in_thread(channel->session)) { + switch_core_session_execute_application(channel->session, app, arg); + } else { + switch_core_session_execute_application_async(channel->session, app, arg); + } } return SWITCH_STATUS_SUCCESS; @@ -2571,7 +2576,12 @@ SWITCH_DECLARE(switch_status_t) switch_channel_perform_mark_pre_answered(switch_ if ((arg = strchr(app, ' '))) { *arg++ = '\0'; } - switch_core_session_execute_application(channel->session, app, arg); + + if (switch_core_session_in_thread(channel->session)) { + switch_core_session_execute_application(channel->session, app, arg); + } else { + switch_core_session_execute_application_async(channel->session, app, arg); + } } if ((var = switch_channel_get_variable(channel, SWITCH_PASSTHRU_PTIME_MISMATCH_VARIABLE))) { @@ -2750,7 +2760,12 @@ SWITCH_DECLARE(switch_status_t) switch_channel_perform_mark_answered(switch_chan } switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_DEBUG, "%s execute on answer: %s(%s)\n", channel->name, app, switch_str_nil(arg)); - switch_core_session_execute_application(channel->session, app, arg); + + if (switch_core_session_in_thread(channel->session)) { + switch_core_session_execute_application(channel->session, app, arg); + } else { + switch_core_session_execute_application_async(channel->session, app, arg); + } } } diff --git a/src/switch_core_rwlock.c b/src/switch_core_rwlock.c index 4285491dc1..57168d9a29 100644 --- a/src/switch_core_rwlock.c +++ b/src/switch_core_rwlock.c @@ -36,6 +36,46 @@ #include "private/switch_core_pvt.h" +SWITCH_DECLARE(switch_status_t) switch_core_session_io_read_lock(switch_core_session_t *session) +{ + switch_status_t status = SWITCH_STATUS_FALSE; + + if (session->io_rwlock) { + if (switch_thread_rwlock_tryrdlock(session->io_rwlock) == SWITCH_STATUS_SUCCESS) { + status = SWITCH_STATUS_SUCCESS; + } + } + + return status; +} + +SWITCH_DECLARE(switch_status_t) switch_core_session_io_write_lock(switch_core_session_t *session) +{ + switch_status_t status = SWITCH_STATUS_FALSE; + + if (session->io_rwlock) { + switch_thread_rwlock_wrlock(session->io_rwlock); + status = SWITCH_STATUS_SUCCESS; + } + + return status; +} + + +SWITCH_DECLARE(switch_status_t) switch_core_session_io_rwunlock(switch_core_session_t *session) +{ + switch_status_t status = SWITCH_STATUS_FALSE; + + if (session->io_rwlock) { + switch_thread_rwlock_unlock(session->io_rwlock); + status = SWITCH_STATUS_SUCCESS; + } + + return status; +} + + + #ifdef SWITCH_DEBUG_RWLOCKS SWITCH_DECLARE(switch_status_t) switch_core_session_perform_read_lock(switch_core_session_t *session, const char *file, const char *func, int line) #else diff --git a/src/switch_core_session.c b/src/switch_core_session.c index b3bb638c76..fc7648155a 100644 --- a/src/switch_core_session.c +++ b/src/switch_core_session.c @@ -855,12 +855,31 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_queue_event(switch_core_sess if (switch_queue_trypush(session->event_queue, *event) == SWITCH_STATUS_SUCCESS) { *event = NULL; status = SWITCH_STATUS_SUCCESS; + + if (switch_channel_test_flag(session->channel, CF_PROXY_MODE) || switch_channel_test_flag(session->channel, CF_THREAD_SLEEPING)) { + switch_core_session_wake_session_thread(session); + } } } return status; } +SWITCH_DECLARE(uint32_t) switch_core_session_messages_waiting(switch_core_session_t *session) +{ + int x = 0; + + if (session->private_event_queue) { + x += switch_queue_size(session->private_event_queue); + } + + if (session->message_queue) { + x += switch_queue_size(session->message_queue); + } + + return x; +} + SWITCH_DECLARE(uint32_t) switch_core_session_event_count(switch_core_session_t *session) { if (session->event_queue) { @@ -1648,6 +1667,7 @@ SWITCH_DECLARE(switch_core_session_t *) switch_core_session_request_uuid(switch_ switch_thread_rwlock_create(&session->bug_rwlock, session->pool); switch_thread_cond_create(&session->cond, session->pool); switch_thread_rwlock_create(&session->rwlock, session->pool); + switch_thread_rwlock_create(&session->io_rwlock, session->pool); switch_queue_create(&session->message_queue, SWITCH_MESSAGE_QUEUE_LEN, session->pool); switch_queue_create(&session->event_queue, SWITCH_EVENT_QUEUE_LEN, session->pool); switch_queue_create(&session->private_event_queue, SWITCH_EVENT_QUEUE_LEN, session->pool); @@ -1799,6 +1819,28 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_get_app_flags(const char *ap } +SWITCH_DECLARE(switch_status_t) switch_core_session_execute_application_async(switch_core_session_t *session, const char *app, const char *arg) +{ + switch_event_t *execute_event; + + if (switch_event_create(&execute_event, SWITCH_EVENT_COMMAND) == SWITCH_STATUS_SUCCESS) { + switch_event_add_header_string(execute_event, SWITCH_STACK_BOTTOM, "call-command", "execute"); + switch_event_add_header_string(execute_event, SWITCH_STACK_BOTTOM, "execute-app-name", app); + + if (arg) { + switch_event_add_header_string(execute_event, SWITCH_STACK_BOTTOM, "execute-app-arg", arg); + } + + switch_event_add_header_string(execute_event, SWITCH_STACK_BOTTOM, "event-lock", "true"); + switch_core_session_queue_private_event(session, &execute_event, SWITCH_FALSE); + + return SWITCH_STATUS_SUCCESS; + } + + return SWITCH_STATUS_FALSE; +} + + SWITCH_DECLARE(switch_status_t) switch_core_session_execute_application_get_flags(switch_core_session_t *session, const char *app, const char *arg, int32_t *flags) { @@ -1831,10 +1873,16 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_execute_application_get_flag switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Application %s Requires media on channel %s!\n", app, switch_channel_get_name(session->channel)); } else if (!switch_test_flag(application_interface, SAF_SUPPORT_NOMEDIA) && !switch_channel_media_ready(session->channel)) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Application %s Requires media! pre_answering channel %s\n", - app, switch_channel_get_name(session->channel)); - if (switch_channel_pre_answer(session->channel) != SWITCH_STATUS_SUCCESS) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Well, that didn't work very well did it? ...\n"); + if (switch_channel_direction(session->channel) == SWITCH_CALL_DIRECTION_INBOUND) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Application %s Requires media! pre_answering channel %s\n", + app, switch_channel_get_name(session->channel)); + if (switch_channel_pre_answer(session->channel) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Well, that didn't work very well did it? ...\n"); + switch_goto_status(SWITCH_STATUS_FALSE, done); + } + } else { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, + "Cannot execute app '%s' media required on an outbound channel that does not have media established\n", app); switch_goto_status(SWITCH_STATUS_FALSE, done); } } diff --git a/src/switch_cpp.cpp b/src/switch_cpp.cpp index 469ae18c4b..40462db567 100644 --- a/src/switch_cpp.cpp +++ b/src/switch_cpp.cpp @@ -1269,120 +1269,7 @@ SWITCH_DECLARE(switch_status_t) CoreSession::process_callback_result(char *resul this_check(SWITCH_STATUS_FALSE); sanity_check(SWITCH_STATUS_FALSE); - if (zstr(result)) { - return SWITCH_STATUS_SUCCESS; - } - - if (fhp) { - if (!switch_test_flag(fhp, SWITCH_FILE_OPEN)) { - return SWITCH_STATUS_FALSE; - } - - if (!strncasecmp(result, "speed", 5)) { - char *p; - - if ((p = strchr(result, ':'))) { - p++; - if (*p == '+' || *p == '-') { - int step; - if (!(step = atoi(p))) { - step = 1; - } - fhp->speed += step; - } else { - int speed = atoi(p); - fhp->speed = speed; - } - return SWITCH_STATUS_SUCCESS; - } - - return SWITCH_STATUS_FALSE; - - } else if (!strncasecmp(result, "volume", 6)) { - char *p; - - if ((p = strchr(result, ':'))) { - p++; - if (*p == '+' || *p == '-') { - int step; - if (!(step = atoi(p))) { - step = 1; - } - fhp->vol += step; - } else { - int vol = atoi(p); - fhp->vol = vol; - } - return SWITCH_STATUS_SUCCESS; - } - - if (fhp->vol) { - switch_normalize_volume(fhp->vol); - } - - return SWITCH_STATUS_FALSE; - } else if (!strcasecmp(result, "pause")) { - if (switch_test_flag(fhp, SWITCH_FILE_PAUSE)) { - switch_clear_flag(fhp, SWITCH_FILE_PAUSE); - } else { - switch_set_flag(fhp, SWITCH_FILE_PAUSE); - } - return SWITCH_STATUS_SUCCESS; - } else if (!strcasecmp(result, "stop")) { - return SWITCH_STATUS_FALSE; - } else if (!strcasecmp(result, "truncate")) { - switch_core_file_truncate(fhp, 0); - } else if (!strcasecmp(result, "restart")) { - unsigned int pos = 0; - fhp->speed = 0; - switch_core_file_seek(fhp, &pos, 0, SEEK_SET); - return SWITCH_STATUS_SUCCESS; - } else if (!strncasecmp(result, "seek", 4)) { - switch_codec_t *codec; - unsigned int samps = 0; - unsigned int pos = 0; - char *p; - codec = switch_core_session_get_read_codec(session); - - if ((p = strchr(result, ':'))) { - p++; - if (*p == '+' || *p == '-') { - int step; - int32_t target; - if (!(step = atoi(p))) { - step = 1000; - } - - samps = step * (codec->implementation->samples_per_second / 1000); - target = (int32_t)fhp->pos + samps; - - if (target < 0) { - target = 0; - } - - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "seek to position %d\n", target); - switch_core_file_seek(fhp, &pos, target, SEEK_SET); - - } else { - samps = atoi(p) * (codec->implementation->samples_per_second / 1000); - if (samps < 0) { - samps = 0; - } - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "seek to position %d\n", samps); - switch_core_file_seek(fhp, &pos, samps, SEEK_SET); - } - } - - return SWITCH_STATUS_SUCCESS; - } - } - - if (!strcmp(result, "true") || !strcmp(result, "undefined")) { - return SWITCH_STATUS_SUCCESS; - } - - - return SWITCH_STATUS_FALSE; + return switch_ivr_process_fh(session, result, fhp); } /* For Emacs: diff --git a/src/switch_ivr.c b/src/switch_ivr.c index f076f6cb9f..00917adc34 100644 --- a/src/switch_ivr.c +++ b/src/switch_ivr.c @@ -763,6 +763,10 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_park(switch_core_session_t *session, write_frame.samples = write_frame.datalen / sizeof(int16_t); } + if (switch_channel_test_flag(channel, CF_RECOVERED) && switch_channel_test_flag(channel, CF_CONTROLLED)) { + switch_channel_clear_flag(channel, CF_CONTROLLED); + } + if (switch_channel_test_flag(channel, CF_CONTROLLED)) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Cannot park channels that are under control already.\n"); return SWITCH_STATUS_FALSE; @@ -2559,6 +2563,124 @@ SWITCH_DECLARE(switch_bool_t) switch_ivr_uuid_exists(const char *uuid) return exists; } +SWITCH_DECLARE(switch_status_t) switch_ivr_process_fh(switch_core_session_t *session, const char *cmd, switch_file_handle_t *fhp) +{ + if (zstr(cmd)) { + return SWITCH_STATUS_SUCCESS; + } + + if (fhp) { + if (!switch_test_flag(fhp, SWITCH_FILE_OPEN)) { + return SWITCH_STATUS_FALSE; + } + + if (!strncasecmp(cmd, "speed", 5)) { + char *p; + + if ((p = strchr(cmd, ':'))) { + p++; + if (*p == '+' || *p == '-') { + int step; + if (!(step = atoi(p))) { + step = 1; + } + fhp->speed += step; + } else { + int speed = atoi(p); + fhp->speed = speed; + } + return SWITCH_STATUS_SUCCESS; + } + + return SWITCH_STATUS_FALSE; + + } else if (!strncasecmp(cmd, "volume", 6)) { + char *p; + + if ((p = strchr(cmd, ':'))) { + p++; + if (*p == '+' || *p == '-') { + int step; + if (!(step = atoi(p))) { + step = 1; + } + fhp->vol += step; + } else { + int vol = atoi(p); + fhp->vol = vol; + } + return SWITCH_STATUS_SUCCESS; + } + + if (fhp->vol) { + switch_normalize_volume(fhp->vol); + } + + return SWITCH_STATUS_FALSE; + } else if (!strcasecmp(cmd, "pause")) { + if (switch_test_flag(fhp, SWITCH_FILE_PAUSE)) { + switch_clear_flag(fhp, SWITCH_FILE_PAUSE); + } else { + switch_set_flag(fhp, SWITCH_FILE_PAUSE); + } + return SWITCH_STATUS_SUCCESS; + } else if (!strcasecmp(cmd, "stop")) { + return SWITCH_STATUS_FALSE; + } else if (!strcasecmp(cmd, "truncate")) { + switch_core_file_truncate(fhp, 0); + } else if (!strcasecmp(cmd, "restart")) { + unsigned int pos = 0; + fhp->speed = 0; + switch_core_file_seek(fhp, &pos, 0, SEEK_SET); + return SWITCH_STATUS_SUCCESS; + } else if (!strncasecmp(cmd, "seek", 4)) { + switch_codec_t *codec; + unsigned int samps = 0; + unsigned int pos = 0; + char *p; + codec = switch_core_session_get_read_codec(session); + + if ((p = strchr(cmd, ':'))) { + p++; + if (*p == '+' || *p == '-') { + int step; + int32_t target; + if (!(step = atoi(p))) { + step = 1000; + } + + samps = step * (codec->implementation->samples_per_second / 1000); + target = (int32_t)fhp->pos + samps; + + if (target < 0) { + target = 0; + } + + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "seek to position %d\n", target); + switch_core_file_seek(fhp, &pos, target, SEEK_SET); + + } else { + samps = atoi(p) * (codec->implementation->samples_per_second / 1000); + if (samps < 0) { + samps = 0; + } + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "seek to position %d\n", samps); + switch_core_file_seek(fhp, &pos, samps, SEEK_SET); + } + } + + return SWITCH_STATUS_SUCCESS; + } + } + + if (!strcmp(cmd, "true") || !strcmp(cmd, "undefined")) { + return SWITCH_STATUS_SUCCESS; + } + + return SWITCH_STATUS_FALSE; + +} + /* For Emacs: * Local Variables: diff --git a/src/switch_ivr_bridge.c b/src/switch_ivr_bridge.c index b6363ffa53..4d320d0e5c 100644 --- a/src/switch_ivr_bridge.c +++ b/src/switch_ivr_bridge.c @@ -155,7 +155,6 @@ struct switch_ivr_bridge_data { switch_input_callback_function_t input_callback; void *session_data; int clean_exit; - uint32_t skip_frames; }; typedef struct switch_ivr_bridge_data switch_ivr_bridge_data_t; @@ -169,7 +168,7 @@ static void *audio_bridge_thread(switch_thread_t *thread, void *obj) switch_channel_t *chan_a, *chan_b; switch_frame_t *read_frame; switch_core_session_t *session_a, *session_b; - uint32_t loop_count = 0; + uint32_t read_frame_count = 0; const char *app_name = NULL, *app_arg = NULL; const char *hook_var = NULL; int inner_bridge = 0; @@ -181,6 +180,8 @@ static void *audio_bridge_thread(switch_thread_t *thread, void *obj) const char *bridge_answer_timeout = NULL; int answer_timeout, sent_update = 0; time_t answer_limit = 0; + const char *exec_app = NULL; + const char *exec_data = NULL; #ifdef SWITCH_VIDEO_IN_THREADS switch_thread_t *vid_thread = NULL; @@ -201,6 +202,10 @@ static void *audio_bridge_thread(switch_thread_t *thread, void *obj) chan_a = switch_core_session_get_channel(session_a); chan_b = switch_core_session_get_channel(session_b); + if ((exec_app = switch_channel_get_variable(chan_a, "bridge_pre_execute_app"))) { + exec_data = switch_channel_get_variable(chan_a, "bridge_pre_execute_data"); + } + bypass_media_after_bridge = switch_channel_test_flag(chan_a, CF_BYPASS_MEDIA_AFTER_BRIDGE); switch_channel_clear_flag(chan_a, CF_BYPASS_MEDIA_AFTER_BRIDGE); @@ -212,7 +217,7 @@ static void *audio_bridge_thread(switch_thread_t *thread, void *obj) } inner_bridge = switch_channel_test_flag(chan_a, CF_INNER_BRIDGE); - + if (!switch_channel_test_flag(chan_a, CF_ANSWERED) && (bridge_answer_timeout = switch_channel_get_variable(chan_a, "bridge_answer_timeout"))) { if ((answer_timeout = atoi(bridge_answer_timeout)) < 0) { answer_timeout = 0; @@ -285,7 +290,6 @@ static void *audio_bridge_thread(switch_thread_t *thread, void *obj) switch_channel_state_t b_state; switch_status_t status; switch_event_t *event; - loop_count++; if (switch_channel_test_flag(chan_a, CF_TRANSFER)) { data->clean_exit = 1; @@ -309,7 +313,7 @@ static void *audio_bridge_thread(switch_thread_t *thread, void *obj) goto end_of_bridge_loop; } - if (loop_count > DEFAULT_LEAD_FRAMES && switch_channel_media_ack(chan_a) && switch_core_session_private_event_count(session_a)) { + if (read_frame_count > DEFAULT_LEAD_FRAMES && switch_channel_media_ack(chan_a) && switch_core_session_private_event_count(session_a)) { switch_channel_set_flag(chan_b, CF_SUSPEND); msg.string_arg = data->b_uuid; msg.message_id = SWITCH_MESSAGE_INDICATE_UNBRIDGE; @@ -341,13 +345,24 @@ static void *audio_bridge_thread(switch_thread_t *thread, void *obj) } #endif - if (loop_count > DEFAULT_LEAD_FRAMES && switch_channel_media_ack(chan_a) && - (bypass_media_after_bridge || switch_channel_test_flag(chan_a, CF_BYPASS_MEDIA_AFTER_BRIDGE)) && switch_channel_test_flag(chan_a, CF_ANSWERED) - && switch_channel_test_flag(chan_b, CF_ANSWERED)) { - switch_ivr_nomedia(switch_core_session_get_uuid(session_a), SMF_REBRIDGE); - bypass_media_after_bridge = 0; - switch_channel_clear_flag(chan_a, CF_BYPASS_MEDIA_AFTER_BRIDGE); - goto end_of_bridge_loop; + if (read_frame_count > DEFAULT_LEAD_FRAMES && switch_channel_media_ack(chan_a)) { + + if (exec_app) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session_a), SWITCH_LOG_DEBUG, "%s Bridge execute app %s(%s)\n", + switch_channel_get_name(chan_a), exec_app, exec_data); + + switch_core_session_execute_application_async(session_a, exec_app, exec_data); + exec_app = exec_data = NULL; + } + + + if ((bypass_media_after_bridge || switch_channel_test_flag(chan_a, CF_BYPASS_MEDIA_AFTER_BRIDGE)) && switch_channel_test_flag(chan_a, CF_ANSWERED) + && switch_channel_test_flag(chan_b, CF_ANSWERED)) { + switch_ivr_nomedia(switch_core_session_get_uuid(session_a), SMF_REBRIDGE); + bypass_media_after_bridge = 0; + switch_channel_clear_flag(chan_a, CF_BYPASS_MEDIA_AFTER_BRIDGE); + goto end_of_bridge_loop; + } } /* if 1 channel has DTMF pass it to the other */ @@ -454,6 +469,7 @@ static void *audio_bridge_thread(switch_thread_t *thread, void *obj) status = switch_core_session_read_frame(session_a, &read_frame, SWITCH_IO_FLAG_NONE, stream_id); if (SWITCH_READ_ACCEPTABLE(status)) { + read_frame_count++; if (switch_test_flag(read_frame, SFF_CNG)) { if (silence_val) { switch_generate_sln_silence((int16_t *) silence_frame.data, silence_frame.samples, silence_val); @@ -463,11 +479,6 @@ static void *audio_bridge_thread(switch_thread_t *thread, void *obj) } } - if (data->skip_frames) { - data->skip_frames--; - continue; - } - if (switch_channel_test_flag(chan_a, CF_BRIDGE_NOWRITE)) { continue; } @@ -1193,35 +1204,22 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_multi_threaded_bridge(switch_core_ses switch_channel_set_variable(peer_channel, SWITCH_SIGNAL_BOND_VARIABLE, switch_core_session_get_uuid(session)); if ((app = switch_channel_get_variable(caller_channel, "bridge_pre_execute_aleg_app"))) { - switch_event_t *execute_event; - - data = switch_channel_get_variable(caller_channel, "bridge_pre_execute_aleg_data"); - if (switch_event_create(&execute_event, SWITCH_EVENT_COMMAND) == SWITCH_STATUS_SUCCESS) { - switch_event_add_header_string(execute_event, SWITCH_STACK_BOTTOM, "call-command", "execute"); - switch_event_add_header_string(execute_event, SWITCH_STACK_BOTTOM, "execute-app-name", app); - switch_event_add_header_string(execute_event, SWITCH_STACK_BOTTOM, "execute-app-arg", data); - switch_event_add_header(execute_event, SWITCH_STACK_BOTTOM, "lead-frames", "%d", 5); - switch_event_add_header_string(execute_event, SWITCH_STACK_BOTTOM, "event-lock", "true"); - switch_core_session_queue_private_event(session, &execute_event, SWITCH_FALSE); - a_leg->skip_frames = DEFAULT_LEAD_FRAMES; + switch_channel_set_variable(caller_channel, "bridge_pre_execute_app", app); + + if ((data = switch_channel_get_variable(caller_channel, "bridge_pre_execute_aleg_data"))) { + switch_channel_set_variable(caller_channel, "bridge_pre_execute_data", data); } - } if ((app = switch_channel_get_variable(caller_channel, "bridge_pre_execute_bleg_app"))) { - switch_event_t *execute_event; - data = switch_channel_get_variable(caller_channel, "bridge_pre_execute_bleg_data"); - if (switch_event_create(&execute_event, SWITCH_EVENT_COMMAND) == SWITCH_STATUS_SUCCESS) { - switch_event_add_header_string(execute_event, SWITCH_STACK_BOTTOM, "call-command", "execute"); - switch_event_add_header_string(execute_event, SWITCH_STACK_BOTTOM, "execute-app-name", app); - switch_event_add_header_string(execute_event, SWITCH_STACK_BOTTOM, "execute-app-arg", data); - switch_event_add_header(execute_event, SWITCH_STACK_BOTTOM, "lead-frames", "%d", 5); - switch_event_add_header_string(execute_event, SWITCH_STACK_BOTTOM, "event-lock", "true"); - switch_core_session_queue_private_event(peer_session, &execute_event, SWITCH_FALSE); - b_leg->skip_frames = DEFAULT_LEAD_FRAMES; - } - } + switch_channel_set_variable(peer_channel, "bridge_pre_execute_app", app); + if ((data = switch_channel_get_variable(caller_channel, "bridge_pre_execute_bleg_data"))) { + switch_channel_set_variable(peer_channel, "bridge_pre_execute_data", data); + } + + } + switch_channel_set_private(peer_channel, "_bridge_", b_leg); switch_channel_set_state(peer_channel, CS_EXCHANGE_MEDIA); audio_bridge_thread(NULL, (void *) a_leg); diff --git a/src/switch_ivr_originate.c b/src/switch_ivr_originate.c index da76cf6cbc..e61534798b 100644 --- a/src/switch_ivr_originate.c +++ b/src/switch_ivr_originate.c @@ -635,8 +635,17 @@ static uint8_t check_channel_status(originate_global_t *oglobals, originate_stat } } } - - switch_ivr_parse_all_events(originate_status[i].peer_session); + + if (!switch_channel_test_flag(originate_status[i].peer_channel, CF_PARK) && + !switch_channel_test_flag(originate_status[i].peer_channel, CF_CONSUME_ON_ORIGINATE)) { + if (switch_core_session_messages_waiting(originate_status[i].peer_session)) { + if (switch_channel_test_flag(originate_status[i].peer_channel, CF_THREAD_SLEEPING)) { + switch_core_session_wake_session_thread(originate_status[i].peer_session); + } else { + switch_ivr_parse_all_events(originate_status[i].peer_session); + } + } + } state = switch_channel_get_state(originate_status[i].peer_channel); if (state >= CS_HANGUP || state == CS_RESET || switch_channel_test_flag(originate_status[i].peer_channel, CF_TRANSFER) || diff --git a/src/switch_ivr_play_say.c b/src/switch_ivr_play_say.c index 7285b894ea..3c8fa5e10f 100644 --- a/src/switch_ivr_play_say.c +++ b/src/switch_ivr_play_say.c @@ -913,6 +913,31 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_gentones(switch_core_session_t *sessi return SWITCH_STATUS_SUCCESS; } +SWITCH_DECLARE(switch_status_t) switch_ivr_get_file_handle(switch_core_session_t *session, switch_file_handle_t **fh) +{ + switch_file_handle_t *fhp; + switch_channel_t *channel = switch_core_session_get_channel(session); + + *fh = NULL; + switch_core_session_io_read_lock(session); + + if ((fhp = switch_channel_get_private(channel, "__fh"))) { + *fh = fhp; + return SWITCH_STATUS_SUCCESS; + } + + switch_core_session_io_rwunlock(session); + + return SWITCH_STATUS_FALSE; +} + +SWITCH_DECLARE(switch_status_t) switch_ivr_release_file_handle(switch_core_session_t *session, switch_file_handle_t **fh) +{ + *fh = NULL; + switch_core_session_io_rwunlock(session); + + return SWITCH_STATUS_SUCCESS; +} #define FILE_STARTSAMPLES 1024 * 32 #define FILE_BLOCKSIZE 1024 * 8 @@ -994,6 +1019,8 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_play_file(switch_core_session_t *sess } + + if (play_delimiter) { file_dup = switch_core_session_strdup(session, file); argc = switch_separate_string(file_dup, play_delimiter, argv, (sizeof(argv) / sizeof(argv[0]))); @@ -1134,6 +1161,11 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_play_file(switch_core_session_t *sess status = SWITCH_STATUS_NOTFOUND; continue; } + + switch_core_session_io_write_lock(session); + switch_channel_set_private(channel, "__fh", fh); + switch_core_session_io_rwunlock(session); + if (switch_test_flag(fh, SWITCH_FILE_NATIVE)) { asis = 1; } @@ -1208,7 +1240,12 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_play_file(switch_core_session_t *sess } else { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Raw Codec Activation Failed %s@%uhz %u channels %dms\n", codec_name, fh->samplerate, fh->channels, interval); + switch_core_session_io_write_lock(session); + switch_channel_set_private(channel, "__fh", NULL); + switch_core_session_io_rwunlock(session); + switch_core_file_close(fh); + switch_core_session_reset(session, SWITCH_TRUE, SWITCH_FALSE); status = SWITCH_STATUS_GENERR; continue; @@ -1228,6 +1265,9 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_play_file(switch_core_session_t *sess if (switch_core_timer_init(&timer, timer_name, interval, samples, pool) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Setup timer failed!\n"); switch_core_codec_destroy(&codec); + switch_core_session_io_write_lock(session); + switch_channel_set_private(channel, "__fh", NULL); + switch_core_session_io_rwunlock(session); switch_core_file_close(fh); switch_core_session_reset(session, SWITCH_TRUE, SWITCH_FALSE); status = SWITCH_STATUS_GENERR; @@ -1538,6 +1578,10 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_play_file(switch_core_session_t *sess } switch_channel_set_variable_printf(channel, "playback_samples", "%d", fh->samples_out); + switch_core_session_io_write_lock(session); + switch_channel_set_private(channel, "__fh", NULL); + switch_core_session_io_rwunlock(session); + switch_core_file_close(fh); if (fh->audio_buffer) { diff --git a/src/switch_odbc.c b/src/switch_odbc.c index 36c3c996e8..a1c476e4a1 100644 --- a/src/switch_odbc.c +++ b/src/switch_odbc.c @@ -364,7 +364,6 @@ SWITCH_DECLARE(switch_odbc_status_t) switch_odbc_handle_exec_string(switch_odbc_ goto done; } - result = SQLExecute(stmt); result = SQLFetch(stmt); if (result != SQL_SUCCESS && result != SQL_SUCCESS_WITH_INFO && result != SQL_NO_DATA) { diff --git a/src/switch_utils.c b/src/switch_utils.c index 75be02a31f..1a29e2b715 100644 --- a/src/switch_utils.c +++ b/src/switch_utils.c @@ -726,18 +726,31 @@ SWITCH_DECLARE(switch_bool_t) switch_is_lan_addr(const char *ip) if (zstr(ip)) return SWITCH_FALSE; - return (strncmp(ip, "10.", 3) && - strncmp(ip, "192.168.", 8) && - strncmp(ip, "127.", 4) && + return (strncmp(ip, "10.", 3) && /* 10.0.0.0 - 10.255.255.255 (10/8 prefix) */ + strncmp(ip, "192.168.", 8) && /* 192.168.0.0 - 192.168.255.255 (192.168/16 prefix) */ + strncmp(ip, "127.", 4) && /* 127.0.0.0 - 127.255.255.255 (127/8 prefix) */ strncmp(ip, "255.", 4) && - strncmp(ip, "0.", 2) && + strncmp(ip, "0.", 2) && strncmp(ip, "1.", 2) && strncmp(ip, "2.", 2) && - strncmp(ip, "172.16.", 7) && + strncmp(ip, "172.16.", 7) && /* 172.16.0.0 - 172.31.255.255 (172.16/12 prefix) */ strncmp(ip, "172.17.", 7) && strncmp(ip, "172.18.", 7) && strncmp(ip, "172.19.", 7) && - strncmp(ip, "172.2", 5) && strncmp(ip, "172.30.", 7) && strncmp(ip, "172.31.", 7) && strncmp(ip, "192.0.2.", 8) && strncmp(ip, "169.254.", 8) + strncmp(ip, "172.20.", 7) && + strncmp(ip, "172.21.", 7) && + strncmp(ip, "172.22.", 7) && + strncmp(ip, "172.23.", 7) && + strncmp(ip, "172.24.", 7) && + strncmp(ip, "172.25.", 7) && + strncmp(ip, "172.26.", 7) && + strncmp(ip, "172.27.", 7) && + strncmp(ip, "172.28.", 7) && + strncmp(ip, "172.29.", 7) && + strncmp(ip, "172.30.", 7) && + strncmp(ip, "172.31.", 7) && + strncmp(ip, "192.0.2.", 8) && /* 192.0.2.0 - 192.0.2.255 (192.0.2/24 prefix) */ + strncmp(ip, "169.254.", 8) /* 169.254.0.0 - 169.254.255.255 (169.254/16 prefix) */ )? SWITCH_FALSE : SWITCH_TRUE; } diff --git a/w32/Setup/Setup.wixproj b/w32/Setup/Setup.wixproj index 7d11c90a4b..fa6c832777 100644 --- a/w32/Setup/Setup.wixproj +++ b/w32/Setup/Setup.wixproj @@ -336,6 +336,15 @@ Binaries;Content;Satellites MODLOCATION + + mod_cepstral + {692f6330-4d87-4c82-81df-40db5892636e} + True + + + Binaries;Content;Satellites + MODLOCATION + mod_pocketsphinx {2286da73-9fc5-45bc-a508-85994c3317ab}