+ * documentation on protected members and protected functions.
*
* @langversion ActionScript 3.0
* @playerversion Flash 9.0
@@ -203,7 +203,7 @@ package com.adobe.net
/**
- * @private Private initializiation.
+ * @private Private initialization.
*/
protected function initialize() : void
{
@@ -332,7 +332,7 @@ package com.adobe.net
* well formed. Sometimes characters that should have been escaped
* are not, and those situations would break a regexp pattern. This
* function attempts to be smart about what it is parsing based on
- * location of characters relative to eachother. This function has
+ * location of characters relative to each other. This function has
* been proven through real-world use to parse the vast majority
* of URI's correctly.
*
@@ -835,7 +835,7 @@ package com.adobe.net
* to be properly escaped and unescaped, it must be split into its
* component parts. This accessor escapes/unescapes the entire query
* part without regard for it's component parts. This has the
- * possibliity of leaving the query string in an ambiguious state in
+ * possibliity of leaving the query string in an ambiguous state in
* regards to its syntax. If the contents of the query part are
* important, it is recommended that get/setQueryValue() or
* get/setQueryByMap() are used instead.
@@ -2340,7 +2340,7 @@ package com.adobe.net
*
This function is intended to be a helper function.
* It is not all-knowning and will probably make mistakes
* when attempting to parse a string of unknown origin. If
- * your applicaiton is receiving input from the user, your
+ * your application is receiving input from the user, your
* application should already have a good idea what the user
* should be entering, and your application should be
* pre-processing the user's input to make sure it is well formed
@@ -2354,7 +2354,7 @@ package com.adobe.net
* on a URI that was created from unknownToURI() may not match
* the input string due to the difference in escaping.
*
- * @param unknown a potental URI string that should be parsed
+ * @param unknown a potential URI string that should be parsed
* and loaded into this object.
* @param defaultScheme if it is determined that the passed string
* looks like a URI, but it is missing the scheme part, this
diff --git a/clients/flex/com/adobe/serialization/json/JSONEncoder.as b/clients/flex/com/adobe/serialization/json/JSONEncoder.as
index 639df02c2c..1b5311e970 100644
--- a/clients/flex/com/adobe/serialization/json/JSONEncoder.as
+++ b/clients/flex/com/adobe/serialization/json/JSONEncoder.as
@@ -104,7 +104,7 @@ package com.adobe.serialization.json
}
/**
- * Escapes a string accoding to the JSON specification.
+ * Escapes a string according to the JSON specification.
*
* @param str The string to be escaped
* @return The string with escaped special characters
diff --git a/clients/flex/com/adobe/serialization/json/JSONParseError.as b/clients/flex/com/adobe/serialization/json/JSONParseError.as
index 5aec1e3b02..1c25b71da4 100644
--- a/clients/flex/com/adobe/serialization/json/JSONParseError.as
+++ b/clients/flex/com/adobe/serialization/json/JSONParseError.as
@@ -47,7 +47,7 @@ package com.adobe.serialization.json {
/**
* Constructs a new JSONParseError.
*
- * @param message The error message that occured during parsing
+ * @param message The error message that occurred during parsing
* @langversion ActionScript 3.0
* @playerversion Flash 9.0
* @tiptext
diff --git a/clients/flex/com/adobe/utils/DateUtil.as b/clients/flex/com/adobe/utils/DateUtil.as
index a741df0d76..13d4ee647c 100644
--- a/clients/flex/com/adobe/utils/DateUtil.as
+++ b/clients/flex/com/adobe/utils/DateUtil.as
@@ -74,7 +74,7 @@ package com.adobe.utils
* @param Optional parameter indicating whether the search should be case
* sensitive
*
- * @return A int that represents that month represented by the specifed
+ * @return A int that represents that month represented by the specified
* short name.
*
* @langversion ActionScript 3.0
@@ -114,7 +114,7 @@ package com.adobe.utils
*
* @param m A full month name.
*
- * @return A int that represents that month represented by the specifed
+ * @return A int that represents that month represented by the specified
* full month name.
*
* @langversion ActionScript 3.0
@@ -154,7 +154,7 @@ package com.adobe.utils
*
* @param m A short day name.
*
- * @return A int that represents that short day represented by the specifed
+ * @return A int that represents that short day represented by the specified
* full month name.
*
* @langversion ActionScript 3.0
@@ -194,7 +194,7 @@ package com.adobe.utils
*
* @param m A full day name.
*
- * @return A int that represents that full day represented by the specifed
+ * @return A int that represents that full day represented by the specified
* full month name.
*
* @langversion ActionScript 3.0
@@ -675,7 +675,7 @@ package com.adobe.utils
}
/**
- * Converts a date into just befor midnight.
+ * Converts a date into just before midnight.
*/
public static function makeNight(d:Date):Date
{
diff --git a/clients/flex/com/adobe/utils/StringUtil.as b/clients/flex/com/adobe/utils/StringUtil.as
index d7e98ed08b..af236d210e 100644
--- a/clients/flex/com/adobe/utils/StringUtil.as
+++ b/clients/flex/com/adobe/utils/StringUtil.as
@@ -79,7 +79,7 @@ package com.adobe.utils
* @param input The String whose beginning and ending whitespace will
* will be removed.
*
- * @returns A String with whitespace removed from the begining and end
+ * @returns A String with whitespace removed from the beginning and end
*
* @langversion ActionScript 3.0
* @playerversion Flash 9.0
@@ -95,7 +95,7 @@ package com.adobe.utils
*
* @param input The String whose beginning whitespace will will be removed.
*
- * @returns A String with whitespace removed from the begining
+ * @returns A String with whitespace removed from the beginning
*
* @langversion ActionScript 3.0
* @playerversion Flash 9.0
@@ -236,4 +236,4 @@ package com.adobe.utils
return (s != null && s.length > 0);
}
}
-}
\ No newline at end of file
+}
diff --git a/clients/flex/jquery-1.4.2.js b/clients/flex/jquery-1.4.2.js
index fff6776433..cc6e7dd4ea 100644
--- a/clients/flex/jquery-1.4.2.js
+++ b/clients/flex/jquery-1.4.2.js
@@ -519,7 +519,7 @@ jQuery.extend({
noop: function() {},
- // Evalulates a script in a global context
+ // Evaluates a script in a global context
globalEval: function( data ) {
if ( data && rnotwhite.test(data) ) {
// Inspired by code by Andrea Giammarchi
@@ -855,7 +855,7 @@ function now() {
htmlSerialize: !!div.getElementsByTagName("link").length,
// Get the style information from getAttribute
- // (IE uses .cssText insted)
+ // (IE uses .cssText instead)
style: /red/.test( a.getAttribute("style") ),
// Make sure that URLs aren't manipulated
@@ -1310,7 +1310,7 @@ jQuery.fn.extend({
classNames = value.split( rspace );
while ( (className = classNames[ i++ ]) ) {
- // check each className given, space seperated list
+ // check each className given, space separated list
state = isBool ? state : !self.hasClass( className );
self[ state ? "addClass" : "removeClass" ]( className );
}
@@ -1364,7 +1364,7 @@ jQuery.fn.extend({
var option = options[ i ];
if ( option.selected ) {
- // Get the specifc value for the option
+ // Get the specific value for the option
value = jQuery(option).val();
// We don't need an array for one selects
@@ -2636,7 +2636,7 @@ var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^
baseHasDuplicate = true;
// Here we check if the JavaScript engine is using some sort of
-// optimization where it does not always call our comparision
+// optimization where it does not always call our comparison
// function. If that is the case, discard the hasDuplicate value.
// Thus far that includes Google Chrome.
[0, 0].sort(function(){
@@ -3415,7 +3415,7 @@ if ( document.documentElement.compareDocumentPosition ) {
};
}
-// Utility function for retreiving the text value of an array of DOM nodes
+// Utility function for retrieving the text value of an array of DOM nodes
function getText( elems ) {
var ret = "", elem;
@@ -4149,7 +4149,7 @@ jQuery.fn.extend({
if ( !jQuery.support.noCloneEvent && !jQuery.isXMLDoc(this) ) {
// IE copies events bound via attachEvent when
// using cloneNode. Calling detachEvent on the
- // clone will also remove the events from the orignal
+ // clone will also remove the events from the original
// In order to get around this, we use innerHTML.
// Unfortunately, this means some modifications to
// attributes in IE that are actually only stored
@@ -4886,7 +4886,7 @@ jQuery.each( "ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".sp
jQuery.extend({
get: function( url, data, callback, type ) {
- // shift arguments if data argument was omited
+ // shift arguments if data argument was omitted
if ( jQuery.isFunction( data ) ) {
type = type || callback;
callback = data;
@@ -4911,7 +4911,7 @@ jQuery.extend({
},
post: function( url, data, callback, type ) {
- // shift arguments if data argument was omited
+ // shift arguments if data argument was omitted
if ( jQuery.isFunction( data ) ) {
type = type || callback;
callback = data;
@@ -4948,7 +4948,7 @@ jQuery.extend({
// Create the request object; Microsoft failed to properly
// implement the XMLHttpRequest in IE7 (can't request local files),
// so we use the ActiveXObject when it is available
- // This function can be overriden by calling jQuery.ajaxSetup
+ // This function can be overridden by calling jQuery.ajaxSetup
xhr: window.XMLHttpRequest && (window.location.protocol !== "file:" || !window.ActiveXObject) ?
function() {
return new window.XMLHttpRequest();
diff --git a/clients/flex/jquery.tmpl.js b/clients/flex/jquery.tmpl.js
index 7e850f9d06..24188733b6 100644
--- a/clients/flex/jquery.tmpl.js
+++ b/clients/flex/jquery.tmpl.js
@@ -362,7 +362,7 @@
function updateWrapped( options, wrapped ) {
// Build the wrapped content.
options._wrap = build( options, true,
- // Suport imperative scenario in which options.wrapped can be set to a selector or an HTML string.
+ // Support imperative scenario in which options.wrapped can be set to a selector or an HTML string.
jQuery.isArray( wrapped ) ? wrapped : [htmlExpr.test( wrapped ) ? wrapped : jQuery( wrapped ).html()]
).join("");
}
diff --git a/conf/curl/autoload_configs/conference.conf.xml b/conf/curl/autoload_configs/conference.conf.xml
index dad34b2cce..75a12c78fd 100644
--- a/conf/curl/autoload_configs/conference.conf.xml
+++ b/conf/curl/autoload_configs/conference.conf.xml
@@ -53,7 +53,7 @@
-
+
diff --git a/conf/curl/autoload_configs/xml_cdr.conf.xml b/conf/curl/autoload_configs/xml_cdr.conf.xml
index 7f635d64aa..6aed35ac91 100644
--- a/conf/curl/autoload_configs/xml_cdr.conf.xml
+++ b/conf/curl/autoload_configs/xml_cdr.conf.xml
@@ -6,7 +6,7 @@
-
+
diff --git a/conf/insideout/autoload_configs/conference.conf.xml b/conf/insideout/autoload_configs/conference.conf.xml
index dad34b2cce..75a12c78fd 100644
--- a/conf/insideout/autoload_configs/conference.conf.xml
+++ b/conf/insideout/autoload_configs/conference.conf.xml
@@ -53,7 +53,7 @@
-
+
diff --git a/conf/insideout/autoload_configs/xml_cdr.conf.xml b/conf/insideout/autoload_configs/xml_cdr.conf.xml
index 7f635d64aa..6aed35ac91 100644
--- a/conf/insideout/autoload_configs/xml_cdr.conf.xml
+++ b/conf/insideout/autoload_configs/xml_cdr.conf.xml
@@ -6,7 +6,7 @@
-
+
diff --git a/conf/insideout/dialplan/default.xml b/conf/insideout/dialplan/default.xml
index 560b3023bb..6290dd53b0 100644
--- a/conf/insideout/dialplan/default.xml
+++ b/conf/insideout/dialplan/default.xml
@@ -2,7 +2,7 @@
NOTICE:
This context is usually accessed via authenticated callers on the sip profile on port 5060
- or transfered callers from the public context which arrived via the sip profile on port 5080.
+ or transferred callers from the public context which arrived via the sip profile on port 5080.
Authenticated users will use the user_context variable on the user to determine what context
they can access. You can also add a user in the directory with the cidr= attribute acl.conf.xml
@@ -330,7 +330,7 @@
-
+
diff --git a/conf/rayo/autoload_configs/conference.conf.xml b/conf/rayo/autoload_configs/conference.conf.xml
index 1ccd675d75..0641df764e 100644
--- a/conf/rayo/autoload_configs/conference.conf.xml
+++ b/conf/rayo/autoload_configs/conference.conf.xml
@@ -64,7 +64,7 @@
-
+
diff --git a/conf/rayo/autoload_configs/spandsp.conf.xml b/conf/rayo/autoload_configs/spandsp.conf.xml
index f70416bc66..f9556d3c78 100644
--- a/conf/rayo/autoload_configs/spandsp.conf.xml
+++ b/conf/rayo/autoload_configs/spandsp.conf.xml
@@ -10,7 +10,7 @@
2) copy conf/config.FS0 to /var/spool/hylafax/etc (or wherver the appropriate dir is on your system)
- Subsequent modem configs would incrment the 0 to 1 and so on.
+ Subsequent modem configs would increment the 0 to 1 and so on.
-->
diff --git a/debian/README.source b/debian/README.source
index f1d4cff376..c5dc90b5de 100644
--- a/debian/README.source
+++ b/debian/README.source
@@ -63,7 +63,7 @@ The format of debian/modules.conf is:
Building the Debian packaging
-----------------------------
-If you want actualy Debian binary or source packages to upload to your
+If you want actually Debian binary or source packages to upload to your
own repository, you'll need to build them as described here. We have
some fancy automatic tools to accomplish this. The tools allow you to
start from a very bare Debian image and generate working packages.
diff --git a/docker/base_image/README.md b/docker/base_image/README.md
index 75e6e02dae..25ffe1a85f 100644
--- a/docker/base_image/README.md
+++ b/docker/base_image/README.md
@@ -70,7 +70,7 @@ systemd enable freeswitch-docker.service
.bashrc file
------------
-To simplify freeswitch managment you can add alias for ```fs_cli``` to ```.bashrc``` file as example bellow.
+To simplify freeswitch management you can add alias for ```fs_cli``` to ```.bashrc``` file as example bellow.
```sh
alias fs_cli='docker exec -i -t freeswitch /usr/bin/fs_cli'
```
diff --git a/docker/base_image/docker-entrypoint.sh b/docker/base_image/docker-entrypoint.sh
index f3e0519f23..030ee543ad 100755
--- a/docker/base_image/docker-entrypoint.sh
+++ b/docker/base_image/docker-entrypoint.sh
@@ -43,7 +43,7 @@ wget_helper() {
local SOUND_FILE=$1
grep -q $SOUND_FILE /usr/share/freeswitch/sounds/soundfiles_present.txt 2> /dev/null
if [ "$?" -eq 0 ]; then
- echo "Skiping download of $SOUND_FILE. Already present"
+ echo "Skipping download of $SOUND_FILE. Already present"
return
fi
wget $BASEURL/$SOUND_FILE
@@ -99,7 +99,7 @@ SOUND_RATES=$(echo "$SOUND_RATES" | sed -e 's/:/\n/g')
SOUND_TYPES=$(echo "$SOUND_TYPES" | sed -e 's/:/\n/g')
if [ -z "$SOUND_RATES" -o -z "$SOUND_TYPES" ]; then
- echo "Environment variables 'SOUND_RATES' or 'SOUND_TYPES' not defined. Skiping sound files checking."
+ echo "Environment variables 'SOUND_RATES' or 'SOUND_TYPES' not defined. Skipping sound files checking."
else
download_sound_types
extract_sound_files
diff --git a/docs/Doxygen.conf b/docs/Doxygen.conf
index 692a9f9e6c..5df2a2bcb2 100644
--- a/docs/Doxygen.conf
+++ b/docs/Doxygen.conf
@@ -278,10 +278,10 @@ TYPEDEF_HIDES_STRUCT = NO
# For small to medium size projects (<1000 input files) the default value is
# probably good enough. For larger projects a too small cache size can cause
# doxygen to be busy swapping symbols to and from disk most of the time
-# causing a significant performance penality.
+# causing a significant performance penalty.
# If the system has enough physical memory increasing the cache will improve the
# performance by keeping more symbols in memory. Note that the value works on
-# a logarithmic scale so increasing the size by one will rougly double the
+# a logarithmic scale so increasing the size by one will roughly double the
# memory usage. The cache size is given by this formula:
# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0,
# corresponding to a cache size of 2^16 = 65536 symbols
diff --git a/docs/phrase/README.TXT b/docs/phrase/README.TXT
index 463718289f..088147652c 100644
--- a/docs/phrase/README.TXT
+++ b/docs/phrase/README.TXT
@@ -8,9 +8,9 @@ language. If you are capable of recording each language please do so and
contribute them to the project. As phrases are added, the files will need to be
updated for the respective phrase_xx.xml file.
make_checks.sh - script to compare phrase_en.xml with other language xml files.
-Script output contans prompt elements with attributes:
+Script output contains prompt elements with attributes:
translated - value 'false' or not displayed;
-transpated-to - tranlation value if exists;
+translated-to - translation value if exists;
more-then-one-translation - displayed if exist two or more for given wav file.
How can you contribute?
diff --git a/docs/phrase/make_checks.sh b/docs/phrase/make_checks.sh
index 72e6105987..17bf93fa09 100755
--- a/docs/phrase/make_checks.sh
+++ b/docs/phrase/make_checks.sh
@@ -3,13 +3,13 @@ SAXON_JAR=/usr/share/java/saxon9he.jar
XML=$1
if [ ! -f "$SAXON_JAR" ]; then
- echo "Please update 'SAXON_JAR' varaiable value to location of SAXON jar"
+ echo "Please update 'SAXON_JAR' variable value to location of SAXON jar"
exit -1
fi
if [ -z "$XML" ]; then
echo "Error: Please enter xml file name that must be ckecked."
- echo "Exmple: make_checks.sh phrase_es_ES.xml > comparison_result.xml"
+ echo "Example: make_checks.sh phrase_es_ES.xml > comparison_result.xml"
exit -1
fi
diff --git a/freeswitch.spec b/freeswitch.spec
index dfd71f5429..4cf49c2118 100644
--- a/freeswitch.spec
+++ b/freeswitch.spec
@@ -296,7 +296,7 @@ Group: System/Libraries
Requires: %{name} = %{version}-%{release}
%description application-directory
-Provides FreeSWITCH mod_directory, a dial by name directory application.
+Provides FreeSWITCH mod_directory, a dial by name directory application.
%package application-distributor
Summary: FreeSWITCH mod_distributor
@@ -304,7 +304,7 @@ Group: System/Libraries
Requires: %{name} = %{version}-%{release}
%description application-distributor
-Provides FreeSWITCH mod_distributor, a simple round-robbin style distribution
+Provides FreeSWITCH mod_distributor, a simple round-robin style distribution
to call gateways.
%package application-easyroute
@@ -461,7 +461,7 @@ Group: System/Libraries
Requires: %{name} = %{version}-%{release}
%description application-rad_auth
-Provides FreeSWITCH mod_rad_auth, authetication via RADIUS protocol from FreeSWITCH dialplan
+Provides FreeSWITCH mod_rad_auth, authentication via RADIUS protocol from FreeSWITCH dialplan
%package application-redis
Summary: FreeSWITCH mod_redis
@@ -839,7 +839,7 @@ XMPP support for FreeSWITCH open source telephony platform. Allows FreeSWITCH
to be used as a client for GoogleTalk or other XMPP Servers.
#%package endpoint-gsmopen
-#Summary: Generic GSM enpoint support for FreeSWITCH open source telephony platform
+#Summary: Generic GSM endpoint support for FreeSWITCH open source telephony platform
#Group: System/Libraries
#Requires: %{name} = %{version}-%{release}
#
@@ -849,12 +849,12 @@ to be used as a client for GoogleTalk or other XMPP Servers.
#SMS is handled via the standard CHAT API in FreeSWITCH.
#%package endpoint-h323
-#Summary: H.323 enpoint support for FreeSWITCH open source telephony platform
+#Summary: H.323 endpoint support for FreeSWITCH open source telephony platform
#Group: System/Libraries
#Requires: %{name} = %{version}-%{release}
#
#%description endpoint-h323
-#H.323 enpoint support for FreeSWITCH open source telephony platform
+#H.323 endpoint support for FreeSWITCH open source telephony platform
#%package endpoint-khomp
#Summary: khomp endpoint support for FreeSWITCH open source telephony platform
@@ -1170,7 +1170,7 @@ Requires: %{name} = %{version}-%{release}
######################################################################################################################
%package lang-en
-Summary: Provides english language dependand modules and speech config for the FreeSWITCH Open Source telephone platform.
+Summary: Provides english language dependent modules and speech config for the FreeSWITCH Open Source telephone platform.
Group: System/Libraries
Requires: %{name} = %{version}-%{release}
@@ -1178,7 +1178,7 @@ Requires: %{name} = %{version}-%{release}
English language phrases module and directory structure for say module and voicemail
%package lang-ru
-Summary: Provides russian language dependand modules and speech config for the FreeSWITCH Open Source telephone platform.
+Summary: Provides russian language dependent modules and speech config for the FreeSWITCH Open Source telephone platform.
Group: System/Libraries
Requires: %{name} = %{version}-%{release}
@@ -1218,12 +1218,12 @@ Requires: %{name} = %{version}-%{release}
Spanish language phrases module and directory structure for say module and voicemail
%package lang-pt
-Summary: Provides Portugese language dependend modules and speech config for the FreeSWITCH Open Source telephone platform.
+Summary: Provides Portuguese language dependend modules and speech config for the FreeSWITCH Open Source telephone platform.
Group: System/Libraries
Requires: %{name} = %{version}-%{release}
%description lang-pt
-Portugese language phrases module and directory structure for say module and voicemail
+Portuguese language phrases module and directory structure for say module and voicemail
%package lang-sv
Summary: Provides Swedish language dependend modules and speech config for the FreeSWITCH Open Source telephone platform.
@@ -1982,7 +1982,7 @@ fi
%config(noreplace) %attr(0640, freeswitch, daemon) %{sysconfdir}/directory/*.xml
%config(noreplace) %attr(0640, freeswitch, daemon) %{sysconfdir}/directory/default/*
######################################################################################################################
-# IVR Menues
+# IVR Menus
######################################################################################################################
%config(noreplace) %attr(0640, freeswitch, daemon) %{sysconfdir}/ivr_menus/*.xml
######################################################################################################################
@@ -2557,7 +2557,7 @@ fi
* Wed Jun 19 2013 - krice@freeswitch.org
- tweak files included for vanilla configs
* Wed Sep 19 2012 - krice@freeswitch.org
-- Add support for Spanish and Portugese say language modules
+- Add support for Spanish and Portuguese say language modules
* Thu Jan 26 2012 - krice@freeswitch.org
- complete rework of spec file
* Tue Jun 14 2011 - michal.bielicki@seventhsignal.de
@@ -2576,7 +2576,7 @@ fi
- fixes for ss7 freetdm modules
- added mod_opus
- added selector for sangoma modules
-- addded python esl module to rpm
+- added python esl module to rpm
- some minor cleanups
- cut sangoma modules into separate rpms as addons for freetdm
* Tue Jan 18 2011 - michal.bielicki@seventhsignal.de
@@ -2594,7 +2594,7 @@ fi
- added mod_nibblebill to standard modules
* Sun Sep 26 2010 - michal.bielicki@seventhsignal.de
- added portaudio_stream module
-- some more formating work
+- some more formatting work
* Mon Jul 19 2010 - michal.bielicki@seventhsignal.de
- new hash module config file added to freeswitch.spec
* Mon Jul 19 2010 - michal.bielicki@seventhsignal.de
@@ -2607,7 +2607,7 @@ fi
- Added Contributors
- Added Anthony's copyright for the whole package into the header
* Tue Jun 22 2010 - michal.bielicki@seventhsignal.de
-- Reorganized the modules alphabeticaly
+- Reorganized the modules alphabetically
- synced SFEopensolaris and centos spec
- started to fix Run Dependencies
- added mod_say_ru which seemd to have gone missing
@@ -2619,7 +2619,7 @@ fi
- replaced mod_limit with mod_db
- added mod_spy
- added mod_valet_parking
-- addded mod_memcache
+- added mod_memcache
- added mod_distributor
- added mod_avmd
* Thu Apr 29 2010 - michal.bielicki@seventhsignal.de
@@ -2639,7 +2639,7 @@ fi
* Sat Nov 21 2009 - michal.bielicki@seventhsignal.de
- added patch by Igor Neves : Added some checkup in %post and %postun to prevent upgrades from removing freeswitch user
* Wed Nov 18 2009 - michal.bielicki@seventhsignal.de
-- added new config files for diretory and distributor
+- added new config files for directory and distributor
- removed sangoma boost from openzap for builds that do not inherit wanpipe while building.
* Fri Jul 24 2009 - mike@jerris.com
- removed mod_http
@@ -2704,7 +2704,7 @@ fi
- fixed odbc requirements
- added all buildable modules
- added redhat style init file
-- splitted off language dependant stuff into separate language files
+- split off language dependent stuff into separate language files
- disable non complete language modules
* Tue Apr 24 2007 - peter+rpmspam@suntel.com.tr
- Added a debug package
diff --git a/fscomm/preferences/prefdialog.ui b/fscomm/preferences/prefdialog.ui
index aca5eff198..66742f2c78 100644
--- a/fscomm/preferences/prefdialog.ui
+++ b/fscomm/preferences/prefdialog.ui
@@ -1092,7 +1092,7 @@
- Noise Supressor
+ Noise Suppressor
diff --git a/src/switch_xml_config.c b/src/switch_xml_config.c
index 21a6af38af..6d67ccdad4 100644
--- a/src/switch_xml_config.c
+++ b/src/switch_xml_config.c
@@ -333,7 +333,7 @@ SWITCH_DECLARE(switch_status_t) switch_xml_config_parse_event(switch_event_t *ev
} else if (value && switch_false(value)) {
newval = SWITCH_FALSE;
} else if (value) {
- /* Value isnt true or false */
+ /* Value isn't true or false */
newval = (switch_bool_t) (intptr_t) item->defaultvalue;
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid value [%s] for parameter [%s], setting default [%s]\n",
value, item->key, newval ? "true" : "false");
diff --git a/tests/unit/conf/vpx.conf.xml b/tests/unit/conf/vpx.conf.xml
index 63372ff5e7..2fce09dc13 100644
--- a/tests/unit/conf/vpx.conf.xml
+++ b/tests/unit/conf/vpx.conf.xml
@@ -189,7 +189,7 @@
-
+
diff --git a/w32/Setup/GitInfo/GitInfo.targets b/w32/Setup/GitInfo/GitInfo.targets
index 7c587c62d6..3d5da69590 100644
--- a/w32/Setup/GitInfo/GitInfo.targets
+++ b/w32/Setup/GitInfo/GitInfo.targets
@@ -57,7 +57,7 @@
GitInfo.txt
-
+
$(MSBuildProjectDirectory)$([MSBuild]::GetDirectoryNameOfFileAbove($(GitInfoBaseDir), $(GitVersionFile)))\$(GitVersionFile)
From a4a7afdca8e2bd320f4dc66a95723ec38bd47ce5 Mon Sep 17 00:00:00 2001
From: Stefan Weil
Date: Fri, 1 May 2020 14:08:14 +0200
Subject: [PATCH 016/655] Fix typo and convert line endings from CRLF to LF
Signed-off-by: Stefan Weil
---
README.md | 126 +++++++++++++++++++++++++++---------------------------
1 file changed, 63 insertions(+), 63 deletions(-)
diff --git a/README.md b/README.md
index 77de167e3e..f2525918f3 100644
--- a/README.md
+++ b/README.md
@@ -1,63 +1,63 @@
-# FreeSWITCH
-
-FreeSWITCH is a Software Defined Telecom Stack enabling the digital transformation from proprietary telecom switches to a versatile software implementation that runs on any commodity hardware. From a Raspberry PI to a multi-core server, FreeSWITCH can unlock the telecommunications potential of any device. Combined with our hosted cloud platform, SignalWire, FreeSWITCH can interconnect with the outside world and scale to any size.
-
-Visit [https://signalwire.com](https://signalwire.com/) or https://github.com/signalwire for more info.
-
-## Getting Started
-
-FreeSWITCH is available on [Github](https://github.com/signalwire/freeswitch) in source code format. You can checkout the development branch and build for many poplular platforms including Linux, Windows, MacOSX and BSD. There is an issue tracker and pull request system available as part of the repo online.
-
-See [https://freeswitch.com/#getting-started](https://freeswitch.com/#getting-started) for more detailed instructions.
-
-## Additional Help
-
-If you need assistance or have an interest in using a commercially supported build, you can contact coreteam@freeswitch.com to learn about professional services to support your project.
-
-## Voice-over-IP services - SIP / SMS - App Integrations
-
-[SignalWire](https://signalwire.com) is the primary sponsor of the FreeSWITCH project and was founded by the original developers of FreeSWITCH. SignalWire provides scalable services to enhance and scale your project such as SMS, SIP, Serverless Application hosting as well as programmable telecom. mod_signalwire which is distributed in this code base allows you to instantly pair with SignalWire and extend your FreeSWITCH.
-
-## Documentation
-
-The main index for documentation is available at:
-
- * https://freeswitch.org/confluence/
-
-### Release notes:
-
- * https://freeswitch.org/confluence/display/FREESWITCH/Release+Notes
-
-### Installation
-
-Step by step tutorials to install FreeSWITCH from packages or source code are available at:
-
- * [Debian 10 Buster](https://freeswitch.org/confluence/display/FREESWITCH/Debian+10+Buster) [Recommended]
- * [Raspberry Pi](https://freeswitch.org/confluence/display/FREESWITCH/Raspberry+Pi)
- * [CentOS 7](https://freeswitch.org/confluence/display/FREESWITCH/CentOS+7+and+RHEL+7)
-
-## Downloads
-
- * [Tarballs](https://files.freeswitch.org/releases/freeswitch/)
- * [Windows Installer](http://files.freeswitch.org/windows/installer/x64/)
- * [Windows Sound Packages](http://files.freeswitch.org/windows/installer/x64/sounds/)
-
-## Contributions
-
-GitHub pull requests are the recommended way to contribute to the FreeSWITCH source code:
-
- * https://github.com/signalwire/freeswitch/pulls
-
-## Community
-
-Slack is our chat system where the developers, the FreeSWITCH team, and the most active users are present.
-This is the place to get answers faster and chat with other users in real time. All you need to do is enter your email and verify it on the Slack signup page and you are ready to join in the discussion!
-
-Slack Community:
- * https://signalwire.community/
-
-Mailing list:
-
- * http://lists.freeswitch.org/mailman/listinfo/freeswitch-users
-
-**Thank you for using FreeSWITCH!**
\ No newline at end of file
+# FreeSWITCH
+
+FreeSWITCH is a Software Defined Telecom Stack enabling the digital transformation from proprietary telecom switches to a versatile software implementation that runs on any commodity hardware. From a Raspberry PI to a multi-core server, FreeSWITCH can unlock the telecommunications potential of any device. Combined with our hosted cloud platform, SignalWire, FreeSWITCH can interconnect with the outside world and scale to any size.
+
+Visit [https://signalwire.com](https://signalwire.com/) or https://github.com/signalwire for more info.
+
+## Getting Started
+
+FreeSWITCH is available on [Github](https://github.com/signalwire/freeswitch) in source code format. You can checkout the development branch and build for many popular platforms including Linux, Windows, MacOSX and BSD. There is an issue tracker and pull request system available as part of the repo online.
+
+See [https://freeswitch.com/#getting-started](https://freeswitch.com/#getting-started) for more detailed instructions.
+
+## Additional Help
+
+If you need assistance or have an interest in using a commercially supported build, you can contact coreteam@freeswitch.com to learn about professional services to support your project.
+
+## Voice-over-IP services - SIP / SMS - App Integrations
+
+[SignalWire](https://signalwire.com) is the primary sponsor of the FreeSWITCH project and was founded by the original developers of FreeSWITCH. SignalWire provides scalable services to enhance and scale your project such as SMS, SIP, Serverless Application hosting as well as programmable telecom. mod_signalwire which is distributed in this code base allows you to instantly pair with SignalWire and extend your FreeSWITCH.
+
+## Documentation
+
+The main index for documentation is available at:
+
+ * https://freeswitch.org/confluence/
+
+### Release notes:
+
+ * https://freeswitch.org/confluence/display/FREESWITCH/Release+Notes
+
+### Installation
+
+Step by step tutorials to install FreeSWITCH from packages or source code are available at:
+
+ * [Debian 10 Buster](https://freeswitch.org/confluence/display/FREESWITCH/Debian+10+Buster) [Recommended]
+ * [Raspberry Pi](https://freeswitch.org/confluence/display/FREESWITCH/Raspberry+Pi)
+ * [CentOS 7](https://freeswitch.org/confluence/display/FREESWITCH/CentOS+7+and+RHEL+7)
+
+## Downloads
+
+ * [Tarballs](https://files.freeswitch.org/releases/freeswitch/)
+ * [Windows Installer](http://files.freeswitch.org/windows/installer/x64/)
+ * [Windows Sound Packages](http://files.freeswitch.org/windows/installer/x64/sounds/)
+
+## Contributions
+
+GitHub pull requests are the recommended way to contribute to the FreeSWITCH source code:
+
+ * https://github.com/signalwire/freeswitch/pulls
+
+## Community
+
+Slack is our chat system where the developers, the FreeSWITCH team, and the most active users are present.
+This is the place to get answers faster and chat with other users in real time. All you need to do is enter your email and verify it on the Slack signup page and you are ready to join in the discussion!
+
+Slack Community:
+ * https://signalwire.community/
+
+Mailing list:
+
+ * http://lists.freeswitch.org/mailman/listinfo/freeswitch-users
+
+**Thank you for using FreeSWITCH!**
From 0426ffaec77322cb0c6572b4cb37c12220a5e084 Mon Sep 17 00:00:00 2001
From: Andrey Volk
Date: Sat, 27 Feb 2021 00:09:44 +0300
Subject: [PATCH 017/655] [Build-System] Add src/include/switch_swigable_cpp.h
requirement to make swigall
---
Makefile.am | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Makefile.am b/Makefile.am
index fa0bb9abd7..984872c36d 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -745,7 +745,7 @@ update-clean: clean python-reconf
cd libs/esl && $(MAKE) clean
cd libs/srtp && $(MAKE) clean
-swigall:
+swigall: src/include/switch_swigable_cpp.h
@echo reswigging all
sh $(switch_srcdir)/build/swigall.sh
From fd2ed2546c588e6a2313a0387ff881e2ae1a9b04 Mon Sep 17 00:00:00 2001
From: Mike Jerris
Date: Wed, 3 Mar 2021 10:02:29 -0700
Subject: [PATCH 018/655] [build] fix configure checks for ipv6 on latest osx
---
libs/apr/build/apr_common.m4 | 3 +++
libs/apr/build/apr_network.m4 | 18 ++++++++++++++++++
libs/apr/configure.ac | 3 +++
3 files changed, 24 insertions(+)
diff --git a/libs/apr/build/apr_common.m4 b/libs/apr/build/apr_common.m4
index 1f79f7acd0..e8e9f51f08 100644
--- a/libs/apr/build/apr_common.m4
+++ b/libs/apr/build/apr_common.m4
@@ -519,6 +519,9 @@ AC_TRY_RUN([
#include
#include
#include
+#ifdef HAVE_STDLIB_H
+#include
+#endif
int main(void)
{
char buf[1024];
diff --git a/libs/apr/build/apr_network.m4 b/libs/apr/build/apr_network.m4
index d8b1bcad27..df582960ac 100644
--- a/libs/apr/build/apr_network.m4
+++ b/libs/apr/build/apr_network.m4
@@ -40,6 +40,9 @@ AC_DEFUN([APR_CHECK_WORKING_GETADDRINFO],[
#ifdef HAVE_SYS_SOCKET_H
#include
#endif
+#ifdef HAVE_STDLIB_H
+#include
+#endif
int main(void) {
struct addrinfo hints, *ai;
@@ -134,6 +137,12 @@ AC_DEFUN([APR_CHECK_WORKING_GETNAMEINFO],[
#ifdef HAVE_NETINET_IN_H
#include
#endif
+#ifdef HAVE_ARPA_INET_H
+#include
+#endif
+#ifdef HAVE_STDLIB_H
+#include
+#endif
int main(void) {
struct sockaddr_in sa;
@@ -177,6 +186,9 @@ AC_DEFUN([APR_CHECK_NEGATIVE_EAI],[
#ifdef HAVE_NETDB_H
#include
#endif
+#ifdef HAVE_STDLIB_H
+#include
+#endif
int main(void) {
if (EAI_ADDRFAMILY < 0) {
@@ -282,6 +294,9 @@ AC_DEFUN([APR_CHECK_TCP_NODELAY_INHERITED],[
#ifndef HAVE_SOCKLEN_T
typedef int socklen_t;
#endif
+#ifdef HAVE_STDLIB_H
+#include
+#endif
int main(void) {
int listen_s, connected_s, client_s;
int listen_port, rc;
@@ -453,6 +468,9 @@ typedef int socklen_t;
#ifdef HAVE_FCNTL_H
#include
#endif
+#ifdef HAVE_STDLIB_H
+#include
+#endif
int main(void) {
int listen_s, connected_s, client_s;
int listen_port, rc;
diff --git a/libs/apr/configure.ac b/libs/apr/configure.ac
index fa5796ecca..2b8f551880 100644
--- a/libs/apr/configure.ac
+++ b/libs/apr/configure.ac
@@ -1552,6 +1552,7 @@ AC_TRY_RUN([
#include
#include
#include
+#include
main()
{
struct rlimit limit;
@@ -1580,6 +1581,7 @@ AC_TRY_RUN([
#include
#include
#include
+#include
main()
{
sem_t *psem;
@@ -1634,6 +1636,7 @@ if test "$threads" = "1"; then
AC_TRY_RUN([
#include
#include
+#include
int main()
{
pthread_mutex_t mutex;
From 752e1c3386414c8413aedaecdcfbbdf75fcdaadd Mon Sep 17 00:00:00 2001
From: Dragos Oancea
Date: Thu, 25 Feb 2021 16:16:14 +0200
Subject: [PATCH 019/655] [mod_amr] handle frame type NO_DATA and add unit
test.
---
src/mod/codecs/mod_amr/Makefile.am | 11 +++
src/mod/codecs/mod_amr/amr_be.c | 2 +-
src/mod/codecs/mod_amr/mod_amr.c | 8 +-
src/mod/codecs/mod_amr/test/freeswitch.xml | 21 +++++
src/mod/codecs/mod_amr/test/test_amr.c | 100 +++++++++++++++++++++
5 files changed, 137 insertions(+), 5 deletions(-)
create mode 100644 src/mod/codecs/mod_amr/test/freeswitch.xml
create mode 100644 src/mod/codecs/mod_amr/test/test_amr.c
diff --git a/src/mod/codecs/mod_amr/Makefile.am b/src/mod/codecs/mod_amr/Makefile.am
index ac80d8ac35..43fa399305 100644
--- a/src/mod/codecs/mod_amr/Makefile.am
+++ b/src/mod/codecs/mod_amr/Makefile.am
@@ -20,3 +20,14 @@ else
mod_amr_la_CFLAGS += -DAMR_PASSTHROUGH
endif
+if HAVE_AMR
+noinst_PROGRAMS = test/test_amr
+
+test_test_amr_SOURCES = test/test_amr.c
+test_test_amr_CFLAGS = $(AM_CFLAGS) -I./ -I../ -DSWITCH_TEST_BASE_DIR_FOR_CONF=\"${abs_builddir}/test\" -DSWITCH_TEST_BASE_DIR_OVERRIDE=\"${abs_builddir}/test\" $(AMR_CFLAGS)
+test_test_amr_LDFLAGS = $(AM_LDFLAGS) -avoid-version -no-undefined $(freeswitch_LDFLAGS) $(switch_builddir)/libfreeswitch.la $(CORE_LIBS) $(APR_LIBS) $(AMR_LIBS)
+
+TESTS = $(noinst_PROGRAMS)
+endif
+
+
diff --git a/src/mod/codecs/mod_amr/amr_be.c b/src/mod/codecs/mod_amr/amr_be.c
index b7d9c9053d..339d0c703e 100644
--- a/src/mod/codecs/mod_amr/amr_be.c
+++ b/src/mod/codecs/mod_amr/amr_be.c
@@ -106,7 +106,7 @@ extern switch_bool_t switch_amr_unpack_be(unsigned char *encoded_buf, uint8_t *t
switch_amr_array_lshift(2, shift_buf, encoded_len - 1);
/* get frame size */
index = ((shift_tocs[0] >> 3) & 0x0f);
- if (index > 9) {
+ if (index > 9 && index != 0xf) {
return SWITCH_FALSE;
}
framesz = switch_amr_frame_sizes[index];
diff --git a/src/mod/codecs/mod_amr/mod_amr.c b/src/mod/codecs/mod_amr/mod_amr.c
index b9d2c5882d..04717ca52c 100644
--- a/src/mod/codecs/mod_amr/mod_amr.c
+++ b/src/mod/codecs/mod_amr/mod_amr.c
@@ -139,7 +139,7 @@ static struct {
int debug;
} globals;
-const int switch_amr_frame_sizes[] = {12,13,15,17,19,20,26,31,5,0};
+const int switch_amr_frame_sizes[] = {12,13,15,17,19,20,26,31,5,0,0,0,0,0,0,1};
#define SWITCH_AMR_OUT_MAX_SIZE 32
#define SWITCH_AMR_MODES 9 /* plus SID */
@@ -157,7 +157,7 @@ static switch_bool_t switch_amr_unpack_oa(unsigned char *buf, uint8_t *tmp, int
tocs = buf;
index = ((tocs[0]>>3) & 0xf);
buf++; /* point to voice payload */
- if (index > SWITCH_AMR_MODES) {
+ if (index > SWITCH_AMR_MODES && index != 0xf) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "AMR decoder (OA): Invalid Table Of Contents (TOC): 0x%x\n", index);
return SWITCH_FALSE;
}
@@ -195,7 +195,7 @@ static switch_bool_t switch_amr_info(unsigned char *encoded_buf, int encoded_dat
encoded_buf++; /* CMR skip */
tocs = encoded_buf;
index = (tocs[0] >> 3) & 0x0f;
- if (index > SWITCH_AMR_MODES) {
+ if (index > SWITCH_AMR_MODES && index != 0xf) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "AMR decoder (OA): Invalid Table Of Contents (TOC): 0x%x\n", index);
return SWITCH_FALSE;
}
@@ -215,7 +215,7 @@ static switch_bool_t switch_amr_info(unsigned char *encoded_buf, int encoded_dat
ft = shift_tocs[0] >> 3 ;
ft &= ~(1 << 5); /* Frame Type */
index = (shift_tocs[0] >> 3) & 0x0f;
- if (index > SWITCH_AMR_MODES) {
+ if (index > SWITCH_AMR_MODES && index != 0xf) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "AMR decoder (BE): Invalid Table Of Contents (TOC): 0x%x\n", index);
return SWITCH_FALSE;
}
diff --git a/src/mod/codecs/mod_amr/test/freeswitch.xml b/src/mod/codecs/mod_amr/test/freeswitch.xml
new file mode 100644
index 0000000000..900073a6f0
--- /dev/null
+++ b/src/mod/codecs/mod_amr/test/freeswitch.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/mod/codecs/mod_amr/test/test_amr.c b/src/mod/codecs/mod_amr/test/test_amr.c
new file mode 100644
index 0000000000..f81401e6aa
--- /dev/null
+++ b/src/mod/codecs/mod_amr/test/test_amr.c
@@ -0,0 +1,100 @@
+/*
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ * Copyright (C) 2005-2021, Anthony Minessale II
+ *
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ *
+ * The Initial Developer of the Original Code is
+ * Anthony Minessale II
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Dragos Oancea
+ *
+ *
+ * test_amr.c -- tests mod_amr
+ *
+ */
+
+#ifndef AMR_PASSTHROUGH
+#include
+#include
+
+#include
+FST_CORE_BEGIN(".")
+{
+ FST_SUITE_BEGIN(test_amr)
+ {
+ FST_SETUP_BEGIN()
+ {
+ fst_requires_module("mod_loopback");
+ fst_requires_module("mod_amr");
+ }
+ FST_SETUP_END()
+
+ FST_TEARDOWN_BEGIN()
+ {
+ }
+ FST_TEARDOWN_END()
+
+ FST_TEST_BEGIN(amr_decode)
+ {
+ switch_codec_t read_codec = { 0 };
+ switch_status_t status;
+ switch_codec_settings_t codec_settings = {{ 0 }};
+ uint32_t flags = 0;
+ uint32_t rate;
+ /*amr frame types*/
+ static char no_data[] = "\x77\xc0";
+ static char fail[] = "\x76\xc0";
+ /*decode*/
+ uint32_t decoded_len;
+ unsigned char decbuf[SWITCH_RECOMMENDED_BUFFER_SIZE] = { 0 };
+ switch_stream_handle_t stream = { 0 };
+
+ status = switch_core_codec_init(&read_codec,
+ "AMR",
+ "mod_amr",
+ NULL,
+ 8000,
+ 20,
+ 1, SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE,
+ &codec_settings, fst_pool);
+ fst_check(status == SWITCH_STATUS_SUCCESS);
+
+ SWITCH_STANDARD_STREAM(stream);
+
+ switch_api_execute("amr_debug", "on", NULL, &stream);
+
+ switch_safe_free(stream.data);
+
+ /*NO DATA = 0xf*/
+ status = switch_core_codec_decode(&read_codec, NULL, &no_data, 2, 8000, &decbuf, &decoded_len, &rate, &flags);
+ fst_check(status == SWITCH_STATUS_SUCCESS);
+
+ /*Invalid frame type*/
+ status = switch_core_codec_decode(&read_codec, NULL, &fail, 2, 8000, &decbuf, &decoded_len, &rate, &flags);
+ fst_check(status != SWITCH_STATUS_SUCCESS);
+
+ switch_core_codec_destroy(&read_codec);
+ }
+
+ FST_TEST_END()
+ }
+ FST_SUITE_END()
+}
+FST_CORE_END()
+#endif
From 1d07634d7dcee98057c64262e0f4732782adcda4 Mon Sep 17 00:00:00 2001
From: Dragos Oancea
Date: Fri, 5 Mar 2021 11:24:22 +0200
Subject: [PATCH 020/655] [mod_amrwb] handle frame types SPEECH_LOST and
NO_DATA. add unit test.
---
src/mod/codecs/mod_amrwb/Makefile.am | 10 ++
src/mod/codecs/mod_amrwb/amrwb_be.c | 2 +-
src/mod/codecs/mod_amrwb/mod_amrwb.c | 10 +-
src/mod/codecs/mod_amrwb/test/freeswitch.xml | 21 ++++
src/mod/codecs/mod_amrwb/test/test_amrwb.c | 105 +++++++++++++++++++
5 files changed, 143 insertions(+), 5 deletions(-)
create mode 100644 src/mod/codecs/mod_amrwb/test/freeswitch.xml
create mode 100644 src/mod/codecs/mod_amrwb/test/test_amrwb.c
diff --git a/src/mod/codecs/mod_amrwb/Makefile.am b/src/mod/codecs/mod_amrwb/Makefile.am
index d3a7d67761..176a0ed614 100644
--- a/src/mod/codecs/mod_amrwb/Makefile.am
+++ b/src/mod/codecs/mod_amrwb/Makefile.am
@@ -20,3 +20,13 @@ else
mod_amrwb_la_CFLAGS += -DAMRWB_PASSTHROUGH
endif
+if HAVE_AMRWB
+noinst_PROGRAMS = test/test_amrwb
+
+test_test_amrwb_SOURCES = test/test_amrwb.c
+test_test_amrwb_CFLAGS = $(AM_CFLAGS) -I./ -I../ -DSWITCH_TEST_BASE_DIR_FOR_CONF=\"${abs_builddir}/test\" -DSWITCH_TEST_BASE_DIR_OVERRIDE=\"${abs_builddir}/test\" $(AMRWB_CFLAGS)
+test_test_amrwb_LDFLAGS = $(AM_LDFLAGS) -avoid-version -no-undefined $(freeswitch_LDFLAGS) $(switch_builddir)/libfreeswitch.la $(CORE_LIBS) $(APR_LIBS) $(AMRWB_LIBS)
+
+TESTS = $(noinst_PROGRAMS)
+endif
+
diff --git a/src/mod/codecs/mod_amrwb/amrwb_be.c b/src/mod/codecs/mod_amrwb/amrwb_be.c
index c668ac94cb..7b43b2b583 100644
--- a/src/mod/codecs/mod_amrwb/amrwb_be.c
+++ b/src/mod/codecs/mod_amrwb/amrwb_be.c
@@ -109,7 +109,7 @@ extern switch_bool_t switch_amrwb_unpack_be(unsigned char *encoded_buf, uint8_t
switch_amr_array_lshift(2, shift_buf, encoded_len - 1);
/* get frame size */
index = ((shift_tocs[0] >> 3) & 0x0f);
- if (index > 10) {
+ if (index > 10 && index != 0xe && index != 0xf) {
return SWITCH_FALSE;
}
framesz = switch_amrwb_frame_sizes[index];
diff --git a/src/mod/codecs/mod_amrwb/mod_amrwb.c b/src/mod/codecs/mod_amrwb/mod_amrwb.c
index db18082983..ef7891cde6 100644
--- a/src/mod/codecs/mod_amrwb/mod_amrwb.c
+++ b/src/mod/codecs/mod_amrwb/mod_amrwb.c
@@ -91,11 +91,13 @@ static struct {
int debug;
} globals;
-const int switch_amrwb_frame_sizes[] = {17, 23, 32, 36, 40, 46, 50, 58, 60, 5};
+const int switch_amrwb_frame_sizes[] = {17, 23, 32, 36, 40, 46, 50, 58, 60, 5, 0, 0, 0, 0, 1, 1};
#define SWITCH_AMRWB_OUT_MAX_SIZE 61
#define SWITCH_AMRWB_MODES 10 /* Silence Indicator (SID) included */
+#define invalid_frame_type (index > SWITCH_AMRWB_MODES && index != 0xe && index != 0xf) /* include SPEECH_LOST and NO_DATA*/
+
static switch_bool_t switch_amrwb_unpack_oa(unsigned char *buf, uint8_t *tmp, int encoded_data_len)
{
uint8_t *tocs;
@@ -107,7 +109,7 @@ static switch_bool_t switch_amrwb_unpack_oa(unsigned char *buf, uint8_t *tmp, in
index = ((tocs[0]>>3) & 0xf);
buf++; /* point to voice payload */
- if (index > 10) {
+ if (invalid_frame_type) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "AMRWB decoder (OA): Invalid TOC: 0x%x", index);
return SWITCH_FALSE;
}
@@ -144,7 +146,7 @@ static switch_bool_t switch_amrwb_info(switch_codec_t *codec, unsigned char *enc
encoded_buf++; /* CMR skip */
tocs = encoded_buf;
index = (tocs[0] >> 3) & 0x0f;
- if (index > SWITCH_AMRWB_MODES) {
+ if (invalid_frame_type) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(codec->session), SWITCH_LOG_ERROR, "AMRWB decoder (OA): Invalid TOC 0x%x\n", index);
return SWITCH_FALSE;
}
@@ -163,7 +165,7 @@ static switch_bool_t switch_amrwb_info(switch_codec_t *codec, unsigned char *enc
ft = shift_tocs[0] >> 3;
ft &= ~(1 << 5); /* Frame Type */
index = (shift_tocs[0] >> 3) & 0x0f;
- if (index > SWITCH_AMRWB_MODES) {
+ if (invalid_frame_type) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(codec->session), SWITCH_LOG_ERROR, "AMRWB decoder (BE): Invalid TOC 0x%x\n", index);
return SWITCH_FALSE;
}
diff --git a/src/mod/codecs/mod_amrwb/test/freeswitch.xml b/src/mod/codecs/mod_amrwb/test/freeswitch.xml
new file mode 100644
index 0000000000..14e5629f12
--- /dev/null
+++ b/src/mod/codecs/mod_amrwb/test/freeswitch.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/mod/codecs/mod_amrwb/test/test_amrwb.c b/src/mod/codecs/mod_amrwb/test/test_amrwb.c
new file mode 100644
index 0000000000..1b63f644eb
--- /dev/null
+++ b/src/mod/codecs/mod_amrwb/test/test_amrwb.c
@@ -0,0 +1,105 @@
+/*
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ * Copyright (C) 2005-2021, Anthony Minessale II
+ *
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ *
+ * The Initial Developer of the Original Code is
+ * Anthony Minessale II
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Dragos Oancea
+ *
+ *
+ * test_amrwb.c -- tests mod_amrwb
+ *
+ */
+
+#ifndef AMRWB_PASSTHROUGH
+#include
+#include
+
+#include
+FST_CORE_BEGIN(".")
+{
+ FST_SUITE_BEGIN(test_amrwb)
+ {
+ FST_SETUP_BEGIN()
+ {
+ fst_requires_module("mod_loopback");
+ fst_requires_module("mod_amrwb");
+ }
+ FST_SETUP_END()
+
+ FST_TEARDOWN_BEGIN()
+ {
+ }
+ FST_TEARDOWN_END()
+
+ FST_TEST_BEGIN(amrwb_decode)
+ {
+ switch_codec_t read_codec = { 0 };
+ switch_status_t status;
+ switch_codec_settings_t codec_settings = {{ 0 }};
+ uint32_t flags = 0;
+ uint32_t rate;
+ /*amrwb frame types*/
+ static char no_data[] = "\x77\xc0";
+ static char speech_lost[] = "\x77\x00";
+ static char fail[] = "\x76\xc0";
+ /*decode*/
+ uint32_t decoded_len;
+ unsigned char decbuf[SWITCH_RECOMMENDED_BUFFER_SIZE] = { 0 };
+ switch_stream_handle_t stream = { 0 };
+
+ status = switch_core_codec_init(&read_codec,
+ "AMR-WB",
+ "mod_amrwb",
+ NULL,
+ 16000,
+ 20,
+ 1, SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE,
+ &codec_settings, fst_pool);
+ fst_check(status == SWITCH_STATUS_SUCCESS);
+
+ SWITCH_STANDARD_STREAM(stream);
+
+ switch_api_execute("amrwb_debug", "on", NULL, &stream);
+
+ switch_safe_free(stream.data);
+
+ /*NO DATA = 0xf*/
+ status = switch_core_codec_decode(&read_codec, NULL, &no_data, 2, 16000, &decbuf, &decoded_len, &rate, &flags);
+ fst_check(status == SWITCH_STATUS_SUCCESS);
+
+ /*SPEECH LOST = 0xe*/
+ status = switch_core_codec_decode(&read_codec, NULL, &speech_lost, 2, 16000, &decbuf, &decoded_len, &rate, &flags);
+ fst_check(status == SWITCH_STATUS_SUCCESS);
+
+ /*Invalid frame type*/
+ status = switch_core_codec_decode(&read_codec, NULL, &fail, 2, 16000, &decbuf, &decoded_len, &rate, &flags);
+ fst_check(status != SWITCH_STATUS_SUCCESS);
+
+ switch_core_codec_destroy(&read_codec);
+ }
+
+ FST_TEST_END()
+ }
+ FST_SUITE_END()
+}
+FST_CORE_END()
+#endif
From 9da3408d2d63eb6b2b5fbc6aab276f6d74b2d0fc Mon Sep 17 00:00:00 2001
From: Dragos Oancea
Date: Fri, 5 Mar 2021 11:57:25 +0200
Subject: [PATCH 021/655] [mod_tts_commandline] check return of switch_system()
against 127 too
---
src/mod/asr_tts/mod_tts_commandline/mod_tts_commandline.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/src/mod/asr_tts/mod_tts_commandline/mod_tts_commandline.c b/src/mod/asr_tts/mod_tts_commandline/mod_tts_commandline.c
index a19af3a18d..e5cfbb5c42 100644
--- a/src/mod/asr_tts/mod_tts_commandline/mod_tts_commandline.c
+++ b/src/mod/asr_tts/mod_tts_commandline/mod_tts_commandline.c
@@ -133,6 +133,7 @@ static switch_status_t tts_commandline_speech_feed_tts(switch_speech_handle_t *s
switch_status_t ret=SWITCH_STATUS_SUCCESS;
char *message, *tmp, *mtmp, *rate;
tts_commandline_t *info = (tts_commandline_t *) sh->private_info;
+ int sys_ret;
assert(info != NULL);
@@ -159,7 +160,8 @@ static switch_status_t tts_commandline_speech_feed_tts(switch_speech_handle_t *s
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Executing: %s\n", message);
- if (switch_system(message, SWITCH_TRUE) < 0) {
+ sys_ret = switch_system(message, SWITCH_TRUE);
+ if (sys_ret < 0 || sys_ret == 127) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to execute command: %s\n", message);
ret = SWITCH_STATUS_FALSE; goto done;
}
From 5d80d53c9701cd9455deaed3b716f6902a1aeba6 Mon Sep 17 00:00:00 2001
From: Paul Mateer <78475208+Paul-Mateer@users.noreply.github.com>
Date: Mon, 8 Mar 2021 11:28:27 +0000
Subject: [PATCH 022/655] [Core] Capture return value of 2nd call to
LoadLibraryEx and add a third call to widen the search to the module in
switch_dso_open().
---
src/switch_dso.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/src/switch_dso.c b/src/switch_dso.c
index 8ec57139b1..a78bba2f8c 100644
--- a/src/switch_dso.c
+++ b/src/switch_dso.c
@@ -39,7 +39,11 @@ SWITCH_DECLARE(switch_dso_lib_t) switch_dso_open(const char *path, int global, c
lib = LoadLibraryEx(path, NULL, 0);
if (!lib) {
- LoadLibraryEx(path, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
+ lib = LoadLibraryEx(path, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
+ }
+
+ if (!lib) {
+ lib = LoadLibraryEx(path, NULL, LOAD_LIBRARY_SEARCH_DEFAULT_DIRS);
}
if (!lib) {
From 4734904d2d42b29fac5dee8c10a6871abd96d613 Mon Sep 17 00:00:00 2001
From: Dragos Oancea
Date: Wed, 10 Mar 2021 15:43:45 +0200
Subject: [PATCH 023/655] [mod_amr] introduce new cfg setting force-oa to
change between OA/BE when originating, show session in debug logs, update
configs.
---
conf/testing/autoload_configs/amrwb.conf.xml | 22 +++++++++++++++++
conf/vanilla/autoload_configs/amr.conf.xml | 2 ++
conf/vanilla/autoload_configs/amrwb.conf.xml | 23 ++++++++++++++----
src/mod/codecs/mod_amr/mod_amr.c | 25 +++++++++++++-------
4 files changed, 59 insertions(+), 13 deletions(-)
create mode 100644 conf/testing/autoload_configs/amrwb.conf.xml
diff --git a/conf/testing/autoload_configs/amrwb.conf.xml b/conf/testing/autoload_configs/amrwb.conf.xml
new file mode 100644
index 0000000000..0bd8e6b733
--- /dev/null
+++ b/conf/testing/autoload_configs/amrwb.conf.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/conf/vanilla/autoload_configs/amr.conf.xml b/conf/vanilla/autoload_configs/amr.conf.xml
index e1c3e3cc1b..19b8cb8891 100644
--- a/conf/vanilla/autoload_configs/amr.conf.xml
+++ b/conf/vanilla/autoload_configs/amr.conf.xml
@@ -15,5 +15,7 @@
+
+
diff --git a/conf/vanilla/autoload_configs/amrwb.conf.xml b/conf/vanilla/autoload_configs/amrwb.conf.xml
index 9dac3505a4..0bd8e6b733 100644
--- a/conf/vanilla/autoload_configs/amrwb.conf.xml
+++ b/conf/vanilla/autoload_configs/amrwb.conf.xml
@@ -1,7 +1,22 @@
-
-
-
-
+
+
+
+
+
+
+
+
+
diff --git a/src/mod/codecs/mod_amr/mod_amr.c b/src/mod/codecs/mod_amr/mod_amr.c
index 04717ca52c..e7c45c7aff 100644
--- a/src/mod/codecs/mod_amr/mod_amr.c
+++ b/src/mod/codecs/mod_amr/mod_amr.c
@@ -137,6 +137,7 @@ static struct {
switch_byte_t volte; /* enable special fmtp for VoLTE compliance */
switch_byte_t adjust_bitrate;
int debug;
+ switch_byte_t force_oa; /*force OA when originating*/
} globals;
const int switch_amr_frame_sizes[] = {12,13,15,17,19,20,26,31,5,0,0,0,0,0,0,1};
@@ -179,7 +180,7 @@ static switch_bool_t switch_amr_pack_oa(unsigned char *shift_buf, int n)
return SWITCH_TRUE;
}
-static switch_bool_t switch_amr_info(unsigned char *encoded_buf, int encoded_data_len, int payload_format, char *print_text)
+static switch_bool_t switch_amr_info(switch_codec_t *codec, unsigned char *encoded_buf, int encoded_data_len, int payload_format, char *print_text)
{
uint8_t *tocs;
int framesz, index, not_last_frame, q, ft;
@@ -196,7 +197,7 @@ static switch_bool_t switch_amr_info(unsigned char *encoded_buf, int encoded_dat
tocs = encoded_buf;
index = (tocs[0] >> 3) & 0x0f;
if (index > SWITCH_AMR_MODES && index != 0xf) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "AMR decoder (OA): Invalid Table Of Contents (TOC): 0x%x\n", index);
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(codec->session), SWITCH_LOG_ERROR, "AMR decoder (OA): Invalid Table Of Contents (TOC): 0x%x\n", index);
return SWITCH_FALSE;
}
framesz = switch_amr_frame_sizes[index];
@@ -216,15 +217,15 @@ static switch_bool_t switch_amr_info(unsigned char *encoded_buf, int encoded_dat
ft &= ~(1 << 5); /* Frame Type */
index = (shift_tocs[0] >> 3) & 0x0f;
if (index > SWITCH_AMR_MODES && index != 0xf) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "AMR decoder (BE): Invalid Table Of Contents (TOC): 0x%x\n", index);
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(codec->session), SWITCH_LOG_ERROR, "AMR decoder (BE): Invalid Table Of Contents (TOC): 0x%x\n", index);
return SWITCH_FALSE;
}
framesz = switch_amr_frame_sizes[index];
}
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s (%s): FT: [0x%x] Q: [0x%x] Frame flag: [%d]\n",
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(codec->session), SWITCH_LOG_DEBUG, "%s (%s): FT: [0x%x] Q: [0x%x] Frame flag: [%d]\n",
print_text, payload_format ? "OA":"BE", ft, q, not_last_frame);
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s (%s): AMR encoded voice payload sz: [%d] : | encoded_data_len: [%d]\n",
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(codec->session), SWITCH_LOG_DEBUG, "%s (%s): AMR encoded voice payload sz: [%d] : | encoded_data_len: [%d]\n",
print_text, payload_format ? "OA":"BE", framesz, encoded_data_len);
return SWITCH_TRUE;
@@ -276,8 +277,11 @@ static switch_status_t switch_amr_init(switch_codec_t *codec, switch_codec_flag_
* bandwidth-efficient operation is employed."
*
*/
- switch_clear_flag(context, AMR_OPT_OCTET_ALIGN);
-
+ if (!globals.force_oa) {
+ switch_clear_flag(context, AMR_OPT_OCTET_ALIGN);
+ } else {
+ switch_set_flag(context, AMR_OPT_OCTET_ALIGN);
+ }
if (codec->fmtp_in) {
argc = switch_separate_string(codec->fmtp_in, ';', argv, (sizeof(argv) / sizeof(argv[0])));
for (x = 0; x < argc; x++) {
@@ -452,7 +456,7 @@ static switch_status_t switch_amr_encode(switch_codec_t *codec,
}
if (globals.debug) {
- switch_amr_info(shift_buf, *encoded_data_len, switch_test_flag(context, AMR_OPT_OCTET_ALIGN) ? 1 : 0, "AMR encoder");
+ switch_amr_info(codec, shift_buf, *encoded_data_len, switch_test_flag(context, AMR_OPT_OCTET_ALIGN) ? 1 : 0, "AMR encoder");
}
return SWITCH_STATUS_SUCCESS;
@@ -479,7 +483,7 @@ static switch_status_t switch_amr_decode(switch_codec_t *codec,
}
if (globals.debug) {
- switch_amr_info(buf, encoded_data_len, switch_test_flag(context, AMR_OPT_OCTET_ALIGN) ? 1 : 0, "AMR decoder");
+ switch_amr_info(codec, buf, encoded_data_len, switch_test_flag(context, AMR_OPT_OCTET_ALIGN) ? 1 : 0, "AMR decoder");
}
if (switch_test_flag(context, AMR_OPT_OCTET_ALIGN)) {
@@ -643,6 +647,9 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_amr_load)
if (!strcasecmp(var, "adjust-bitrate")) {
globals.adjust_bitrate = (switch_byte_t) atoi(val);
}
+ if (!strcasecmp(var, "force-oa")) {
+ globals.force_oa = (switch_byte_t) atoi(val);
+ }
}
}
}
From b775c1f91a94d101e47a528db879ecb3007cf6c1 Mon Sep 17 00:00:00 2001
From: Dragos Oancea
Date: Tue, 16 Mar 2021 14:45:12 +0000
Subject: [PATCH 025/655] [mod_enum] fix mem leak - ldns_resolver_new() -
vanilla cfg.
---
src/mod/applications/mod_enum/mod_enum.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/src/mod/applications/mod_enum/mod_enum.c b/src/mod/applications/mod_enum/mod_enum.c
index f6ca99abce..de5804e1fd 100644
--- a/src/mod/applications/mod_enum/mod_enum.c
+++ b/src/mod/applications/mod_enum/mod_enum.c
@@ -496,6 +496,9 @@ switch_status_t ldns_lookup(const char *number, const char *root, char *server_n
if (!added_server) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "No Nameservers specified, using host default\n");
/* create a new resolver from /etc/resolv.conf */
+ if (res) {
+ ldns_resolver_free(res);
+ }
s = ldns_resolver_new_frm_file(&res, NULL);
}
From e8fa2d37b2db06a4f80ddc38758db88c8efe3b7e Mon Sep 17 00:00:00 2001
From: surendrasignalwire
<56929670+surendrasignalwire@users.noreply.github.com>
Date: Tue, 29 Oct 2019 23:36:59 +0530
Subject: [PATCH 026/655] [Core] execute_on_audio_change on codec change
---
src/switch_core_media.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/src/switch_core_media.c b/src/switch_core_media.c
index 1449724782..0ae007ad90 100644
--- a/src/switch_core_media.c
+++ b/src/switch_core_media.c
@@ -3860,8 +3860,9 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_set_codec(switch_core_session_
end:
if (resetting) {
- switch_core_session_unlock_codec_write(session);
- switch_core_session_unlock_codec_read(session);
+ switch_channel_execute_on(session->channel, "execute_on_audio_change");
+ switch_core_session_unlock_codec_write(session);
+ switch_core_session_unlock_codec_read(session);
}
return status;
From 16ee826e2b8172345aff12ac0c651c46791b5f67 Mon Sep 17 00:00:00 2001
From: surendrasignalwire
<56929670+surendrasignalwire@users.noreply.github.com>
Date: Sat, 21 Dec 2019 03:36:57 +0530
Subject: [PATCH 027/655] [mod_sofia] Url encode the sip_to_user before using
in 200 ok contact
---
src/mod/endpoints/mod_sofia/sofia.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/src/mod/endpoints/mod_sofia/sofia.c b/src/mod/endpoints/mod_sofia/sofia.c
index 7d8b2fe6eb..32ed268b7e 100644
--- a/src/mod/endpoints/mod_sofia/sofia.c
+++ b/src/mod/endpoints/mod_sofia/sofia.c
@@ -10891,9 +10891,10 @@ void sofia_handle_sip_i_invite(switch_core_session_t *session, nua_t *nua, sofia
if (switch_channel_get_variable(channel, "sip_to_uri")) {
const char *ipv6;
const char *tmp, *at, *url = NULL;
-
+ const char *tmp_user = switch_channel_get_variable(channel, "sip_to_user");
+
+ user = switch_core_session_url_encode(session, tmp_user);
host = switch_channel_get_variable(channel, "sip_to_host");
- user = switch_channel_get_variable(channel, "sip_to_user");
switch_channel_set_variable(channel, "sip_to_comment", sip->sip_to->a_comment);
From 21a536e774cfb389505831a8cfca72ec0e50564f Mon Sep 17 00:00:00 2001
From: Seven Du
Date: Thu, 12 Mar 2020 22:01:56 +0800
Subject: [PATCH 028/655] [mod_video_filter] Disable waiting video ready which
blocks the channel 10 seconds in early media
---
src/mod/applications/mod_video_filter/mod_video_filter.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/mod/applications/mod_video_filter/mod_video_filter.c b/src/mod/applications/mod_video_filter/mod_video_filter.c
index 3cd8c84ce9..613f8d9195 100644
--- a/src/mod/applications/mod_video_filter/mod_video_filter.c
+++ b/src/mod/applications/mod_video_filter/mod_video_filter.c
@@ -970,7 +970,7 @@ SWITCH_STANDARD_APP(video_replace_start_function)
return;
}
- switch_channel_wait_for_flag(channel, CF_VIDEO_READY, SWITCH_TRUE, 10000, NULL);
+ // switch_channel_wait_for_flag(channel, CF_VIDEO_READY, SWITCH_TRUE, 10000, NULL);
context = (video_replace_context_t *) switch_core_session_alloc(session, sizeof(*context));
switch_assert(context != NULL);
From 3c5773719e1908a5a31102dd1001318225b9e447 Mon Sep 17 00:00:00 2001
From: phonecomwire <62449660+phonecomwire@users.noreply.github.com>
Date: Fri, 24 Apr 2020 15:10:41 -0700
Subject: [PATCH 029/655] [Core] Adding fix for switch_ivr_originate to not
copy group_confirm variables to the channel
---
src/switch_ivr_originate.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/src/switch_ivr_originate.c b/src/switch_ivr_originate.c
index 2ae0919519..99370d7e79 100644
--- a/src/switch_ivr_originate.c
+++ b/src/switch_ivr_originate.c
@@ -830,6 +830,12 @@ static uint8_t check_channel_status(originate_global_t *oglobals, uint32_t len,
}
} else if (switch_channel_test_flag(oglobals->originate_status[i].peer_channel, CF_WINNER)) {
+ /* unset group_confirm variables */
+ switch_channel_set_variable(oglobals->originate_status[i].peer_channel, "group_confirm_key", NULL);
+ switch_channel_set_variable(oglobals->originate_status[i].peer_channel, "group_confirm_file", NULL);
+ switch_channel_set_variable(oglobals->originate_status[i].peer_channel, "group_confirm_error_file", NULL);
+ switch_channel_set_variable(oglobals->originate_status[i].peer_channel, "group_confirm_cancel_timeout", NULL);
+ switch_channel_set_variable(oglobals->originate_status[i].peer_channel, "group_confirm_read_timeout", NULL);
oglobals->idx = i;
rval = 0;
pindex = (uint32_t) i;
From 9875e190aad74e47929703b1f9ceef144c7cd7c8 Mon Sep 17 00:00:00 2001
From: Seven Du
Date: Wed, 15 Apr 2020 10:36:32 +0800
Subject: [PATCH 030/655] [mod_av] enable resampler when sample rate mismatch
(#153)
---
src/mod/applications/mod_av/avformat.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/mod/applications/mod_av/avformat.c b/src/mod/applications/mod_av/avformat.c
index ae7d2e840c..0b3a452325 100644
--- a/src/mod/applications/mod_av/avformat.c
+++ b/src/mod/applications/mod_av/avformat.c
@@ -702,7 +702,7 @@ GCC_DIAG_ON(deprecated-declarations)
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "sample_rate: %d nb_samples: %d\n", mst->frame->sample_rate, mst->frame->nb_samples);
- if (c->sample_fmt != AV_SAMPLE_FMT_S16) {
+ if (c->sample_fmt != AV_SAMPLE_FMT_S16 || c->sample_rate != mst->sample_rate) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "sample_fmt %d != AV_SAMPLE_FMT_S16, start resampler\n", c->sample_fmt);
mst->resample_ctx = swr_alloc();
@@ -1231,7 +1231,7 @@ GCC_DIAG_ON(deprecated-declarations)
context->audio_st[1].sample_rate = handle->samplerate;
GCC_DIAG_OFF(deprecated-declarations)
- if (context->audio_st[0].st->codec->sample_fmt != AV_SAMPLE_FMT_S16) {
+ if (context->audio_st[0].st->codec->sample_fmt != AV_SAMPLE_FMT_S16 || context->audio_st[0].st->codec->sample_rate != handle->samplerate) {
GCC_DIAG_ON(deprecated-declarations)
int x;
for (x = 0; x < context->has_audio && x < 2 && c[x]; x++) {
From 561a31d72374d81a7ce35701fb483334c8826fca Mon Sep 17 00:00:00 2001
From: Seven Du
Date: Sat, 25 Apr 2020 04:47:45 +0800
Subject: [PATCH 031/655] [mod_sndfile] fix read sndfiles with float data
---
src/mod/formats/mod_sndfile/mod_sndfile.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/src/mod/formats/mod_sndfile/mod_sndfile.c b/src/mod/formats/mod_sndfile/mod_sndfile.c
index 5d2962a8c4..0977a4950b 100644
--- a/src/mod/formats/mod_sndfile/mod_sndfile.c
+++ b/src/mod/formats/mod_sndfile/mod_sndfile.c
@@ -309,6 +309,12 @@ static switch_status_t sndfile_file_open(switch_file_handle_t *handle, const cha
sf_command(context->handle, SFC_FILE_TRUNCATE, &frames, sizeof(frames));
}
+ /*
+ http://www.mega-nerd.com/libsndfile/api.html#note2
+ */
+ if (switch_test_flag(handle, SWITCH_FILE_DATA_SHORT)) {
+ sf_command(context->handle, SFC_SET_SCALE_FLOAT_INT_READ, NULL, SF_TRUE);
+ }
end:
From b774c5e23f99c419c4421629f93a29710563d5fe Mon Sep 17 00:00:00 2001
From: Dragos Oancea
Date: Tue, 28 Apr 2020 17:46:15 +0100
Subject: [PATCH 032/655] [core] eavesdrop: reduce lock contention, fix error
condition + enable eavesdrop stereo
---
src/include/switch_types.h | 3 ++-
src/switch_ivr_async.c | 33 +++++++++++++++++++++------------
2 files changed, 23 insertions(+), 13 deletions(-)
diff --git a/src/include/switch_types.h b/src/include/switch_types.h
index 133422764b..2037889c01 100644
--- a/src/include/switch_types.h
+++ b/src/include/switch_types.h
@@ -353,7 +353,8 @@ typedef enum {
ED_BRIDGE_READ = (1 << 4),
ED_BRIDGE_WRITE = (1 << 5),
ED_TAP_READ = (1 << 6),
- ED_TAP_WRITE = (1 << 7)
+ ED_TAP_WRITE = (1 << 7),
+ ED_STEREO = (1 << 8)
} switch_eavesdrop_flag_enum_t;
typedef uint32_t switch_eavesdrop_flag_t;
diff --git a/src/switch_ivr_async.c b/src/switch_ivr_async.c
index 705142228c..cc5ec0581a 100644
--- a/src/switch_ivr_async.c
+++ b/src/switch_ivr_async.c
@@ -2209,9 +2209,10 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_eavesdrop_session(switch_core_session
char cid_buf[1024] = "";
switch_caller_profile_t *cp = NULL;
uint32_t sanity = 600;
- switch_media_bug_flag_t read_flags = 0, write_flags = 0;
+ switch_media_bug_flag_t read_flags = 0, write_flags = 0, stereo_flag = 0;
const char *vval;
int buf_size = 0;
+ int channels;
if (!switch_channel_media_up(channel)) {
goto end;
@@ -2280,8 +2281,6 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_eavesdrop_session(switch_core_session
ep = switch_core_session_alloc(session, sizeof(*ep));
- tlen = tread_impl.decoded_bytes_per_packet;
-
if (switch_channel_pre_answer(channel) != SWITCH_STATUS_SUCCESS) {
goto end;
@@ -2355,7 +2354,10 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_eavesdrop_session(switch_core_session
write_flags = SMBF_TAP_NATIVE_WRITE;
read_flags = 0;
}
-
+
+ if (flags & ED_STEREO) {
+ stereo_flag = SMBF_STEREO;
+ }
if (switch_channel_test_flag(session->channel, CF_VIDEO) && switch_channel_test_flag(tsession->channel, CF_VIDEO)) {
if ((vval = switch_channel_get_variable(session->channel, "eavesdrop_show_listener_video"))) {
@@ -2384,7 +2386,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_eavesdrop_session(switch_core_session
if (switch_core_media_bug_add(tsession, "eavesdrop", uuid,
eavesdrop_callback, ep, 0,
- read_flags | write_flags | SMBF_READ_PING | SMBF_THREAD_LOCK | SMBF_NO_PAUSE,
+ read_flags | write_flags | SMBF_READ_PING | SMBF_THREAD_LOCK | SMBF_NO_PAUSE | stereo_flag,
&bug) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Cannot attach bug\n");
goto end;
@@ -2561,18 +2563,27 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_eavesdrop_session(switch_core_session
switch_buffer_unlock(ep->w_buffer);
}
+ channels = switch_core_media_bug_test_flag(bug, SMBF_STEREO) ? 2 : tread_impl.number_of_channels;
+
+ if (channels == 0) {
+ channels = 1;
+ }
+
+ tlen = tread_impl.decoded_bytes_per_packet * channels;
+
if (len > tlen) {
len = tlen;
}
- if (ep->buffer && switch_buffer_inuse(ep->buffer) >= len) {
- switch_buffer_lock(ep->buffer);
+ if (ep->buffer) {
while (switch_buffer_inuse(ep->buffer) >= len) {
int tchanged = 0, changed = 0;
+ switch_buffer_lock(ep->buffer);
write_frame.datalen = (uint32_t) switch_buffer_read(ep->buffer, buf, len);
- write_frame.samples = write_frame.datalen / 2;
-
+ switch_buffer_unlock(ep->buffer);
+ write_frame.samples = write_frame.datalen / 2 / channels;
+ write_frame.channels = channels;
switch_core_session_get_read_impl(tsession, &tread_impl);
switch_core_session_get_read_impl(session, &read_impl);
@@ -2606,7 +2617,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_eavesdrop_session(switch_core_session
tread_impl.actual_samples_per_second,
tread_impl.number_of_channels);
- tlen = tread_impl.decoded_bytes_per_packet;
+ tlen = tread_impl.decoded_bytes_per_packet * channels;
if (len > tlen) {
len = tlen;
@@ -2624,7 +2635,6 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_eavesdrop_session(switch_core_session
SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE,
NULL, switch_core_session_get_pool(session)) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Cannot init codec\n");
- switch_core_session_rwunlock(tsession);
goto end;
}
}
@@ -2646,7 +2656,6 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_eavesdrop_session(switch_core_session
break;
}
}
- switch_buffer_unlock(ep->buffer);
}
}
From bb6ec01d1e377572c5cc343bcf54678aec984548 Mon Sep 17 00:00:00 2001
From: Seven Du
Date: Tue, 12 May 2020 01:33:14 +0800
Subject: [PATCH 033/655] [mod_sofia] fix session log
---
src/mod/endpoints/mod_sofia/mod_sofia.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.c b/src/mod/endpoints/mod_sofia/mod_sofia.c
index e236b09a38..8ce1996ccb 100644
--- a/src/mod/endpoints/mod_sofia/mod_sofia.c
+++ b/src/mod/endpoints/mod_sofia/mod_sofia.c
@@ -5070,7 +5070,7 @@ static switch_call_cause_t sofia_outgoing_channel(switch_core_session_t *session
if (gateway_ptr && gateway_ptr->ob_vars) {
switch_event_header_t *hp;
for (hp = gateway_ptr->ob_vars->headers; hp; hp = hp->next) {
- switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s setting variable [%s]=[%s]\n",
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(nsession), SWITCH_LOG_DEBUG, "%s setting variable [%s]=[%s]\n",
switch_channel_get_name(nchannel), hp->name, hp->value);
if (!strncmp(hp->name, "p:", 2)) {
switch_channel_set_profile_var(nchannel, hp->name + 2, hp->value);
From 09d4ec64338a32463577e8d7c48bf77cb0159418 Mon Sep 17 00:00:00 2001
From: Andrey Volk
Date: Tue, 19 May 2020 02:48:02 +0400
Subject: [PATCH 034/655] [Core] Fix multiple missing session unlocks in
switch_core_media.c
---
src/switch_core_media.c | 13 +++++++++----
1 file changed, 9 insertions(+), 4 deletions(-)
diff --git a/src/switch_core_media.c b/src/switch_core_media.c
index 0ae007ad90..d69e1286f5 100644
--- a/src/switch_core_media.c
+++ b/src/switch_core_media.c
@@ -6791,6 +6791,7 @@ static void *SWITCH_THREAD_FUNC video_write_thread(switch_thread_t *thread, void
}
if (!(smh = session->media_handle)) {
+ switch_core_session_rwunlock(session);
return NULL;
}
@@ -7301,12 +7302,14 @@ static void *SWITCH_THREAD_FUNC text_helper_thread(switch_thread_t *thread, void
return NULL;
}
- mh->ready = 1;
-
if (!(smh = session->media_handle)) {
+ switch_core_session_rwunlock(session);
+ mh->ready = -1;
return NULL;
}
+ mh->ready = 1;
+
channel = switch_core_session_get_channel(session);
if (switch_channel_var_true(session->channel, "fire_text_events")) {
@@ -7460,12 +7463,14 @@ static void *SWITCH_THREAD_FUNC video_helper_thread(switch_thread_t *thread, voi
return NULL;
}
- mh->ready = 1;
-
if (!(smh = session->media_handle)) {
+ switch_core_session_rwunlock(session);
+ mh->ready = -1;
return NULL;
}
+ mh->ready = 1;
+
channel = switch_core_session_get_channel(session);
switch_core_autobind_cpu();
From a931220af6969edc0c9fda81e44efcf2867691b4 Mon Sep 17 00:00:00 2001
From: Andrey Volk
Date: Tue, 19 May 2020 19:55:36 +0400
Subject: [PATCH 035/655] [Core] Fix wrong switch_assert expressions in
switch_core_session_write_frame()
---
src/switch_core_media.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/src/switch_core_media.c b/src/switch_core_media.c
index d69e1286f5..810306a91d 100644
--- a/src/switch_core_media.c
+++ b/src/switch_core_media.c
@@ -16018,7 +16018,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_write_frame(switch_core_sess
session->write_codec->cur_frame = frame;
frame->codec->cur_frame = frame;
switch_assert(enc_frame->datalen <= SWITCH_RECOMMENDED_BUFFER_SIZE);
- switch_assert(session->enc_read_frame.datalen <= SWITCH_RECOMMENDED_BUFFER_SIZE);
+ switch_assert(session->enc_write_frame.datalen <= SWITCH_RECOMMENDED_BUFFER_SIZE);
status = switch_core_codec_encode(session->write_codec,
frame->codec,
enc_frame->data,
@@ -16026,7 +16026,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_write_frame(switch_core_sess
session->write_impl.actual_samples_per_second,
session->enc_write_frame.data, &session->enc_write_frame.datalen, &session->enc_write_frame.rate, &flag);
- switch_assert(session->enc_read_frame.datalen <= SWITCH_RECOMMENDED_BUFFER_SIZE);
+ switch_assert(session->enc_write_frame.datalen <= SWITCH_RECOMMENDED_BUFFER_SIZE);
session->write_codec->cur_frame = NULL;
frame->codec->cur_frame = NULL;
@@ -16128,7 +16128,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_write_frame(switch_core_sess
session->write_codec->cur_frame = frame;
frame->codec->cur_frame = frame;
switch_assert(enc_frame->datalen <= SWITCH_RECOMMENDED_BUFFER_SIZE);
- switch_assert(session->enc_read_frame.datalen <= SWITCH_RECOMMENDED_BUFFER_SIZE);
+ switch_assert(session->enc_write_frame.datalen <= SWITCH_RECOMMENDED_BUFFER_SIZE);
status = switch_core_codec_encode(session->write_codec,
frame->codec,
enc_frame->data,
@@ -16136,7 +16136,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_write_frame(switch_core_sess
rate,
session->enc_write_frame.data, &session->enc_write_frame.datalen, &session->enc_write_frame.rate, &flag);
- switch_assert(session->enc_read_frame.datalen <= SWITCH_RECOMMENDED_BUFFER_SIZE);
+ switch_assert(session->enc_write_frame.datalen <= SWITCH_RECOMMENDED_BUFFER_SIZE);
session->write_codec->cur_frame = NULL;
frame->codec->cur_frame = NULL;
From 2dfda2f40947bb5c682e64f2756e774c4a7245f7 Mon Sep 17 00:00:00 2001
From: Andrey Volk
Date: Tue, 19 May 2020 20:29:25 +0400
Subject: [PATCH 036/655] [Core] Fix reference counter lock order when
protect/unprotect interface.
---
src/include/switch_module_interfaces.h | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/include/switch_module_interfaces.h b/src/include/switch_module_interfaces.h
index d49f7f3eb6..d347b1c7fb 100644
--- a/src/include/switch_module_interfaces.h
+++ b/src/include/switch_module_interfaces.h
@@ -854,8 +854,8 @@ struct switch_json_api_interface {
struct switch_json_api_interface *next;
};
-#define PROTECT_INTERFACE(_it) if (_it) {switch_mutex_lock(_it->reflock); switch_thread_rwlock_rdlock(_it->parent->rwlock); switch_thread_rwlock_rdlock(_it->rwlock); _it->refs++; _it->parent->refs++; switch_mutex_unlock(_it->reflock);} //if (!strcmp(_it->interface_name, "user")) switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "+++++++++++LOCK %s %d/%d\n", _it->interface_name, _it->refs, _it->parent->refs);
-#define UNPROTECT_INTERFACE(_it) if (_it) {switch_mutex_lock(_it->reflock); switch_thread_rwlock_unlock(_it->rwlock); switch_thread_rwlock_unlock(_it->parent->rwlock); _it->refs--; _it->parent->refs--; switch_mutex_unlock(_it->reflock);} //if (!strcmp(_it->interface_name, "user")) switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "---------UNLOCK %s %d/%d\n", _it->interface_name, _it->refs, _it->parent->refs);
+#define PROTECT_INTERFACE(_it) if (_it) {switch_thread_rwlock_rdlock(_it->parent->rwlock); switch_thread_rwlock_rdlock(_it->rwlock); switch_mutex_lock(_it->reflock); _it->refs++; _it->parent->refs++; switch_mutex_unlock(_it->reflock);} //if (!strcmp(_it->interface_name, "user")) switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "+++++++++++LOCK %s %d/%d\n", _it->interface_name, _it->refs, _it->parent->refs);
+#define UNPROTECT_INTERFACE(_it) if (_it) {switch_mutex_lock(_it->reflock); _it->refs--; _it->parent->refs--; switch_mutex_unlock(_it->reflock); switch_thread_rwlock_unlock(_it->rwlock); switch_thread_rwlock_unlock(_it->parent->rwlock);} //if (!strcmp(_it->interface_name, "user")) switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "---------UNLOCK %s %d/%d\n", _it->interface_name, _it->refs, _it->parent->refs);
#include "switch_frame.h"
From 7e2c9393dcdbf1620c39650cce6e0d21a7c1bf44 Mon Sep 17 00:00:00 2001
From: surendrasignalwire
Date: Wed, 10 Jun 2020 20:09:01 +0400
Subject: [PATCH 037/655] [core] Fix ODBC column size performance issue
---
src/switch_odbc.c | 57 +++++++++++++++++++++++++++++++++++++++++++----
1 file changed, 53 insertions(+), 4 deletions(-)
diff --git a/src/switch_odbc.c b/src/switch_odbc.c
index 31161ee158..9ea062d997 100644
--- a/src/switch_odbc.c
+++ b/src/switch_odbc.c
@@ -605,17 +605,66 @@ SWITCH_DECLARE(switch_odbc_status_t) switch_odbc_handle_callback_exec_detailed(c
for (x = 1; x <= c; x++) {
SQLSMALLINT NameLength = 0, DataType = 0, DecimalDigits = 0, Nullable = 0;
SQLULEN ColumnSize = 0;
+ SQLLEN numRecs = 0;
+ SQLCHAR SqlState[6], Msg[SQL_MAX_MESSAGE_LENGTH];
+ SQLINTEGER NativeError;
+ SQLSMALLINT diagCount, MsgLen;
names[y] = malloc(name_len);
switch_assert(names[y]);
memset(names[y], 0, name_len);
SQLDescribeCol(stmt, x, (SQLCHAR *) names[y], (SQLSMALLINT) name_len, &NameLength, &DataType, &ColumnSize, &DecimalDigits, &Nullable);
- if (!ColumnSize) {
+ if (ColumnSize <= 16383 || ColumnSize == 2147483647) {
SQLCHAR val[16384] = { 0 };
+ SQLLEN StrLen_or_IndPtr;
+ SQLRETURN rc;
ColumnSize = 16384;
- SQLGetData(stmt, x, SQL_C_CHAR, val, ColumnSize, NULL);
- vals[y] = strdup((char *)val);
+
+ /* check diag record and see if we can get real size
+ * https://docs.microsoft.com/en-us/sql/odbc/reference/develop-app/using-sqlgetdiagrec-and-sqlgetdiagfield?view=sql-server-ver15
+ * szSqlState = "01004" and StrLen_or_IndPtr=15794
+ */
+ rc = SQLGetData(stmt, x, SQL_C_CHAR, val, ColumnSize, &StrLen_or_IndPtr);
+
+ if (rc == SQL_SUCCESS_WITH_INFO) {
+ int truncated = 0;
+ diagCount = 1;
+
+ SQLGetDiagField(SQL_HANDLE_STMT, stmt, 0, SQL_DIAG_NUMBER, &numRecs, 0, 0);
+
+ while (diagCount <= numRecs) {
+ SQLGetDiagRec(SQL_HANDLE_STMT, stmt, diagCount, SqlState, &NativeError,Msg, sizeof(Msg), &MsgLen);
+ if (!strcmp((char*)SqlState,"01004")){
+ truncated = 1;
+ break;
+ }
+
+ diagCount++;
+ }
+
+ if (truncated) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "sql data truncated - %s\n",SqlState);
+ if (StrLen_or_IndPtr && StrLen_or_IndPtr <= 268435456) {
+ ColumnSize = StrLen_or_IndPtr + 1;
+ vals[y] = malloc(ColumnSize);
+ switch_assert(vals[y]);
+ memset(vals[y], 0, ColumnSize);
+ SQLGetData(stmt, x, SQL_C_CHAR, (SQLCHAR *) vals[y], ColumnSize, NULL);
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "SQLGetData failed");
+ vals[y] = NULL;
+ }
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "SQLGetData failed");
+ vals[y] = NULL;
+ }
+ } else if (rc == SQL_SUCCESS){
+ vals[y] = strdup((char *)val);
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "SQLGetData failed");
+ vals[y] = NULL;
+ }
} else {
ColumnSize++;
@@ -633,7 +682,7 @@ SWITCH_DECLARE(switch_odbc_status_t) switch_odbc_handle_callback_exec_detailed(c
for (x = 0; x < y; x++) {
free(names[x]);
- free(vals[x]);
+ switch_safe_free(vals[x]);
}
free(names);
free(vals);
From b5459fb5f558d79c7b87ac9d43f12d6eed3aceba Mon Sep 17 00:00:00 2001
From: Seven Du
Date: Sat, 13 Jun 2020 06:53:25 +0800
Subject: [PATCH 038/655] [mod_av] remove extra space
---
src/mod/applications/mod_av/avcodec.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/mod/applications/mod_av/avcodec.c b/src/mod/applications/mod_av/avcodec.c
index f1a58cb7d7..01c862cf11 100644
--- a/src/mod/applications/mod_av/avcodec.c
+++ b/src/mod/applications/mod_av/avcodec.c
@@ -110,7 +110,7 @@ static void dump_encoder_ctx(AVCodecContext *ctx)
#ifdef DUMP_ENCODER_CTX
#define STRINGIFY(x) #x
#define my_dump_int(x) switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR, STRINGIFY(x) " = %d\n", ctx->x);
-#define my_dump_int64(x) switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR, STRINGIFY(x) " = % " SWITCH_INT64_T_FMT "\n", ctx->x);
+#define my_dump_int64(x) switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR, STRINGIFY(x) " = %" SWITCH_INT64_T_FMT "\n", ctx->x);
#define my_dump_float(x) switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR, STRINGIFY(x) " = %f\n", ctx->x);
#define my_dump_enum(x) switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR, STRINGIFY(x) " = %d\n", ctx->x);
#define my_dump_uint(x) switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR, STRINGIFY(x) " = 0x%x\n", ctx->x);
From 034a7eea5edeb313f40ce10ac84fcd8570115776 Mon Sep 17 00:00:00 2001
From: Andrey Volk
Date: Wed, 17 Jun 2020 18:52:20 +0400
Subject: [PATCH 039/655] [mod_pgsql] Fix potential hang when calling
PQconsumeInput() while checking if db_is_up().
---
src/mod/databases/mod_pgsql/mod_pgsql.c | 23 ++++++++++++++++++-----
1 file changed, 18 insertions(+), 5 deletions(-)
diff --git a/src/mod/databases/mod_pgsql/mod_pgsql.c b/src/mod/databases/mod_pgsql/mod_pgsql.c
index a534594548..b94b1abc73 100644
--- a/src/mod/databases/mod_pgsql/mod_pgsql.c
+++ b/src/mod/databases/mod_pgsql/mod_pgsql.c
@@ -113,6 +113,7 @@ static int db_is_up(switch_pgsql_handle_t *handle)
int max_tries = DEFAULT_PGSQL_RETRIES;
int code = 0;
int recon = 0;
+ switch_byte_t sanity = 255;
if (handle) {
max_tries = handle->num_retries;
@@ -132,10 +133,24 @@ top:
}
/* Try a non-blocking read on the connection to gobble up any EOF from a closed connection and mark the connection BAD if it is closed. */
- PQconsumeInput(handle->con);
+ while (--sanity > 0)
+ {
+ if (PQisBusy(handle->con)) {
+ PQconsumeInput(handle->con);
+ switch_yield(1);
+ continue;
+ }
+ break;
+ }
+
+ if (!sanity) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Can not check DB Connection status: sanity = 0. Reconnecting...\n");
+ goto reset;
+ }
if (PQstatus(handle->con) == CONNECTION_BAD) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "PQstatus returned bad connection; reconnecting...\n");
+reset:
handle->state = SWITCH_PGSQL_STATE_ERROR;
PQreset(handle->con);
if (PQstatus(handle->con) == CONNECTION_BAD) {
@@ -486,15 +501,13 @@ error:
err_str = pgsql_handle_get_error(handle);
if (zstr(err_str)) {
- if (zstr(er)) {
+ if (!er) {
err_str = strdup((char *)"SQL ERROR!");
} else {
err_str = er;
}
} else {
- if (!zstr(er)) {
- free(er);
- }
+ switch_safe_free(er);
}
if (err_str) {
From cffc29927b45d4c36490d4e1b42f4df0761f439a Mon Sep 17 00:00:00 2001
From: surendrasignalwire
<56929670+surendrasignalwire@users.noreply.github.com>
Date: Fri, 10 Jul 2020 02:56:42 +0530
Subject: [PATCH 040/655] [Core] Fix crash while writing text_frame in
conference
---
src/switch_core_media.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/src/switch_core_media.c b/src/switch_core_media.c
index 810306a91d..674c5b92f9 100644
--- a/src/switch_core_media.c
+++ b/src/switch_core_media.c
@@ -15502,6 +15502,11 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_write_text_frame(switch_core
t_engine = &smh->engines[SWITCH_MEDIA_TYPE_TEXT];
+ if (!t_engine || !t_engine->tf) {
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "text engine not available for processing\n");
+ switch_goto_status(SWITCH_STATUS_BREAK, done);
+ }
+
if (!is_msrp && switch_channel_test_cap(session->channel, CC_RTP_RTT)) {
if (frame) {
From 23321373edfb5c568d5e604008ab5e3cbd43e5c1 Mon Sep 17 00:00:00 2001
From: Andrey Volk
Date: Tue, 7 Jul 2020 18:00:35 +0400
Subject: [PATCH 041/655] [Core] Fix double close of a socket in switch_rtp
---
src/switch_rtp.c | 24 +++++++++++++++---------
1 file changed, 15 insertions(+), 9 deletions(-)
diff --git a/src/switch_rtp.c b/src/switch_rtp.c
index e7aafd0482..e2e6dedc2d 100644
--- a/src/switch_rtp.c
+++ b/src/switch_rtp.c
@@ -2991,7 +2991,7 @@ static void ping_socket(switch_rtp_t *rtp_session)
switch_size_t len = sizeof(o);
switch_socket_sendto(rtp_session->sock_input, rtp_session->local_addr, 0, (void *) &o, &len);
- if (rtp_session->flags[SWITCH_RTP_FLAG_ENABLE_RTCP] && rtp_session->rtcp_sock_input) {
+ if (rtp_session->flags[SWITCH_RTP_FLAG_ENABLE_RTCP] && rtp_session->rtcp_sock_input && rtp_session->rtcp_sock_input != rtp_session->sock_input) {
switch_socket_sendto(rtp_session->rtcp_sock_input, rtp_session->rtcp_local_addr, 0, (void *) &o, &len);
}
}
@@ -5077,11 +5077,11 @@ SWITCH_DECLARE(void) switch_rtp_kill_socket(switch_rtp_t *rtp_session)
}
if (rtp_session->flags[SWITCH_RTP_FLAG_ENABLE_RTCP]) {
- if (rtp_session->rtcp_sock_input) {
+ if (rtp_session->rtcp_sock_input && rtp_session->rtcp_sock_input != rtp_session->sock_input) {
ping_socket(rtp_session);
switch_socket_shutdown(rtp_session->rtcp_sock_input, SWITCH_SHUTDOWN_READWRITE);
}
- if (rtp_session->rtcp_sock_output && rtp_session->rtcp_sock_output != rtp_session->rtcp_sock_input) {
+ if (rtp_session->rtcp_sock_output && rtp_session->rtcp_sock_output != rtp_session->sock_output && rtp_session->rtcp_sock_output != rtp_session->rtcp_sock_input) {
switch_socket_shutdown(rtp_session->rtcp_sock_output, SWITCH_SHUTDOWN_READWRITE);
}
}
@@ -5197,6 +5197,13 @@ SWITCH_DECLARE(void) switch_rtp_destroy(switch_rtp_t **rtp_session)
free_dtls(&(*rtp_session)->rtcp_dtls);
}
+ if ((*rtp_session)->rtcp_sock_input == (*rtp_session)->sock_input) {
+ (*rtp_session)->rtcp_sock_input = NULL;
+ }
+
+ if ((*rtp_session)->rtcp_sock_output == (*rtp_session)->sock_output) {
+ (*rtp_session)->rtcp_sock_output = NULL;
+ }
sock = (*rtp_session)->sock_input;
(*rtp_session)->sock_input = NULL;
@@ -5211,13 +5218,12 @@ SWITCH_DECLARE(void) switch_rtp_destroy(switch_rtp_t **rtp_session)
if ((sock = (*rtp_session)->rtcp_sock_input)) {
(*rtp_session)->rtcp_sock_input = NULL;
switch_socket_close(sock);
+ }
- if ((*rtp_session)->rtcp_sock_output && (*rtp_session)->rtcp_sock_output != sock) {
- if ((sock = (*rtp_session)->rtcp_sock_output)) {
- (*rtp_session)->rtcp_sock_output = NULL;
- switch_socket_close(sock);
- }
- }
+ if ((*rtp_session)->rtcp_sock_output && (*rtp_session)->rtcp_sock_output != sock) {
+ sock = (*rtp_session)->rtcp_sock_output;
+ (*rtp_session)->rtcp_sock_output = NULL;
+ switch_socket_close(sock);
}
#ifdef ENABLE_SRTP
From 167ab110064f45f9a52458b2300129d6f30e773a Mon Sep 17 00:00:00 2001
From: Andrey Volk
Date: Fri, 17 Jul 2020 20:38:15 +0400
Subject: [PATCH 042/655] [mod_sofia] Fix potential leak of uuid in
sofia_event_callback().
---
src/mod/endpoints/mod_sofia/sofia.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/src/mod/endpoints/mod_sofia/sofia.c b/src/mod/endpoints/mod_sofia/sofia.c
index 32ed268b7e..7f7b0c2b75 100644
--- a/src/mod/endpoints/mod_sofia/sofia.c
+++ b/src/mod/endpoints/mod_sofia/sofia.c
@@ -2435,11 +2435,16 @@ void sofia_event_callback(nua_event_t event,
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "detaching session %s\n", sofia_private->uuid);
if (!zstr(tech_pvt->call_id)) {
+ char *uuid = strdup(switch_core_session_get_uuid(session));
tech_pvt->sofia_private = NULL;
tech_pvt->nh = NULL;
sofia_set_flag(tech_pvt, TFLAG_BYE);
switch_mutex_lock(profile->flag_mutex);
- switch_core_hash_insert_auto_free(profile->chat_hash, tech_pvt->call_id, strdup(switch_core_session_get_uuid(session)));
+
+ if (switch_core_hash_insert_auto_free(profile->chat_hash, tech_pvt->call_id, uuid) != SWITCH_STATUS_SUCCESS) {
+ switch_safe_free(uuid);
+ }
+
switch_mutex_unlock(profile->flag_mutex);
nua_handle_destroy(nh);
} else {
From b220a05010679ca4760c32ec05bb4a601fc9831c Mon Sep 17 00:00:00 2001
From: surendrasignalwire
<56929670+surendrasignalwire@users.noreply.github.com>
Date: Thu, 23 Jul 2020 03:00:31 +0530
Subject: [PATCH 043/655] [Core] Fixed issue while setting mode on reinvite or
outbound direction
---
src/switch_core_media.c | 6 +-----
1 file changed, 1 insertion(+), 5 deletions(-)
diff --git a/src/switch_core_media.c b/src/switch_core_media.c
index 674c5b92f9..4778edbf8c 100644
--- a/src/switch_core_media.c
+++ b/src/switch_core_media.c
@@ -4815,11 +4815,7 @@ static void switch_core_media_set_rmode(switch_core_session_t *session, switch_m
if (switch_core_session_get_partner(session, &other_session) == SWITCH_STATUS_SUCCESS) {
- if (!switch_channel_media_up(session->channel) && sdp_type == SDP_TYPE_REQUEST) {
- engine->rmode = switch_core_session_remote_media_flow(other_session, type);
-
- media_flow_get_mode(engine->rmode, &rmode_str, &opp_rmode);
- } else if (sdp_type == SDP_TYPE_RESPONSE && (switch_channel_test_flag(other_session->channel, CF_REINVITE) || switch_channel_direction(session->channel) == SWITCH_CALL_DIRECTION_OUTBOUND)) {
+ if (sdp_type == SDP_TYPE_RESPONSE && (switch_channel_test_flag(other_session->channel, CF_REINVITE) || switch_channel_direction(session->channel) == SWITCH_CALL_DIRECTION_OUTBOUND)) {
switch_core_media_set_smode(other_session, type, rmode, sdp_type);
}
From f09ed875b95823e7a52c155e2152d9becb83f27f Mon Sep 17 00:00:00 2001
From: Andrey Volk
Date: Fri, 24 Jul 2020 22:42:49 +0400
Subject: [PATCH 044/655] [Core] Fix buffer race in
switch_ivr_eavesdrop_session()
---
src/switch_ivr_async.c | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/src/switch_ivr_async.c b/src/switch_ivr_async.c
index cc5ec0581a..621836de00 100644
--- a/src/switch_ivr_async.c
+++ b/src/switch_ivr_async.c
@@ -2576,12 +2576,11 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_eavesdrop_session(switch_core_session
}
if (ep->buffer) {
+ switch_buffer_lock(ep->buffer);
while (switch_buffer_inuse(ep->buffer) >= len) {
int tchanged = 0, changed = 0;
- switch_buffer_lock(ep->buffer);
write_frame.datalen = (uint32_t) switch_buffer_read(ep->buffer, buf, len);
- switch_buffer_unlock(ep->buffer);
write_frame.samples = write_frame.datalen / 2 / channels;
write_frame.channels = channels;
@@ -2635,6 +2634,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_eavesdrop_session(switch_core_session
SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE,
NULL, switch_core_session_get_pool(session)) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Cannot init codec\n");
+ switch_buffer_unlock(ep->buffer);
goto end;
}
}
@@ -2655,7 +2655,12 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_eavesdrop_session(switch_core_session
if ((status = switch_core_session_write_frame(session, &write_frame, SWITCH_IO_FLAG_NONE, 0)) != SWITCH_STATUS_SUCCESS) {
break;
}
+
+ switch_buffer_unlock(ep->buffer);
+ switch_buffer_lock(ep->buffer);
}
+
+ switch_buffer_unlock(ep->buffer);
}
}
From 4fe8aecbfb3f96de4a8b7afddc1c22b61d771370 Mon Sep 17 00:00:00 2001
From: Andrey Volk
Date: Mon, 27 Jul 2020 21:41:13 +0400
Subject: [PATCH 045/655] [Core] Make switch_core_media_set_codec() and
switch_core_media_set_video_codec() thread-safe so there is no race when a
session's codec is initiated by different threads simultaneously.
---
src/include/private/switch_core_pvt.h | 1 +
src/switch_core_media.c | 27 +++++++++++++++++++--------
src/switch_core_session.c | 1 +
3 files changed, 21 insertions(+), 8 deletions(-)
diff --git a/src/include/private/switch_core_pvt.h b/src/include/private/switch_core_pvt.h
index c3478f109e..68a8d9c463 100644
--- a/src/include/private/switch_core_pvt.h
+++ b/src/include/private/switch_core_pvt.h
@@ -132,6 +132,7 @@ struct switch_core_session {
switch_mutex_t *mutex;
switch_mutex_t *stack_count_mutex;
switch_mutex_t *resample_mutex;
+ switch_mutex_t *codec_init_mutex;
switch_mutex_t *codec_read_mutex;
switch_mutex_t *codec_write_mutex;
switch_mutex_t *video_codec_read_mutex;
diff --git a/src/switch_core_media.c b/src/switch_core_media.c
index 4778edbf8c..8173996e3d 100644
--- a/src/switch_core_media.c
+++ b/src/switch_core_media.c
@@ -3587,24 +3587,27 @@ static void switch_core_session_parse_codec_settings(switch_core_session_t *sess
//?
SWITCH_DECLARE(switch_status_t) switch_core_media_set_video_codec(switch_core_session_t *session, int force)
{
+ switch_status_t status = SWITCH_STATUS_SUCCESS;
switch_media_handle_t *smh;
switch_rtp_engine_t *v_engine;
switch_assert(session);
+ switch_mutex_lock(session->codec_init_mutex);
+
if (!(smh = session->media_handle)) {
- return SWITCH_STATUS_FALSE;
+ switch_goto_status(SWITCH_STATUS_FALSE, end);
}
v_engine = &smh->engines[SWITCH_MEDIA_TYPE_VIDEO];
if (!v_engine->codec_negotiated) {
- return SWITCH_STATUS_FALSE;
+ switch_goto_status(SWITCH_STATUS_FALSE, end);
}
if (v_engine->read_codec.implementation && switch_core_codec_ready(&v_engine->read_codec)) {
if (!force) {
- return SWITCH_STATUS_SUCCESS;
+ switch_goto_status(SWITCH_STATUS_SUCCESS, end);
}
if (strcasecmp(v_engine->read_codec.implementation->iananame, v_engine->cur_payload_map->rm_encoding) ||
v_engine->read_codec.implementation->samples_per_second != v_engine->cur_payload_map->rm_rate) {
@@ -3616,7 +3619,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_set_video_codec(switch_core_se
} else {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Already using %s\n",
v_engine->read_codec.implementation->iananame);
- return SWITCH_STATUS_SUCCESS;
+ switch_goto_status(SWITCH_STATUS_SUCCESS, end);
}
}
@@ -3632,7 +3635,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_set_video_codec(switch_core_se
SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE,
&v_engine->codec_settings, switch_core_session_get_pool(session)) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Can't load codec?\n");
- return SWITCH_STATUS_FALSE;
+ switch_goto_status(SWITCH_STATUS_FALSE, end);
} else {
if (switch_core_codec_init(&v_engine->write_codec,
v_engine->cur_payload_map->rm_encoding,
@@ -3644,7 +3647,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_set_video_codec(switch_core_se
SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE,
&v_engine->codec_settings, switch_core_session_get_pool(session)) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Can't load codec?\n");
- return SWITCH_STATUS_FALSE;
+ switch_goto_status(SWITCH_STATUS_FALSE, end);
} else {
v_engine->read_frame.rate = v_engine->cur_payload_map->rm_rate;
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Set VIDEO Codec %s %s/%ld %d ms\n",
@@ -3685,7 +3688,11 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_set_video_codec(switch_core_se
switch_channel_set_variable_printf(session->channel, "rtp_use_video_codec_ptime", "%d", 0);
}
}
- return SWITCH_STATUS_SUCCESS;
+
+end:
+ switch_mutex_unlock(session->codec_init_mutex);
+
+ return status;
}
@@ -3698,9 +3705,11 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_set_codec(switch_core_session_
switch_rtp_engine_t *a_engine;
switch_assert(session);
+
+ switch_mutex_lock(session->codec_init_mutex);
if (!(smh = session->media_handle)) {
- return SWITCH_STATUS_FALSE;
+ switch_goto_status(SWITCH_STATUS_FALSE, end);
}
a_engine = &smh->engines[SWITCH_MEDIA_TYPE_AUDIO];
@@ -3865,6 +3874,8 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_set_codec(switch_core_session_
switch_core_session_unlock_codec_read(session);
}
+ switch_mutex_unlock(session->codec_init_mutex);
+
return status;
}
static void clear_ice(switch_core_session_t *session, switch_media_type_t type)
diff --git a/src/switch_core_session.c b/src/switch_core_session.c
index ca58566b2f..36cf62f111 100644
--- a/src/switch_core_session.c
+++ b/src/switch_core_session.c
@@ -2417,6 +2417,7 @@ SWITCH_DECLARE(switch_core_session_t *) switch_core_session_request_uuid(switch_
switch_mutex_init(&session->mutex, SWITCH_MUTEX_NESTED, session->pool);
switch_mutex_init(&session->stack_count_mutex, SWITCH_MUTEX_NESTED, session->pool);
switch_mutex_init(&session->resample_mutex, SWITCH_MUTEX_NESTED, session->pool);
+ switch_mutex_init(&session->codec_init_mutex, SWITCH_MUTEX_NESTED, session->pool);
switch_mutex_init(&session->codec_read_mutex, SWITCH_MUTEX_NESTED, session->pool);
switch_mutex_init(&session->codec_write_mutex, SWITCH_MUTEX_NESTED, session->pool);
switch_mutex_init(&session->video_codec_read_mutex, SWITCH_MUTEX_NESTED, session->pool);
From 785d92a5f52d91f428677032235f27cc0365a570 Mon Sep 17 00:00:00 2001
From: Andrey Volk
Date: Tue, 4 Aug 2020 23:06:59 +0400
Subject: [PATCH 046/655] [mod_pgsql] Prevent a stall of PQconsumeInput().
---
src/mod/databases/mod_pgsql/mod_pgsql.c | 150 +++++++++++++-----------
1 file changed, 83 insertions(+), 67 deletions(-)
diff --git a/src/mod/databases/mod_pgsql/mod_pgsql.c b/src/mod/databases/mod_pgsql/mod_pgsql.c
index b94b1abc73..e2efa5252c 100644
--- a/src/mod/databases/mod_pgsql/mod_pgsql.c
+++ b/src/mod/databases/mod_pgsql/mod_pgsql.c
@@ -373,6 +373,20 @@ switch_status_t pgsql_handle_connect(switch_pgsql_handle_t *handle)
return SWITCH_STATUS_FALSE;
}
+ if (PQsetnonblocking(handle->con, 1) == -1) {
+ char *err_str;
+
+ if ((err_str = pgsql_handle_get_error(handle))) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "%s\n", err_str);
+ switch_safe_free(err_str);
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to setup socket for the database [%s]\n", handle->dsn);
+ pgsql_handle_disconnect(handle);
+ }
+
+ return SWITCH_STATUS_FALSE;
+ }
+
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "Connected to [%s]\n", handle->dsn);
handle->state = SWITCH_PGSQL_STATE_CONNECTED;
handle->sock = PQsocket(handle->con);
@@ -635,89 +649,91 @@ switch_status_t pgsql_next_result_timed(switch_pgsql_handle_t *handle, switch_pg
return SWITCH_STATUS_FALSE;
}
- /* Try to consume input that might be waiting right away */
- if (PQconsumeInput(handle->con)) {
- /* And check to see if we have a full result ready for reading */
- if (PQisBusy(handle->con)) {
+ if (PQisBusy(handle->con)) {
+ /* Try to consume input that might be waiting right away */
+ if (PQconsumeInput(handle->con)) {
+ /* And check to see if we have a full result ready for reading */
+ if (PQisBusy(handle->con)) {
- /* Wait for a result to become available, up to msec milliseconds */
- start = switch_micro_time_now();
- while ((ctime = switch_micro_time_now()) - start <= usec) {
- switch_time_t wait_time = (usec - (ctime - start)) / 1000;
- /* Wait for the PostgreSQL socket to be ready for data reads. */
+ /* Wait for a result to become available, up to msec milliseconds */
+ start = switch_micro_time_now();
+ while ((ctime = switch_micro_time_now()) - start <= usec) {
+ switch_time_t wait_time = (usec - (ctime - start)) / 1000;
+ /* Wait for the PostgreSQL socket to be ready for data reads. */
#ifndef _WIN32
- fds[0].fd = handle->sock;
- fds[0].events |= POLLIN;
- fds[0].events |= POLLERR;
- fds[0].events |= POLLNVAL;
- fds[0].events |= POLLHUP;
- fds[0].events |= POLLPRI;
- fds[0].events |= POLLRDNORM;
- fds[0].events |= POLLRDBAND;
+ fds[0].fd = handle->sock;
+ fds[0].events |= POLLIN;
+ fds[0].events |= POLLERR;
+ fds[0].events |= POLLNVAL;
+ fds[0].events |= POLLHUP;
+ fds[0].events |= POLLPRI;
+ fds[0].events |= POLLRDNORM;
+ fds[0].events |= POLLRDBAND;
- poll_res = poll(&fds[0], 1, wait_time);
+ poll_res = poll(&fds[0], 1, wait_time);
#else
- struct timeval wait = { (long)wait_time * 1000, 0 };
- FD_ZERO(&rs);
- FD_SET(handle->sock, &rs);
- FD_ZERO(&es);
- FD_SET(handle->sock, &es);
- poll_res = select(0, &rs, 0, &es, &wait);
+ struct timeval wait = { (long)wait_time * 1000, 0 };
+ FD_ZERO(&rs);
+ FD_SET(handle->sock, &rs);
+ FD_ZERO(&es);
+ FD_SET(handle->sock, &es);
+ poll_res = select(0, &rs, 0, &es, &wait);
#endif
- if (poll_res > 0) {
+ if (poll_res > 0) {
#ifndef _WIN32
- if (fds[0].revents & POLLHUP || fds[0].revents & POLLNVAL) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "PGSQL socket closed or invalid while waiting for result for query (%s)\n", handle->sql);
- goto error;
- } else if (fds[0].revents & POLLERR) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Poll error trying to read PGSQL socket for query (%s)\n", handle->sql);
- goto error;
- } else if (fds[0].revents & POLLIN || fds[0].revents & POLLPRI || fds[0].revents & POLLRDNORM || fds[0].revents & POLLRDBAND) {
+ if (fds[0].revents & POLLHUP || fds[0].revents & POLLNVAL) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "PGSQL socket closed or invalid while waiting for result for query (%s)\n", handle->sql);
+ goto error;
+ } else if (fds[0].revents & POLLERR) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Poll error trying to read PGSQL socket for query (%s)\n", handle->sql);
+ goto error;
+ } else if (fds[0].revents & POLLIN || fds[0].revents & POLLPRI || fds[0].revents & POLLRDNORM || fds[0].revents & POLLRDBAND) {
#else
- if (FD_ISSET(handle->sock, &rs)) {
+ if (FD_ISSET(handle->sock, &rs)) {
#endif
- /* Then try to consume any input waiting. */
- if (PQconsumeInput(handle->con)) {
- if (PQstatus(handle->con) == CONNECTION_BAD) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Connection terminated while waiting for result.\n");
- handle->state = SWITCH_PGSQL_STATE_ERROR;
+ /* Then try to consume any input waiting. */
+ if (PQconsumeInput(handle->con)) {
+ if (PQstatus(handle->con) == CONNECTION_BAD) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Connection terminated while waiting for result.\n");
+ handle->state = SWITCH_PGSQL_STATE_ERROR;
+ goto error;
+ }
+
+ /* And check to see if we have a full result ready for reading */
+ if (!PQisBusy(handle->con)) {
+ /* If we can pull a full result without blocking, then break this loop */
+ break;
+ }
+ } else {
+ /* If we had an error trying to consume input, report it and cancel the query. */
+ err_str = pgsql_handle_get_error(handle);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "An error occurred trying to consume input for query (%s): %s\n", handle->sql, err_str);
+ switch_safe_free(err_str);
+ pgsql_cancel(handle);
goto error;
}
-
- /* And check to see if we have a full result ready for reading */
- if (!PQisBusy(handle->con)) {
- /* If we can pull a full result without blocking, then break this loop */
- break;
- }
- } else {
- /* If we had an error trying to consume input, report it and cancel the query. */
- err_str = pgsql_handle_get_error(handle);
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "An error occurred trying to consume input for query (%s): %s\n", handle->sql, err_str);
- switch_safe_free(err_str);
- pgsql_cancel(handle);
- goto error;
}
+ } else if (poll_res == -1) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Poll failed trying to read PGSQL socket for query (%s)\n", handle->sql);
+ goto error;
}
- } else if (poll_res == -1) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Poll failed trying to read PGSQL socket for query (%s)\n", handle->sql);
+ }
+
+ /* If we broke the loop above because of a timeout, report that and cancel the query. */
+ if (ctime - start > usec) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Query (%s) took too long to complete or database not responding.\n", handle->sql);
+ pgsql_cancel(handle);
goto error;
}
}
-
- /* If we broke the loop above because of a timeout, report that and cancel the query. */
- if (ctime - start > usec) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Query (%s) took too long to complete or database not responding.\n", handle->sql);
- pgsql_cancel(handle);
- goto error;
- }
+ } else {
+ /* If we had an error trying to consume input, report it and cancel the query. */
+ err_str = pgsql_handle_get_error(handle);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "An error occurred trying to consume input for query (%s): %s\n", handle->sql, err_str);
+ switch_safe_free(err_str);
+ /* pgsql_cancel(handle); */
+ goto error;
}
- } else {
- /* If we had an error trying to consume input, report it and cancel the query. */
- err_str = pgsql_handle_get_error(handle);
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "An error occurred trying to consume input for query (%s): %s\n", handle->sql, err_str);
- switch_safe_free(err_str);
- /* pgsql_cancel(handle); */
- goto error;
}
/* At this point, we know we can read a full result without blocking. */
From 1fee1fc6adcdad2808716ed99d03831724349f01 Mon Sep 17 00:00:00 2001
From: Andrey Volk
Date: Wed, 12 Aug 2020 21:53:06 +0400
Subject: [PATCH 047/655] [Core] Fix SDP parsing causing segfault.
---
src/switch_core_media.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/src/switch_core_media.c b/src/switch_core_media.c
index 8173996e3d..23e77047b9 100644
--- a/src/switch_core_media.c
+++ b/src/switch_core_media.c
@@ -9051,6 +9051,10 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_activate_rtp(switch_core_sessi
// goto video;
//}
+ if (!t_engine->cur_payload_map) {
+ goto text_up;
+ }
+
if (switch_channel_test_flag(session->channel, CF_TEXT_POSSIBLE) && t_engine->cur_payload_map->rm_encoding && t_engine->cur_payload_map->remote_sdp_port) {
/******************************************************************************************/
if (t_engine->rtp_session && is_reinvite) {
From 7b8a36c2a98281e2c31db1c908842a327d2cfdca Mon Sep 17 00:00:00 2001
From: surendrasignalwire
Date: Thu, 13 Aug 2020 14:49:47 +0400
Subject: [PATCH 048/655] [mod_sofia] Fix recovery reinvite issue
---
src/mod/endpoints/mod_sofia/sofia.c | 9 +++++++++
src/mod/endpoints/mod_sofia/sofia_glue.c | 11 +++++------
2 files changed, 14 insertions(+), 6 deletions(-)
diff --git a/src/mod/endpoints/mod_sofia/sofia.c b/src/mod/endpoints/mod_sofia/sofia.c
index 7f7b0c2b75..4975ca8feb 100644
--- a/src/mod/endpoints/mod_sofia/sofia.c
+++ b/src/mod/endpoints/mod_sofia/sofia.c
@@ -1733,6 +1733,10 @@ static void our_sofia_event_callback(nua_event_t event,
switch_channel_set_variable(channel, "sip_call_id", sip->sip_call_id->i_id);
}
+ if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) {
+ switch_channel_set_variable(channel, "dlg_req_swap_direction", "true");
+ }
+
extract_header_vars(profile, sip, session, nh);
switch_core_recovery_track(session);
sofia_set_flag(tech_pvt, TFLAG_GOT_ACK);
@@ -7111,8 +7115,13 @@ static void sofia_handle_sip_r_invite(switch_core_session_t *session, int status
sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE);
}
+ if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_INBOUND) {
+ switch_channel_set_variable(channel, "dlg_req_swap_direction", "true");
+ }
+
extract_header_vars(profile, sip, session, nh);
extract_vars(profile, sip, session);
+ switch_core_recovery_track(session);
switch_channel_clear_flag(tech_pvt->channel, CF_RECOVERING);
}
diff --git a/src/mod/endpoints/mod_sofia/sofia_glue.c b/src/mod/endpoints/mod_sofia/sofia_glue.c
index a49bd998a9..2eea09bd5e 100644
--- a/src/mod/endpoints/mod_sofia/sofia_glue.c
+++ b/src/mod/endpoints/mod_sofia/sofia_glue.c
@@ -2235,7 +2235,7 @@ int sofia_recover_callback(switch_core_session_t *session)
const char *rr;
int r = 0;
const char *profile_name = switch_channel_get_variable_dup(channel, "recovery_profile_name", SWITCH_FALSE, -1);
-
+ int swap = switch_channel_var_true(channel, "dlg_req_swap_direction");
if (zstr(profile_name)) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "Missing profile\n");
@@ -2275,10 +2275,9 @@ int sofia_recover_callback(switch_core_session_t *session)
rr = switch_channel_get_variable(channel, "sip_invite_record_route");
if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) {
- int break_rfc = switch_true(switch_channel_get_variable(channel, "sip_recovery_break_rfc"));
tech_pvt->dest = switch_core_session_sprintf(session, "sip:%s", switch_channel_get_variable(channel, "sip_req_uri"));
- switch_channel_set_variable(channel, "sip_handle_full_from", switch_channel_get_variable(channel, break_rfc ? "sip_full_to" : "sip_full_from"));
- switch_channel_set_variable(channel, "sip_handle_full_to", switch_channel_get_variable(channel, break_rfc ? "sip_full_from" : "sip_full_to"));
+ switch_channel_set_variable(channel, "sip_handle_full_from", switch_channel_get_variable(channel, swap ? "sip_full_to" : "sip_full_from"));
+ switch_channel_set_variable(channel, "sip_handle_full_to", switch_channel_get_variable(channel, swap ? "sip_full_from" : "sip_full_to"));
} else {
const char *contact_params = switch_channel_get_variable(channel, "sip_contact_params");
const char *contact_uri = switch_channel_get_variable(channel, "sip_contact_uri");
@@ -2297,11 +2296,11 @@ int sofia_recover_callback(switch_core_session_t *session)
tech_pvt->dest = switch_core_session_sprintf(session, "sip:%s", switch_channel_get_variable(channel, "sip_from_uri"));
if (!switch_channel_get_variable_dup(channel, "sip_handle_full_from", SWITCH_FALSE, -1)) {
- switch_channel_set_variable(channel, "sip_handle_full_from", switch_channel_get_variable(channel, "sip_full_to"));
+ switch_channel_set_variable(channel, "sip_handle_full_from", switch_channel_get_variable(channel, swap ? "sip_full_from" :"sip_full_to"));
}
if (!switch_channel_get_variable_dup(channel, "sip_handle_full_to", SWITCH_FALSE, -1)) {
- switch_channel_set_variable(channel, "sip_handle_full_to", switch_channel_get_variable(channel, "sip_full_from"));
+ switch_channel_set_variable(channel, "sip_handle_full_to", switch_channel_get_variable(channel, swap ? "sip_full_to" : "sip_full_from"));
}
}
From 3509ae537e944b967d29f23340baf358ade4314c Mon Sep 17 00:00:00 2001
From: Dragos Oancea
Date: Thu, 17 Sep 2020 00:20:17 +0300
Subject: [PATCH 049/655] [core] native tap fix (pass the copy of the frame to
switch_core_session_write_frame() so it does not get encoded)
---
src/switch_ivr_async.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/switch_ivr_async.c b/src/switch_ivr_async.c
index 621836de00..a6972e847c 100644
--- a/src/switch_ivr_async.c
+++ b/src/switch_ivr_async.c
@@ -2084,7 +2084,7 @@ static switch_bool_t eavesdrop_callback(switch_media_bug_t *bug, void *user_data
memcpy(frame.data, nframe->data, nframe->datalen);
- if (switch_core_session_write_frame(ep->eavesdropper, nframe, SWITCH_IO_FLAG_NONE, 0) != SWITCH_STATUS_SUCCESS) {
+ if (switch_core_session_write_frame(ep->eavesdropper, &frame, SWITCH_IO_FLAG_NONE, 0) != SWITCH_STATUS_SUCCESS) {
return SWITCH_FALSE;
}
}
From 5aabb54f68f495bfd51c083bd89d4fdaa1a9ba6c Mon Sep 17 00:00:00 2001
From: Dragos Oancea
Date: Fri, 4 Sep 2020 08:57:28 +0000
Subject: [PATCH 050/655] [core] eavesdrop: init L16 codec at right ptime in
certain conditions.
[core] eavesdrop: avoid eavesdropping on itself and return error.
[core] eavesdrop: adjust buffer operations for ptime mismatch and for when ptimes are the same.
[core] eavesdrop: add buffering based on LCM (Least Common Multiple) when ptime mismatch,
and have audio write thread enabled when ptime eavesdropee < ptime eavesdropper.
[unit-tests] add unit-tests for eavesdrop.
---
src/switch_ivr_async.c | 113 +++++-
tests/unit/Makefile.am | 5 +
tests/unit/conf_eavesdrop/freeswitch.xml | 238 +++++++++++++
tests/unit/conf_eavesdrop/gw/eavestest.xml | 14 +
tests/unit/switch_eavesdrop.c | 392 +++++++++++++++++++++
5 files changed, 743 insertions(+), 19 deletions(-)
create mode 100644 tests/unit/conf_eavesdrop/freeswitch.xml
create mode 100644 tests/unit/conf_eavesdrop/gw/eavestest.xml
create mode 100644 tests/unit/switch_eavesdrop.c
diff --git a/src/switch_ivr_async.c b/src/switch_ivr_async.c
index a6972e847c..07f28a36e8 100644
--- a/src/switch_ivr_async.c
+++ b/src/switch_ivr_async.c
@@ -2184,6 +2184,25 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_eavesdrop_update_display(switch_core_
return status;
}
+/*Greatest Common Divisor*/
+static uint32_t switch_gcd(uint32_t x, uint32_t y)
+{
+ if (y == 0) {
+ return x;
+ }
+
+ return switch_gcd(y, x % y);
+}
+
+/*Least Common Multiple*/
+static uint32_t switch_lcm(uint32_t x, uint32_t y)
+{
+ uint32_t gcd = switch_gcd(x, y);
+
+ if (gcd) return (x * y) / gcd;
+
+ return 0;
+}
SWITCH_DECLARE(switch_status_t) switch_ivr_eavesdrop_session(switch_core_session_t *session,
const char *uuid, const char *require_group, switch_eavesdrop_flag_t flags)
@@ -2213,11 +2232,17 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_eavesdrop_session(switch_core_session
const char *vval;
int buf_size = 0;
int channels;
+ int lcm, buff_min_len, buffered = 1;
if (!switch_channel_media_up(channel)) {
goto end;
}
+ if (tsession == session) {
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Eavesdrop target invalid.\n");
+ goto end;
+ }
+
while(switch_channel_state_change_pending(tchannel) || !switch_channel_media_up(tchannel)) {
switch_yield(10000);
if (!--sanity) break;
@@ -2286,8 +2311,21 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_eavesdrop_session(switch_core_session
goto end;
}
-
- if (switch_core_codec_init(&codec,
+ if (tread_impl.decoded_bytes_per_packet < read_impl.decoded_bytes_per_packet) {
+ if (switch_core_codec_init(&codec,
+ "L16",
+ NULL,
+ NULL,
+ read_impl.actual_samples_per_second,
+ read_impl.microseconds_per_packet / 1000,
+ read_impl.number_of_channels,
+ SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE,
+ NULL, switch_core_session_get_pool(session)) != SWITCH_STATUS_SUCCESS) {
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Cannot init codec\n");
+ goto end;
+ }
+ } else {
+ if (switch_core_codec_init(&codec,
"L16",
NULL,
NULL,
@@ -2298,10 +2336,10 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_eavesdrop_session(switch_core_session
NULL, switch_core_session_get_pool(session)) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Cannot init codec\n");
goto end;
+ }
+ buffered = 0;
}
- switch_core_session_get_read_impl(session, &read_impl);
-
ep->read_impl = read_impl;
ep->tread_impl = tread_impl;
@@ -2440,6 +2478,8 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_eavesdrop_session(switch_core_session
switch_core_session_receive_message(tsession, &msg);
}
+ lcm = switch_lcm(tread_impl.decoded_bytes_per_packet, read_impl.decoded_bytes_per_packet);
+
while (switch_channel_up_nosig(tchannel) && switch_channel_ready(channel)) {
uint32_t len = sizeof(buf);
switch_event_t *event = NULL;
@@ -2569,15 +2609,24 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_eavesdrop_session(switch_core_session
channels = 1;
}
- tlen = tread_impl.decoded_bytes_per_packet * channels;
+ tlen = ep->read_impl.decoded_bytes_per_packet * channels;
if (len > tlen) {
len = tlen;
}
+ if (buffered) {
+ buff_min_len = lcm * 2;
+ if (switch_buffer_inuse(ep->buffer) < buff_min_len) {
+ continue;
+ }
+ } else {
+ buff_min_len = len;
+ }
+
if (ep->buffer) {
switch_buffer_lock(ep->buffer);
- while (switch_buffer_inuse(ep->buffer) >= len) {
+ while (switch_buffer_inuse(ep->buffer) >= buff_min_len) {
int tchanged = 0, changed = 0;
write_frame.datalen = (uint32_t) switch_buffer_read(ep->buffer, buf, len);
@@ -2592,7 +2641,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_eavesdrop_session(switch_core_session
tchanged = 1;
}
- if (read_impl.number_of_channels != ep->tread_impl.number_of_channels ||
+ if (read_impl.number_of_channels != ep->read_impl.number_of_channels ||
read_impl.actual_samples_per_second != ep->read_impl.actual_samples_per_second) {
changed = 1;
}
@@ -2606,6 +2655,13 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_eavesdrop_session(switch_core_session
ep->read_impl.number_of_channels,
read_impl.actual_samples_per_second,
read_impl.number_of_channels);
+
+ tlen = read_impl.decoded_bytes_per_packet * channels;
+
+ if (len > tlen) {
+ len = tlen;
+ }
+
}
if (tchanged) {
@@ -2615,28 +2671,44 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_eavesdrop_session(switch_core_session
ep->tread_impl.number_of_channels,
tread_impl.actual_samples_per_second,
tread_impl.number_of_channels);
+ }
+
- tlen = tread_impl.decoded_bytes_per_packet * channels;
-
- if (len > tlen) {
- len = tlen;
- }
-
- switch_core_codec_destroy(&codec);
+ switch_core_codec_destroy(&codec);
+ if (tread_impl.decoded_bytes_per_packet < read_impl.decoded_bytes_per_packet) {
if (switch_core_codec_init(&codec,
"L16",
NULL,
NULL,
- tread_impl.actual_samples_per_second,
- tread_impl.microseconds_per_packet / 1000,
- tread_impl.number_of_channels,
+ read_impl.actual_samples_per_second,
+ read_impl.microseconds_per_packet / 1000,
+ read_impl.number_of_channels,
SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE,
NULL, switch_core_session_get_pool(session)) != SWITCH_STATUS_SUCCESS) {
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Cannot init codec\n");
+ switch_buffer_unlock(ep->buffer);
+ goto end;
+ }
+ buffered = 1;
+ lcm = switch_lcm(tread_impl.decoded_bytes_per_packet, read_impl.decoded_bytes_per_packet);
+ } else {
+ if (switch_core_codec_init(&codec,
+ "L16",
+ NULL,
+ NULL,
+ tread_impl.actual_samples_per_second,
+ tread_impl.microseconds_per_packet / 1000,
+ tread_impl.number_of_channels,
+ SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE,
+ NULL, switch_core_session_get_pool(session)) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Cannot init codec\n");
switch_buffer_unlock(ep->buffer);
goto end;
}
+ if (buffered == 1) {
+ buffered = 0;
+ }
}
ep->read_impl = read_impl;
@@ -2658,11 +2730,14 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_eavesdrop_session(switch_core_session
switch_buffer_unlock(ep->buffer);
switch_buffer_lock(ep->buffer);
- }
+ if (ep->tread_impl.decoded_bytes_per_packet == ep->read_impl.decoded_bytes_per_packet) {
+ /* push just the number of samples worth of a packet. */
+ break;
+ }
+ }
switch_buffer_unlock(ep->buffer);
}
-
}
end_loop:
diff --git a/tests/unit/Makefile.am b/tests/unit/Makefile.am
index 6e7e128d62..2511a143c2 100644
--- a/tests/unit/Makefile.am
+++ b/tests/unit/Makefile.am
@@ -7,8 +7,13 @@ noinst_PROGRAMS += switch_core_video switch_core_db switch_vad switch_core_asr
AM_LDFLAGS += -avoid-version -no-undefined $(SWITCH_AM_LDFLAGS) $(openssl_LIBS)
AM_LDFLAGS += $(FREESWITCH_LIBS) $(switch_builddir)/libfreeswitch.la $(CORE_LIBS) $(APR_LIBS)
+# "make check" will not run these.
+examples = switch_eavesdrop
+
if HAVE_FVAD
AM_CFLAGS += -DSWITCH_HAVE_FVAD
endif
TESTS = $(noinst_PROGRAMS)
+
+bin_PROGRAMS = $(examples)
diff --git a/tests/unit/conf_eavesdrop/freeswitch.xml b/tests/unit/conf_eavesdrop/freeswitch.xml
new file mode 100644
index 0000000000..4a65caf6d8
--- /dev/null
+++ b/tests/unit/conf_eavesdrop/freeswitch.xml
@@ -0,0 +1,238 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/unit/conf_eavesdrop/gw/eavestest.xml b/tests/unit/conf_eavesdrop/gw/eavestest.xml
new file mode 100644
index 0000000000..a2f268424e
--- /dev/null
+++ b/tests/unit/conf_eavesdrop/gw/eavestest.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/unit/switch_eavesdrop.c b/tests/unit/switch_eavesdrop.c
new file mode 100644
index 0000000000..867ad7a6bc
--- /dev/null
+++ b/tests/unit/switch_eavesdrop.c
@@ -0,0 +1,392 @@
+#include
+#include
+#include
+
+static switch_memory_pool_t *pool = NULL;
+
+static switch_status_t test_detect_long_tone_in_file(const char *filepath, int rate, int freq, int ptime) {
+ teletone_multi_tone_t mt;
+ teletone_tone_map_t map;
+ int16_t data[SWITCH_RECOMMENDED_BUFFER_SIZE] = { 0 };
+ size_t len = (rate * ptime / 1000) /*packet len in samples */ * 8; /*length of chunk that must contain tone*/
+ size_t fin = 0;
+ switch_status_t status;
+ switch_file_handle_t fh = { 0 };
+ uint8_t fail = 0, gaps = 0, audio = 0;
+ uint32_t pos = 0;
+ size_t full_len = 0;
+
+ status = switch_core_file_open(&fh, filepath, 1, rate, SWITCH_FILE_FLAG_READ | SWITCH_FILE_DATA_SHORT, NULL);
+ if (status != SWITCH_STATUS_SUCCESS) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot open file [%s]\n", filepath);
+ return SWITCH_STATUS_FALSE;
+ }
+
+ mt.sample_rate = rate;
+ map.freqs[0] = (teletone_process_t)freq;
+
+ teletone_multi_tone_init(&mt, &map);
+
+ len = (rate * 2 / 100) /*packet len in samples */ * 8;
+
+ while (switch_core_file_read(&fh, &data, &len) == SWITCH_STATUS_SUCCESS) {
+ fin += len;
+ /*skip silence at the beginning of the file, 1 second max. */
+ if (!teletone_multi_tone_detect(&mt, data, len)) {
+ if ((fin > rate && !audio) || gaps > 30) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Too many gaps in audio or no tone detected 1st second. [%u][%d]\n", fin, gaps);
+ fail = 1;
+ break;
+ }
+ gaps++;
+ continue;
+ } else {
+ audio++;
+ }
+ }
+
+ switch_core_file_close(&fh);
+
+ if (fail) {
+ return SWITCH_STATUS_FALSE;
+ }
+ return SWITCH_STATUS_SUCCESS;
+}
+
+FST_CORE_BEGIN("./conf_eavesdrop")
+
+{
+FST_SUITE_BEGIN(switch_eavesdrop)
+{
+ FST_SETUP_BEGIN()
+ {
+ fst_requires_module("mod_loopback");
+ fst_requires_module("mod_sofia");
+ switch_core_set_variable("link_ip", switch_core_get_variable("local_ip_v4"));
+ }
+ FST_SETUP_END()
+
+ FST_TEARDOWN_BEGIN()
+ {
+ }
+ FST_TEARDOWN_END()
+
+ FST_TEST_BEGIN(test_eavesdrop_bridged_same_ptime_20ms)
+ {
+ switch_core_session_t *session1 = NULL;
+ switch_core_session_t *session2 = NULL;
+ switch_core_session_t *session3 = NULL;
+
+ switch_channel_t *channel1 = NULL;
+ switch_channel_t *channel2 = NULL;
+ switch_channel_t *channel3 = NULL;
+
+ switch_status_t status;
+ switch_call_cause_t cause;
+ switch_stream_handle_t stream = { 0 };
+ char eavesdrop_command[256] = { 0 };
+ char rec_path[256];
+ char rec_uuid[SWITCH_UUID_FORMATTED_LENGTH + 1] = { 0 };
+ char eaves_dialstr[256] = { 0 };
+
+ switch_uuid_str(rec_uuid, sizeof(rec_uuid));
+
+ /*parked 20 ms ptime */
+ status = switch_ivr_originate(NULL, &session1, &cause, "{ignore_early_media=true}sofia/gateway/eavestest/+15553332220", 2, NULL, NULL, NULL, NULL, NULL, SOF_NONE, NULL, NULL);
+ fst_requires(session1);
+ fst_check(status == SWITCH_STATUS_SUCCESS);
+ channel1 = switch_core_session_get_channel(session1);
+ fst_requires(channel1);
+
+ snprintf(eaves_dialstr, sizeof(eaves_dialstr), "{ignore_early_media=true}{sip_h_X-UnitTestRecfile=%s}sofia/gateway/eavestest/+15553332230", rec_uuid);
+
+ /*eavesdropper 20 ms ptime*/
+ status = switch_ivr_originate(NULL, &session2, &cause, eaves_dialstr, 2, NULL, NULL, NULL, NULL, NULL, SOF_NONE, NULL, NULL);
+ fst_requires(session2);
+ fst_check(status == SWITCH_STATUS_SUCCESS);
+ channel2 = switch_core_session_get_channel(session2);
+ fst_requires(channel2);
+
+ /*milliwatt tone 20 ms ptime*/
+ status = switch_ivr_originate(NULL, &session3, &cause, "{ignore_early_media=true}sofia/gateway/eavestest/+15553332226", 2, NULL, NULL, NULL, NULL, NULL, SOF_NONE, NULL, NULL);
+ fst_requires(session3);
+ fst_check(status == SWITCH_STATUS_SUCCESS);
+ channel3 = switch_core_session_get_channel(session3);
+ fst_requires(channel3);
+
+ SWITCH_STANDARD_STREAM(stream);
+ switch_snprintf(eavesdrop_command, sizeof(eavesdrop_command), "uuid_bridge %s %s", switch_core_session_get_uuid(session1), switch_core_session_get_uuid(session2));
+ switch_api_execute("bgapi", eavesdrop_command, session1, &stream);
+ memset(eavesdrop_command, 0, sizeof(eavesdrop_command));
+ switch_snprintf(eavesdrop_command, sizeof(eavesdrop_command),"uuid_setvar_multi %s eavesdrop_enable_dtmf=false;eavesdrop_whisper_bleg=true;eavesdrop_whisper_aleg=false", switch_core_session_get_uuid(session3));
+ switch_api_execute("bgapi", eavesdrop_command, session3, &stream);
+ memset(eavesdrop_command, 0, sizeof(eavesdrop_command));
+ switch_snprintf(eavesdrop_command, sizeof(eavesdrop_command), "uuid_transfer %s 'eavesdrop:%s' inline", switch_core_session_get_uuid(session3), switch_core_session_get_uuid(session2));
+ switch_api_execute("bgapi", eavesdrop_command, session3, &stream);
+ switch_safe_free(stream.data);
+
+ sleep(5); // it will record ~ 5 secs
+
+ snprintf(rec_path, sizeof(rec_path), "/tmp/eaves-%s.wav", rec_uuid);
+
+ fst_requires(switch_file_exists(rec_path, fst_pool) == SWITCH_STATUS_SUCCESS);
+
+ fst_requires(test_detect_long_tone_in_file(rec_path, 8000, 300, 20) == SWITCH_STATUS_SUCCESS);
+
+ unlink(rec_path);
+
+ switch_channel_hangup(channel1, SWITCH_CAUSE_NORMAL_CLEARING);
+ switch_channel_hangup(channel2, SWITCH_CAUSE_NORMAL_CLEARING);
+ switch_channel_hangup(channel3, SWITCH_CAUSE_NORMAL_CLEARING);
+
+ switch_core_session_rwunlock(session1);
+ switch_core_session_rwunlock(session2);
+ switch_core_session_rwunlock(session3);
+
+ }
+ FST_TEST_END()
+
+ FST_TEST_BEGIN(test_eavesdrop_bridged_ptime_mismatch_20ms_30ms)
+ {
+ switch_core_session_t *session1 = NULL;
+ switch_core_session_t *session2 = NULL;
+ switch_core_session_t *session3 = NULL;
+
+ switch_channel_t *channel1 = NULL;
+ switch_channel_t *channel2 = NULL;
+ switch_channel_t *channel3 = NULL;
+
+ switch_status_t status;
+ switch_call_cause_t cause;
+ switch_stream_handle_t stream = { 0 };
+ char eavesdrop_command[256] = { 0 };
+ char rec_path[256];
+ char rec_uuid[SWITCH_UUID_FORMATTED_LENGTH + 1] = { 0 };
+ char eaves_dialstr[256] = { 0 };
+
+ switch_uuid_str(rec_uuid, sizeof(rec_uuid));
+
+ /*parked 20 ms ptime */
+ status = switch_ivr_originate(NULL, &session1, &cause, "{ignore_early_media=true}sofia/gateway/eavestest/+15553332220", 2, NULL, NULL, NULL, NULL, NULL, SOF_NONE, NULL, NULL);
+ fst_requires(session1);
+ fst_check(status == SWITCH_STATUS_SUCCESS);
+ channel1 = switch_core_session_get_channel(session1);
+ fst_requires(channel1);
+
+ snprintf(eaves_dialstr, sizeof(eaves_dialstr), "{ignore_early_media=true}{sip_h_X-UnitTestRecfile=%s}sofia/gateway/eavestest/+15553332230", rec_uuid);
+
+ /*eavesdropper 20 ms ptime*/
+ status = switch_ivr_originate(NULL, &session2, &cause, eaves_dialstr, 2, NULL, NULL, NULL, NULL, NULL, SOF_NONE, NULL, NULL);
+ fst_requires(session2);
+ fst_check(status == SWITCH_STATUS_SUCCESS);
+ channel2 = switch_core_session_get_channel(session2);
+ fst_requires(channel2);
+
+ /*milliwatt tone 30 ms ptime*/
+ status = switch_ivr_originate(NULL, &session3, &cause, "{ignore_early_media=true}sofia/gateway/eavestest/+15553332222", 2, NULL, NULL, NULL, NULL, NULL, SOF_NONE, NULL, NULL);
+ fst_requires(session3);
+ fst_check(status == SWITCH_STATUS_SUCCESS);
+ channel3 = switch_core_session_get_channel(session3);
+ fst_requires(channel3);
+
+ SWITCH_STANDARD_STREAM(stream);
+ switch_snprintf(eavesdrop_command, sizeof(eavesdrop_command), "uuid_bridge %s %s", switch_core_session_get_uuid(session1), switch_core_session_get_uuid(session2));
+ switch_api_execute("bgapi", eavesdrop_command, session1, &stream);
+ memset(eavesdrop_command, 0, sizeof(eavesdrop_command));
+ switch_snprintf(eavesdrop_command, sizeof(eavesdrop_command),"uuid_setvar_multi %s eavesdrop_enable_dtmf=false;eavesdrop_whisper_bleg=true;eavesdrop_whisper_aleg=false", switch_core_session_get_uuid(session3));
+ switch_api_execute("bgapi", eavesdrop_command, session3, &stream);
+ memset(eavesdrop_command, 0, sizeof(eavesdrop_command));
+ switch_snprintf(eavesdrop_command, sizeof(eavesdrop_command), "uuid_transfer %s 'eavesdrop:%s' inline", switch_core_session_get_uuid(session3), switch_core_session_get_uuid(session2));
+ switch_api_execute("bgapi", eavesdrop_command, session3, &stream);
+ switch_safe_free(stream.data);
+
+ sleep(5); // it will record ~ 5 secs
+
+ snprintf(rec_path, sizeof(rec_path), "/tmp/eaves-%s.wav", rec_uuid);
+
+ fst_requires(switch_file_exists(rec_path, fst_pool) == SWITCH_STATUS_SUCCESS);
+
+ fst_requires(test_detect_long_tone_in_file(rec_path, 8000, 300, 20) == SWITCH_STATUS_SUCCESS);
+
+ unlink(rec_path);
+
+ switch_channel_hangup(channel1, SWITCH_CAUSE_NORMAL_CLEARING);
+ switch_channel_hangup(channel2, SWITCH_CAUSE_NORMAL_CLEARING);
+ switch_channel_hangup(channel3, SWITCH_CAUSE_NORMAL_CLEARING);
+
+ switch_core_session_rwunlock(session1);
+ switch_core_session_rwunlock(session2);
+ switch_core_session_rwunlock(session3);
+
+ }
+ FST_TEST_END()
+
+ FST_TEST_BEGIN(test_eavesdrop_bridged_ptime_mismatch_30ms_20ms)
+ {
+ switch_core_session_t *session1 = NULL;
+ switch_core_session_t *session2 = NULL;
+ switch_core_session_t *session3 = NULL;
+
+ switch_channel_t *channel1 = NULL;
+ switch_channel_t *channel2 = NULL;
+ switch_channel_t *channel3 = NULL;
+
+ switch_status_t status;
+ switch_call_cause_t cause;
+ switch_stream_handle_t stream = { 0 };
+ char eavesdrop_command[256] = { 0 };
+ char rec_path[256];
+ char rec_uuid[SWITCH_UUID_FORMATTED_LENGTH + 1] = { 0 };
+ char eaves_dialstr[256] = { 0 };
+
+ switch_uuid_str(rec_uuid, sizeof(rec_uuid));
+
+ /*parked 30 ms ptime */
+ status = switch_ivr_originate(NULL, &session1, &cause, "{ignore_early_media=true}sofia/gateway/eavestest/+15553332231", 2, NULL, NULL, NULL, NULL, NULL, SOF_NONE, NULL, NULL);
+ fst_requires(session1);
+ fst_check(status == SWITCH_STATUS_SUCCESS);
+ channel1 = switch_core_session_get_channel(session1);
+ fst_requires(channel1);
+
+ snprintf(eaves_dialstr, sizeof(eaves_dialstr), "{ignore_early_media=true}{sip_h_X-UnitTestRecfile=%s}sofia/gateway/eavestest/+15553332240", rec_uuid);
+
+ /*eavesdropper 30 ms ptime*/
+ status = switch_ivr_originate(NULL, &session2, &cause, eaves_dialstr, 2, NULL, NULL, NULL, NULL, NULL, SOF_NONE, NULL, NULL);
+ fst_requires(session2);
+ fst_check(status == SWITCH_STATUS_SUCCESS);
+ channel2 = switch_core_session_get_channel(session2);
+ fst_requires(channel2);
+
+ /*milliwatt tone 20 ms ptime*/
+ status = switch_ivr_originate(NULL, &session3, &cause, "{ignore_early_media=true}sofia/gateway/eavestest/+15553332226", 2, NULL, NULL, NULL, NULL, NULL, SOF_NONE, NULL, NULL);
+ fst_requires(session3);
+ fst_check(status == SWITCH_STATUS_SUCCESS);
+ channel3 = switch_core_session_get_channel(session3);
+ fst_requires(channel3);
+
+ SWITCH_STANDARD_STREAM(stream);
+ switch_snprintf(eavesdrop_command, sizeof(eavesdrop_command), "uuid_bridge %s %s", switch_core_session_get_uuid(session1), switch_core_session_get_uuid(session2));
+ switch_api_execute("bgapi", eavesdrop_command, session1, &stream);
+ memset(eavesdrop_command, 0, sizeof(eavesdrop_command));
+ switch_snprintf(eavesdrop_command, sizeof(eavesdrop_command),"uuid_setvar_multi %s eavesdrop_enable_dtmf=false;eavesdrop_whisper_bleg=true;eavesdrop_whisper_aleg=false", switch_core_session_get_uuid(session3));
+ switch_api_execute("bgapi", eavesdrop_command, session3, &stream);
+ memset(eavesdrop_command, 0, sizeof(eavesdrop_command));
+ switch_snprintf(eavesdrop_command, sizeof(eavesdrop_command), "uuid_transfer %s 'eavesdrop:%s' inline", switch_core_session_get_uuid(session3), switch_core_session_get_uuid(session2));
+ switch_api_execute("bgapi", eavesdrop_command, session3, &stream);
+ switch_safe_free(stream.data);
+
+ sleep(5); // it will record ~ 5 secs
+
+ snprintf(rec_path, sizeof(rec_path), "/tmp/eaves-%s.wav", rec_uuid);
+
+ fst_requires(switch_file_exists(rec_path, fst_pool) == SWITCH_STATUS_SUCCESS);
+
+ fst_requires(test_detect_long_tone_in_file(rec_path, 8000, 300, 30) == SWITCH_STATUS_SUCCESS);
+
+ unlink(rec_path);
+
+ switch_channel_hangup(channel1, SWITCH_CAUSE_NORMAL_CLEARING);
+ switch_channel_hangup(channel2, SWITCH_CAUSE_NORMAL_CLEARING);
+ switch_channel_hangup(channel3, SWITCH_CAUSE_NORMAL_CLEARING);
+
+ switch_core_session_rwunlock(session1);
+ switch_core_session_rwunlock(session2);
+ switch_core_session_rwunlock(session3);
+
+ }
+ FST_TEST_END()
+
+ FST_TEST_BEGIN(test_eavesdrop_bridged_ptime_mismatch_reneg)
+ {
+ switch_core_session_t *session1 = NULL;
+ switch_core_session_t *session2 = NULL;
+ switch_core_session_t *session3 = NULL;
+
+ switch_channel_t *channel1 = NULL;
+ switch_channel_t *channel2 = NULL;
+ switch_channel_t *channel3 = NULL;
+
+ switch_status_t status;
+ switch_call_cause_t cause;
+ switch_stream_handle_t stream = { 0 };
+ char eavesdrop_command[256] = { 0 };
+ char rec_path[256];
+ char rec_uuid[SWITCH_UUID_FORMATTED_LENGTH + 1] = { 0 };
+ char eaves_dialstr[256] = { 0 };
+
+ switch_uuid_str(rec_uuid, sizeof(rec_uuid));
+
+ /*parked 30 ms ptime */
+ status = switch_ivr_originate(NULL, &session1, &cause, "{ignore_early_media=true}sofia/gateway/eavestest/+15553332231", 2, NULL, NULL, NULL, NULL, NULL, SOF_NONE, NULL, NULL);
+ fst_requires(session1);
+ fst_check(status == SWITCH_STATUS_SUCCESS);
+ channel1 = switch_core_session_get_channel(session1);
+ fst_requires(channel1);
+
+ snprintf(eaves_dialstr, sizeof(eaves_dialstr), "{ignore_early_media=true}{sip_h_X-UnitTestRecfile=%s}sofia/gateway/eavestest/+15553332240", rec_uuid);
+
+ /*eavesdropper 30 ms ptime*/
+ status = switch_ivr_originate(NULL, &session2, &cause, eaves_dialstr, 2, NULL, NULL, NULL, NULL, NULL, SOF_NONE, NULL, NULL);
+ fst_requires(session2);
+ fst_check(status == SWITCH_STATUS_SUCCESS);
+ channel2 = switch_core_session_get_channel(session2);
+ fst_requires(channel2);
+
+ /*milliwatt tone 20 ms ptime*/
+ status = switch_ivr_originate(NULL, &session3, &cause, "{ignore_early_media=true}sofia/gateway/eavestest/+15553332226", 2, NULL, NULL, NULL, NULL, NULL, SOF_NONE, NULL, NULL);
+ fst_requires(session3);
+ fst_check(status == SWITCH_STATUS_SUCCESS);
+ channel3 = switch_core_session_get_channel(session3);
+ fst_requires(channel3);
+
+ SWITCH_STANDARD_STREAM(stream);
+ switch_snprintf(eavesdrop_command, sizeof(eavesdrop_command), "uuid_bridge %s %s", switch_core_session_get_uuid(session1), switch_core_session_get_uuid(session2));
+ switch_api_execute("bgapi", eavesdrop_command, session1, &stream);
+ memset(eavesdrop_command, 0, sizeof(eavesdrop_command));
+ switch_snprintf(eavesdrop_command, sizeof(eavesdrop_command),"uuid_setvar_multi %s eavesdrop_enable_dtmf=false;eavesdrop_whisper_bleg=true;eavesdrop_whisper_aleg=false", switch_core_session_get_uuid(session3));
+ switch_api_execute("bgapi", eavesdrop_command, session3, &stream);
+ memset(eavesdrop_command, 0, sizeof(eavesdrop_command));
+ switch_snprintf(eavesdrop_command, sizeof(eavesdrop_command), "uuid_transfer %s 'eavesdrop:%s' inline", switch_core_session_get_uuid(session3), switch_core_session_get_uuid(session2));
+ switch_api_execute("bgapi", eavesdrop_command, session3, &stream);
+
+ sleep(2);
+
+ // codec reneg for eavesdropper
+ memset(eavesdrop_command, 0, sizeof(eavesdrop_command));
+ switch_snprintf(eavesdrop_command, sizeof(eavesdrop_command), "uuid_media_reneg %s = PCMU@20i", switch_core_session_get_uuid(session2));
+ switch_api_execute("bgapi", eavesdrop_command, session3, &stream);
+
+ sleep(1);
+
+ // codec reneg for eavesdroppee
+ memset(eavesdrop_command, 0, sizeof(eavesdrop_command));
+ switch_snprintf(eavesdrop_command, sizeof(eavesdrop_command), "uuid_media_reneg %s = PCMU@30i", switch_core_session_get_uuid(session3));
+ switch_api_execute("bgapi", eavesdrop_command, session3, &stream);
+ switch_safe_free(stream.data);
+
+ sleep(2);
+
+ snprintf(rec_path, sizeof(rec_path), "/tmp/eaves-%s.wav", rec_uuid);
+
+ fst_requires(switch_file_exists(rec_path, fst_pool) == SWITCH_STATUS_SUCCESS);
+
+ fst_requires(test_detect_long_tone_in_file(rec_path, 8000, 300, 30) == SWITCH_STATUS_SUCCESS);
+
+ unlink(rec_path);
+
+ switch_channel_hangup(channel1, SWITCH_CAUSE_NORMAL_CLEARING);
+ switch_channel_hangup(channel2, SWITCH_CAUSE_NORMAL_CLEARING);
+ switch_channel_hangup(channel3, SWITCH_CAUSE_NORMAL_CLEARING);
+
+ switch_core_session_rwunlock(session1);
+ switch_core_session_rwunlock(session2);
+ switch_core_session_rwunlock(session3);
+
+ }
+ FST_TEST_END()
+
+}
+FST_SUITE_END()
+}
+FST_CORE_END()
+
From dbc894d95912d903ed5e5a7acccdea1c03e0b10f Mon Sep 17 00:00:00 2001
From: surendrasignalwire
<56929670+surendrasignalwire@users.noreply.github.com>
Date: Tue, 29 Sep 2020 20:40:33 +0530
Subject: [PATCH 051/655] [Core] Reuse caller profile
---
src/include/switch_types.h | 2 ++
src/mod/applications/mod_dptools/mod_dptools.c | 8 ++++++++
src/switch_ivr.c | 11 +++++++++--
3 files changed, 19 insertions(+), 2 deletions(-)
diff --git a/src/include/switch_types.h b/src/include/switch_types.h
index 2037889c01..79ef9caa26 100644
--- a/src/include/switch_types.h
+++ b/src/include/switch_types.h
@@ -1416,6 +1416,7 @@ CF_HOLD_BLEG - B leg is on hold
CF_SERVICE - Channel has a service thread
CF_TAGGED - Channel is tagged
CF_WINNER - Channel is the winner
+CF_REUSE_CALLER_PROFILE - Channel reuse caller profile
CF_CONTROLLED - Channel is under control
CF_PROXY_MODE - Channel has no media
CF_SUSPEND - Suspend i/o
@@ -1468,6 +1469,7 @@ typedef enum {
CF_SERVICE,
CF_TAGGED,
CF_WINNER,
+ CF_REUSE_CALLER_PROFILE,
CF_CONTROLLED,
CF_PROXY_MODE,
CF_PROXY_OFF,
diff --git a/src/mod/applications/mod_dptools/mod_dptools.c b/src/mod/applications/mod_dptools/mod_dptools.c
index f891c6a513..43329eb006 100644
--- a/src/mod/applications/mod_dptools/mod_dptools.c
+++ b/src/mod/applications/mod_dptools/mod_dptools.c
@@ -1150,6 +1150,13 @@ SWITCH_STANDARD_APP(break_function)
}
}
+SWITCH_STANDARD_APP(reuse_caller_profile_function)
+{
+ switch_channel_t *channel;
+ channel = switch_core_session_get_channel(session);
+ switch_channel_set_flag(channel, CF_REUSE_CALLER_PROFILE);
+}
+
SWITCH_STANDARD_APP(queue_dtmf_function)
{
switch_channel_queue_dtmf_string(switch_core_session_get_channel(session), (const char *) data);
@@ -6551,6 +6558,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_dptools_load)
SAF_SUPPORT_NOMEDIA);
SWITCH_ADD_APP(app_interface, "deflect", "Send call deflect", "Send a call deflect.", deflect_function, "", SAF_SUPPORT_NOMEDIA);
SWITCH_ADD_APP(app_interface, "recovery_refresh", "Send call recovery_refresh", "Send a call recovery_refresh.", recovery_refresh_function, "", SAF_SUPPORT_NOMEDIA);
+ SWITCH_ADD_APP(app_interface, "reuse_caller_profile", "Reuse the caller profile", "Reuse the caller profile", reuse_caller_profile_function, "", SAF_SUPPORT_NOMEDIA);
SWITCH_ADD_APP(app_interface, "queue_dtmf", "Queue dtmf to be sent", "Queue dtmf to be sent from a session", queue_dtmf_function, "",
SAF_SUPPORT_NOMEDIA);
SWITCH_ADD_APP(app_interface, "send_dtmf", "Send dtmf to be sent", "Send dtmf to be sent from a session", send_dtmf_function, "",
diff --git a/src/switch_ivr.c b/src/switch_ivr.c
index 8d21513388..be319e353e 100644
--- a/src/switch_ivr.c
+++ b/src/switch_ivr.c
@@ -2192,7 +2192,12 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_session_transfer(switch_core_session_
extension = "service";
}
- new_profile = switch_caller_profile_clone(session, profile);
+
+ if (switch_channel_test_flag(channel, CF_REUSE_CALLER_PROFILE)){
+ new_profile = switch_channel_get_caller_profile(channel);
+ } else {
+ new_profile = switch_caller_profile_clone(session, profile);
+ }
new_profile->dialplan = switch_core_strdup(new_profile->pool, use_dialplan);
new_profile->context = switch_core_strdup(new_profile->pool, use_context);
@@ -2238,7 +2243,9 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_session_transfer(switch_core_session_
switch_core_session_rwunlock(other_session);
}
- switch_channel_set_caller_profile(channel, new_profile);
+ if (!switch_channel_test_flag(channel, CF_REUSE_CALLER_PROFILE)){
+ switch_channel_set_caller_profile(channel, new_profile);
+ }
switch_channel_set_state(channel, CS_ROUTING);
switch_channel_audio_sync(channel);
From 22ae5a1ba124632c17159edfe0cc51deff76e859 Mon Sep 17 00:00:00 2001
From: Andrey Volk
Date: Mon, 5 Oct 2020 02:49:08 +0400
Subject: [PATCH 052/655] [Core] Fix memory leak of local_var_event in
switch_ivr_originate() when caller_channel is not ready.
---
src/switch_ivr_originate.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/switch_ivr_originate.c b/src/switch_ivr_originate.c
index 99370d7e79..d2baeb2741 100644
--- a/src/switch_ivr_originate.c
+++ b/src/switch_ivr_originate.c
@@ -2861,6 +2861,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess
if (oglobals.session) {
if (!switch_channel_ready(caller_channel)) {
status = SWITCH_STATUS_FALSE;
+ if (local_var_event) switch_event_destroy(&local_var_event);
goto done;
}
From 8e4b418ee4d85545d20f3af08ae25311a9920ea9 Mon Sep 17 00:00:00 2001
From: Mike Jerris
Date: Tue, 6 Oct 2020 11:26:42 -0400
Subject: [PATCH 053/655] [core] fix leak in http request parser
---
src/switch_utils.c | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/src/switch_utils.c b/src/switch_utils.c
index e4e26a6eef..5d6b8f2aaf 100644
--- a/src/switch_utils.c
+++ b/src/switch_utils.c
@@ -4176,11 +4176,12 @@ SWITCH_DECLARE(void) switch_http_parse_qs(switch_http_request_t *request, char *
char *q;
char *next;
char *name, *val;
+ char *dup = NULL;
if (qs) {
q = qs;
} else { /*parse our own qs, dup to avoid modify the original string */
- q = strdup(request->qs);
+ dup = q = strdup(request->qs);
}
switch_assert(q);
@@ -4207,9 +4208,7 @@ SWITCH_DECLARE(void) switch_http_parse_qs(switch_http_request_t *request, char *
q = next;
} while (q);
- if (!qs) {
- switch_safe_free(q);
- }
+ switch_safe_free(dup);
}
/* clean the uri to protect us from vulnerability attack */
From dcb75a79e36cb131cc6fa8827ffdfcd852fa5adf Mon Sep 17 00:00:00 2001
From: Andrey Volk
Date: Wed, 7 Oct 2020 03:21:16 +0400
Subject: [PATCH 054/655] [mod_sofia] Fix multiple memory leaks in
sofia_presence_handle_sip_i_subscribe()
---
src/mod/endpoints/mod_sofia/sofia_presence.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/src/mod/endpoints/mod_sofia/sofia_presence.c b/src/mod/endpoints/mod_sofia/sofia_presence.c
index e1c31c99c8..e27b0495ff 100644
--- a/src/mod/endpoints/mod_sofia/sofia_presence.c
+++ b/src/mod/endpoints/mod_sofia/sofia_presence.c
@@ -4284,7 +4284,11 @@ void sofia_presence_handle_sip_i_subscribe(int status,
}
}
}
+
+ switch_xml_free(xml);
}
+
+ switch_safe_free(pd_dup);
}
switch_event_fire(&event);
} else if (!strcasecmp(event, "message-summary")) {
From 3065cb9168e994b5388c37170c61b0956c91e0d2 Mon Sep 17 00:00:00 2001
From: Andrey Volk
Date: Wed, 28 Oct 2020 23:49:36 +0400
Subject: [PATCH 055/655] [mod_sofia] Fix memory leaks caused by improper
profile destroy. Add a unit-test.
---
src/mod/endpoints/mod_sofia/sofia.c | 25 +++--
tests/unit/Makefile.am | 2 +-
tests/unit/conf_sofia/freeswitch.xml | 144 +++++++++++++++++++++++++++
tests/unit/test_sofia.c | 31 ++++++
4 files changed, 191 insertions(+), 11 deletions(-)
create mode 100644 tests/unit/conf_sofia/freeswitch.xml
create mode 100644 tests/unit/test_sofia.c
diff --git a/src/mod/endpoints/mod_sofia/sofia.c b/src/mod/endpoints/mod_sofia/sofia.c
index 4975ca8feb..87b09e5406 100644
--- a/src/mod/endpoints/mod_sofia/sofia.c
+++ b/src/mod/endpoints/mod_sofia/sofia.c
@@ -3180,7 +3180,6 @@ void *SWITCH_THREAD_FUNC sofia_profile_thread_run(switch_thread_t *thread, void
if (!sofia_glue_init_sql(profile)) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Cannot Open SQL Database [%s]!\n", profile->name);
sofia_profile_start_failure(profile, profile->name);
- sofia_glue_del_profile(profile);
goto end;
}
@@ -3332,7 +3331,6 @@ void *SWITCH_THREAD_FUNC sofia_profile_thread_run(switch_thread_t *thread, void
}
sofia_profile_start_failure(profile, profile->name);
- sofia_glue_del_profile(profile);
goto end;
}
@@ -3500,6 +3498,20 @@ void *SWITCH_THREAD_FUNC sofia_profile_thread_run(switch_thread_t *thread, void
}
}
+ /* Do gateway cleanups */
+ sofia_glue_del_every_gateway(profile);
+ sofia_reg_check_gateway(profile, switch_epoch_time_now(NULL));
+ sofia_sub_check_gateway(profile, switch_epoch_time_now(NULL));
+ sofia_glue_fire_events(profile);
+
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Waiting for worker thread\n");
+
+ if (worker_thread) {
+ switch_thread_join(&st, worker_thread);
+ }
+ else {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "ERROR: Sofia worker thead failed to start\n");
+ }
sofia_reg_unregister(profile);
nua_shutdown(profile->nua);
@@ -3514,13 +3526,6 @@ void *SWITCH_THREAD_FUNC sofia_profile_thread_run(switch_thread_t *thread, void
sofia_clear_pflag_locked(profile, PFLAG_RUNNING);
sofia_clear_pflag_locked(profile, PFLAG_SHUTDOWN);
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Waiting for worker thread\n");
-
- if ( worker_thread ) {
- switch_thread_join(&st, worker_thread);
- } else {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "ERROR: Sofia worker thead failed to start\n");
- }
sanity = 4;
while (profile->inuse) {
@@ -3569,6 +3574,7 @@ void *SWITCH_THREAD_FUNC sofia_profile_thread_run(switch_thread_t *thread, void
}
}
+ end:
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Write lock %s\n", profile->name);
switch_thread_rwlock_wrlock(profile->rwlock);
@@ -3590,7 +3596,6 @@ void *SWITCH_THREAD_FUNC sofia_profile_thread_run(switch_thread_t *thread, void
sofia_profile_destroy(profile);
- end:
switch_mutex_lock(mod_sofia_globals.mutex);
mod_sofia_globals.threads--;
switch_mutex_unlock(mod_sofia_globals.mutex);
diff --git a/tests/unit/Makefile.am b/tests/unit/Makefile.am
index 2511a143c2..231225c5aa 100644
--- a/tests/unit/Makefile.am
+++ b/tests/unit/Makefile.am
@@ -2,7 +2,7 @@ include $(top_srcdir)/build/modmake.rulesam
noinst_PROGRAMS = switch_event switch_hash switch_ivr_originate switch_utils switch_core switch_console switch_vpx switch_core_file \
switch_ivr_play_say switch_core_codec switch_rtp switch_xml
-noinst_PROGRAMS += switch_core_video switch_core_db switch_vad switch_core_asr
+noinst_PROGRAMS += switch_core_video switch_core_db switch_vad switch_core_asr test_sofia
AM_LDFLAGS += -avoid-version -no-undefined $(SWITCH_AM_LDFLAGS) $(openssl_LIBS)
AM_LDFLAGS += $(FREESWITCH_LIBS) $(switch_builddir)/libfreeswitch.la $(CORE_LIBS) $(APR_LIBS)
diff --git a/tests/unit/conf_sofia/freeswitch.xml b/tests/unit/conf_sofia/freeswitch.xml
new file mode 100644
index 0000000000..793ac5a04a
--- /dev/null
+++ b/tests/unit/conf_sofia/freeswitch.xml
@@ -0,0 +1,144 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/unit/test_sofia.c b/tests/unit/test_sofia.c
new file mode 100644
index 0000000000..e45bd5d3fd
--- /dev/null
+++ b/tests/unit/test_sofia.c
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2018-2019, Signalwire, Inc. ALL RIGHTS RESERVED
+ * test_sofia.c -- Tests mod_sofia for memory leaks
+ */
+
+#include
+#include
+
+FST_CORE_DB_BEGIN("conf_sofia")
+{
+ FST_SUITE_BEGIN(switch_sofia)
+ {
+ FST_SETUP_BEGIN()
+ {
+ fst_requires_module("mod_sofia");
+ }
+ FST_SETUP_END()
+
+ FST_TEARDOWN_BEGIN()
+ {
+ }
+ FST_TEARDOWN_END()
+
+ FST_TEST_BEGIN(sofia_leaks)
+ {
+ }
+ FST_TEST_END()
+ }
+ FST_SUITE_END()
+}
+FST_CORE_END()
From 5ed17dd19cdda148c6d9f48b0dcc7ea9afb653cf Mon Sep 17 00:00:00 2001
From: Andrey Volk
Date: Fri, 23 Oct 2020 21:48:53 +0400
Subject: [PATCH 056/655] [Core] Scheduler: Fix race between
switch_scheduler_add_task() and task_thread_loop(). Add new
switch_scheduler_add_task_ex() method.
---
src/include/switch_scheduler.h | 17 +++++++++++++++++
src/switch_scheduler.c | 26 +++++++++++++++++++++-----
2 files changed, 38 insertions(+), 5 deletions(-)
diff --git a/src/include/switch_scheduler.h b/src/include/switch_scheduler.h
index 14403917ca..1100fdb052 100644
--- a/src/include/switch_scheduler.h
+++ b/src/include/switch_scheduler.h
@@ -66,6 +66,23 @@ SWITCH_DECLARE(uint32_t) switch_scheduler_add_task(time_t task_runtime,
switch_scheduler_func_t func,
const char *desc, const char *group, uint32_t cmd_id, void *cmd_arg, switch_scheduler_flag_t flags);
+/*!
+ \brief Schedule a task in the future
+ \param task_runtime the time in epoch seconds to execute the task.
+ \param func the callback function to execute when the task is executed.
+ \param desc an arbitrary description of the task.
+ \param group a group id tag to link multiple tasks to a single entity.
+ \param cmd_id an arbitrary index number be used in the callback.
+ \param cmd_arg user data to be passed to the callback.
+ \param flags flags to alter behaviour
+ \param task_id pointer to put the id of the task to
+ \return the id of the task
+*/
+
+SWITCH_DECLARE(uint32_t) switch_scheduler_add_task_ex(time_t task_runtime,
+ switch_scheduler_func_t func,
+ const char *desc, const char *group, uint32_t cmd_id, void *cmd_arg, switch_scheduler_flag_t flags, uint32_t *task_id);
+
/*!
\brief Delete a scheduled task
\param task_id the id of the task
diff --git a/src/switch_scheduler.c b/src/switch_scheduler.c
index c08d1071b4..9c0f29a35b 100644
--- a/src/switch_scheduler.c
+++ b/src/switch_scheduler.c
@@ -209,9 +209,21 @@ static void *SWITCH_THREAD_FUNC switch_scheduler_task_thread(switch_thread_t *th
}
SWITCH_DECLARE(uint32_t) switch_scheduler_add_task(time_t task_runtime,
- switch_scheduler_func_t func,
- const char *desc, const char *group, uint32_t cmd_id, void *cmd_arg, switch_scheduler_flag_t flags)
+ switch_scheduler_func_t func,
+ const char *desc, const char *group, uint32_t cmd_id, void *cmd_arg, switch_scheduler_flag_t flags)
{
+ uint32_t task_id;
+
+ switch_scheduler_add_task_ex(task_runtime, func, desc, group, cmd_id, cmd_arg, flags, &task_id);
+
+ return task_id;
+}
+
+SWITCH_DECLARE(uint32_t) switch_scheduler_add_task_ex(time_t task_runtime,
+ switch_scheduler_func_t func,
+ const char *desc, const char *group, uint32_t cmd_id, void *cmd_arg, switch_scheduler_flag_t flags, uint32_t *task_id)
+{
+ uint32_t result;
switch_scheduler_task_container_t *container, *tp;
switch_event_t *event;
switch_time_t now = switch_epoch_time_now(NULL);
@@ -220,6 +232,7 @@ SWITCH_DECLARE(uint32_t) switch_scheduler_add_task(time_t task_runtime,
switch_mutex_lock(globals.task_mutex);
switch_zmalloc(container, sizeof(*container));
switch_assert(func);
+ switch_assert(task_id);
if (task_runtime < now) {
container->task.repeat = (uint32_t)task_runtime;
@@ -246,8 +259,6 @@ SWITCH_DECLARE(uint32_t) switch_scheduler_add_task(time_t task_runtime,
for (container->task.task_id = 0; !container->task.task_id; container->task.task_id = ++globals.task_id);
- switch_mutex_unlock(globals.task_mutex);
-
tp = container;
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Added task %u %s (%s) to run at %" SWITCH_INT64_T_FMT "\n",
tp->task.task_id, tp->desc, switch_str_nil(tp->task.group), tp->task.runtime);
@@ -260,7 +271,12 @@ SWITCH_DECLARE(uint32_t) switch_scheduler_add_task(time_t task_runtime,
switch_queue_push(globals.event_queue, event);
event = NULL;
}
- return container->task.task_id;
+
+ result = *task_id = container->task.task_id;
+
+ switch_mutex_unlock(globals.task_mutex);
+
+ return result;
}
SWITCH_DECLARE(uint32_t) switch_scheduler_del_task_id(uint32_t task_id)
From eaf5a70246e2786bd02c257e26946eb07d58c090 Mon Sep 17 00:00:00 2001
From: Andrey Volk
Date: Wed, 17 Mar 2021 01:15:42 +0300
Subject: [PATCH 057/655] [Unit-tests] Fix build issues in switch_eavesdrop.c
test file.
---
tests/unit/switch_eavesdrop.c | 27 +++++++++++----------------
1 file changed, 11 insertions(+), 16 deletions(-)
diff --git a/tests/unit/switch_eavesdrop.c b/tests/unit/switch_eavesdrop.c
index 867ad7a6bc..18c293f833 100644
--- a/tests/unit/switch_eavesdrop.c
+++ b/tests/unit/switch_eavesdrop.c
@@ -1,20 +1,15 @@
-#include
#include
#include
-static switch_memory_pool_t *pool = NULL;
-
static switch_status_t test_detect_long_tone_in_file(const char *filepath, int rate, int freq, int ptime) {
teletone_multi_tone_t mt;
teletone_tone_map_t map;
int16_t data[SWITCH_RECOMMENDED_BUFFER_SIZE] = { 0 };
- size_t len = (rate * ptime / 1000) /*packet len in samples */ * 8; /*length of chunk that must contain tone*/
- size_t fin = 0;
+ switch_size_t len = (rate * ptime / 1000) /*packet len in samples */ * 8; /*length of chunk that must contain tone*/
+ switch_size_t fin = 0;
switch_status_t status;
switch_file_handle_t fh = { 0 };
uint8_t fail = 0, gaps = 0, audio = 0;
- uint32_t pos = 0;
- size_t full_len = 0;
status = switch_core_file_open(&fh, filepath, 1, rate, SWITCH_FILE_FLAG_READ | SWITCH_FILE_DATA_SHORT, NULL);
if (status != SWITCH_STATUS_SUCCESS) {
@@ -34,7 +29,7 @@ static switch_status_t test_detect_long_tone_in_file(const char *filepath, int r
/*skip silence at the beginning of the file, 1 second max. */
if (!teletone_multi_tone_detect(&mt, data, len)) {
if ((fin > rate && !audio) || gaps > 30) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Too many gaps in audio or no tone detected 1st second. [%u][%d]\n", fin, gaps);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Too many gaps in audio or no tone detected 1st second. [%" SWITCH_SIZE_T_FMT "][%d]\n", fin, gaps);
fail = 1;
break;
}
@@ -85,9 +80,9 @@ FST_SUITE_BEGIN(switch_eavesdrop)
switch_call_cause_t cause;
switch_stream_handle_t stream = { 0 };
char eavesdrop_command[256] = { 0 };
- char rec_path[256];
+ char rec_path[1024];
char rec_uuid[SWITCH_UUID_FORMATTED_LENGTH + 1] = { 0 };
- char eaves_dialstr[256] = { 0 };
+ char eaves_dialstr[512] = { 0 };
switch_uuid_str(rec_uuid, sizeof(rec_uuid));
@@ -160,9 +155,9 @@ FST_SUITE_BEGIN(switch_eavesdrop)
switch_call_cause_t cause;
switch_stream_handle_t stream = { 0 };
char eavesdrop_command[256] = { 0 };
- char rec_path[256];
+ char rec_path[1024];
char rec_uuid[SWITCH_UUID_FORMATTED_LENGTH + 1] = { 0 };
- char eaves_dialstr[256] = { 0 };
+ char eaves_dialstr[512] = { 0 };
switch_uuid_str(rec_uuid, sizeof(rec_uuid));
@@ -235,9 +230,9 @@ FST_SUITE_BEGIN(switch_eavesdrop)
switch_call_cause_t cause;
switch_stream_handle_t stream = { 0 };
char eavesdrop_command[256] = { 0 };
- char rec_path[256];
+ char rec_path[1024];
char rec_uuid[SWITCH_UUID_FORMATTED_LENGTH + 1] = { 0 };
- char eaves_dialstr[256] = { 0 };
+ char eaves_dialstr[512] = { 0 };
switch_uuid_str(rec_uuid, sizeof(rec_uuid));
@@ -310,9 +305,9 @@ FST_SUITE_BEGIN(switch_eavesdrop)
switch_call_cause_t cause;
switch_stream_handle_t stream = { 0 };
char eavesdrop_command[256] = { 0 };
- char rec_path[256];
+ char rec_path[1024];
char rec_uuid[SWITCH_UUID_FORMATTED_LENGTH + 1] = { 0 };
- char eaves_dialstr[256] = { 0 };
+ char eaves_dialstr[512] = { 0 };
switch_uuid_str(rec_uuid, sizeof(rec_uuid));
From a746d12f6c8f5651fc52c3c63bf5f8e3eeae51c1 Mon Sep 17 00:00:00 2001
From: Andrey Volk
Date: Thu, 29 Oct 2020 00:14:00 +0400
Subject: [PATCH 058/655] [mod_sofia] Keep noreg gateways as NOREG, mark
unregistered gateways as DOWN.
Co-authored-by: Mike Jerris
---
src/mod/endpoints/mod_sofia/mod_sofia.c | 33 ++++++++++++++++---------
src/mod/endpoints/mod_sofia/mod_sofia.h | 1 +
src/mod/endpoints/mod_sofia/sofia_reg.c | 3 ++-
3 files changed, 24 insertions(+), 13 deletions(-)
diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.c b/src/mod/endpoints/mod_sofia/mod_sofia.c
index 8ce1996ccb..3143fffa42 100644
--- a/src/mod/endpoints/mod_sofia/mod_sofia.c
+++ b/src/mod/endpoints/mod_sofia/mod_sofia.c
@@ -2740,6 +2740,7 @@ const char *sofia_state_names[] = {
"FAIL_WAIT",
"EXPIRED",
"NOREG",
+ "DOWN",
"TIMEOUT",
NULL
};
@@ -3653,15 +3654,19 @@ static switch_status_t cmd_profile(char **argv, int argc, switch_stream_handle_t
if (!strcasecmp(gname, "all")) {
for (gateway_ptr = profile->gateways; gateway_ptr; gateway_ptr = gateway_ptr->next) {
- gateway_ptr->retry = 0;
- gateway_ptr->state = REG_STATE_UNREGED;
+ if (gateway_ptr->state != REG_STATE_NOREG) {
+ gateway_ptr->retry = 0;
+ gateway_ptr->state = REG_STATE_UNREGED;
+ }
}
stream->write_function(stream, "+OK\n");
} else if ((gateway_ptr = sofia_reg_find_gateway(gname))) {
- gateway_ptr->retry = 0;
- gateway_ptr->state = REG_STATE_UNREGED;
- stream->write_function(stream, "+OK\n");
- sofia_reg_release_gateway(gateway_ptr);
+ if (gateway_ptr->state != REG_STATE_NOREG) {
+ gateway_ptr->retry = 0;
+ gateway_ptr->state = REG_STATE_UNREGED;
+ stream->write_function(stream, "+OK\n");
+ sofia_reg_release_gateway(gateway_ptr);
+ }
} else {
stream->write_function(stream, "Invalid gateway!\n");
}
@@ -3680,15 +3685,19 @@ static switch_status_t cmd_profile(char **argv, int argc, switch_stream_handle_t
if (!strcasecmp(gname, "all")) {
for (gateway_ptr = profile->gateways; gateway_ptr; gateway_ptr = gateway_ptr->next) {
- gateway_ptr->retry = 0;
- gateway_ptr->state = REG_STATE_UNREGISTER;
+ if (gateway_ptr->state != REG_STATE_NOREG) {
+ gateway_ptr->retry = 0;
+ gateway_ptr->state = REG_STATE_UNREGISTER;
+ }
}
stream->write_function(stream, "+OK\n");
} else if ((gateway_ptr = sofia_reg_find_gateway(gname))) {
- gateway_ptr->retry = 0;
- gateway_ptr->state = REG_STATE_UNREGISTER;
- stream->write_function(stream, "+OK\n");
- sofia_reg_release_gateway(gateway_ptr);
+ if (gateway_ptr->state != REG_STATE_NOREG) {
+ gateway_ptr->retry = 0;
+ gateway_ptr->state = REG_STATE_UNREGISTER;
+ stream->write_function(stream, "+OK\n");
+ sofia_reg_release_gateway(gateway_ptr);
+ }
} else {
stream->write_function(stream, "Invalid gateway!\n");
}
diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.h b/src/mod/endpoints/mod_sofia/mod_sofia.h
index 3249533730..d4631b02d6 100644
--- a/src/mod/endpoints/mod_sofia/mod_sofia.h
+++ b/src/mod/endpoints/mod_sofia/mod_sofia.h
@@ -432,6 +432,7 @@ typedef enum {
REG_STATE_FAIL_WAIT,
REG_STATE_EXPIRED,
REG_STATE_NOREG,
+ REG_STATE_DOWN,
REG_STATE_TIMEOUT,
REG_STATE_LAST
} reg_state_t;
diff --git a/src/mod/endpoints/mod_sofia/sofia_reg.c b/src/mod/endpoints/mod_sofia/sofia_reg.c
index 81d2ffdabd..b1586405b7 100644
--- a/src/mod/endpoints/mod_sofia/sofia_reg.c
+++ b/src/mod/endpoints/mod_sofia/sofia_reg.c
@@ -398,6 +398,7 @@ void sofia_reg_check_gateway(sofia_profile_t *profile, time_t now)
}
switch (ostate) {
+ case REG_STATE_DOWN:
case REG_STATE_NOREG:
if (!gateway_ptr->ping && !gateway_ptr->pinging && gateway_ptr->status != SOFIA_GATEWAY_UP) {
gateway_ptr->status = SOFIA_GATEWAY_UP;
@@ -432,7 +433,7 @@ void sofia_reg_check_gateway(sofia_profile_t *profile, time_t now)
case REG_STATE_UNREGISTER:
sofia_reg_kill_reg(gateway_ptr);
- gateway_ptr->state = REG_STATE_NOREG;
+ gateway_ptr->state = REG_STATE_DOWN;
gateway_ptr->status = SOFIA_GATEWAY_DOWN;
break;
case REG_STATE_UNREGED:
From 96e139854e57cdce3c3dccc0206b76fc5d8cee4a Mon Sep 17 00:00:00 2001
From: Andrey Volk
Date: Fri, 13 Nov 2020 21:23:20 +0400
Subject: [PATCH 059/655] [mod_sofia] Prevent crash in sofia_handle_sip_i_state
on switch_channel_set_state() when PFLAG_3PCC_PROXY flag is set.
---
src/mod/endpoints/mod_sofia/sofia.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/src/mod/endpoints/mod_sofia/sofia.c b/src/mod/endpoints/mod_sofia/sofia.c
index 87b09e5406..7e71717aff 100644
--- a/src/mod/endpoints/mod_sofia/sofia.c
+++ b/src/mod/endpoints/mod_sofia/sofia.c
@@ -7930,7 +7930,9 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status,
//switch_core_media_gen_local_sdp(session, NULL, 0, NULL, 0);
sofia_set_flag(tech_pvt, TFLAG_LATE_NEGOTIATION);
//Moves into CS_INIT so call moves forward into the dialplan
- switch_channel_set_state(channel, CS_INIT);
+ if (switch_channel_get_state(channel) == CS_NEW) {
+ switch_channel_set_state(channel, CS_INIT);
+ }
} else {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "No SDP in INVITE and 3pcc not enabled, hanging up.\n");
switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "3PCC DISABLED");
From 7539921ecae86df78b7c198e31103d817c4ad307 Mon Sep 17 00:00:00 2001
From: Mike Jerris
Date: Mon, 16 Nov 2020 17:08:43 -0700
Subject: [PATCH 060/655] [core] improve logging on oversized fields in odbc
---
src/switch_odbc.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/src/switch_odbc.c b/src/switch_odbc.c
index 9ea062d997..4445eb4c1f 100644
--- a/src/switch_odbc.c
+++ b/src/switch_odbc.c
@@ -644,25 +644,25 @@ SWITCH_DECLARE(switch_odbc_status_t) switch_odbc_handle_callback_exec_detailed(c
}
if (truncated) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "sql data truncated - %s\n",SqlState);
if (StrLen_or_IndPtr && StrLen_or_IndPtr <= 268435456) {
ColumnSize = StrLen_or_IndPtr + 1;
vals[y] = malloc(ColumnSize);
switch_assert(vals[y]);
memset(vals[y], 0, ColumnSize);
SQLGetData(stmt, x, SQL_C_CHAR, (SQLCHAR *) vals[y], ColumnSize, NULL);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "SQLGetData large column [%lu]\n", (unsigned long)ColumnSize);
} else {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "SQLGetData failed");
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "sql data truncated - %s\n",SqlState);
vals[y] = NULL;
}
} else {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "SQLGetData failed");
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "SQLGetData failed\n");
vals[y] = NULL;
}
} else if (rc == SQL_SUCCESS){
vals[y] = strdup((char *)val);
} else {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "SQLGetData failed");
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "SQLGetData failed\n");
vals[y] = NULL;
}
} else {
From 81aa6fa9d0417ea43be32f06671e7d3e3cfb9092 Mon Sep 17 00:00:00 2001
From: Mike Jerris
Date: Wed, 18 Nov 2020 00:01:03 +0400
Subject: [PATCH 061/655] [Core] ODBC: Fix large column logic and improve error
handling.
---
src/switch_odbc.c | 13 +++++++++++--
1 file changed, 11 insertions(+), 2 deletions(-)
diff --git a/src/switch_odbc.c b/src/switch_odbc.c
index 4445eb4c1f..fbad0e371a 100644
--- a/src/switch_odbc.c
+++ b/src/switch_odbc.c
@@ -645,12 +645,21 @@ SWITCH_DECLARE(switch_odbc_status_t) switch_odbc_handle_callback_exec_detailed(c
if (truncated) {
if (StrLen_or_IndPtr && StrLen_or_IndPtr <= 268435456) {
+ int ValLen = strlen((char*)val);
ColumnSize = StrLen_or_IndPtr + 1;
vals[y] = malloc(ColumnSize);
switch_assert(vals[y]);
memset(vals[y], 0, ColumnSize);
- SQLGetData(stmt, x, SQL_C_CHAR, (SQLCHAR *) vals[y], ColumnSize, NULL);
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "SQLGetData large column [%lu]\n", (unsigned long)ColumnSize);
+ strcpy(vals[y], (char*)val);
+ rc = SQLGetData(stmt, x, SQL_C_CHAR, (SQLCHAR *)vals[y] + ValLen, ColumnSize - ValLen, NULL);
+ if (rc != SQL_SUCCESS
+#if (ODBCVER >= 0x0300)
+ && rc != SQL_NO_DATA
+#endif
+ ) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "SQLGetData was truncated and failed to complete.\n");
+ switch_safe_free(vals[y]);
+ }
} else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "sql data truncated - %s\n",SqlState);
vals[y] = NULL;
From 9608a5687399223910690adb8318f80b6ad4d3cc Mon Sep 17 00:00:00 2001
From: Andrey Volk
Date: Wed, 18 Nov 2020 21:50:04 +0400
Subject: [PATCH 062/655] [Core] Fix leaks in switch_ivr_park when initially no
rate.
---
src/switch_ivr.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/switch_ivr.c b/src/switch_ivr.c
index be319e353e..9aa05fcd73 100644
--- a/src/switch_ivr.c
+++ b/src/switch_ivr.c
@@ -1011,7 +1011,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_park(switch_core_session_t *session,
rate = read_impl.actual_samples_per_second;
bpf = read_impl.decoded_bytes_per_packet;
- if ((var = switch_channel_get_variable(channel, SWITCH_SEND_SILENCE_WHEN_IDLE_VARIABLE)) && (sval = atoi(var))) {
+ if (rate && (var = switch_channel_get_variable(channel, SWITCH_SEND_SILENCE_WHEN_IDLE_VARIABLE)) && (sval = atoi(var))) {
switch_core_session_get_read_impl(session, &imp);
if (switch_core_codec_init(&codec,
From 90c35685c315b0deb2413d623839e2f3641140a6 Mon Sep 17 00:00:00 2001
From: Andrey Volk
Date: Thu, 19 Nov 2020 21:18:09 +0400
Subject: [PATCH 063/655] [mod_mongo, mod_redis, mod_voicemail] Fix leaking
hash iterators.
---
src/mod/applications/mod_mongo/mod_mongo.c | 1 +
src/mod/applications/mod_redis/mod_redis.c | 2 ++
src/mod/applications/mod_voicemail/mod_voicemail.c | 1 +
3 files changed, 4 insertions(+)
diff --git a/src/mod/applications/mod_mongo/mod_mongo.c b/src/mod/applications/mod_mongo/mod_mongo.c
index aac3221fe7..b66b01369a 100644
--- a/src/mod/applications/mod_mongo/mod_mongo.c
+++ b/src/mod/applications/mod_mongo/mod_mongo.c
@@ -698,6 +698,7 @@ SWITCH_LIMIT_RELEASE(mod_mongo_limit_release)
if (mod_mongo_increment(session, (const char *)p_key, -1, 0, NULL) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Couldn't decrement %s\n", (const char *)p_key);
status = SWITCH_STATUS_FALSE;
+ free(hi);
break;
} else {
switch_core_hash_delete(pvt->resources, (const char *) p_key);
diff --git a/src/mod/applications/mod_redis/mod_redis.c b/src/mod/applications/mod_redis/mod_redis.c
index 7f140fe7d6..5d4c132cd7 100644
--- a/src/mod/applications/mod_redis/mod_redis.c
+++ b/src/mod/applications/mod_redis/mod_redis.c
@@ -197,11 +197,13 @@ SWITCH_LIMIT_RELEASE(limit_release_redis)
if (credis_decr(redis, (const char*)p_key, &val) != 0) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Couldn't decrement value corresponding to %s\n", (char *)p_key);
+ free(hi);
switch_goto_status(SWITCH_STATUS_FALSE, end);
}
p_uuid_key = switch_core_session_sprintf(session, "%s_%s", switch_core_get_switchname(), (char *)p_key);
if (credis_decr(redis,p_uuid_key,&uuid_val) != 0) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Couldn't decrement value corresponding to %s\n", p_uuid_key);
+ free(hi);
switch_goto_status(SWITCH_STATUS_FALSE, end);
}
switch_core_hash_delete(pvt->hash, (const char *) p_key);
diff --git a/src/mod/applications/mod_voicemail/mod_voicemail.c b/src/mod/applications/mod_voicemail/mod_voicemail.c
index aba1dc4cf0..dd3a74a463 100644
--- a/src/mod/applications/mod_voicemail/mod_voicemail.c
+++ b/src/mod/applications/mod_voicemail/mod_voicemail.c
@@ -3855,6 +3855,7 @@ SWITCH_STANDARD_API(boxcount_api_function)
total_new_messages = total_saved_messages = 0;
message_count(profile, id, domain, "inbox", &total_new_messages, &total_saved_messages,
&total_new_urgent_messages, &total_saved_urgent_messages);
+ free(hi);
}
switch_mutex_unlock(globals.mutex);
}
From b78c9a115e4ce43e7d37c65816c82f078fd6466c Mon Sep 17 00:00:00 2001
From: Andrey Volk
Date: Mon, 30 Nov 2020 22:24:21 +0400
Subject: [PATCH 064/655] [mod_sofia] Properly handle nua events came without
nua handles.
---
src/mod/endpoints/mod_sofia/sofia.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/mod/endpoints/mod_sofia/sofia.c b/src/mod/endpoints/mod_sofia/sofia.c
index 7e71717aff..dcedbc7e43 100644
--- a/src/mod/endpoints/mod_sofia/sofia.c
+++ b/src/mod/endpoints/mod_sofia/sofia.c
@@ -2282,7 +2282,7 @@ void sofia_process_dispatch_event(sofia_dispatch_event_t **dep)
profile->queued_events--;
switch_mutex_unlock(profile->flag_mutex);
- nua_handle_unref(nh);
+ if (nh) nua_handle_unref(nh);
nua_unref(nua);
}
@@ -2516,7 +2516,7 @@ void sofia_event_callback(nua_event_t event,
de = su_alloc(nua_handle_get_home(nh), sizeof(*de));
memset(de, 0, sizeof(*de));
nua_save_event(nua, de->event);
- de->nh = nua_handle_ref(nh);
+ de->nh = nh ? nua_handle_ref(nh) : NULL;
de->data = nua_event_data(de->event);
de->sip = sip_object(de->data->e_msg);
de->profile = profile;
From e3e0c7c2596c3870db79eedb51fe77cf45a89fc7 Mon Sep 17 00:00:00 2001
From: Andrey Volk
Date: Tue, 1 Dec 2020 04:21:57 +0400
Subject: [PATCH 065/655] [mod_sofia] Protect insertion into
profile->reg_nh_hash with a mutex.
---
src/mod/endpoints/mod_sofia/sofia_reg.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/src/mod/endpoints/mod_sofia/sofia_reg.c b/src/mod/endpoints/mod_sofia/sofia_reg.c
index b1586405b7..5eee1c17e3 100644
--- a/src/mod/endpoints/mod_sofia/sofia_reg.c
+++ b/src/mod/endpoints/mod_sofia/sofia_reg.c
@@ -1933,7 +1933,6 @@ uint8_t sofia_reg_handle_register_token(nua_t *nua, sofia_profile_t *profile, nu
switch_mutex_lock(profile->flag_mutex);
hnh = switch_core_hash_find(profile->reg_nh_hash, key);
- switch_mutex_unlock(profile->flag_mutex);
if (!hnh) {
if (!(sofia_private = su_alloc(nua_handle_get_home(nh), sizeof(*sofia_private)))) {
@@ -1954,6 +1953,8 @@ uint8_t sofia_reg_handle_register_token(nua_t *nua, sofia_profile_t *profile, nu
nua_handle_ref(nh);
switch_core_hash_insert(profile->reg_nh_hash, key, nh);
}
+
+ switch_mutex_unlock(profile->flag_mutex);
}
From f6e076507e6645745b733e0c91305bba7a832473 Mon Sep 17 00:00:00 2001
From: Andrey Volk
Date: Tue, 15 Dec 2020 00:46:08 +0400
Subject: [PATCH 066/655] [mod_loopback] Fix new_session leak in the case of a
hangup_cause.
---
src/mod/endpoints/mod_loopback/mod_loopback.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/mod/endpoints/mod_loopback/mod_loopback.c b/src/mod/endpoints/mod_loopback/mod_loopback.c
index 88400fcaf6..6fa0d4fbd4 100644
--- a/src/mod/endpoints/mod_loopback/mod_loopback.c
+++ b/src/mod/endpoints/mod_loopback/mod_loopback.c
@@ -1700,6 +1700,7 @@ static switch_call_cause_t null_channel_outgoing_channel(switch_core_session_t *
if (hangup_cause || !strncmp(caller_profile->destination_number, "cause-", 6)) {
if (!hangup_cause) hangup_cause = caller_profile->destination_number + 6;
+ switch_core_session_destroy(new_session);
return switch_channel_str2cause(hangup_cause);
}
From 82b6f01b692afe3a76a28e6650b7b51361300bbe Mon Sep 17 00:00:00 2001
From: Andrey Volk
Date: Sat, 16 Jan 2021 22:53:23 +0300
Subject: [PATCH 067/655] [Core] Fix codec ready checks in
switch_core_session_read_frame()
---
src/switch_core_io.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/switch_core_io.c b/src/switch_core_io.c
index 22d0474e3e..1d5ff7510b 100644
--- a/src/switch_core_io.c
+++ b/src/switch_core_io.c
@@ -227,7 +227,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_read_frame(switch_core_sessi
switch_assert((*frame)->codec != NULL);
- if (!(session->read_codec && (*frame)->codec && (*frame)->codec->implementation) && switch_core_codec_ready((*frame)->codec)) {
+ if (!switch_core_codec_ready(session->read_codec) || !switch_core_codec_ready((*frame)->codec)) {
status = SWITCH_STATUS_FALSE;
goto done;
}
From 29b50439042d012d0eb020efc94201df38b0a6f8 Mon Sep 17 00:00:00 2001
From: Andrey Volk
Date: Wed, 20 Jan 2021 18:30:32 +0300
Subject: [PATCH 068/655] [mod_shout] Fix memory leak in do_telecast
---
src/mod/formats/mod_shout/mod_shout.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/mod/formats/mod_shout/mod_shout.c b/src/mod/formats/mod_shout/mod_shout.c
index 6799b38391..14cba068d3 100644
--- a/src/mod/formats/mod_shout/mod_shout.c
+++ b/src/mod/formats/mod_shout/mod_shout.c
@@ -1333,8 +1333,6 @@ void do_telecast(switch_stream_handle_t *stream)
end:
- switch_safe_free(uuid);
-
if (gfp) {
lame_close(gfp);
gfp = NULL;
@@ -1350,6 +1348,8 @@ void do_telecast(switch_stream_handle_t *stream)
switch_core_session_rwunlock(tsession);
}
+
+ switch_safe_free(uuid);
}
void do_broadcast(switch_stream_handle_t *stream)
From c8e7a57b4c177c19d9289e0c5db76a720c9a1e16 Mon Sep 17 00:00:00 2001
From: Andrey Volk
Date: Wed, 20 Jan 2021 22:31:35 +0300
Subject: [PATCH 069/655] [Unit-Tests] Fix leak of arg in the case of an error
in fct_clp__parse()
---
src/include/test/switch_fct.h | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/src/include/test/switch_fct.h b/src/include/test/switch_fct.h
index a9b3595d0e..f88821b49c 100644
--- a/src/include/test/switch_fct.h
+++ b/src/include/test/switch_fct.h
@@ -1716,6 +1716,12 @@ fct_clp__parse(fct_clp_t *clp, int argc, char const *argv[])
arg =NULL;
}
}
+
+ if (arg != NULL)
+ {
+ free(arg);
+ arg = NULL;
+ }
}
From 3e7ba04cbecb12642373ae1215925372c5137cd3 Mon Sep 17 00:00:00 2001
From: Andrey Volk
Date: Thu, 21 Jan 2021 00:46:40 +0300
Subject: [PATCH 070/655] [mod_curl] Avoid passing null pointer value via data
parameter of do_lookup_url()
---
src/mod/applications/mod_curl/mod_curl.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/mod/applications/mod_curl/mod_curl.c b/src/mod/applications/mod_curl/mod_curl.c
index e82502cb6c..f0c952a215 100644
--- a/src/mod/applications/mod_curl/mod_curl.c
+++ b/src/mod/applications/mod_curl/mod_curl.c
@@ -799,7 +799,7 @@ SWITCH_STANDARD_APP(curl_app_function)
switch_channel_t *channel = switch_core_session_get_channel(session);
char *url = NULL;
char *method = NULL;
- char *postdata = NULL;
+ char *postdata = "";
char *content_type = NULL;
switch_bool_t do_headers = SWITCH_FALSE;
switch_bool_t do_json = SWITCH_FALSE;
@@ -920,7 +920,7 @@ SWITCH_STANDARD_API(curl_function)
char *mydata = NULL;
char *url = NULL;
char *method = NULL;
- char *postdata = NULL;
+ char *postdata = "";
char *content_type = NULL;
switch_bool_t do_headers = SWITCH_FALSE;
switch_bool_t do_json = SWITCH_FALSE;
From e614f08c9342062b4bdb5dc52809d8c25eb05744 Mon Sep 17 00:00:00 2001
From: Andrey Volk
Date: Thu, 21 Jan 2021 17:40:29 +0300
Subject: [PATCH 071/655] [mod_httapi] Fix memory leak of dup_creds in
httapi_sync()
---
src/mod/applications/mod_httapi/mod_httapi.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/mod/applications/mod_httapi/mod_httapi.c b/src/mod/applications/mod_httapi/mod_httapi.c
index 76d273d020..cc2c857a58 100644
--- a/src/mod/applications/mod_httapi/mod_httapi.c
+++ b/src/mod/applications/mod_httapi/mod_httapi.c
@@ -1534,6 +1534,7 @@ static switch_status_t httapi_sync(client_t *client)
char *q, *p = strstr(dynamic_url, "://");
use_url++;
+ switch_safe_free(dup_creds);
dup_creds = strdup(p+3);
*p = '\0';
From c282386fdb9d8944eaf2414ec817da936c4500cb Mon Sep 17 00:00:00 2001
From: Andrey Volk
Date: Thu, 21 Jan 2021 18:29:44 +0300
Subject: [PATCH 072/655] [mod_pgsql] Fix memory leek in the case of an empty
string of err_str in pgsql_handle_exec_base_detailed()
---
src/mod/databases/mod_pgsql/mod_pgsql.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/mod/databases/mod_pgsql/mod_pgsql.c b/src/mod/databases/mod_pgsql/mod_pgsql.c
index e2efa5252c..f7c2983f91 100644
--- a/src/mod/databases/mod_pgsql/mod_pgsql.c
+++ b/src/mod/databases/mod_pgsql/mod_pgsql.c
@@ -515,6 +515,7 @@ error:
err_str = pgsql_handle_get_error(handle);
if (zstr(err_str)) {
+ switch_safe_free(err_str);
if (!er) {
err_str = strdup((char *)"SQL ERROR!");
} else {
From be6b40b024d38b64ca515be3087a5a39db0f867b Mon Sep 17 00:00:00 2001
From: Andrey Volk
Date: Thu, 21 Jan 2021 18:43:02 +0300
Subject: [PATCH 073/655] [mod_lcr] Fix order_by and sql_stream streams leaking
in the case of a DB error in lcr_load_config()
---
src/mod/applications/mod_lcr/mod_lcr.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/src/mod/applications/mod_lcr/mod_lcr.c b/src/mod/applications/mod_lcr/mod_lcr.c
index a9adb3db10..ab7c163ce5 100644
--- a/src/mod/applications/mod_lcr/mod_lcr.c
+++ b/src/mod/applications/mod_lcr/mod_lcr.c
@@ -1186,6 +1186,8 @@ static switch_status_t lcr_load_config()
if (db_check("ALTER TABLE carrier_gateway add codec varchar(255);") == SWITCH_TRUE) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "adding codec field your lcr carrier_gateway database schema.\n");
} else {
+ switch_safe_free(order_by.data);
+ switch_safe_free(sql_stream.data);
switch_goto_status(SWITCH_STATUS_FALSE, done);
}
}
@@ -1197,6 +1199,8 @@ static switch_status_t lcr_load_config()
if (db_check("ALTER TABLE lcr add cid varchar(32);") == SWITCH_TRUE) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "adding cid field to your lcr database schema.\n");
} else {
+ switch_safe_free(order_by.data);
+ switch_safe_free(sql_stream.data);
switch_goto_status(SWITCH_STATUS_FALSE, done);
}
}
@@ -1205,6 +1209,8 @@ static switch_status_t lcr_load_config()
if (db_check("ALTER TABLE lcr ADD lrn BOOLEAN NOT NULL DEFAULT false")) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "adding lrn field to your lcr database schema.\n");
} else {
+ switch_safe_free(order_by.data);
+ switch_safe_free(sql_stream.data);
switch_goto_status(SWITCH_STATUS_FALSE, done);
}
}
From 91066f56fa85d1ca592d78a61846c45cc7409b0c Mon Sep 17 00:00:00 2001
From: Andrey Volk
Date: Thu, 21 Jan 2021 19:38:37 +0300
Subject: [PATCH 074/655] [Core] Fix leaking stream in
switch_event_expand_headers_check()
---
src/switch_event.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/src/switch_event.c b/src/switch_event.c
index efe43e603a..295708eda3 100644
--- a/src/switch_event.c
+++ b/src/switch_event.c
@@ -2464,8 +2464,6 @@ SWITCH_DECLARE(char *) switch_event_expand_headers_check(switch_event_t *event,
char *expanded = NULL;
char *expanded_vname = NULL;
- SWITCH_STANDARD_STREAM(stream);
-
if ((expanded_vname = switch_event_expand_headers_check(event, (char *) vname, var_list, api_list, recur+1)) == vname) {
expanded_vname = NULL;
} else {
@@ -2482,6 +2480,7 @@ SWITCH_DECLARE(char *) switch_event_expand_headers_check(switch_event_t *event,
func_val = NULL;
sub_val = "";
} else {
+ SWITCH_STANDARD_STREAM(stream);
if (switch_api_execute(vname, vval, NULL, &stream) == SWITCH_STATUS_SUCCESS) {
func_val = stream.data;
sub_val = func_val;
From 2a8804af9760b8038cc3edc58741f4f0626c5af6 Mon Sep 17 00:00:00 2001
From: Andrey Volk
Date: Thu, 21 Jan 2021 22:32:12 +0300
Subject: [PATCH 075/655] [Core] Fix leak of switch_event_header_t in
switch_event_base_add_header(). Code cleanup.
---
src/switch_event.c | 88 ++++++++++++++++++++--------------------------
1 file changed, 39 insertions(+), 49 deletions(-)
diff --git a/src/switch_event.c b/src/switch_event.c
index 295708eda3..709ea95e7e 100644
--- a/src/switch_event.c
+++ b/src/switch_event.c
@@ -129,6 +129,8 @@ static char *my_dup(const char *s)
#define FREE(ptr) switch_safe_free(ptr)
#endif
+static void free_header(switch_event_header_t **header);
+
/* make sure this is synced with the switch_event_types_t enum in switch_types.h
also never put any new ones before EVENT_ALL
*/
@@ -891,27 +893,7 @@ SWITCH_DECLARE(switch_status_t) switch_event_del_header_val(switch_event_t *even
if (hp == event->last_header || !hp->next) {
event->last_header = lp;
}
- FREE(hp->name);
-
- if (hp->idx) {
- int i = 0;
-
- for (i = 0; i < hp->idx; i++) {
- FREE(hp->array[i]);
- }
- FREE(hp->array);
- }
-
- FREE(hp->value);
-
- memset(hp, 0, sizeof(*hp));
-#ifdef SWITCH_EVENT_RECYCLE
- if (switch_queue_trypush(EVENT_HEADER_RECYCLE_QUEUE, hp) != SWITCH_STATUS_SUCCESS) {
- FREE(hp);
- }
-#else
- FREE(hp);
-#endif
+ free_header(&hp);
status = SWITCH_STATUS_SUCCESS;
} else {
lp = hp;
@@ -944,6 +926,37 @@ static switch_event_header_t *new_header(const char *header_name)
}
+static void free_header(switch_event_header_t **header)
+{
+ assert(header);
+
+ if (*header) {
+ if ((*header)->idx) {
+ if (!(*header)->array) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "INDEX WITH NO ARRAY ?? [%s][%s]\n", (*header)->name, (*header)->value);
+ } else {
+ int i = 0;
+
+ for (i = 0; i < (*header)->idx; i++) {
+ FREE((*header)->array[i]);
+ }
+ FREE((*header)->array);
+ }
+ }
+
+ FREE((*header)->name);
+ FREE((*header)->value);
+
+#ifdef SWITCH_EVENT_RECYCLE
+ if (switch_queue_trypush(EVENT_HEADER_RECYCLE_QUEUE, *header) != SWITCH_STATUS_SUCCESS) {
+ FREE(*header);
+ }
+#else
+ FREE(*header);
+#endif
+ }
+}
+
SWITCH_DECLARE(int) switch_event_add_array(switch_event_t *event, const char *var, const char *val)
{
char *data;
@@ -1012,10 +1025,11 @@ static switch_status_t switch_event_base_add_header(switch_event_t *event, switc
}
if (index_ptr || (stack & SWITCH_STACK_PUSH) || (stack & SWITCH_STACK_UNSHIFT)) {
+ switch_event_header_t *tmp_header = NULL;
if (!(header = switch_event_get_header_ptr(event, header_name)) && index_ptr) {
- header = new_header(header_name);
+ tmp_header = header = new_header(header_name);
if (switch_test_flag(event, EF_UNIQ_HEADERS)) {
switch_event_del_header(event, header_name);
@@ -1049,6 +1063,8 @@ static switch_status_t switch_event_base_add_header(switch_event_t *event, switc
goto redraw;
}
+ } else if (tmp_header) {
+ free_header(&tmp_header);
}
goto end;
} else {
@@ -1266,33 +1282,7 @@ SWITCH_DECLARE(void) switch_event_destroy(switch_event_t **event)
for (hp = ep->headers; hp;) {
this = hp;
hp = hp->next;
-
- if (this->idx) {
- if (!this->array) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "INDEX WITH NO ARRAY WTF?? [%s][%s]\n", this->name, this->value);
- } else {
- int i = 0;
-
- for (i = 0; i < this->idx; i++) {
- FREE(this->array[i]);
- }
- FREE(this->array);
- }
- }
-
- FREE(this->name);
- FREE(this->value);
-
-
-#ifdef SWITCH_EVENT_RECYCLE
- if (switch_queue_trypush(EVENT_HEADER_RECYCLE_QUEUE, this) != SWITCH_STATUS_SUCCESS) {
- FREE(this);
- }
-#else
- FREE(this);
-#endif
-
-
+ free_header(&this);
}
FREE(ep->body);
FREE(ep->subclass_name);
From d127eeeeccc4f3c137e5d6f8195d45c0710140fc Mon Sep 17 00:00:00 2001
From: Andrey Volk
Date: Fri, 22 Jan 2021 21:45:37 +0300
Subject: [PATCH 076/655] [mod_snom, mod_snmp] Replace strncpy with snprintf
---
src/mod/applications/mod_snom/mod_snom.c | 2 +-
src/mod/event_handlers/mod_snmp/subagent.c | 28 +++++++++++-----------
2 files changed, 15 insertions(+), 15 deletions(-)
diff --git a/src/mod/applications/mod_snom/mod_snom.c b/src/mod/applications/mod_snom/mod_snom.c
index af460e7523..2f706c2556 100644
--- a/src/mod/applications/mod_snom/mod_snom.c
+++ b/src/mod/applications/mod_snom/mod_snom.c
@@ -143,7 +143,7 @@ SWITCH_STANDARD_API(snom_command_api_function)
}
if (switch_inet_pton(AF_INET, argv[0], &ip)) {
- strncpy(host, argv[0], sizeof(host));
+ snprintf(host, sizeof(host), "%s", argv[0]);
} else {
char *sql = NULL;
char *ret = NULL;
diff --git a/src/mod/event_handlers/mod_snmp/subagent.c b/src/mod/event_handlers/mod_snmp/subagent.c
index dd29939e6a..cd61955461 100644
--- a/src/mod/event_handlers/mod_snmp/subagent.c
+++ b/src/mod/event_handlers/mod_snmp/subagent.c
@@ -79,22 +79,22 @@ static int channelList_callback(void *pArg, int argc, char **argv, char **column
row->data = entry;
entry->idx = idx++;
- strncpy(entry->uuid, switch_str_nil(argv[0]), sizeof(entry->uuid));
- strncpy(entry->direction, switch_str_nil(argv[1]), sizeof(entry->direction));
+ snprintf(entry->uuid, sizeof(entry->uuid), "%s", switch_str_nil(argv[0]));
+ snprintf(entry->direction, sizeof(entry->direction), "%s", switch_str_nil(argv[1]));
entry->created_epoch = atoi(argv[3]);
- strncpy(entry->name, switch_str_nil(argv[4]), sizeof(entry->name));
- strncpy(entry->state, switch_str_nil(argv[5]), sizeof(entry->state));
- strncpy(entry->cid_name, switch_str_nil(argv[6]), sizeof(entry->cid_name));
- strncpy(entry->cid_num, switch_str_nil(argv[7]), sizeof(entry->cid_num));
- strncpy(entry->dest, switch_str_nil(argv[9]), sizeof(entry->dest));
- strncpy(entry->application, switch_str_nil(argv[10]), sizeof(entry->application));
- strncpy(entry->application_data, switch_str_nil(argv[11]), sizeof(entry->application_data));
- strncpy(entry->dialplan, switch_str_nil(argv[12]), sizeof(entry->dialplan));
- strncpy(entry->context, switch_str_nil(argv[13]), sizeof(entry->context));
- strncpy(entry->read_codec, switch_str_nil(argv[14]), sizeof(entry->read_codec));
+ snprintf(entry->name, sizeof(entry->name), "%s", switch_str_nil(argv[4]));
+ snprintf(entry->state, sizeof(entry->state), "%s", switch_str_nil(argv[5]));
+ snprintf(entry->cid_name, sizeof(entry->cid_name), "%s", switch_str_nil(argv[6]));
+ snprintf(entry->cid_num, sizeof(entry->cid_num), "%s", switch_str_nil(argv[7]));
+ snprintf(entry->dest, sizeof(entry->dest), "%s", switch_str_nil(argv[9]));
+ snprintf(entry->application, sizeof(entry->application), "%s", switch_str_nil(argv[10]));
+ snprintf(entry->application_data, sizeof(entry->application_data), "%s", switch_str_nil(argv[11]));
+ snprintf(entry->dialplan, sizeof(entry->dialplan), "%s", switch_str_nil(argv[12]));
+ snprintf(entry->context, sizeof(entry->context), "%s", switch_str_nil(argv[13]));
+ snprintf(entry->read_codec, sizeof(entry->read_codec), "%s", switch_str_nil(argv[14]));
entry->read_rate = atoi(switch_str_nil(argv[15]));
entry->read_bitrate = atoi(switch_str_nil(argv[16]));
- strncpy(entry->write_codec, switch_str_nil(argv[17]), sizeof(entry->write_codec));
+ snprintf(entry->write_codec, sizeof(entry->write_codec), "%s", switch_str_nil(argv[17]));
entry->write_rate = atoi(switch_str_nil(argv[18]));
entry->write_bitrate = atoi(switch_str_nil(argv[19]));
@@ -186,7 +186,7 @@ int handle_identity(netsnmp_mib_handler *handler, netsnmp_handler_registration *
snmp_set_var_typed_value(requests->requestvb, ASN_OCTET_STR, (u_char *) &version, strlen(version));
break;
case ID_UUID:
- strncpy(uuid, switch_core_get_uuid(), sizeof(uuid));
+ snprintf(uuid, sizeof(uuid), "%s", switch_core_get_uuid());
snmp_set_var_typed_value(requests->requestvb, ASN_OCTET_STR, (u_char *) &uuid, strlen(uuid));
break;
default:
From 97930570dce98a436ce720ec00e886c8458979b9 Mon Sep 17 00:00:00 2001
From: Andrey Volk
Date: Fri, 22 Jan 2021 21:57:24 +0300
Subject: [PATCH 077/655] [Core] Fix possible memory leak of
switch_core_session_message_t in switch_core_session_queue_indication()
---
src/switch_core_session.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/src/switch_core_session.c b/src/switch_core_session.c
index 36cf62f111..4dde4cba84 100644
--- a/src/switch_core_session.c
+++ b/src/switch_core_session.c
@@ -1026,8 +1026,12 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_queue_indication(switch_core
msg->message_id = indication;
msg->from = __FILE__;
switch_set_flag(msg, SCSMF_DYNAMIC);
- switch_core_session_queue_message(session, msg);
- return SWITCH_STATUS_SUCCESS;
+
+ if (switch_core_session_queue_message(session, msg) == SWITCH_STATUS_SUCCESS) {
+ return SWITCH_STATUS_SUCCESS;
+ }
+
+ free(msg);
}
return SWITCH_STATUS_FALSE;
From 4aa1c1736fb46887dc89194a79a188506321f074 Mon Sep 17 00:00:00 2001
From: Andrey Volk
Date: Wed, 20 Jan 2021 18:48:01 +0300
Subject: [PATCH 078/655] [mod_sofia] scan-build in sofia_glue_do_invite():
Null pointer passed as an argument to a 'nonnull' parameter
---
src/mod/endpoints/mod_sofia/sofia_glue.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/mod/endpoints/mod_sofia/sofia_glue.c b/src/mod/endpoints/mod_sofia/sofia_glue.c
index 2eea09bd5e..0c0035412f 100644
--- a/src/mod/endpoints/mod_sofia/sofia_glue.c
+++ b/src/mod/endpoints/mod_sofia/sofia_glue.c
@@ -1211,7 +1211,7 @@ switch_status_t sofia_glue_do_invite(switch_core_session_t *session)
}
sofia_glue_get_url_from_contact(rpid_domain, 0);
- if ((rpid_domain = strrchr(rpid_domain, '@'))) {
+ if (rpid_domain && (rpid_domain = strrchr(rpid_domain, '@'))) {
rpid_domain++;
if ((p = strchr(rpid_domain, ';'))) {
*p = '\0';
From cfdd1d9be89ae4b1e9d654ff84512671ff73bc2c Mon Sep 17 00:00:00 2001
From: Andrey Volk
Date: Tue, 26 Jan 2021 20:26:14 +0300
Subject: [PATCH 079/655] [mod_http_cache] Handle error cases to avoid using
uninitialized variables in aws logic.
---
src/mod/applications/mod_http_cache/aws.c | 27 +++++++++++++----------
1 file changed, 15 insertions(+), 12 deletions(-)
diff --git a/src/mod/applications/mod_http_cache/aws.c b/src/mod/applications/mod_http_cache/aws.c
index 740fe2e9c4..cc02b4e5b5 100644
--- a/src/mod/applications/mod_http_cache/aws.c
+++ b/src/mod/applications/mod_http_cache/aws.c
@@ -144,10 +144,12 @@ static char* aws_s3_signature_key(char* key_signing, switch_aws_s3_profile* aws_
char key_service[SHA256_DIGEST_LENGTH];
char* aws4_secret_access_key = switch_mprintf("AWS4%s", aws_s3_profile->access_key_secret);
- hmac256(key_date, SHA256_DIGEST_LENGTH, aws4_secret_access_key, strlen(aws4_secret_access_key), aws_s3_profile->date_stamp);
- hmac256(key_region, SHA256_DIGEST_LENGTH, key_date, SHA256_DIGEST_LENGTH, aws_s3_profile->region);
- hmac256(key_service, SHA256_DIGEST_LENGTH, key_region, SHA256_DIGEST_LENGTH, "s3");
- hmac256(key_signing, SHA256_DIGEST_LENGTH, key_service, SHA256_DIGEST_LENGTH, "aws4_request");
+ if (!hmac256(key_date, SHA256_DIGEST_LENGTH, aws4_secret_access_key, (unsigned int)strlen(aws4_secret_access_key), aws_s3_profile->date_stamp)
+ || !hmac256(key_region, SHA256_DIGEST_LENGTH, key_date, SHA256_DIGEST_LENGTH, aws_s3_profile->region)
+ || !hmac256(key_service, SHA256_DIGEST_LENGTH, key_region, SHA256_DIGEST_LENGTH, "s3")
+ || !hmac256(key_signing, SHA256_DIGEST_LENGTH, key_service, SHA256_DIGEST_LENGTH, "aws4_request")) {
+ key_signing = NULL;
+ }
switch_safe_free(aws4_secret_access_key);
@@ -166,7 +168,7 @@ static char* aws_s3_standardized_query_string(switch_aws_s3_profile* aws_s3_prof
char* standardized_query_string;
credential = switch_mprintf("%s%%2F%s%%2F%s%%2Fs3%%2Faws4_request", aws_s3_profile->access_key_id, aws_s3_profile->date_stamp, aws_s3_profile->region);
- switch_snprintf(expires, 9, "%ld", aws_s3_profile->expires);
+ switch_snprintf(expires, 9, "%" SWITCH_TIME_T_FMT, aws_s3_profile->expires);
standardized_query_string = switch_mprintf(
"X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=%s&X-Amz-Date=%s&X-Amz-Expires=%s&X-Amz-SignedHeaders=host",
@@ -243,13 +245,14 @@ static char *aws_s3_authentication_create(switch_aws_s3_profile* aws_s3_profile)
string_to_sign = aws_s3_string_to_sign(standardized_request, aws_s3_profile);
// Get signature_key
- aws_s3_signature_key(signature_key, aws_s3_profile);
-
- // Get signature
- hmac256_hex(signature, signature_key, SHA256_DIGEST_LENGTH, string_to_sign);
-
- // Build final query string
- query_param = switch_mprintf("%s&X-Amz-Signature=%s", standardized_query_string, signature);
+ if (!aws_s3_signature_key(signature_key, aws_s3_profile)
+ // Get signature
+ || !hmac256_hex(signature, signature_key, SHA256_DIGEST_LENGTH, string_to_sign)) {
+ query_param = NULL;
+ } else {
+ // Build final query string
+ query_param = switch_mprintf("%s&X-Amz-Signature=%s", standardized_query_string, signature);
+ }
switch_safe_free(string_to_sign);
switch_safe_free(standardized_query_string);
From f348ab9d3893ad116e7c94a7fd2d42f4307b7313 Mon Sep 17 00:00:00 2001
From: Andrey Volk
Date: Tue, 26 Jan 2021 20:23:52 +0300
Subject: [PATCH 080/655] [mod_sofia] Fix use of uninitialized network_ip in
sofia_handle_sip_r_invite()
---
src/mod/endpoints/mod_sofia/sofia.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/mod/endpoints/mod_sofia/sofia.c b/src/mod/endpoints/mod_sofia/sofia.c
index dcedbc7e43..e1e6435670 100644
--- a/src/mod/endpoints/mod_sofia/sofia.c
+++ b/src/mod/endpoints/mod_sofia/sofia.c
@@ -6516,7 +6516,7 @@ static void sofia_handle_sip_r_invite(switch_core_session_t *session, int status
const char *uuid;
switch_core_session_t *other_session;
private_object_t *tech_pvt = switch_core_session_get_private(session);
- char network_ip[80];
+ char network_ip[80] = "";
int network_port = 0;
switch_caller_profile_t *caller_profile = NULL;
int has_t38 = 0;
From 3134c9aa578d119528a610c5d1fcfa2ec1ac4c6e Mon Sep 17 00:00:00 2001
From: Andrey Volk
Date: Tue, 26 Jan 2021 20:24:38 +0300
Subject: [PATCH 081/655] [mod_callcenter] Fix use of uninitialized res
variable in cc_agent_update()
---
src/mod/applications/mod_callcenter/mod_callcenter.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/mod/applications/mod_callcenter/mod_callcenter.c b/src/mod/applications/mod_callcenter/mod_callcenter.c
index 58816ea0ac..cba6dc84f4 100644
--- a/src/mod/applications/mod_callcenter/mod_callcenter.c
+++ b/src/mod/applications/mod_callcenter/mod_callcenter.c
@@ -998,7 +998,7 @@ cc_status_t cc_agent_update(const char *key, const char *value, const char *agen
{
cc_status_t result = CC_STATUS_SUCCESS;
char *sql;
- char res[256];
+ char res[256] = "";
switch_event_t *event;
/* Check to see if agent already exist */
From e6e227d1f4f44f64966417f37b2cb9bb7fd6daae Mon Sep 17 00:00:00 2001
From: Andrey Volk
Date: Thu, 28 Jan 2021 03:13:13 +0300
Subject: [PATCH 082/655] [Core] Fix leaking stream in
switch_channel_expand_variables_check()
---
src/switch_channel.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/switch_channel.c b/src/switch_channel.c
index c5c61d43ae..09a0697f9f 100644
--- a/src/switch_channel.c
+++ b/src/switch_channel.c
@@ -4175,6 +4175,7 @@ SWITCH_DECLARE(char *) switch_channel_expand_variables_check(switch_channel_t *c
if (!switch_core_test_flag(SCF_API_EXPANSION) || (api_list && !switch_event_check_permission_list(api_list, vname))) {
func_val = NULL;
sub_val = "";
+ free(stream.data);
} else {
if (switch_api_execute(vname, vval, channel->session, &stream) == SWITCH_STATUS_SUCCESS) {
func_val = stream.data;
From 2ca0d02531f91f66cc2f34b909eb14221dc04f54 Mon Sep 17 00:00:00 2001
From: Andrey Volk
Date: Thu, 18 Feb 2021 19:02:03 +0300
Subject: [PATCH 083/655] [Core] Fix leaking codec, timer and abuf in
switch_ivr_play_file() in the case of failing switch_ivr_phrase_macro() or
switch_ivr_speak_text()
---
src/switch_ivr_play_say.c | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/src/switch_ivr_play_say.c b/src/switch_ivr_play_say.c
index e217950958..a8cb5fd4a1 100644
--- a/src/switch_ivr_play_say.c
+++ b/src/switch_ivr_play_say.c
@@ -1309,8 +1309,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_play_file(switch_core_session_t *sess
*arg++ = '\0';
}
if ((status = switch_ivr_phrase_macro(session, dup, arg, lang, args)) != SWITCH_STATUS_SUCCESS) {
- arg_recursion_check_stop(args);
- return status;
+ break;
}
continue;
} else {
@@ -1327,8 +1326,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_play_file(switch_core_session_t *sess
if (engine && text) {
if ((status = switch_ivr_speak_text(session, engine, voice, (char *)text, args)) != SWITCH_STATUS_SUCCESS) {
- arg_recursion_check_stop(args);
- return status;
+ break;
}
} else {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Invalid Args\n");
From 8e2234a205f9b19b628670df6d517974c62b2317 Mon Sep 17 00:00:00 2001
From: Andrey Volk
Date: Sat, 20 Feb 2021 21:14:15 +0300
Subject: [PATCH 084/655] [Core] Fix race between switch_ivr_park_session() and
the state machine. switch_core_session_run() wants to clear the CF_TRANSFER
flag on state change while parking sets the flag.
---
src/switch_ivr.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/switch_ivr.c b/src/switch_ivr.c
index 9aa05fcd73..f1493a723d 100644
--- a/src/switch_ivr.c
+++ b/src/switch_ivr.c
@@ -3522,8 +3522,8 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_generate_json_cdr(switch_core_session
SWITCH_DECLARE(void) switch_ivr_park_session(switch_core_session_t *session)
{
switch_channel_t *channel = switch_core_session_get_channel(session);
- switch_channel_set_state(channel, CS_PARK);
switch_channel_set_flag(channel, CF_TRANSFER);
+ switch_channel_set_state(channel, CS_PARK);
}
From 9e49a4176b3f1583eb3064076f8676918e4dcf35 Mon Sep 17 00:00:00 2001
From: Chris Rienzo
Date: Sat, 20 Feb 2021 19:17:50 +0000
Subject: [PATCH 085/655] [test] Fix fst_session_park() to wait for CF_PARK
instead of CS_PARK. CF_PARK will be set when the channel has actually
parked.
---
src/include/test/switch_test.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/include/test/switch_test.h b/src/include/test/switch_test.h
index eb6f7f3ee6..3413884145 100644
--- a/src/include/test/switch_test.h
+++ b/src/include/test/switch_test.h
@@ -141,7 +141,7 @@ static switch_status_t fst_init_core_and_modload(const char *confdir, const char
*/
#define fst_session_park(session) \
switch_ivr_park_session(session); \
- switch_channel_wait_for_state(switch_core_session_get_channel(session), NULL, CS_PARK);
+ switch_channel_wait_for_flag(switch_core_session_get_channel(session), CF_PARK, SWITCH_TRUE, 10000, NULL);
/**
* check for test requirement - execute teardown on failure
From 0059f0cc1b34a59818a7bfc5074b7be94b2e432a Mon Sep 17 00:00:00 2001
From: Andrey Volk
Date: Thu, 18 Mar 2021 00:53:38 +0300
Subject: [PATCH 086/655] [mod_sofia] Gateways DOWN state introduced a
regression: REG gateways in DOWN state could not be killed. NOREG gateways
could change state in some conditions. Register and Unregister commands will
now error if a gateway is NOREG.
---
src/mod/endpoints/mod_sofia/mod_sofia.c | 4 ++++
src/mod/endpoints/mod_sofia/sofia_reg.c | 4 ++--
2 files changed, 6 insertions(+), 2 deletions(-)
diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.c b/src/mod/endpoints/mod_sofia/mod_sofia.c
index 3143fffa42..ecc925cf78 100644
--- a/src/mod/endpoints/mod_sofia/mod_sofia.c
+++ b/src/mod/endpoints/mod_sofia/mod_sofia.c
@@ -3666,6 +3666,8 @@ static switch_status_t cmd_profile(char **argv, int argc, switch_stream_handle_t
gateway_ptr->state = REG_STATE_UNREGED;
stream->write_function(stream, "+OK\n");
sofia_reg_release_gateway(gateway_ptr);
+ } else {
+ stream->write_function(stream, "-ERR NOREG gateway [%s] can't be registered!\n", gname);
}
} else {
stream->write_function(stream, "Invalid gateway!\n");
@@ -3697,6 +3699,8 @@ static switch_status_t cmd_profile(char **argv, int argc, switch_stream_handle_t
gateway_ptr->state = REG_STATE_UNREGISTER;
stream->write_function(stream, "+OK\n");
sofia_reg_release_gateway(gateway_ptr);
+ } else {
+ stream->write_function(stream, "-ERR NOREG gateway [%s] can't be unregistered!\n", gname);
}
} else {
stream->write_function(stream, "Invalid gateway!\n");
diff --git a/src/mod/endpoints/mod_sofia/sofia_reg.c b/src/mod/endpoints/mod_sofia/sofia_reg.c
index 5eee1c17e3..22997cecae 100644
--- a/src/mod/endpoints/mod_sofia/sofia_reg.c
+++ b/src/mod/endpoints/mod_sofia/sofia_reg.c
@@ -323,7 +323,7 @@ void sofia_reg_check_gateway(sofia_profile_t *profile, time_t now)
free(pkey);
}
- if (gateway_ptr->state == REG_STATE_NOREG) {
+ if (gateway_ptr->state == REG_STATE_NOREG || gateway_ptr->state == REG_STATE_DOWN) {
if (last) {
last->next = gateway_ptr->next;
@@ -356,7 +356,7 @@ void sofia_reg_check_gateway(sofia_profile_t *profile, time_t now)
char *user_via = NULL;
char *register_host = NULL;
- if (!now) {
+ if (!now && ostate != REG_STATE_NOREG) {
gateway_ptr->state = ostate = REG_STATE_UNREGED;
gateway_ptr->expires_str = "0";
}
From 9c589b7750f277a52e82c7c773cd093af40c4e6a Mon Sep 17 00:00:00 2001
From: sergey-safarov
Date: Fri, 19 Mar 2021 00:30:08 +0300
Subject: [PATCH 087/655] [Build-System] freeswitch.spec update
* freeswitch.spec: mod_shout - build always enabled
* Removed not nessary erlang spec file
* freeswitch.spec: Added cache direcory to http_cache module
* freeswitch.spec: added zrtp feature in packaging
* freeswitch.spec: added dependency for gumbo-parser-devel on fedora dist (HTML parser for MSRP)
* remove autoload_configs dir dublication
---
erlang.spec | 297 ------------------------------------------------
freeswitch.spec | 21 ++--
2 files changed, 7 insertions(+), 311 deletions(-)
delete mode 100644 erlang.spec
diff --git a/erlang.spec b/erlang.spec
deleted file mode 100644
index 6cdd7245b9..0000000000
--- a/erlang.spec
+++ /dev/null
@@ -1,297 +0,0 @@
-%define ver %{VERSION_NUMBER}
-%define rel %{RELEASE_NUMBER}
-
-Name: erlang
-Version: %{ver}
-Release: %{rel}.1%{?dist}
-Summary: General-purpose programming language and runtime environment
-
-Group: Development/Languages
-License: ERPL
-URL: http://www.erlang.org
-Source: http://www.erlang.org/download/otp_src_R14B03.tar.gz
-Source1: http://www.erlang.org/download/otp_doc_html_R14B03.tar.gz
-Source2: http://www.erlang.org/download/otp_doc_man_R14B03.tar.gz
-Patch1: otp-R14B-00-0001-Do-not-format-man-pages.patch
-BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
-
-BuildRequires: ncurses-devel
-BuildRequires: openssl-devel
-BuildRequires: unixODBC-devel
-BuildRequires: tcl-devel
-BuildRequires: tk-devel
-BuildRequires: gd-devel
-# BuildRequires: jdk
-BuildRequires: flex
-BuildRequires: m4
-
-Requires: tk
-
-# Added virtual Provides for each erlang module
-Provides: erlang-appmon = %{version}-%{release}
-Provides: erlang-asn1 = %{version}-%{release}
-Provides: erlang-common_test = %{version}-%{release}
-Provides: erlang-compiler = %{version}-%{release}
-Provides: erlang-cosEvent = %{version}-%{release}
-Provides: erlang-cosEventDomain = %{version}-%{release}
-Provides: erlang-cosFileTransfer = %{version}-%{release}
-Provides: erlang-cosNotification = %{version}-%{release}
-Provides: erlang-cosProperty = %{version}-%{release}
-Provides: erlang-cosTime = %{version}-%{release}
-Provides: erlang-cosTransactions = %{version}-%{release}
-Provides: erlang-crypto = %{version}-%{release}
-Provides: erlang-debugger = %{version}-%{release}
-Provides: erlang-dialyzer = %{version}-%{release}
-Provides: erlang-docbuilder = %{version}-%{release}
-Provides: erlang-edoc = %{version}-%{release}
-Provides: erlang-erts = %{version}-%{release}
-Provides: erlang-et = %{version}-%{release}
-Provides: erlang-eunit = %{version}-%{release}
-Provides: erlang-gs = %{version}-%{release}
-Provides: erlang-hipe = %{version}-%{release}
-Provides: erlang-ic = %{version}-%{release}
-Provides: erlang-inets = %{version}-%{release}
-Provides: erlang-inviso = %{version}-%{release}
-Provides: erlang-kernel = %{version}-%{release}
-Provides: erlang-megaco = %{version}-%{release}
-Provides: erlang-mnesia = %{version}-%{release}
-Provides: erlang-observer = %{version}-%{release}
-Provides: erlang-odbc = %{version}-%{release}
-Provides: erlang-orber = %{version}-%{release}
-Provides: erlang-os_mon = %{version}-%{release}
-Provides: erlang-otp_mibs = %{version}-%{release}
-Provides: erlang-parsetools = %{version}-%{release}
-Provides: erlang-percept = %{version}-%{release}
-Provides: erlang-pman = %{version}-%{release}
-Provides: erlang-public_key = %{version}-%{release}
-Provides: erlang-runtime_tools = %{version}-%{release}
-Provides: erlang-sasl = %{version}-%{release}
-Provides: erlang-snmp = %{version}-%{release}
-Provides: erlang-ssh = %{version}-%{release}
-Provides: erlang-ssl = %{version}-%{release}
-Provides: erlang-stdlib = %{version}-%{release}
-Provides: erlang-syntax_tools = %{version}-%{release}
-Provides: erlang-test_server = %{version}-%{release}
-Provides: erlang-toolbar = %{version}-%{release}
-Provides: erlang-tools = %{version}-%{release}
-Provides: erlang-tv = %{version}-%{release}
-Provides: erlang-typer = %{version}-%{release}
-Provides: erlang-webtool = %{version}-%{release}
-Provides: erlang-xmerl = %{version}-%{release}
-
-%description
-Erlang is a general-purpose programming language and runtime
-environment. Erlang has built-in support for concurrency, distribution
-and fault tolerance. Erlang is used in several large telecommunication
-systems from Ericsson.
-
-
-%package doc
-Summary: Erlang documentation
-Group: Development/Languages
-
-%description doc
-Documentation for Erlang.
-
-
-%prep
-%setup -q -n otp_src_%{ver}%{rel}
-#%setup -q -n otp_src_%{ver}
-
-%build
-# WARN: --enable-dynamic-ssl-lib needed for preventing strange messages about missing dependencies on EPEL
-# see https://bugzilla.redhat.com/458646 and https://bugzilla.redhat.com/499525
-%ifarch sparcv9 sparc64
-CFLAGS="$RPM_OPT_FLAGS -mcpu=ultrasparc -fno-strict-aliasing" %configure --enable-dynamic-ssl-lib
-%else
-CFLAGS="$RPM_OPT_FLAGS -fno-strict-aliasing" %configure --enable-dynamic-ssl-lib
-%endif
-chmod -R u+w .
-make
-
-
-%install
-rm -rf $RPM_BUILD_ROOT
-make INSTALL_PREFIX=$RPM_BUILD_ROOT install
-
-# clean up
-find $RPM_BUILD_ROOT%{_libdir}/erlang -perm 0775 | xargs chmod 755
-find $RPM_BUILD_ROOT%{_libdir}/erlang -name Makefile | xargs chmod 644
-find $RPM_BUILD_ROOT%{_libdir}/erlang -name \*.o | xargs chmod 644
-find $RPM_BUILD_ROOT%{_libdir}/erlang -name \*.bat | xargs rm -f
-find $RPM_BUILD_ROOT%{_libdir}/erlang -name index.txt.old | xargs rm -f
-
-# doc
-mkdir -p erlang_doc
-tar -C erlang_doc -zxf %{SOURCE1}
-tar -C $RPM_BUILD_ROOT/%{_libdir}/erlang -zxf %{SOURCE2}
-
-# make links to binaries
-#mkdir -p $RPM_BUILD_ROOT/%{_bindir}
-#cd $RPM_BUILD_ROOT/%{_bindir}
-#for file in erl erlc escript dialyzer
-#do
-# ln -sf ../%{_lib}/erlang/bin/$file .
-#done
-
-# remove buildroot from installed files
-cd $RPM_BUILD_ROOT/%{_libdir}/erlang
-sed -i "s|$RPM_BUILD_ROOT||" erts*/bin/{erl,start} releases/RELEASES bin/{erl,start}
-
-
-%clean
-rm -rf $RPM_BUILD_ROOT
-
-
-%files
-%defattr(-,root,root)
-%doc AUTHORS EPLICENCE README.md
-%{_bindir}/*
-%{_libdir}/erlang
-
-
-%files doc
-%defattr(-,root,root)
-%doc erlang_doc/*
-
-
-%post
-%{_libdir}/erlang/Install -minimal %{_libdir}/erlang >/dev/null 2>/dev/null
-
-
-%changelog
-* Wed Sep 29 2010 Anthony Molinaro - R14B-00.1
-- modified R13B04 spec to work with R14B
-
-* Wed Jul 7 2010 Anthony Molinaro - R13B-04.1
-- modified the R12B spec to work with R13B04
-
-* Mon Jun 7 2010 Peter Lemenkov - R12B-5.10
-- Added missing virtual provides erlang-erts
-
-* Tue May 25 2010 Peter Lemenkov - R12B-5.9
-- Use java-1.4.2 only for EL-[45]
-- Added virtual provides for each erlang module
-- Small typo fix
-
-* Mon Apr 19 2010 Peter Lemenkov - R12B-5.8
-- Patches rebased
-- Added patches 6,7 from trunk
-- Use %%configure
-
-* Tue Apr 21 2009 Debarshi Ray R12B-5.7
-- Updated rpath patch.
-- Fixed configure to respect $RPM_OPT_FLAGS.
-
-* Sun Mar 1 2009 Gerard Milmeister - R12B-5.6
-- new release R12B-5
-- link escript and dialyzer to %{_bindir}
-
-* Tue Feb 24 2009 Fedora Release Engineering - R12B-5.5
-- Rebuilt for https://fedoraproject.org/wiki/Fedora_11_Mass_Rebuild
-
-* Sat Feb 14 2009 Dennis Gilmore - R12B-4.5
-- fix sparc arches to compile
-
-* Fri Jan 16 2009 Tomas Mraz - R12B-4.4
-- rebuild with new openssl
-
-* Sat Oct 25 2008 Gerard Milmeister - R12B-4.1
-- new release R12B-4
-
-* Fri Sep 5 2008 Gerard Milmeister - R12B-3.3
-- fixed sslrpath patch
-
-* Thu Jul 17 2008 Tom "spot" Callaway - R12B-3.2
-- fix license tag
-
-* Sun Jul 6 2008 Gerard Milmeister - R12B-3.1
-- new release R12B-3
-
-* Thu Mar 27 2008 Gerard Milmeister - R12B-1.1
-- new release R12B-1
-
-* Sat Feb 23 2008 Gerard Milmeister - R12B-0.3
-- disable strict aliasing optimization
-
-* Mon Feb 18 2008 Fedora Release Engineering - R12B-0.2
-- Autorebuild for GCC 4.3
-
-* Sat Dec 8 2007 Gerard Milmeister - R12B-0.1
-- new release R12B-0
-
-* Wed Dec 05 2007 Release Engineering - R11B-6
- - Rebuild for deps
-
-* Sun Aug 19 2007 Gerard Milmeister - R11B-5.3
-- fix some permissions
-
-* Sat Aug 18 2007 Gerard Milmeister - R11B-5.2
-- enable dynamic linking for ssl
-
-* Sat Aug 18 2007 Gerard Milmeister - R11B-5.1
-- new release R11B-5
-
-* Sat Mar 24 2007 Thomas Fitzsimmons - R11B-2.4
-- Require java-1.5.0-gcj-devel for build.
-
-* Sun Dec 31 2006 Gerard Milmeister - R11B-2.3
-- remove buildroot from installed files
-
-* Sat Dec 30 2006 Gerard Milmeister - R11B-2.2
-- added patch for compiling with glibc 2.5
-
-* Sat Dec 30 2006 Gerard Milmeister - R11B-2.1
-- new version R11B-2
-
-* Mon Aug 28 2006 Gerard Milmeister - R11B-0.3
-- Rebuild for FE6
-
-* Wed Jul 5 2006 Gerard Milmeister - R11B-0.2
-- add BR m4
-
-* Thu May 18 2006 Gerard Milmeister - R11B-0.1
-- new version R11B-0
-
-* Wed May 3 2006 Gerard Milmeister - R10B-10.3
-- added patch for run_erl by Knut-Håvard Aksnes
-
-* Mon Mar 13 2006 Gerard Milmeister - R10B-10.1
-- new version R10B-10
-
-* Thu Dec 29 2005 Gerard Milmeister - R10B-9.1
-- New Version R10B-9
-
-* Sat Oct 29 2005 Gerard Milmeister - R10B-8.2
-- updated rpath patch
-
-* Sat Oct 29 2005 Gerard Milmeister - R10B-8.1
-- New Version R10B-8
-
-* Sat Oct 1 2005 Gerard Milmeister - R10B-6.4
-- Added tk-devel and tcl-devel to buildreq
-- Added tk to req
-
-* Tue Sep 6 2005 Gerard Milmeister - R10B-6.3
-- Remove perl BuildRequires
-
-* Tue Aug 30 2005 Gerard Milmeister - R10B-6.2
-- change /usr/lib to %%{_libdir}
-- redirect output in %%post to /dev/null
-- add unixODBC-devel to BuildRequires
-- split doc off to erlang-doc package
-
-* Sat Jun 25 2005 Gerard Milmeister - R10B-6.1
-- New Version R10B-6
-
-* Sun Feb 13 2005 Gerard Milmeister - R10B-3.1
-- New Version R10B-3
-
-* Mon Dec 27 2004 Gerard Milmeister - 0:R10B-2-0.fdr.1
-- New Version R10B-2
-
-* Wed Oct 6 2004 Gerard Milmeister - 0:R10B-0.fdr.1
-- New Version R10B
-
-* Thu Oct 16 2003 Gerard Milmeister - 0:R9B-1.fdr.1
-- First Fedora release
diff --git a/freeswitch.spec b/freeswitch.spec
index 4cf49c2118..66bd762caa 100644
--- a/freeswitch.spec
+++ b/freeswitch.spec
@@ -37,7 +37,6 @@
%define build_mod_esl 0
%define build_mod_rayo 1
%define build_mod_ssml 1
-%define build_mod_shout 1
%define build_mod_opusfile 0
%define build_mod_v8 0
@@ -47,7 +46,6 @@
%{?with_py26_esl:%define build_py26_esl 1 }
%{?with_timerfd:%define build_timerfd 1 }
%{?with_mod_esl:%define build_mod_esl 1 }
-%{?with_mod_shout:%define build_mod_shout 1 }
%{?with_mod_opusfile:%define build_mod_opusfile 1 }
%{?with_mod_v8:%define build_mod_v8 1 }
@@ -176,6 +174,9 @@ Requires: libsndfile
PreReq: %insserv_prereq %fillup_prereq
%endif
+%if 0%{?fedora}
+BuildRequires: gumbo-parser-devel
+%endif
######################################################################################################################
#
@@ -1078,7 +1079,6 @@ Mod shell stream is a FreeSWITCH module to allow you to stream audio from an
arbitrary shell command. You could use it to read audio from a database, from
a soundcard, etc.
-%if %{build_mod_shout}
%package format-mod-shout
Summary: Implements Media Steaming from arbitrary shell commands for the FreeSWITCH open source telephony platform
Group: System/Libraries
@@ -1093,7 +1093,6 @@ BuildRequires: lame-devel
%description format-mod-shout
Mod Shout is a FreeSWITCH module to allow you to stream audio from MP3s or a i
shoutcast stream.
-%endif
%if %{build_mod_opusfile}
%package format-mod-opusfile
@@ -1503,10 +1502,7 @@ EVENT_HANDLERS_MODULES+=" event_handlers/mod_rayo"
#
######################################################################################################################
FORMATS_MODULES="formats/mod_local_stream formats/mod_native_file formats/mod_portaudio_stream \
- formats/mod_shell_stream formats/mod_sndfile formats/mod_tone_stream"
-%if %{build_mod_shout}
-FORMATS_MODULES+=" formats/mod_shout "
-%endif
+ formats/mod_shell_stream formats/mod_shout formats/mod_sndfile formats/mod_tone_stream"
%if %{build_mod_ssml}
FORMATS_MODULES+=" formats/mod_ssml"
%endif
@@ -1622,6 +1618,7 @@ autoreconf --force --install
--with-odbc \
--with-erlang \
--with-openssl \
+--enable-zrtp \
%{?configure_options}
unset MODULES
@@ -1645,6 +1642,7 @@ cd libs/esl
%{__mkdir} -p %{buildroot}%{prefix}/log
%{__mkdir} -p %{buildroot}%{logfiledir}
%{__mkdir} -p %{buildroot}%{runtimedir}
+%{__mkdir} -p %{buildroot}%{_localstatedir}/cache/freeswitch
#install the esl stuff
cd libs/esl
@@ -2073,6 +2071,7 @@ fi
%{MODINSTDIR}/mod_httapi.so*
%files application-http-cache
+%dir %attr(0750, freeswitch, daemon) %{_localstatedir}/cache/freeswitch
%{MODINSTDIR}/mod_http_cache.so*
%files application-lcr
@@ -2324,10 +2323,8 @@ fi
%files format-shell-stream
%{MODINSTDIR}/mod_shell_stream.so*
-%if %{build_mod_shout}
%files format-mod-shout
%{MODINSTDIR}/mod_shout.so*
-%endif
%if %{build_mod_ssml}
%files format-ssml
@@ -2344,18 +2341,15 @@ fi
######################################################################################################################
%files lua
%{MODINSTDIR}/mod_lua*.so*
-%dir %attr(0750, freeswitch, daemon) %{sysconfdir}/autoload_configs
%config(noreplace) %attr(0640, freeswitch, daemon) %{sysconfdir}/autoload_configs/lua.conf.xml
%files perl
%{MODINSTDIR}/mod_perl*.so*
%{prefix}/perl/*
-%dir %attr(0750, freeswitch, daemon) %{sysconfdir}/autoload_configs
%config(noreplace) %attr(0640, freeswitch, daemon) %{sysconfdir}/autoload_configs/perl.conf.xml
%files python
%{MODINSTDIR}/mod_python*.so*
-%dir %attr(0750, freeswitch, daemon) %{sysconfdir}/autoload_configs
%config(noreplace) %attr(0640, freeswitch, daemon) %{sysconfdir}/autoload_configs/python.conf.xml
%if %{build_mod_v8}
@@ -2365,7 +2359,6 @@ fi
%{LIBDIR}/libicui18n.so
%{LIBDIR}/libicuuc.so
%endif
-%dir %attr(0750, freeswitch, daemon) %{sysconfdir}/autoload_configs
%config(noreplace) %attr(0640, freeswitch, daemon) %{sysconfdir}/autoload_configs/v8.conf.xml
######################################################################################################################
From 48c4db71c229444bc12a53550d7fd12f51131956 Mon Sep 17 00:00:00 2001
From: Alexander Traud
Date: Tue, 13 Oct 2020 14:33:19 +0200
Subject: [PATCH 088/655] [core] Allow other (D)TLS Curves/Groups beside P-256
Five years ago, commit 8e1b2ea enabled ECDHE for the DTLS server by hard-coding P-256. Released before that, OpenSSL 1.0.2, allows auto selection of the curve (P-256, P-384, and P-512). OpenSSL 1.1.x has this enabled on default, which adds groups/curves like X25519 and X448 automatically. This change here allows DTLS clients with a demand for Security Level 4 (192 bit) and 5 (256 bit) connecting to the DTLS server.
---
src/switch_rtp.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/src/switch_rtp.c b/src/switch_rtp.c
index e2e6dedc2d..fbe49eb15a 100644
--- a/src/switch_rtp.c
+++ b/src/switch_rtp.c
@@ -3734,8 +3734,10 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_add_dtls(switch_rtp_t *rtp_session, d
DH *dh;
switch_status_t status = SWITCH_STATUS_SUCCESS;
#ifndef OPENSSL_NO_EC
+#if OPENSSL_VERSION_NUMBER < 0x10002000L
EC_KEY* ecdh;
#endif
+#endif
#ifndef HAVE_OPENSSL_DTLS_SRTP
return SWITCH_STATUS_FALSE;
@@ -3871,6 +3873,7 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_add_dtls(switch_rtp_t *rtp_session, d
//SSL_set_verify(dtls->ssl, (SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT), cb_verify_peer);
#ifndef OPENSSL_NO_EC
+#if OPENSSL_VERSION_NUMBER < 0x10002000L
ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
if (!ecdh) {
switch_goto_status(SWITCH_STATUS_FALSE, done);
@@ -3878,6 +3881,10 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_add_dtls(switch_rtp_t *rtp_session, d
SSL_set_options(dtls->ssl, SSL_OP_SINGLE_ECDH_USE);
SSL_set_tmp_ecdh(dtls->ssl, ecdh);
EC_KEY_free(ecdh);
+#elif OPENSSL_VERSION_NUMBER < 0x10100000L
+ SSL_set_ecdh_auto(dtls->ssl, 1);
+ SSL_set_options(dtls->ssl, SSL_OP_SINGLE_ECDH_USE);
+#endif
#endif
SSL_set_verify(dtls->ssl, SSL_VERIFY_NONE, NULL);
From fddc6adf8d3d1581f041984bd475ff18336a3f4e Mon Sep 17 00:00:00 2001
From: Aron Podrigal
Date: Thu, 18 Mar 2021 17:13:01 -0500
Subject: [PATCH 089/655] [mod_pgsql] Use PQcmdTuples() to get number of
effected rows to support UPDATE and INSERT without RETURNING.
---
src/mod/databases/mod_pgsql/mod_pgsql.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/src/mod/databases/mod_pgsql/mod_pgsql.c b/src/mod/databases/mod_pgsql/mod_pgsql.c
index f7c2983f91..8c24cf9fce 100644
--- a/src/mod/databases/mod_pgsql/mod_pgsql.c
+++ b/src/mod/databases/mod_pgsql/mod_pgsql.c
@@ -633,6 +633,7 @@ error:
switch_status_t pgsql_next_result_timed(switch_pgsql_handle_t *handle, switch_pgsql_result_t **result_out, int msec)
{
+ char *affected_rows = NULL;
switch_pgsql_result_t *res;
switch_time_t start;
switch_time_t ctime;
@@ -747,6 +748,11 @@ switch_status_t pgsql_next_result_timed(switch_pgsql_handle_t *handle, switch_pg
res->result = PQgetResult(handle->con);
if (res->result) {
+ affected_rows = PQcmdTuples(res->result);
+ if (!zstr(affected_rows)) {
+ handle->affected_rows = atoi(affected_rows);
+ }
+
*result_out = res;
res->status = PQresultStatus(res->result);
switch (res->status) {
@@ -757,7 +763,6 @@ switch_status_t pgsql_next_result_timed(switch_pgsql_handle_t *handle, switch_pg
case PGRES_TUPLES_OK:
{
res->rows = PQntuples(res->result);
- handle->affected_rows = res->rows;
res->cols = PQnfields(res->result);
}
break;
From af272f517947c99faa08ac22f70866f8c7150bb2 Mon Sep 17 00:00:00 2001
From: Andrey Volk
Date: Fri, 19 Mar 2021 23:31:46 +0300
Subject: [PATCH 090/655] [mod_conference] Bridged conference did not wait it's
last member before destroy and crashed.
---
.../applications/mod_conference/mod_conference.c | 16 +++++-----------
1 file changed, 5 insertions(+), 11 deletions(-)
diff --git a/src/mod/applications/mod_conference/mod_conference.c b/src/mod/applications/mod_conference/mod_conference.c
index a2b5058656..d1ee467757 100644
--- a/src/mod/applications/mod_conference/mod_conference.c
+++ b/src/mod/applications/mod_conference/mod_conference.c
@@ -1895,7 +1895,7 @@ SWITCH_STANDARD_APP(conference_function)
const char *cflags_str, *v_cflags_str;
member_flag_t mflags[MFLAG_MAX] = { 0 };
switch_core_session_message_t msg = { 0 };
- uint8_t rl = 0, isbr = 0;
+ uint8_t isbr = 0;
char *dpin = "";
const char *mdpin = "";
conference_xml_cfg_t xml_cfg = { 0 };
@@ -2200,14 +2200,6 @@ SWITCH_STANDARD_APP(conference_function)
/* Indicate the conference is dynamic */
conference_utils_set_flag_locked(conference, CFLAG_DYNAMIC);
- /* acquire a read lock on the thread so it can't leave without us */
- if (switch_thread_rwlock_tryrdlock(conference->rwlock) != SWITCH_STATUS_SUCCESS) {
- switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "Read Lock Fail\n");
- goto done;
- }
-
- rl++;
-
/* Start the conference thread for this conference */
conference_launch_thread(conference);
@@ -2215,7 +2207,6 @@ SWITCH_STANDARD_APP(conference_function)
} else { /* setup user variable */
switch_channel_set_variable(channel, "conference_name", conference->name);
switch_channel_set_variable(channel, SWITCH_RFC7989_APP_SESSION_ID_VARIABLE, conference->uuid_str);
- rl++;
}
/* Moderator PIN as a channel variable */
@@ -2595,7 +2586,7 @@ SWITCH_STANDARD_APP(conference_function)
switch_core_session_reset(session, SWITCH_TRUE, SWITCH_TRUE);
/* release the readlock */
- if (rl) {
+ if (conference) {
switch_thread_rwlock_unlock(conference->rwlock);
}
@@ -3798,6 +3789,9 @@ conference_obj_t *conference_new(char *name, conference_xml_cfg_t cfg, switch_co
switch_event_fire(&event);
end:
+ if (conference) {
+ switch_thread_rwlock_rdlock(conference->rwlock);
+ }
switch_mutex_unlock(conference_globals.hash_mutex);
From dfb9541b08f033b89a25994fc5c8708ef4889404 Mon Sep 17 00:00:00 2001
From: Andrey Volk
Date: Fri, 11 Dec 2020 22:32:25 +0300
Subject: [PATCH 091/655] [mod_sofia] Use thread-safe alternatives when
destroying nua and nua_handle references. Bump sofia-sip library requirement
to version 1.13.3
---
configure.ac | 2 +-
debian/bootstrap.sh | 2 +-
freeswitch.spec | 2 +-
src/mod/endpoints/mod_sofia/mod_sofia.c | 4 ++--
src/mod/endpoints/mod_sofia/mod_sofia.h | 2 +-
src/mod/endpoints/mod_sofia/sofia.c | 26 ++++++++++++++++---------
src/mod/endpoints/mod_sofia/sofia_reg.c | 4 ++--
7 files changed, 25 insertions(+), 17 deletions(-)
diff --git a/configure.ac b/configure.ac
index 9ea2d11b87..810003eda2 100644
--- a/configure.ac
+++ b/configure.ac
@@ -725,7 +725,7 @@ PKG_CHECK_MODULES([SPANDSP], [spandsp >= 3.0],[
AC_MSG_ERROR([no usable spandsp; please install spandsp3 devel package or equivalent])
])
-PKG_CHECK_MODULES([SOFIA_SIP], [sofia-sip-ua >= 1.12.12],[
+PKG_CHECK_MODULES([SOFIA_SIP], [sofia-sip-ua >= 1.13.3],[
AM_CONDITIONAL([HAVE_SOFIA_SIP],[true])],[
AC_MSG_ERROR([no usable sofia-sip; please install sofia-sip-ua devel package or equivalent])
])
diff --git a/debian/bootstrap.sh b/debian/bootstrap.sh
index c9b2d522f9..594e7adb7c 100755
--- a/debian/bootstrap.sh
+++ b/debian/bootstrap.sh
@@ -332,7 +332,7 @@ Build-Depends:
uuid-dev, libexpat1-dev, libgdbm-dev, libdb-dev,
# used by many modules
libcurl4-openssl-dev | libcurl4-gnutls-dev | libcurl-dev,
- bison, zlib1g-dev, libsofia-sip-ua-dev (>= 1.12.12),
+ bison, zlib1g-dev, libsofia-sip-ua-dev (>= 1.13.3),
libspandsp3-dev,
# used to format the private freeswitch apt-repo key properly
gnupg,
diff --git a/freeswitch.spec b/freeswitch.spec
index 66bd762caa..3bbc518119 100644
--- a/freeswitch.spec
+++ b/freeswitch.spec
@@ -142,7 +142,7 @@ BuildRequires: curl-devel >= 7.19
BuildRequires: gcc-c++
BuildRequires: libtool >= 1.5.17
BuildRequires: openssl-devel >= 1.0.1e
-BuildRequires: sofia-sip-devel >= 1.12.12
+BuildRequires: sofia-sip-devel >= 1.13.3
BuildRequires: spandsp3-devel >= 3.0
BuildRequires: pcre-devel
BuildRequires: speex-devel
diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.c b/src/mod/endpoints/mod_sofia/mod_sofia.c
index ecc925cf78..8c1b7fd325 100644
--- a/src/mod/endpoints/mod_sofia/mod_sofia.c
+++ b/src/mod/endpoints/mod_sofia/mod_sofia.c
@@ -1328,7 +1328,7 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi
de->session = session;
}
- sofia_process_dispatch_event(&de);
+ sofia_process_dispatch_event(&de, SWITCH_FALSE);
switch_mutex_unlock(tech_pvt->sofia_mutex);
@@ -5791,7 +5791,7 @@ void general_event_handler(switch_event_t *event)
TAG_IF(call_info, SIPTAG_CALL_INFO_STR(call_info)), TAG_IF(!zstr(body), SIPTAG_PAYLOAD_STR(body)), TAG_END());
if (call_id && nh) {
- nua_handle_unref(nh);
+ nua_handle_unref_user(nh);
}
done:
diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.h b/src/mod/endpoints/mod_sofia/mod_sofia.h
index d4631b02d6..db709b9721 100644
--- a/src/mod/endpoints/mod_sofia/mod_sofia.h
+++ b/src/mod/endpoints/mod_sofia/mod_sofia.h
@@ -1237,7 +1237,7 @@ uint32_t sofia_presence_get_cseq(sofia_profile_t *profile);
void sofia_glue_build_vid_refresh_message(switch_core_session_t *session, const char *pl);
char *sofia_glue_gen_contact_str(sofia_profile_t *profile, sip_t const *sip, nua_handle_t *nh, sofia_dispatch_event_t *de, sofia_nat_parse_t *np);
void sofia_glue_pause_jitterbuffer(switch_core_session_t *session, switch_bool_t on);
-void sofia_process_dispatch_event(sofia_dispatch_event_t **dep);
+void sofia_process_dispatch_event(sofia_dispatch_event_t **dep, switch_bool_t stack_thread);
void sofia_process_dispatch_event_in_thread(sofia_dispatch_event_t **dep);
char *sofia_glue_get_host(const char *str, switch_memory_pool_t *pool);
void sofia_presence_check_subscriptions(sofia_profile_t *profile, time_t now);
diff --git a/src/mod/endpoints/mod_sofia/sofia.c b/src/mod/endpoints/mod_sofia/sofia.c
index e1e6435670..b76a804e8e 100644
--- a/src/mod/endpoints/mod_sofia/sofia.c
+++ b/src/mod/endpoints/mod_sofia/sofia.c
@@ -2230,7 +2230,7 @@ void *SWITCH_THREAD_FUNC sofia_msg_thread_run_once(switch_thread_t *thread, void
if (de) {
pool = de->pool;
de->pool = NULL;
- sofia_process_dispatch_event(&de);
+ sofia_process_dispatch_event(&de, SWITCH_FALSE);
}
if (pool) {
@@ -2263,7 +2263,7 @@ void sofia_process_dispatch_event_in_thread(sofia_dispatch_event_t **dep)
switch_thread_pool_launch_thread(&td);
}
-void sofia_process_dispatch_event(sofia_dispatch_event_t **dep)
+void sofia_process_dispatch_event(sofia_dispatch_event_t **dep, switch_bool_t stack_thread)
{
sofia_dispatch_event_t *de = *dep;
nua_handle_t *nh = de->nh;
@@ -2282,8 +2282,15 @@ void sofia_process_dispatch_event(sofia_dispatch_event_t **dep)
profile->queued_events--;
switch_mutex_unlock(profile->flag_mutex);
- if (nh) nua_handle_unref(nh);
- nua_unref(nua);
+ if (stack_thread) {
+ /* Safe to unref directly */
+ if (nh) nua_handle_unref(nh);
+ nua_unref(nua);
+ } else {
+ /* This is not a stack thread, need to call via stack (_user) using events */
+ if (nh) nua_handle_unref_user(nh);
+ nua_unref_user(nua);
+ }
}
@@ -2320,7 +2327,7 @@ void *SWITCH_THREAD_FUNC sofia_msg_thread_run(switch_thread_t *thread, void *obj
if (pop) {
sofia_dispatch_event_t *de = (sofia_dispatch_event_t *) pop;
- sofia_process_dispatch_event(&de);
+ sofia_process_dispatch_event(&de, SWITCH_FALSE);
} else {
break;
}
@@ -2374,7 +2381,8 @@ void sofia_queue_message(sofia_dispatch_event_t *de)
int launch = 0;
if (mod_sofia_globals.running == 0 || !mod_sofia_globals.msg_queue) {
- sofia_process_dispatch_event(&de);
+ /* Calling with SWITCH_TRUE as we are sure this is the stack's thread */
+ sofia_process_dispatch_event(&de, SWITCH_TRUE);
return;
}
@@ -7877,7 +7885,7 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status,
switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "ATTENDED_TRANSFER_ERROR");
switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
}
- nua_handle_unref(bnh);
+ nua_handle_unref_user(bnh);
}
su_home_unref(home);
home = NULL;
@@ -9311,7 +9319,7 @@ void sofia_handle_sip_i_refer(nua_t *nua, sofia_profile_t *profile, nua_handle_t
}
switch_core_session_rwunlock(b_session);
}
- nua_handle_unref(bnh);
+ nua_handle_unref_user(bnh);
} else { /* the other channel is on a different box, we have to go find them */
if (exten && (br_a = switch_channel_get_partner_uuid(channel_a))) {
switch_core_session_t *a_session;
@@ -11344,7 +11352,7 @@ void sofia_handle_sip_i_invite(switch_core_session_t *session, nua_t *nua, sofia
switch_core_session_rwunlock(b_session);
}
}
- nua_handle_unref(bnh);
+ nua_handle_unref_user(bnh);
} else if (sip->sip_replaces && sip->sip_replaces->rp_call_id) {
switch_core_session_t *b_session = NULL;
if ((b_session = switch_core_session_locate((char*) sip->sip_replaces->rp_call_id))) {
diff --git a/src/mod/endpoints/mod_sofia/sofia_reg.c b/src/mod/endpoints/mod_sofia/sofia_reg.c
index 22997cecae..582de54cb4 100644
--- a/src/mod/endpoints/mod_sofia/sofia_reg.c
+++ b/src/mod/endpoints/mod_sofia/sofia_reg.c
@@ -694,7 +694,7 @@ void sofia_reg_check_socket(sofia_profile_t *profile, const char *call_id, const
switch_mutex_lock(profile->flag_mutex);
if ((hnh = switch_core_hash_find(profile->reg_nh_hash, key))) {
switch_core_hash_delete(profile->reg_nh_hash, key);
- nua_handle_unref(hnh);
+ nua_handle_unref_user(hnh);
nua_handle_destroy(hnh);
}
switch_mutex_unlock(profile->flag_mutex);
@@ -1214,7 +1214,7 @@ void sofia_reg_close_handles(sofia_profile_t *profile)
for (hi = switch_core_hash_first_iter( profile->reg_nh_hash, hi); hi; hi = switch_core_hash_next(&hi)) {
switch_core_hash_this(hi, &var, NULL, &val);
if ((nh = (nua_handle_t *) val)) {
- nua_handle_unref(nh);
+ nua_handle_unref_user(nh);
nua_handle_destroy(nh);
switch_core_hash_delete(profile->reg_nh_hash, (char *) var);
goto top;
From c63f9524eebf2f03f8d0a496294c8be2b2a567e8 Mon Sep 17 00:00:00 2001
From: Chris Rienzo
Date: Thu, 25 Feb 2021 06:04:27 -0500
Subject: [PATCH 092/655] [core] Remove unused buffers and mutexes in
switch_core_session. Remove destruction of resamplers that will already be
destroyed by switch_core_session_reset().
---
src/include/private/switch_core_pvt.h | 13 +------------
src/switch_core_media.c | 17 +----------------
src/switch_core_session.c | 15 +--------------
3 files changed, 3 insertions(+), 42 deletions(-)
diff --git a/src/include/private/switch_core_pvt.h b/src/include/private/switch_core_pvt.h
index 68a8d9c463..388813701f 100644
--- a/src/include/private/switch_core_pvt.h
+++ b/src/include/private/switch_core_pvt.h
@@ -1,6 +1,6 @@
/*
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
- * Copyright (C) 2005-2014, Anthony Minessale II
+ * Copyright (C) 2005-2021, Anthony Minessale II
*
* Version: MPL 1.1
*
@@ -135,8 +135,6 @@ struct switch_core_session {
switch_mutex_t *codec_init_mutex;
switch_mutex_t *codec_read_mutex;
switch_mutex_t *codec_write_mutex;
- switch_mutex_t *video_codec_read_mutex;
- switch_mutex_t *video_codec_write_mutex;
switch_thread_cond_t *cond;
switch_mutex_t *frame_read_mutex;
@@ -170,15 +168,6 @@ struct switch_core_session {
uint8_t raw_read_buf[SWITCH_RECOMMENDED_BUFFER_SIZE];
uint8_t enc_read_buf[SWITCH_RECOMMENDED_BUFFER_SIZE];
- /* video frame.data being trated differently than audio, allocate a dynamic data buffer if necessary*/
- switch_buffer_t *video_raw_write_buffer;
- switch_frame_t video_raw_write_frame;
- // switch_frame_t video_enc_write_frame;
-
- switch_buffer_t *video_raw_read_buffer;
- switch_frame_t video_raw_read_frame;
- // switch_frame_t video_enc_read_frame;
-
switch_codec_t bug_codec;
uint32_t read_frame_count;
uint32_t track_duration;
diff --git a/src/switch_core_media.c b/src/switch_core_media.c
index 23e77047b9..fe0abd918d 100644
--- a/src/switch_core_media.c
+++ b/src/switch_core_media.c
@@ -1,6 +1,6 @@
/*
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
- * Copyright (C) 2005-2018, Anthony Minessale II
+ * Copyright (C) 2005-2021, Anthony Minessale II
*
* Version: MPL 1.1
*
@@ -3583,7 +3583,6 @@ static void switch_core_session_parse_codec_settings(switch_core_session_t *sess
}
}
-
//?
SWITCH_DECLARE(switch_status_t) switch_core_media_set_video_codec(switch_core_session_t *session, int force)
{
@@ -3727,20 +3726,6 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_set_codec(switch_core_session_
(uint32_t) a_engine->read_impl.microseconds_per_packet / 1000 != a_engine->cur_payload_map->codec_ms ||
a_engine->read_impl.samples_per_second != a_engine->cur_payload_map->rm_rate ) {
- if (session->read_resampler) {
- switch_mutex_lock(session->resample_mutex);
- switch_resample_destroy(&session->read_resampler);
- switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_NOTICE, "Deactivating read resampler\n");
- switch_mutex_unlock(session->resample_mutex);
- }
-
- if (session->write_resampler) {
- switch_mutex_lock(session->resample_mutex);
- switch_resample_destroy(&session->write_resampler);
- switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_NOTICE, "Deactivating write resampler\n");
- switch_mutex_unlock(session->resample_mutex);
- }
-
switch_core_session_reset(session, 0, 0);
switch_channel_audio_sync(session->channel);
diff --git a/src/switch_core_session.c b/src/switch_core_session.c
index 4dde4cba84..f8ebe3db72 100644
--- a/src/switch_core_session.c
+++ b/src/switch_core_session.c
@@ -1,6 +1,6 @@
/*
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
- * Copyright (C) 2005-2014, Anthony Minessale II
+ * Copyright (C) 2005-2021, Anthony Minessale II
*
* Version: MPL 1.1
*
@@ -1393,17 +1393,6 @@ SWITCH_DECLARE(void) switch_core_session_reset(switch_core_session_t *session, s
switch_buffer_destroy(&session->raw_read_buffer);
switch_mutex_unlock(session->codec_read_mutex);
- switch_mutex_lock(session->video_codec_write_mutex);
- switch_buffer_destroy(&session->video_raw_write_buffer);
- switch_mutex_unlock(session->video_codec_write_mutex);
-
- switch_mutex_lock(session->video_codec_read_mutex);
- switch_buffer_destroy(&session->video_raw_read_buffer);
- switch_mutex_unlock(session->video_codec_read_mutex);
-
- //video_raw_read_frame.data is dynamically allocated if necessary, so wipe this also
- switch_safe_free(session->video_raw_read_frame.data);
-
if (flush_dtmf) {
while ((has = switch_channel_has_dtmf(channel))) {
switch_channel_flush_dtmf(channel);
@@ -2424,8 +2413,6 @@ SWITCH_DECLARE(switch_core_session_t *) switch_core_session_request_uuid(switch_
switch_mutex_init(&session->codec_init_mutex, SWITCH_MUTEX_NESTED, session->pool);
switch_mutex_init(&session->codec_read_mutex, SWITCH_MUTEX_NESTED, session->pool);
switch_mutex_init(&session->codec_write_mutex, SWITCH_MUTEX_NESTED, session->pool);
- switch_mutex_init(&session->video_codec_read_mutex, SWITCH_MUTEX_NESTED, session->pool);
- switch_mutex_init(&session->video_codec_write_mutex, SWITCH_MUTEX_NESTED, session->pool);
switch_mutex_init(&session->frame_read_mutex, SWITCH_MUTEX_NESTED, session->pool);
switch_thread_rwlock_create(&session->bug_rwlock, session->pool);
switch_thread_cond_create(&session->cond, session->pool);
From c61d89a47fc793475aa7ef97b39c58d266284889 Mon Sep 17 00:00:00 2001
From: Andrey Volk
Date: Sat, 27 Feb 2021 01:04:16 +0300
Subject: [PATCH 093/655] [Core] Add new switch_core_session_try_reset() API to
fix a deadlock for the case when two threads want to set session codecs.
---
src/include/switch_core.h | 8 ++++++++
src/switch_core_media.c | 17 +++++++++++++++--
src/switch_core_session.c | 17 +++++++++++++++++
3 files changed, 40 insertions(+), 2 deletions(-)
diff --git a/src/include/switch_core.h b/src/include/switch_core.h
index 92e1452aa0..6299e09c52 100644
--- a/src/include/switch_core.h
+++ b/src/include/switch_core.h
@@ -1359,6 +1359,14 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_set_video_write_impl(switch_
*/
SWITCH_DECLARE(void) switch_core_session_reset(_In_ switch_core_session_t *session, switch_bool_t flush_dtmf, switch_bool_t reset_read_codec);
+/*!
+ \brief Reset the buffers and resampler on a session, fail if can not lock codec mutexes
+ \param session the session to reset
+ \param flush_dtmf flush all queued dtmf events too
+ \return SWITCH_STATUS_SUCCESS if the session was reset
+*/
+SWITCH_DECLARE(switch_status_t) switch_core_session_try_reset(switch_core_session_t* session, switch_bool_t flush_dtmf, switch_bool_t reset_read_codec);
+
/*!
\brief Write a frame to a session
\param session the session to write to
diff --git a/src/switch_core_media.c b/src/switch_core_media.c
index fe0abd918d..ac8b9b9f71 100644
--- a/src/switch_core_media.c
+++ b/src/switch_core_media.c
@@ -3702,9 +3702,11 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_set_codec(switch_core_session_
int resetting = 0;
switch_media_handle_t *smh;
switch_rtp_engine_t *a_engine;
+ switch_time_t start = switch_micro_time_now();
switch_assert(session);
-
+
+retry:
switch_mutex_lock(session->codec_init_mutex);
if (!(smh = session->media_handle)) {
@@ -3726,7 +3728,18 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_set_codec(switch_core_session_
(uint32_t) a_engine->read_impl.microseconds_per_packet / 1000 != a_engine->cur_payload_map->codec_ms ||
a_engine->read_impl.samples_per_second != a_engine->cur_payload_map->rm_rate ) {
- switch_core_session_reset(session, 0, 0);
+ if (switch_core_session_try_reset(session, 0, 0) != SWITCH_STATUS_SUCCESS) {
+ switch_time_t elapsed = switch_micro_time_now() - start;
+ if (elapsed > 1000000) {
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Could not reset session in %"SWITCH_TIME_T_FMT" us. Give up.\n", elapsed);
+ switch_goto_status(SWITCH_STATUS_FALSE, end);
+ }
+
+ switch_mutex_unlock(session->codec_init_mutex);
+ switch_yield(10000);
+ goto retry;
+ }
+
switch_channel_audio_sync(session->channel);
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG,
diff --git a/src/switch_core_session.c b/src/switch_core_session.c
index f8ebe3db72..323adfc482 100644
--- a/src/switch_core_session.c
+++ b/src/switch_core_session.c
@@ -1364,6 +1364,23 @@ SWITCH_DECLARE(uint32_t) switch_core_session_flush_private_events(switch_core_se
return x;
}
+SWITCH_DECLARE(switch_status_t) switch_core_session_try_reset(switch_core_session_t* session, switch_bool_t flush_dtmf, switch_bool_t reset_read_codec)
+{
+ switch_status_t status = SWITCH_STATUS_FALSE;
+
+ if (switch_mutex_trylock(session->codec_read_mutex) == SWITCH_STATUS_SUCCESS) {
+ if (switch_mutex_trylock(session->codec_write_mutex) == SWITCH_STATUS_SUCCESS) {
+ switch_core_session_reset(session, flush_dtmf, reset_read_codec);
+ switch_mutex_unlock(session->codec_write_mutex);
+ status = SWITCH_STATUS_SUCCESS;
+ }
+
+ switch_mutex_unlock(session->codec_read_mutex);
+ }
+
+ return status;
+}
+
SWITCH_DECLARE(void) switch_core_session_reset(switch_core_session_t *session, switch_bool_t flush_dtmf, switch_bool_t reset_read_codec)
{
switch_channel_t *channel = switch_core_session_get_channel(session);
From dd399975882ac473f38a6c6ac81d3b63dcad24bb Mon Sep 17 00:00:00 2001
From: Dragos Oancea
Date: Sat, 27 Feb 2021 14:01:27 +0000
Subject: [PATCH 094/655] [mod_av] fix memory leak on file playing
---
src/mod/applications/mod_av/avformat.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/src/mod/applications/mod_av/avformat.c b/src/mod/applications/mod_av/avformat.c
index 0b3a452325..d45f584b2d 100644
--- a/src/mod/applications/mod_av/avformat.c
+++ b/src/mod/applications/mod_av/avformat.c
@@ -1571,6 +1571,8 @@ GCC_DIAG_ON(deprecated-declarations)
}
+ } else {
+ av_packet_unref(&pkt);
}
}
From 2e65ca908d0fc74016fcb43be09ea3d2eb8d61b4 Mon Sep 17 00:00:00 2001
From: Dragos Oancea
Date: Mon, 1 Mar 2021 19:48:45 +0200
Subject: [PATCH 095/655] [core] rtp: fix #ifdef DEBUG_TS_ROLLOVER (#357)
---
src/switch_rtp.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/src/switch_rtp.c b/src/switch_rtp.c
index fbe49eb15a..a461c9ba32 100644
--- a/src/switch_rtp.c
+++ b/src/switch_rtp.c
@@ -50,7 +50,9 @@
#include
//#define DEBUG_TS_ROLLOVER
-//#define TS_ROLLOVER_START 4294951295
+#ifdef DEBUG_TS_ROLLOVER
+#define TS_ROLLOVER_START 4294951295
+#endif
//#define DEBUG_2833
//#define RTP_DEBUG_WRITE_DELTA
From effafb6993a963b425dc8a4b8be162f5c510131d Mon Sep 17 00:00:00 2001
From: Andrey Volk
Date: Wed, 10 Mar 2021 16:10:54 +0300
Subject: [PATCH 096/655] [Core] switch_ivr_set_user_xml: Buffer is wrongly
truncated when it's small in get_prefixed_str()
---
src/switch_ivr.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/switch_ivr.c b/src/switch_ivr.c
index f1493a723d..97bece7c36 100644
--- a/src/switch_ivr.c
+++ b/src/switch_ivr.c
@@ -3861,7 +3861,7 @@ static const char *get_prefixed_str(char *buffer, size_t buffer_size, const char
if (str_len + prefix_size + 1 > buffer_size) {
memcpy(buffer + prefix_size, str, buffer_size - prefix_size - 1);
- buffer[buffer_size - prefix_size - 1] = '\0';
+ buffer[buffer_size - 1] = '\0';
} else {
memcpy(buffer + prefix_size, str, str_len + 1);
}
From 0cab42bfb6284aff2e25c611d0df142a8864ed6f Mon Sep 17 00:00:00 2001
From: Andrey Volk
Date: Fri, 12 Mar 2021 17:27:07 +0300
Subject: [PATCH 097/655] [Core] Hangup call instead of crashing system on
SSL_CTX_new failure. Improve logging.
---
src/switch_rtp.c | 27 +++++++++++++++++++++++----
1 file changed, 23 insertions(+), 4 deletions(-)
diff --git a/src/switch_rtp.c b/src/switch_rtp.c
index a461c9ba32..d75219c6cf 100644
--- a/src/switch_rtp.c
+++ b/src/switch_rtp.c
@@ -3732,6 +3732,10 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_add_dtls(switch_rtp_t *rtp_session, d
const char *var;
int ret;
const char *kind = "";
+ unsigned long ssl_method_error = 0;
+ unsigned long ssl_ctx_error = 0;
+ const SSL_METHOD *ssl_method;
+ SSL_CTX *ssl_ctx;
BIO *bio;
DH *dh;
switch_status_t status = SWITCH_STATUS_SUCCESS;
@@ -3787,14 +3791,29 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_add_dtls(switch_rtp_t *rtp_session, d
dtls->ca = switch_core_sprintf(rtp_session->pool, "%s%sca-bundle.crt", SWITCH_GLOBAL_dirs.certs_dir, SWITCH_PATH_SEPARATOR);
#if OPENSSL_VERSION_NUMBER >= 0x10100000
- dtls->ssl_ctx = SSL_CTX_new((type & DTLS_TYPE_SERVER) ? DTLS_server_method() : DTLS_client_method());
+ ssl_method = (type & DTLS_TYPE_SERVER) ? DTLS_server_method() : DTLS_client_method();
#else
#ifdef HAVE_OPENSSL_DTLSv1_2_method
- dtls->ssl_ctx = SSL_CTX_new((type & DTLS_TYPE_SERVER) ? (want_DTLSv1_2 ? DTLSv1_2_server_method() : DTLSv1_server_method()) : (want_DTLSv1_2 ? DTLSv1_2_client_method() : DTLSv1_client_method()));
- #else
- dtls->ssl_ctx = SSL_CTX_new((type & DTLS_TYPE_SERVER) ? DTLSv1_server_method() : DTLSv1_client_method());
+ ssl_method = (type & DTLS_TYPE_SERVER) ? (want_DTLSv1_2 ? DTLSv1_2_server_method() : DTLSv1_server_method()) : (want_DTLSv1_2 ? DTLSv1_2_client_method() : DTLSv1_client_method());
+ #else
+ ssl_method = (type & DTLS_TYPE_SERVER) ? DTLSv1_server_method() : DTLSv1_client_method();
#endif // HAVE_OPENSSL_DTLSv1_2_method
#endif
+
+ if (!ssl_method) {
+ ssl_method_error = ERR_peek_error();
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_ERROR, "%s ssl_method is NULL [%lu]\n", rtp_type(rtp_session), ssl_method_error);
+ }
+
+ dtls->ssl_ctx = ssl_ctx = SSL_CTX_new(ssl_method);
+
+ if (!ssl_ctx) {
+ ssl_ctx_error = ERR_peek_error();
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_ERROR, "%s SSL_CTX_new failed [%lu]\n", rtp_type(rtp_session), ssl_ctx_error);
+ switch_channel_hangup(switch_core_session_get_channel(rtp_session->session), SWITCH_CAUSE_NORMAL_TEMPORARY_FAILURE);
+ switch_goto_status(SWITCH_STATUS_FALSE, done);
+ }
+
switch_assert(dtls->ssl_ctx);
bio = BIO_new_file(dtls->pem, "r");
From e3a6ec86f8542b3ec059ed3e2ff26bc72f1a0fe2 Mon Sep 17 00:00:00 2001
From: Chris Rienzo
Date: Fri, 19 Mar 2021 02:28:40 +0300
Subject: [PATCH 098/655] [core] Update switch_ivr_enterprise_originate() to
accept optional switch_dial_handle_list_t instead of dialstring.
---
src/include/switch_ivr.h | 15 +-
src/include/switch_types.h | 4 +-
src/switch_ivr_originate.c | 348 +++++++++++++++++++++++++++++-
tests/unit/switch_ivr_originate.c | 190 ++++++++++++++++
4 files changed, 543 insertions(+), 14 deletions(-)
diff --git a/src/include/switch_ivr.h b/src/include/switch_ivr.h
index 34d6625541..09577152b4 100644
--- a/src/include/switch_ivr.h
+++ b/src/include/switch_ivr.h
@@ -1,6 +1,6 @@
/*
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
- * Copyright (C) 2005-2019, Anthony Minessale II
+ * Copyright (C) 2005-2021, Anthony Minessale II
*
* Version: MPL 1.1
*
@@ -525,7 +525,8 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_enterprise_originate(switch_core_sess
const char *cid_num_override,
switch_caller_profile_t *caller_profile_override,
switch_event_t *ovars, switch_originate_flag_t flags,
- switch_call_cause_t *cancel_cause);
+ switch_call_cause_t *cancel_cause,
+ switch_dial_handle_list_t *hl);
SWITCH_DECLARE(void) switch_ivr_bridge_display(switch_core_session_t *session, switch_core_session_t *peer_session);
@@ -1057,6 +1058,16 @@ SWITCH_DECLARE(switch_event_t *) switch_dial_handle_get_global_vars(switch_dial_
SWITCH_DECLARE(switch_event_t *) switch_dial_leg_get_vars(switch_dial_leg_t *leg);
SWITCH_DECLARE(const char *) switch_dial_leg_get_var(switch_dial_leg_t *leg, const char *key);
SWITCH_DECLARE(int) switch_dial_handle_get_total(switch_dial_handle_t *handle);
+SWITCH_DECLARE(switch_status_t) switch_dial_handle_list_serialize_json_obj(switch_dial_handle_list_t *hl, cJSON **json);
+SWITCH_DECLARE(switch_status_t) switch_dial_handle_list_serialize_json(switch_dial_handle_list_t *hl, char **str);
+SWITCH_DECLARE(switch_status_t) switch_dial_handle_list_create_json_obj(switch_dial_handle_list_t **handle, cJSON *json);
+SWITCH_DECLARE(switch_status_t) switch_dial_handle_list_create_json(switch_dial_handle_list_t **handle, const char *handle_string);
+SWITCH_DECLARE(switch_status_t) switch_dial_handle_list_create(switch_dial_handle_list_t **hl);
+SWITCH_DECLARE(switch_status_t) switch_dial_handle_list_create_handle(switch_dial_handle_list_t *hl, switch_dial_handle_t **handle);
+SWITCH_DECLARE(void) switch_dial_handle_list_destroy(switch_dial_handle_list_t **hl);
+SWITCH_DECLARE(void) switch_dial_handle_list_add_global_var(switch_dial_handle_list_t *hl, const char *var, const char *val);
+SWITCH_DECLARE(void) switch_dial_handle_list_add_global_var_printf(switch_dial_handle_list_t *hl, const char *var, const char *fmt, ...);
+SWITCH_DECLARE(switch_status_t) switch_ivr_enterprise_orig_and_bridge(switch_core_session_t *session, const char *data, switch_dial_handle_list_t *hl, switch_call_cause_t *cause);
SWITCH_DECLARE(switch_status_t) switch_ivr_orig_and_bridge(switch_core_session_t *session, const char *data, switch_dial_handle_t *dh, switch_call_cause_t *cause);
SWITCH_DECLARE(switch_status_t) switch_ivr_play_and_collect_input(switch_core_session_t *session,
diff --git a/src/include/switch_types.h b/src/include/switch_types.h
index 79ef9caa26..58f708729d 100644
--- a/src/include/switch_types.h
+++ b/src/include/switch_types.h
@@ -1,6 +1,6 @@
/*
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
- * Copyright (C) 2005-2015, Anthony Minessale II
+ * Copyright (C) 2005-2021, Anthony Minessale II
*
* Version: MPL 1.1
*
@@ -2868,6 +2868,8 @@ typedef struct switch_dial_leg_s switch_dial_leg_t;
struct switch_dial_leg_list_s;
typedef struct switch_dial_leg_list_s switch_dial_leg_list_t;
+struct switch_dial_handle_list_s;
+typedef struct switch_dial_handle_list_s switch_dial_handle_list_t;
SWITCH_END_EXTERN_C
#endif
diff --git a/src/switch_ivr_originate.c b/src/switch_ivr_originate.c
index d2baeb2741..d81ffcc357 100644
--- a/src/switch_ivr_originate.c
+++ b/src/switch_ivr_originate.c
@@ -1,6 +1,6 @@
/*
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
- * Copyright (C) 2005-2014, Anthony Minessale II
+ * Copyright (C) 2005-2021, Anthony Minessale II
*
* Version: MPL 1.1
*
@@ -106,6 +106,14 @@ struct switch_dial_handle_s {
switch_memory_pool_t *pool;
};
+struct switch_dial_handle_list_s {
+ int handle_idx;
+ switch_dial_handle_t *handles[MAX_PEERS];
+ switch_event_t *global_vars;
+ switch_memory_pool_t *pool;
+};
+
+static switch_status_t switch_dial_handle_dup(switch_dial_handle_t **handle, switch_dial_handle_t *todup);
typedef struct {
switch_core_session_t *down_session;
@@ -1451,6 +1459,7 @@ typedef struct {
int done;
switch_thread_t *thread;
switch_mutex_t *mutex;
+ switch_dial_handle_t *dh;
} enterprise_originate_handle_t;
@@ -1475,7 +1484,7 @@ static void *SWITCH_THREAD_FUNC enterprise_originate_thread(switch_thread_t *thr
handle->ovars,
handle->flags,
&handle->cancel_cause,
- NULL);
+ handle->dh);
handle->done = 1;
@@ -1541,7 +1550,8 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_enterprise_originate(switch_core_sess
const char *cid_num_override,
switch_caller_profile_t *caller_profile_override,
switch_event_t *ovars, switch_originate_flag_t flags,
- switch_call_cause_t *cancel_cause)
+ switch_call_cause_t *cancel_cause,
+ switch_dial_handle_list_t *hl)
{
int x_argc = 0;
char *x_argv[MAX_PEERS] = { 0 };
@@ -1549,7 +1559,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_enterprise_originate(switch_core_sess
int i;
switch_caller_profile_t *cp = NULL;
switch_channel_t *channel = NULL;
- char *data;
+ char *data = NULL;
switch_status_t status = SWITCH_STATUS_FALSE;
switch_threadattr_t *thd_attr = NULL;
int running = 0, over = 0;
@@ -1565,13 +1575,15 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_enterprise_originate(switch_core_sess
switch_core_new_memory_pool(&pool);
- if (zstr(bridgeto)) {
+ if (zstr(bridgeto) && (!hl || hl->handle_idx == 0)) {
*cause = SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
getcause = 0;
switch_goto_status(SWITCH_STATUS_FALSE, end);
}
- data = switch_core_strdup(pool, bridgeto);
+ if (!hl) {
+ data = switch_core_strdup(pool, bridgeto);
+ }
if (session) {
switch_caller_profile_t *cpp = NULL;
@@ -1632,6 +1644,9 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_enterprise_originate(switch_core_sess
data = parsed;
}
+ if (hl && hl->global_vars) {
+ switch_event_merge(var_event, hl->global_vars);
+ }
/* strip leading spaces (again) */
while (data && *data && *data == ' ') {
@@ -1646,10 +1661,14 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_enterprise_originate(switch_core_sess
switch_event_add_header_string(var_event, SWITCH_STACK_BOTTOM, "ignore_early_media", "true");
- if (!(x_argc = switch_separate_string_string(data, SWITCH_ENT_ORIGINATE_DELIM, x_argv, MAX_PEERS))) {
- *cause = SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
- getcause = 0;
- switch_goto_status(SWITCH_STATUS_FALSE, end);
+ if (data) {
+ if (!(x_argc = switch_separate_string_string(data, SWITCH_ENT_ORIGINATE_DELIM, x_argv, MAX_PEERS))) {
+ *cause = SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
+ getcause = 0;
+ switch_goto_status(SWITCH_STATUS_FALSE, end);
+ }
+ } else {
+ x_argc = hl->handle_idx;
}
switch_threadattr_create(&thd_attr, pool);
@@ -1668,6 +1687,9 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_enterprise_originate(switch_core_sess
handles[i].caller_profile_override = cp;
switch_event_dup(&handles[i].ovars, var_event);
handles[i].flags = flags;
+ if (hl) {
+ switch_dial_handle_dup(&handles[i].dh, hl->handles[i]);
+ }
switch_mutex_init(&handles[i].mutex, SWITCH_MUTEX_NESTED, pool);
switch_mutex_lock(handles[i].mutex);
switch_thread_create(&handles[i].thread, thd_attr, enterprise_originate_thread, &handles[i], pool);
@@ -1756,6 +1778,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_enterprise_originate(switch_core_sess
switch_mutex_unlock(hp->mutex);
switch_thread_join(&tstatus, hp->thread);
switch_event_destroy(&hp->ovars);
+ switch_dial_handle_destroy(&hp->dh);
}
for (i = 0; i < x_argc; i++) {
@@ -1789,6 +1812,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_enterprise_originate(switch_core_sess
switch_thread_join(&tstatus, handles[i].thread);
switch_event_destroy(&handles[i].ovars);
+ switch_dial_handle_destroy(&handles[i].dh);
}
if (channel && rb_data.thread) {
@@ -2078,7 +2102,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess
if (strstr(bridgeto, SWITCH_ENT_ORIGINATE_DELIM)) {
return switch_ivr_enterprise_originate(session, bleg, cause, bridgeto, timelimit_sec, table, cid_name_override, cid_num_override,
- caller_profile_override, ovars, flags, cancel_cause);
+ caller_profile_override, ovars, flags, cancel_cause, NULL);
}
oglobals.check_vars = SWITCH_TRUE;
@@ -4234,6 +4258,133 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess
return status;
}
+SWITCH_DECLARE(switch_status_t) switch_dial_handle_list_create(switch_dial_handle_list_t **hl)
+{
+ switch_dial_handle_list_t *hlP = NULL;
+ switch_memory_pool_t *pool = NULL;
+
+ switch_core_new_memory_pool(&pool);
+ switch_assert(pool);
+
+ hlP = switch_core_alloc(pool, sizeof(*hlP));
+ switch_assert(hlP);
+
+ hlP->pool = pool;
+
+ *hl = hlP;
+
+ return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t switch_dial_handle_list_add_handle(switch_dial_handle_list_t *hl, switch_dial_handle_t *handle)
+{
+ if (hl->handle_idx < MAX_PEERS && handle) {
+ hl->handles[hl->handle_idx++] = handle;
+ return SWITCH_STATUS_SUCCESS;
+ }
+ return SWITCH_STATUS_FALSE;
+}
+
+SWITCH_DECLARE(switch_status_t) switch_dial_handle_list_create_handle(switch_dial_handle_list_t *hl, switch_dial_handle_t **handle)
+{
+ switch_dial_handle_t *hp = NULL;
+ if (hl->handle_idx < MAX_PEERS && switch_dial_handle_create(&hp) == SWITCH_STATUS_SUCCESS && hp) {
+ hl->handles[hl->handle_idx++] = hp;
+ *handle = hp;
+ return SWITCH_STATUS_SUCCESS;
+ }
+ return SWITCH_STATUS_FALSE;
+}
+
+SWITCH_DECLARE(void) switch_dial_handle_list_destroy(switch_dial_handle_list_t **hl)
+{
+ switch_dial_handle_list_t *hlP = *hl;
+ switch_memory_pool_t *pool = NULL;
+
+ *hl = NULL;
+
+ if (hlP) {
+ int i;
+ for (i = 0; i < hlP->handle_idx; i++) {
+ switch_dial_handle_destroy(&hlP->handles[i]);
+ }
+
+ switch_event_destroy(&hlP->global_vars);
+ pool = hlP->pool;
+ hlP = NULL;
+ switch_core_destroy_memory_pool(&pool);
+ }
+}
+
+SWITCH_DECLARE(void) switch_dial_handle_list_add_global_var(switch_dial_handle_list_t *hl, const char *var, const char *val)
+{
+ switch_assert(hl);
+
+ if (!hl->global_vars) {
+ switch_event_create_plain(&hl->global_vars, SWITCH_EVENT_CHANNEL_DATA);
+ }
+
+ switch_event_add_header_string(hl->global_vars, SWITCH_STACK_BOTTOM, var, val);
+}
+
+SWITCH_DECLARE(void) switch_dial_handle_list_add_global_var_printf(switch_dial_handle_list_t *hl, const char *var, const char *fmt, ...)
+{
+ int ret = 0;
+ char *data = NULL;
+ va_list ap;
+
+ va_start(ap, fmt);
+ ret = switch_vasprintf(&data, fmt, ap);
+ va_end(ap);
+
+ if (ret == -1) {
+ abort();
+ }
+
+ switch_dial_handle_list_add_global_var(hl, var, data);
+ free(data);
+}
+
+static switch_status_t switch_dial_handle_dup(switch_dial_handle_t **handle, switch_dial_handle_t *todup)
+{
+ int i;
+ switch_dial_handle_t *hp;
+
+ if (!todup || !handle) {
+ return SWITCH_STATUS_FALSE;
+ }
+
+ *handle = NULL;
+
+ switch_dial_handle_create(&hp);
+ switch_assert(hp);
+
+ for (i = 0; i < todup->leg_list_idx; i++) {
+ int j;
+ switch_dial_leg_list_t *ll_todup = todup->leg_lists[i];
+ switch_dial_leg_list_t *ll = NULL;
+ switch_dial_handle_add_leg_list(hp, &ll);
+ for (j = 0; j < ll_todup->leg_idx; j++) {
+ switch_dial_leg_t *leg;
+ switch_dial_leg_t *leg_todup = ll_todup->legs[j];
+ switch_dial_leg_list_add_leg(ll, &leg, leg_todup->dial_string);
+ if (leg_todup->leg_vars) {
+ switch_event_dup(&leg->leg_vars, leg_todup->leg_vars);
+ }
+ }
+ }
+
+ if (todup->global_vars) {
+ switch_event_dup(&hp->global_vars, todup->global_vars);
+ }
+
+ hp->is_sub = todup->is_sub;
+
+ *handle = hp;
+
+ return SWITCH_STATUS_SUCCESS;
+}
+
SWITCH_DECLARE(switch_status_t) switch_dial_handle_create(switch_dial_handle_t **handle)
{
switch_dial_handle_t *hp;
@@ -4605,6 +4756,115 @@ SWITCH_DECLARE(switch_status_t) switch_dial_handle_create_json(switch_dial_handl
}
+SWITCH_DECLARE(switch_status_t) switch_dial_handle_list_serialize_json_obj(switch_dial_handle_list_t *hl, cJSON **json)
+{
+ int i;
+ cJSON *global_vars_json = NULL;
+ cJSON *handles_json = NULL;
+ if (!hl) {
+ return SWITCH_STATUS_FALSE;
+ }
+ *json = cJSON_CreateObject();
+ if (hl->global_vars && vars_serialize_json_obj(hl->global_vars, &global_vars_json) == SWITCH_STATUS_SUCCESS && global_vars_json) {
+ cJSON_AddItemToObject(*json, "vars", global_vars_json);
+ }
+
+ handles_json = cJSON_CreateArray();
+ cJSON_AddItemToObject(*json, "handles", handles_json);
+ for (i = 0; i < hl->handle_idx; i++) {
+ switch_dial_handle_t *handle = hl->handles[i];
+ cJSON *handle_json = NULL;
+ if (switch_dial_handle_serialize_json_obj(handle, &handle_json) == SWITCH_STATUS_SUCCESS && handle_json) {
+ cJSON_AddItemToArray(handles_json, handle_json);
+ }
+ }
+
+ return SWITCH_STATUS_SUCCESS;
+}
+
+
+SWITCH_DECLARE(switch_status_t) switch_dial_handle_list_serialize_json(switch_dial_handle_list_t *hl, char **str)
+{
+ cJSON *json = NULL;
+ if (switch_dial_handle_list_serialize_json_obj(hl, &json) == SWITCH_STATUS_SUCCESS && json) {
+ *str = cJSON_PrintUnformatted(json);
+ cJSON_Delete(json);
+ return SWITCH_STATUS_SUCCESS;
+ }
+ return SWITCH_STATUS_FALSE;
+}
+
+
+SWITCH_DECLARE(switch_status_t) switch_dial_handle_list_create_json_obj(switch_dial_handle_list_t **hl, cJSON *handle_list_json)
+{
+ cJSON *handle_json = NULL;
+ cJSON *handles_json = NULL;
+ cJSON *vars_json = NULL;
+
+ *hl = NULL;
+
+ handles_json = cJSON_GetObjectItem(handle_list_json, "handles");
+ if (!handles_json || !cJSON_IsArray(handles_json)) {
+ return SWITCH_STATUS_FALSE;
+ }
+ switch_dial_handle_list_create(hl);
+ switch_assert(*hl);
+ for (handle_json = handles_json->child; handle_json; handle_json = handle_json->next) {
+ switch_dial_handle_t *handle = NULL;
+ if (switch_dial_handle_create_json_obj(&handle, handle_json) == SWITCH_STATUS_SUCCESS && handle) {
+ if (switch_dial_handle_list_add_handle(*hl, handle) != SWITCH_STATUS_SUCCESS) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Not adding remaining dial handles: exceeded limit of %d handles\n", MAX_PEERS);
+ switch_dial_handle_destroy(&handle);
+ break;
+ }
+ } else {
+ char *handle_json_str = cJSON_PrintUnformatted(handle_json);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Failed to create dial handle: %s\n", handle_json_str);
+ switch_safe_free(handle_json_str);
+ }
+ }
+
+ if ((*hl)->handle_idx == 0) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Failed to create dial handle list: no handles added!\n");
+ switch_dial_handle_list_destroy(hl);
+ return SWITCH_STATUS_FALSE;
+ }
+
+ vars_json = cJSON_GetObjectItem(handle_list_json, "vars");
+ if (vars_json && vars_json->type == cJSON_Object) {
+ cJSON *var_json = NULL;
+ cJSON_ArrayForEach(var_json, vars_json) {
+ if (!var_json || var_json->type != cJSON_String || !var_json->valuestring || !var_json->string) {
+ continue;
+ }
+ switch_dial_handle_list_add_global_var(*hl, var_json->string, var_json->valuestring);
+ }
+ }
+
+ return SWITCH_STATUS_SUCCESS;
+}
+
+
+SWITCH_DECLARE(switch_status_t) switch_dial_handle_list_create_json(switch_dial_handle_list_t **hl, const char *handle_list_string)
+{
+ switch_status_t status;
+ cJSON *handle_list_json = NULL;
+
+ if (zstr(handle_list_string)) {
+ return SWITCH_STATUS_FALSE;
+ }
+
+ handle_list_json = cJSON_Parse(handle_list_string);
+ if (!handle_list_json) {
+ return SWITCH_STATUS_FALSE;
+ }
+
+ status = switch_dial_handle_list_create_json_obj(hl, handle_list_json);
+ cJSON_Delete(handle_list_json);
+ return status;
+}
+
+
static switch_status_t o_bridge_on_dtmf(switch_core_session_t *session, void *input, switch_input_type_t itype, void *buf, unsigned int buflen)
{
char *str = (char *) buf;
@@ -4618,6 +4878,72 @@ static switch_status_t o_bridge_on_dtmf(switch_core_session_t *session, void *in
return SWITCH_STATUS_SUCCESS;
}
+
+SWITCH_DECLARE(switch_status_t) switch_ivr_enterprise_orig_and_bridge(switch_core_session_t *session, const char *data, switch_dial_handle_list_t *hl, switch_call_cause_t *cause)
+{
+ switch_channel_t *caller_channel = switch_core_session_get_channel(session);
+ switch_core_session_t *peer_session = NULL;
+ switch_status_t status = SWITCH_STATUS_FALSE;
+ int fail = 0;
+
+ if ((status = switch_ivr_enterprise_originate(session,
+ &peer_session,
+ cause, data, 0, NULL, NULL, NULL, NULL, NULL, SOF_NONE, NULL, hl)) != SWITCH_STATUS_SUCCESS) {
+ fail = 1;
+ }
+
+
+ if (fail) {
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "Originate Failed. Cause: %s\n", switch_channel_cause2str(*cause));
+
+ switch_channel_set_variable(caller_channel, "originate_failed_cause", switch_channel_cause2str(*cause));
+
+ switch_channel_handle_cause(caller_channel, *cause);
+
+ return status;
+ } else {
+ switch_channel_t *peer_channel = switch_core_session_get_channel(peer_session);
+
+ if (switch_true(switch_channel_get_variable(caller_channel, SWITCH_BYPASS_MEDIA_AFTER_BRIDGE_VARIABLE)) ||
+ switch_true(switch_channel_get_variable(peer_channel, SWITCH_BYPASS_MEDIA_AFTER_BRIDGE_VARIABLE))) {
+ switch_channel_set_flag(caller_channel, CF_BYPASS_MEDIA_AFTER_BRIDGE);
+ }
+
+ if (switch_channel_test_flag(caller_channel, CF_PROXY_MODE)) {
+ switch_ivr_signal_bridge(session, peer_session);
+ } else {
+ char *a_key = (char *) switch_channel_get_variable(caller_channel, "bridge_terminate_key");
+ char *b_key = (char *) switch_channel_get_variable(peer_channel, "bridge_terminate_key");
+ int ok = 0;
+ switch_input_callback_function_t func = NULL;
+
+ if (a_key) {
+ a_key = switch_core_session_strdup(session, a_key);
+ ok++;
+ }
+ if (b_key) {
+ b_key = switch_core_session_strdup(session, b_key);
+ ok++;
+ }
+ if (ok) {
+ func = o_bridge_on_dtmf;
+ } else {
+ a_key = NULL;
+ b_key = NULL;
+ }
+
+ switch_ivr_multi_threaded_bridge(session, peer_session, func, a_key, b_key);
+ }
+
+ if (peer_session) {
+ switch_core_session_rwunlock(peer_session);
+ }
+ }
+
+ return status;
+}
+
+
SWITCH_DECLARE(switch_status_t) switch_ivr_orig_and_bridge(switch_core_session_t *session, const char *data, switch_dial_handle_t *dh, switch_call_cause_t *cause)
{
switch_channel_t *caller_channel = switch_core_session_get_channel(session);
diff --git a/tests/unit/switch_ivr_originate.c b/tests/unit/switch_ivr_originate.c
index 9369506b13..6c34fcc1e8 100644
--- a/tests/unit/switch_ivr_originate.c
+++ b/tests/unit/switch_ivr_originate.c
@@ -209,6 +209,99 @@ FST_CORE_BEGIN("./conf")
}
FST_TEST_END();
+ FST_TEST_BEGIN(dial_handle_list_create_json)
+ {
+ const char *dh_str_1 = "{\n"
+ " \"vars\": {\n"
+ " \"foo\": \"bar\",\n"
+ " \"absolute_codec_string\": \"pcmu,pcma\",\n"
+ " \"ignore_early_media\": \"true\"\n"
+ " },\n"
+ " \"leg_lists\": [\n"
+ " { \"legs\": [\n"
+ " { \n"
+ " \"dial_string\": \"loopback/dest2\", \n"
+ " \"vars\": {\n"
+ " \"bar\": \"bar\"\n"
+ " }\n"
+ " },\n"
+ " { \n"
+ " \"dial_string\": \"sofia/gateway/gw/123456\"\n"
+ " }\n"
+ " ] },\n"
+ " { \"legs\": [\n"
+ " {\n"
+ " \"dial_string\": \"sofia/external/foo@example.com^5551231234\",\n"
+ " \"vars\": {\n"
+ " \"sip_h_X-Custom\": \"my val 2\"\n"
+ " }\n"
+ " }\n"
+ " ] },\n"
+ " { \"legs\": [\n"
+ " {\n"
+ " \"dial_string\": \"group/my_group_2\"\n"
+ " }\n"
+ " ] }\n"
+ " ]\n"
+ "}";
+ const char *dh_str_2 = "{\n"
+ " \"vars\": {\n"
+ " \"foo\": \"bar\",\n"
+ " \"absolute_codec_string\": \"opus,pcmu,pcma\",\n"
+ " \"ignore_early_media\": \"true\"\n"
+ " },\n"
+ " \"leg_lists\": [\n"
+ " { \"legs\": [\n"
+ " { \n"
+ " \"dial_string\": \"loopback/dest\", \n"
+ " \"vars\": {\n"
+ " \"bar\": \"bar\"\n"
+ " }\n"
+ " },\n"
+ " { \n"
+ " \"dial_string\": \"sofia/gateway/gw/12345\"\n"
+ " }\n"
+ " ] },\n"
+ " { \"legs\": [\n"
+ " {\n"
+ " \"dial_string\": \"sofia/external/foo@example.com^5551231234\",\n"
+ " \"vars\": {\n"
+ " \"sip_h_X-Custom\": \"my val\"\n"
+ " }\n"
+ " }\n"
+ " ] },\n"
+ " { \"legs\": [\n"
+ " {\n"
+ " \"dial_string\": \"group/my_group\"\n"
+ " }\n"
+ " ] }\n"
+ " ]\n"
+ "}";
+ const char *dl_str = switch_core_sprintf(fst_pool, "{ \"handles\": [ %s, %s ], \"vars\": { \"global_1\":\"val_1\" } }", dh_str_1, dh_str_2);
+ // create dial handle from json string, convert back to json and compare
+ switch_dial_handle_list_t *dl = NULL;
+ char *dl_str_2 = NULL;
+ char *dl_str_3 = NULL;
+ cJSON *dl_json = NULL;
+ fst_requires(switch_dial_handle_list_create_json(&dl, dl_str) == SWITCH_STATUS_SUCCESS);
+ fst_requires(dl != NULL);
+ fst_requires(switch_dial_handle_list_serialize_json_obj(dl, &dl_json) == SWITCH_STATUS_SUCCESS);
+ fst_requires(dl_json != NULL);
+ fst_requires(switch_dial_handle_list_serialize_json(dl, &dl_str_2) == SWITCH_STATUS_SUCCESS);
+ fst_requires(dl_str_2 != NULL);
+ fst_check_string_equals(dl_str_2, "{\"vars\":{\"global_1\":\"val_1\"},\"handles\":[{\"vars\":{\"foo\":\"bar\",\"absolute_codec_string\":\"pcmu,pcma\",\"ignore_early_media\":\"true\"},\"leg_lists\":[{\"legs\":[{\"dial_string\":\"loopback/dest2\",\"vars\":{\"bar\":\"bar\"}},{\"dial_string\":\"sofia/gateway/gw/123456\"}]},{\"legs\":[{\"dial_string\":\"sofia/external/foo@example.com^5551231234\",\"vars\":{\"sip_h_X-Custom\":\"my val 2\"}}]},{\"legs\":[{\"dial_string\":\"group/my_group_2\"}]}]},{\"vars\":{\"foo\":\"bar\",\"absolute_codec_string\":\"opus,pcmu,pcma\",\"ignore_early_media\":\"true\"},\"leg_lists\":[{\"legs\":[{\"dial_string\":\"loopback/dest\",\"vars\":{\"bar\":\"bar\"}},{\"dial_string\":\"sofia/gateway/gw/12345\"}]},{\"legs\":[{\"dial_string\":\"sofia/external/foo@example.com^5551231234\",\"vars\":{\"sip_h_X-Custom\":\"my val\"}}]},{\"legs\":[{\"dial_string\":\"group/my_group\"}]}]}]}");
+
+ dl_str_3 = cJSON_PrintUnformatted(dl_json);
+ fst_requires(dl_str_3);
+ fst_check_string_equals(dl_str_2, dl_str_3);
+
+ switch_safe_free(dl_str_2);
+ switch_safe_free(dl_str_3);
+ cJSON_Delete(dl_json);
+ switch_dial_handle_list_destroy(&dl);
+ }
+ FST_TEST_END();
+
FST_TEST_BEGIN(originate_test_empty_dial_string)
{
switch_core_session_t *session = NULL;
@@ -622,6 +715,103 @@ FST_CORE_BEGIN("./conf")
fst_check_duration(4500, 600); // (>= 3.9 sec, <= 5.1 sec)
}
FST_TEST_END()
+
+ FST_TEST_BEGIN(enterprise_originate_test_group_confirm_two_handles)
+ {
+ switch_core_session_t *session = NULL;
+ switch_status_t status;
+ switch_call_cause_t cause;
+ switch_dial_handle_list_t *dl;
+ switch_dial_handle_t *dh;
+ switch_dial_leg_list_t *ll;
+ switch_dial_leg_t *leg = NULL;
+
+ switch_dial_handle_list_create(&dl);
+
+ switch_dial_handle_list_create_handle(dl, &dh);
+ switch_dial_handle_add_leg_list(dh, &ll);
+ switch_dial_leg_list_add_leg(ll, &leg, "null/test");
+ switch_dial_handle_add_leg_var(leg, "group_confirm_file", "playback silence_stream://1000");
+ switch_dial_handle_add_leg_var(leg, "group_confirm_key", "exec");
+ switch_dial_handle_add_leg_var(leg, "expected_winner", "true");
+
+ switch_dial_handle_list_create_handle(dl, &dh);
+ switch_dial_handle_add_leg_list(dh, &ll);
+ switch_dial_leg_list_add_leg(ll, &leg, "error/user_busy");
+
+ switch_dial_handle_list_add_global_var(dl, "continue_on_fail", "true");
+ switch_dial_handle_list_add_global_var(dl, "is_from_dial_handle_list", "true");
+
+ status = switch_ivr_enterprise_originate(NULL, &session, &cause, NULL, 0, NULL, NULL, NULL, NULL, NULL, SOF_NONE, NULL, dl);
+ fst_requires(status == SWITCH_STATUS_SUCCESS);
+ fst_requires(session);
+ fst_xcheck(switch_true(switch_channel_get_variable(switch_core_session_get_channel(session), "is_from_dial_handle_list")), "Expect dial handle list global var to be set on channel");
+ fst_xcheck(switch_true(switch_channel_get_variable(switch_core_session_get_channel(session), "expected_winner")), "Wrong winning leg");
+ switch_channel_hangup(switch_core_session_get_channel(session), SWITCH_CAUSE_NORMAL_CLEARING);
+ switch_core_session_rwunlock(session);
+ switch_dial_handle_list_destroy(&dl);
+ }
+ FST_TEST_END()
+
+ FST_SESSION_BEGIN(switch_ivr_enterprise_orig_and_bridge)
+ {
+ switch_status_t status;
+ switch_call_cause_t cause = SWITCH_CAUSE_NONE;
+ switch_dial_handle_list_t *dl;
+ switch_dial_handle_t *dh;
+ switch_dial_leg_list_t *ll;
+ switch_dial_leg_t *leg = NULL;
+
+ switch_dial_handle_list_create(&dl);
+
+ switch_dial_handle_list_create_handle(dl, &dh);
+ switch_dial_handle_add_leg_list(dh, &ll);
+ switch_dial_leg_list_add_leg(ll, &leg, "null/test");
+ switch_dial_handle_add_leg_var(leg, "execute_on_answer", "sched_hangup +2 normal_clearing");
+
+ switch_dial_handle_list_create_handle(dl, &dh);
+ switch_dial_handle_add_leg_list(dh, &ll);
+ switch_dial_leg_list_add_leg(ll, &leg, "error/user_busy");
+
+ switch_dial_handle_list_add_global_var(dl, "continue_on_fail", "true");
+ switch_dial_handle_list_add_global_var(dl, "is_from_dial_handle_list", "true");
+
+ switch_channel_set_variable(fst_channel, "park_after_bridge", "true");
+ status = switch_ivr_enterprise_orig_and_bridge(fst_session, NULL, dl, &cause);
+ fst_xcheck(status == SWITCH_STATUS_SUCCESS, "Expect switch_ivr_enterprise_orig_and_bridge() to succeed");
+ fst_xcheck(cause == SWITCH_CAUSE_SUCCESS, "Expect called party to answer");
+ switch_dial_handle_list_destroy(&dl);
+ }
+ FST_SESSION_END()
+
+ FST_SESSION_BEGIN(switch_ivr_enterprise_orig_and_bridge_fail)
+ {
+ switch_status_t status;
+ switch_call_cause_t cause = SWITCH_CAUSE_NONE;
+ switch_dial_handle_list_t *dl;
+ switch_dial_handle_t *dh;
+ switch_dial_leg_list_t *ll;
+ switch_dial_leg_t *leg = NULL;
+
+ switch_dial_handle_list_create(&dl);
+
+ switch_dial_handle_list_create_handle(dl, &dh);
+ switch_dial_handle_add_leg_list(dh, &ll);
+ switch_dial_leg_list_add_leg(ll, &leg, "error/no_answer");
+
+ switch_dial_handle_list_create_handle(dl, &dh);
+ switch_dial_handle_add_leg_list(dh, &ll);
+ switch_dial_leg_list_add_leg(ll, &leg, "error/user_busy");
+
+ switch_dial_handle_list_add_global_var(dl, "continue_on_fail", "true");
+
+ switch_channel_set_variable(fst_channel, "park_after_bridge", "true");
+ status = switch_ivr_enterprise_orig_and_bridge(fst_session, NULL, dl, &cause);
+ fst_xcheck(status == SWITCH_STATUS_FALSE, "Expect switch_ivr_enterprise_orig_and_bridge() to fail");
+ fst_xcheck(cause == SWITCH_CAUSE_USER_BUSY || cause == SWITCH_CAUSE_NO_ANSWER, "Expect called party not to answer");
+ switch_dial_handle_list_destroy(&dl);
+ }
+ FST_SESSION_END()
}
FST_SUITE_END()
}
From 877102d4b9d66ddf90ec3e7443c9662ca474c7eb Mon Sep 17 00:00:00 2001
From: Andrey Volk
Date: Tue, 23 Mar 2021 17:33:46 +0000
Subject: [PATCH 099/655] swigall
---
.../src/org/freeswitch/swig/Event.java | 4 +
.../org/freeswitch/swig/freeswitchJNI.java | 1 +
.../languages/mod_java/switch_swig_wrap.cpp | 18 ++
src/mod/languages/mod_lua/mod_lua_wrap.cpp | 32 +++
.../languages/mod_managed/freeswitch_wrap.cxx | 229 +++++++++++++++++-
src/mod/languages/mod_managed/managed/swig.cs | 186 +++++++++++++-
src/mod/languages/mod_perl/freeswitch.pm | 1 +
src/mod/languages/mod_perl/mod_perl_wrap.cpp | 39 +++
src/mod/languages/mod_python/freeswitch.py | 3 +
.../languages/mod_python/mod_python_wrap.cpp | 32 +++
10 files changed, 539 insertions(+), 6 deletions(-)
diff --git a/src/mod/languages/mod_java/src/org/freeswitch/swig/Event.java b/src/mod/languages/mod_java/src/org/freeswitch/swig/Event.java
index fd2c933b20..5c3961dc8c 100644
--- a/src/mod/languages/mod_java/src/org/freeswitch/swig/Event.java
+++ b/src/mod/languages/mod_java/src/org/freeswitch/swig/Event.java
@@ -112,4 +112,8 @@ public class Event {
return freeswitchJNI.Event_fire(swigCPtr, this);
}
+ public boolean merge(Event to_merge) {
+ return freeswitchJNI.Event_merge(swigCPtr, this, Event.getCPtr(to_merge), to_merge);
+ }
+
}
diff --git a/src/mod/languages/mod_java/src/org/freeswitch/swig/freeswitchJNI.java b/src/mod/languages/mod_java/src/org/freeswitch/swig/freeswitchJNI.java
index cceea3402a..37786aff1a 100644
--- a/src/mod/languages/mod_java/src/org/freeswitch/swig/freeswitchJNI.java
+++ b/src/mod/languages/mod_java/src/org/freeswitch/swig/freeswitchJNI.java
@@ -71,6 +71,7 @@ public class freeswitchJNI {
public final static native boolean Event_addHeader(long jarg1, Event jarg1_, String jarg2, String jarg3);
public final static native boolean Event_delHeader(long jarg1, Event jarg1_, String jarg2);
public final static native boolean Event_fire(long jarg1, Event jarg1_);
+ public final static native boolean Event_merge(long jarg1, Event jarg1_, long jarg2, Event jarg2_);
public final static native void EventConsumer_events_set(long jarg1, EventConsumer jarg1_, long jarg2);
public final static native long EventConsumer_events_get(long jarg1, EventConsumer jarg1_);
public final static native void EventConsumer_e_event_id_set(long jarg1, EventConsumer jarg1_, long jarg2);
diff --git a/src/mod/languages/mod_java/switch_swig_wrap.cpp b/src/mod/languages/mod_java/switch_swig_wrap.cpp
index f1b004dece..efd0211940 100644
--- a/src/mod/languages/mod_java/switch_swig_wrap.cpp
+++ b/src/mod/languages/mod_java/switch_swig_wrap.cpp
@@ -1450,6 +1450,24 @@ SWIGEXPORT jboolean JNICALL Java_org_freeswitch_swig_freeswitchJNI_Event_1fire(J
}
+SWIGEXPORT jboolean JNICALL Java_org_freeswitch_swig_freeswitchJNI_Event_1merge(JNIEnv *jenv, jclass jcls, jlong jarg1, jobject jarg1_, jlong jarg2, jobject jarg2_) {
+ jboolean jresult = 0 ;
+ Event *arg1 = (Event *) 0 ;
+ Event *arg2 = (Event *) 0 ;
+ bool result;
+
+ (void)jenv;
+ (void)jcls;
+ (void)jarg1_;
+ (void)jarg2_;
+ arg1 = *(Event **)&jarg1;
+ arg2 = *(Event **)&jarg2;
+ result = (bool)(arg1)->merge(arg2);
+ jresult = (jboolean)result;
+ return jresult;
+}
+
+
SWIGEXPORT void JNICALL Java_org_freeswitch_swig_freeswitchJNI_EventConsumer_1events_1set(JNIEnv *jenv, jclass jcls, jlong jarg1, jobject jarg1_, jlong jarg2) {
EventConsumer *arg1 = (EventConsumer *) 0 ;
switch_queue_t *arg2 = (switch_queue_t *) 0 ;
diff --git a/src/mod/languages/mod_lua/mod_lua_wrap.cpp b/src/mod/languages/mod_lua/mod_lua_wrap.cpp
index a54f1faf68..7d91ba33ba 100644
--- a/src/mod/languages/mod_lua/mod_lua_wrap.cpp
+++ b/src/mod/languages/mod_lua/mod_lua_wrap.cpp
@@ -4961,6 +4961,37 @@ fail:
}
+static int _wrap_Event_merge(lua_State* L) {
+ int SWIG_arg = 0;
+ Event *arg1 = (Event *) 0 ;
+ Event *arg2 = (Event *) 0 ;
+ bool result;
+
+ SWIG_check_num_args("Event::merge",2,2)
+ if(!SWIG_isptrtype(L,1)) SWIG_fail_arg("Event::merge",1,"Event *");
+ if(!SWIG_isptrtype(L,2)) SWIG_fail_arg("Event::merge",2,"Event *");
+
+ if (!SWIG_IsOK(SWIG_ConvertPtr(L,1,(void**)&arg1,SWIGTYPE_p_Event,0))){
+ SWIG_fail_ptr("Event_merge",1,SWIGTYPE_p_Event);
+ }
+
+
+ if (!SWIG_IsOK(SWIG_ConvertPtr(L,2,(void**)&arg2,SWIGTYPE_p_Event,0))){
+ SWIG_fail_ptr("Event_merge",2,SWIGTYPE_p_Event);
+ }
+
+ result = (bool)(arg1)->merge(arg2);
+ lua_pushboolean(L,(int)(result!=0)); SWIG_arg++;
+ return SWIG_arg;
+
+ if(0) SWIG_fail;
+
+fail:
+ lua_error(L);
+ return SWIG_arg;
+}
+
+
static void swig_delete_Event(void *obj) {
Event *arg1 = (Event *) obj;
delete arg1;
@@ -4991,6 +5022,7 @@ static swig_lua_method swig_Event_methods[]= {
{ "addHeader", _wrap_Event_addHeader},
{ "delHeader", _wrap_Event_delHeader},
{ "fire", _wrap_Event_fire},
+ { "merge", _wrap_Event_merge},
{0,0}
};
static swig_lua_method swig_Event_meta[] = {
diff --git a/src/mod/languages/mod_managed/freeswitch_wrap.cxx b/src/mod/languages/mod_managed/freeswitch_wrap.cxx
index 7ecadca826..378be590e6 100644
--- a/src/mod/languages/mod_managed/freeswitch_wrap.cxx
+++ b/src/mod/languages/mod_managed/freeswitch_wrap.cxx
@@ -14551,6 +14551,22 @@ SWIGEXPORT void SWIGSTDCALL CSharp_FreeSWITCHfNative_switch_core_session_reset__
}
+SWIGEXPORT int SWIGSTDCALL CSharp_FreeSWITCHfNative_switch_core_session_try_reset___(void * jarg1, int jarg2, int jarg3) {
+ int jresult ;
+ switch_core_session_t *arg1 = (switch_core_session_t *) 0 ;
+ switch_bool_t arg2 ;
+ switch_bool_t arg3 ;
+ switch_status_t result;
+
+ arg1 = (switch_core_session_t *)jarg1;
+ arg2 = (switch_bool_t)jarg2;
+ arg3 = (switch_bool_t)jarg3;
+ result = (switch_status_t)switch_core_session_try_reset(arg1,arg2,arg3);
+ jresult = (int)result;
+ return jresult;
+}
+
+
SWIGEXPORT int SWIGSTDCALL CSharp_FreeSWITCHfNative_switch_core_session_write_frame___(void * jarg1, void * jarg2, unsigned long jarg3, int jarg4) {
int jresult ;
switch_core_session_t *arg1 = (switch_core_session_t *) 0 ;
@@ -15736,6 +15752,22 @@ SWIGEXPORT int SWIGSTDCALL CSharp_FreeSWITCHfNative_switch_core_file_pre_close__
}
+SWIGEXPORT int SWIGSTDCALL CSharp_FreeSWITCHfNative_switch_core_file_handle_dup___(void * jarg1, void * jarg2, void * jarg3) {
+ int jresult ;
+ switch_file_handle_t *arg1 = (switch_file_handle_t *) 0 ;
+ switch_file_handle_t **arg2 = (switch_file_handle_t **) 0 ;
+ switch_memory_pool_t *arg3 = (switch_memory_pool_t *) 0 ;
+ switch_status_t result;
+
+ arg1 = (switch_file_handle_t *)jarg1;
+ arg2 = (switch_file_handle_t **)jarg2;
+ arg3 = (switch_memory_pool_t *)jarg3;
+ result = (switch_status_t)switch_core_file_handle_dup(arg1,arg2,arg3);
+ jresult = (int)result;
+ return jresult;
+}
+
+
SWIGEXPORT int SWIGSTDCALL CSharp_FreeSWITCHfNative_switch_core_file_close___(void * jarg1) {
int jresult ;
switch_file_handle_t *arg1 = (switch_file_handle_t *) 0 ;
@@ -18554,6 +18586,18 @@ SWIGEXPORT int SWIGSTDCALL CSharp_FreeSWITCHfNative_switch_core_gen_certs___(cha
}
+SWIGEXPORT int SWIGSTDCALL CSharp_FreeSWITCHfNative_switch_core_check_dtls_pem___(char * jarg1) {
+ int jresult ;
+ char *arg1 = (char *) 0 ;
+ switch_bool_t result;
+
+ arg1 = (char *)jarg1;
+ result = (switch_bool_t)switch_core_check_dtls_pem((char const *)arg1);
+ jresult = (int)result;
+ return jresult;
+}
+
+
SWIGEXPORT int SWIGSTDCALL CSharp_FreeSWITCHfNative_switch_core_cert_gen_fingerprint___(char * jarg1, void * jarg2) {
int jresult ;
char *arg1 = (char *) 0 ;
@@ -41895,7 +41939,7 @@ SWIGEXPORT int SWIGSTDCALL CSharp_FreeSWITCHfNative_switch_ivr_originate___(void
}
-SWIGEXPORT int SWIGSTDCALL CSharp_FreeSWITCHfNative_switch_ivr_enterprise_originate___(void * jarg1, void * jarg2, void * jarg3, char * jarg4, unsigned long jarg5, void * jarg6, char * jarg7, char * jarg8, void * jarg9, void * jarg10, unsigned long jarg11, void * jarg12) {
+SWIGEXPORT int SWIGSTDCALL CSharp_FreeSWITCHfNative_switch_ivr_enterprise_originate___(void * jarg1, void * jarg2, void * jarg3, char * jarg4, unsigned long jarg5, void * jarg6, char * jarg7, char * jarg8, void * jarg9, void * jarg10, unsigned long jarg11, void * jarg12, void * jarg13) {
int jresult ;
switch_core_session_t *arg1 = (switch_core_session_t *) 0 ;
switch_core_session_t **arg2 = (switch_core_session_t **) 0 ;
@@ -41909,6 +41953,7 @@ SWIGEXPORT int SWIGSTDCALL CSharp_FreeSWITCHfNative_switch_ivr_enterprise_origin
switch_event_t *arg10 = (switch_event_t *) 0 ;
switch_originate_flag_t arg11 ;
switch_call_cause_t *arg12 = (switch_call_cause_t *) 0 ;
+ switch_dial_handle_list_t *arg13 = (switch_dial_handle_list_t *) 0 ;
switch_status_t result;
arg1 = (switch_core_session_t *)jarg1;
@@ -41923,7 +41968,8 @@ SWIGEXPORT int SWIGSTDCALL CSharp_FreeSWITCHfNative_switch_ivr_enterprise_origin
arg10 = (switch_event_t *)jarg10;
arg11 = (switch_originate_flag_t)jarg11;
arg12 = (switch_call_cause_t *)jarg12;
- result = (switch_status_t)switch_ivr_enterprise_originate(arg1,arg2,arg3,(char const *)arg4,arg5,(switch_state_handler_table const *)arg6,(char const *)arg7,(char const *)arg8,arg9,arg10,arg11,arg12);
+ arg13 = (switch_dial_handle_list_t *)jarg13;
+ result = (switch_status_t)switch_ivr_enterprise_originate(arg1,arg2,arg3,(char const *)arg4,arg5,(switch_state_handler_table const *)arg6,(char const *)arg7,(char const *)arg8,arg9,arg10,arg11,arg12,arg13);
jresult = (int)result;
return jresult;
}
@@ -43694,6 +43740,139 @@ SWIGEXPORT int SWIGSTDCALL CSharp_FreeSWITCHfNative_switch_dial_handle_get_total
}
+SWIGEXPORT int SWIGSTDCALL CSharp_FreeSWITCHfNative_switch_dial_handle_list_serialize_json_obj___(void * jarg1, void * jarg2) {
+ int jresult ;
+ switch_dial_handle_list_t *arg1 = (switch_dial_handle_list_t *) 0 ;
+ cJSON **arg2 = (cJSON **) 0 ;
+ switch_status_t result;
+
+ arg1 = (switch_dial_handle_list_t *)jarg1;
+ arg2 = (cJSON **)jarg2;
+ result = (switch_status_t)switch_dial_handle_list_serialize_json_obj(arg1,arg2);
+ jresult = (int)result;
+ return jresult;
+}
+
+
+SWIGEXPORT int SWIGSTDCALL CSharp_FreeSWITCHfNative_switch_dial_handle_list_serialize_json___(void * jarg1, void * jarg2) {
+ int jresult ;
+ switch_dial_handle_list_t *arg1 = (switch_dial_handle_list_t *) 0 ;
+ char **arg2 = (char **) 0 ;
+ switch_status_t result;
+
+ arg1 = (switch_dial_handle_list_t *)jarg1;
+ arg2 = (char **)jarg2;
+ result = (switch_status_t)switch_dial_handle_list_serialize_json(arg1,arg2);
+ jresult = (int)result;
+ return jresult;
+}
+
+
+SWIGEXPORT int SWIGSTDCALL CSharp_FreeSWITCHfNative_switch_dial_handle_list_create_json_obj___(void * jarg1, void * jarg2) {
+ int jresult ;
+ switch_dial_handle_list_t **arg1 = (switch_dial_handle_list_t **) 0 ;
+ cJSON *arg2 = (cJSON *) 0 ;
+ switch_status_t result;
+
+ arg1 = (switch_dial_handle_list_t **)jarg1;
+ arg2 = (cJSON *)jarg2;
+ result = (switch_status_t)switch_dial_handle_list_create_json_obj(arg1,arg2);
+ jresult = (int)result;
+ return jresult;
+}
+
+
+SWIGEXPORT int SWIGSTDCALL CSharp_FreeSWITCHfNative_switch_dial_handle_list_create_json___(void * jarg1, char * jarg2) {
+ int jresult ;
+ switch_dial_handle_list_t **arg1 = (switch_dial_handle_list_t **) 0 ;
+ char *arg2 = (char *) 0 ;
+ switch_status_t result;
+
+ arg1 = (switch_dial_handle_list_t **)jarg1;
+ arg2 = (char *)jarg2;
+ result = (switch_status_t)switch_dial_handle_list_create_json(arg1,(char const *)arg2);
+ jresult = (int)result;
+ return jresult;
+}
+
+
+SWIGEXPORT int SWIGSTDCALL CSharp_FreeSWITCHfNative_switch_dial_handle_list_create___(void * jarg1) {
+ int jresult ;
+ switch_dial_handle_list_t **arg1 = (switch_dial_handle_list_t **) 0 ;
+ switch_status_t result;
+
+ arg1 = (switch_dial_handle_list_t **)jarg1;
+ result = (switch_status_t)switch_dial_handle_list_create(arg1);
+ jresult = (int)result;
+ return jresult;
+}
+
+
+SWIGEXPORT int SWIGSTDCALL CSharp_FreeSWITCHfNative_switch_dial_handle_list_create_handle___(void * jarg1, void * jarg2) {
+ int jresult ;
+ switch_dial_handle_list_t *arg1 = (switch_dial_handle_list_t *) 0 ;
+ switch_dial_handle_t **arg2 = (switch_dial_handle_t **) 0 ;
+ switch_status_t result;
+
+ arg1 = (switch_dial_handle_list_t *)jarg1;
+ arg2 = (switch_dial_handle_t **)jarg2;
+ result = (switch_status_t)switch_dial_handle_list_create_handle(arg1,arg2);
+ jresult = (int)result;
+ return jresult;
+}
+
+
+SWIGEXPORT void SWIGSTDCALL CSharp_FreeSWITCHfNative_switch_dial_handle_list_destroy___(void * jarg1) {
+ switch_dial_handle_list_t **arg1 = (switch_dial_handle_list_t **) 0 ;
+
+ arg1 = (switch_dial_handle_list_t **)jarg1;
+ switch_dial_handle_list_destroy(arg1);
+}
+
+
+SWIGEXPORT void SWIGSTDCALL CSharp_FreeSWITCHfNative_switch_dial_handle_list_add_global_var___(void * jarg1, char * jarg2, char * jarg3) {
+ switch_dial_handle_list_t *arg1 = (switch_dial_handle_list_t *) 0 ;
+ char *arg2 = (char *) 0 ;
+ char *arg3 = (char *) 0 ;
+
+ arg1 = (switch_dial_handle_list_t *)jarg1;
+ arg2 = (char *)jarg2;
+ arg3 = (char *)jarg3;
+ switch_dial_handle_list_add_global_var(arg1,(char const *)arg2,(char const *)arg3);
+}
+
+
+SWIGEXPORT void SWIGSTDCALL CSharp_FreeSWITCHfNative_switch_dial_handle_list_add_global_var_printf___(void * jarg1, char * jarg2, char * jarg3) {
+ switch_dial_handle_list_t *arg1 = (switch_dial_handle_list_t *) 0 ;
+ char *arg2 = (char *) 0 ;
+ char *arg3 = (char *) 0 ;
+ void *arg4 = 0 ;
+
+ arg1 = (switch_dial_handle_list_t *)jarg1;
+ arg2 = (char *)jarg2;
+ arg3 = (char *)jarg3;
+ switch_dial_handle_list_add_global_var_printf(arg1,(char const *)arg2,(char const *)arg3,arg4);
+}
+
+
+SWIGEXPORT int SWIGSTDCALL CSharp_FreeSWITCHfNative_switch_ivr_enterprise_orig_and_bridge___(void * jarg1, char * jarg2, void * jarg3, void * jarg4) {
+ int jresult ;
+ switch_core_session_t *arg1 = (switch_core_session_t *) 0 ;
+ char *arg2 = (char *) 0 ;
+ switch_dial_handle_list_t *arg3 = (switch_dial_handle_list_t *) 0 ;
+ switch_call_cause_t *arg4 = (switch_call_cause_t *) 0 ;
+ switch_status_t result;
+
+ arg1 = (switch_core_session_t *)jarg1;
+ arg2 = (char *)jarg2;
+ arg3 = (switch_dial_handle_list_t *)jarg3;
+ arg4 = (switch_call_cause_t *)jarg4;
+ result = (switch_status_t)switch_ivr_enterprise_orig_and_bridge(arg1,(char const *)arg2,arg3,arg4);
+ jresult = (int)result;
+ return jresult;
+}
+
+
SWIGEXPORT int SWIGSTDCALL CSharp_FreeSWITCHfNative_switch_ivr_orig_and_bridge___(void * jarg1, char * jarg2, void * jarg3, void * jarg4) {
int jresult ;
switch_core_session_t *arg1 = (switch_core_session_t *) 0 ;
@@ -49740,6 +49919,38 @@ SWIGEXPORT unsigned long SWIGSTDCALL CSharp_FreeSWITCHfNative_switch_scheduler_a
}
+SWIGEXPORT unsigned long SWIGSTDCALL CSharp_FreeSWITCHfNative_switch_scheduler_add_task_ex___(void * jarg1, void * jarg2, char * jarg3, char * jarg4, unsigned long jarg5, void * jarg6, unsigned long jarg7, void * jarg8) {
+ unsigned long jresult ;
+ time_t arg1 ;
+ switch_scheduler_func_t arg2 = (switch_scheduler_func_t) 0 ;
+ char *arg3 = (char *) 0 ;
+ char *arg4 = (char *) 0 ;
+ uint32_t arg5 ;
+ void *arg6 = (void *) 0 ;
+ switch_scheduler_flag_t arg7 ;
+ uint32_t *arg8 = (uint32_t *) 0 ;
+ time_t *argp1 ;
+ uint32_t result;
+
+ argp1 = (time_t *)jarg1;
+ if (!argp1) {
+ SWIG_CSharpSetPendingExceptionArgument(SWIG_CSharpArgumentNullException, "Attempt to dereference null time_t", 0);
+ return 0;
+ }
+ arg1 = *argp1;
+ arg2 = (switch_scheduler_func_t)jarg2;
+ arg3 = (char *)jarg3;
+ arg4 = (char *)jarg4;
+ arg5 = (uint32_t)jarg5;
+ arg6 = (void *)jarg6;
+ arg7 = (switch_scheduler_flag_t)jarg7;
+ arg8 = (uint32_t *)jarg8;
+ result = (uint32_t)switch_scheduler_add_task_ex(arg1,arg2,(char const *)arg3,(char const *)arg4,arg5,arg6,arg7,arg8);
+ jresult = (unsigned long)result;
+ return jresult;
+}
+
+
SWIGEXPORT unsigned long SWIGSTDCALL CSharp_FreeSWITCHfNative_switch_scheduler_del_task_id___(unsigned long jarg1) {
unsigned long jresult ;
uint32_t arg1 ;
@@ -50809,6 +51020,20 @@ SWIGEXPORT unsigned int SWIGSTDCALL CSharp_FreeSWITCHfNative_Event_Fire___(void
}
+SWIGEXPORT unsigned int SWIGSTDCALL CSharp_FreeSWITCHfNative_Event_merge___(void * jarg1, void * jarg2) {
+ unsigned int jresult ;
+ Event *arg1 = (Event *) 0 ;
+ Event *arg2 = (Event *) 0 ;
+ bool result;
+
+ arg1 = (Event *)jarg1;
+ arg2 = (Event *)jarg2;
+ result = (bool)(arg1)->merge(arg2);
+ jresult = result;
+ return jresult;
+}
+
+
SWIGEXPORT void SWIGSTDCALL CSharp_FreeSWITCHfNative_EventConsumer_events_set___(void * jarg1, void * jarg2) {
EventConsumer *arg1 = (EventConsumer *) 0 ;
switch_queue_t *arg2 = (switch_queue_t *) 0 ;
diff --git a/src/mod/languages/mod_managed/managed/swig.cs b/src/mod/languages/mod_managed/managed/swig.cs
index 3002981514..25d419680c 100644
--- a/src/mod/languages/mod_managed/managed/swig.cs
+++ b/src/mod/languages/mod_managed/managed/swig.cs
@@ -650,6 +650,11 @@ public partial class Event : global::System.IDisposable {
return ret;
}
+ public bool merge(Event to_merge) {
+ bool ret = freeswitchPINVOKE.Event_merge(swigCPtr, Event.getCPtr(to_merge));
+ return ret;
+ }
+
}
}
@@ -4795,6 +4800,35 @@ public class SWIGTYPE_p_p_switch_device_record_s {
namespace FreeSWITCH.Native {
+public class SWIGTYPE_p_p_switch_dial_handle_list_s {
+ private global::System.Runtime.InteropServices.HandleRef swigCPtr;
+
+ internal SWIGTYPE_p_p_switch_dial_handle_list_s(global::System.IntPtr cPtr, bool futureUse) {
+ swigCPtr = new global::System.Runtime.InteropServices.HandleRef(this, cPtr);
+ }
+
+ protected SWIGTYPE_p_p_switch_dial_handle_list_s() {
+ swigCPtr = new global::System.Runtime.InteropServices.HandleRef(null, global::System.IntPtr.Zero);
+ }
+
+ internal static global::System.Runtime.InteropServices.HandleRef getCPtr(SWIGTYPE_p_p_switch_dial_handle_list_s obj) {
+ return (obj == null) ? new global::System.Runtime.InteropServices.HandleRef(null, global::System.IntPtr.Zero) : obj.swigCPtr;
+ }
+}
+
+}
+//------------------------------------------------------------------------------
+//
+//
+// This file was automatically generated by SWIG (http://www.swig.org).
+// Version 3.0.12
+//
+// Do not make changes to this file unless you know what you are doing--modify
+// the SWIG interface file instead.
+//------------------------------------------------------------------------------
+
+namespace FreeSWITCH.Native {
+
public class SWIGTYPE_p_p_switch_dial_handle_s {
private global::System.Runtime.InteropServices.HandleRef swigCPtr;
@@ -6071,6 +6105,35 @@ public class SWIGTYPE_p_switch_core_session {
namespace FreeSWITCH.Native {
+public class SWIGTYPE_p_switch_dial_handle_list_s {
+ private global::System.Runtime.InteropServices.HandleRef swigCPtr;
+
+ internal SWIGTYPE_p_switch_dial_handle_list_s(global::System.IntPtr cPtr, bool futureUse) {
+ swigCPtr = new global::System.Runtime.InteropServices.HandleRef(this, cPtr);
+ }
+
+ protected SWIGTYPE_p_switch_dial_handle_list_s() {
+ swigCPtr = new global::System.Runtime.InteropServices.HandleRef(null, global::System.IntPtr.Zero);
+ }
+
+ internal static global::System.Runtime.InteropServices.HandleRef getCPtr(SWIGTYPE_p_switch_dial_handle_list_s obj) {
+ return (obj == null) ? new global::System.Runtime.InteropServices.HandleRef(null, global::System.IntPtr.Zero) : obj.swigCPtr;
+ }
+}
+
+}
+//------------------------------------------------------------------------------
+//
+//
+// This file was automatically generated by SWIG (http://www.swig.org).
+// Version 3.0.12
+//
+// Do not make changes to this file unless you know what you are doing--modify
+// the SWIG interface file instead.
+//------------------------------------------------------------------------------
+
+namespace FreeSWITCH.Native {
+
public class SWIGTYPE_p_switch_dial_handle_s {
private global::System.Runtime.InteropServices.HandleRef swigCPtr;
@@ -8907,6 +8970,11 @@ else
freeswitchPINVOKE.switch_core_session_reset(SWIGTYPE_p_switch_core_session.getCPtr(session), (int)flush_dtmf, (int)reset_read_codec);
}
+ public static switch_status_t switch_core_session_try_reset(SWIGTYPE_p_switch_core_session session, switch_bool_t flush_dtmf, switch_bool_t reset_read_codec) {
+ switch_status_t ret = (switch_status_t)freeswitchPINVOKE.switch_core_session_try_reset(SWIGTYPE_p_switch_core_session.getCPtr(session), (int)flush_dtmf, (int)reset_read_codec);
+ return ret;
+ }
+
public static switch_status_t switch_core_session_write_frame(SWIGTYPE_p_switch_core_session session, switch_frame frame, uint flags, int stream_id) {
switch_status_t ret = (switch_status_t)freeswitchPINVOKE.switch_core_session_write_frame(SWIGTYPE_p_switch_core_session.getCPtr(session), switch_frame.getCPtr(frame), flags, stream_id);
return ret;
@@ -9328,6 +9396,11 @@ else
return ret;
}
+ public static switch_status_t switch_core_file_handle_dup(switch_file_handle oldfh, SWIGTYPE_p_p_switch_file_handle newfh, SWIGTYPE_p_apr_pool_t pool) {
+ switch_status_t ret = (switch_status_t)freeswitchPINVOKE.switch_core_file_handle_dup(switch_file_handle.getCPtr(oldfh), SWIGTYPE_p_p_switch_file_handle.getCPtr(newfh), SWIGTYPE_p_apr_pool_t.getCPtr(pool));
+ return ret;
+ }
+
public static switch_status_t switch_core_file_close(switch_file_handle fh) {
switch_status_t ret = (switch_status_t)freeswitchPINVOKE.switch_core_file_close(switch_file_handle.getCPtr(fh));
return ret;
@@ -10207,6 +10280,11 @@ else
return ret;
}
+ public static switch_bool_t switch_core_check_dtls_pem(string file) {
+ switch_bool_t ret = (switch_bool_t)freeswitchPINVOKE.switch_core_check_dtls_pem(file);
+ return ret;
+ }
+
public static int switch_core_cert_gen_fingerprint(string prefix, dtls_fingerprint_t fp) {
int ret = freeswitchPINVOKE.switch_core_cert_gen_fingerprint(prefix, dtls_fingerprint_t.getCPtr(fp));
return ret;
@@ -13076,8 +13154,8 @@ else
return ret;
}
- public static switch_status_t switch_ivr_enterprise_originate(SWIGTYPE_p_switch_core_session session, SWIGTYPE_p_p_switch_core_session bleg, SWIGTYPE_p_switch_call_cause_t cause, string bridgeto, uint timelimit_sec, switch_state_handler_table table, string cid_name_override, string cid_num_override, switch_caller_profile caller_profile_override, switch_event ovars, uint flags, SWIGTYPE_p_switch_call_cause_t cancel_cause) {
- switch_status_t ret = (switch_status_t)freeswitchPINVOKE.switch_ivr_enterprise_originate(SWIGTYPE_p_switch_core_session.getCPtr(session), SWIGTYPE_p_p_switch_core_session.getCPtr(bleg), SWIGTYPE_p_switch_call_cause_t.getCPtr(cause), bridgeto, timelimit_sec, switch_state_handler_table.getCPtr(table), cid_name_override, cid_num_override, switch_caller_profile.getCPtr(caller_profile_override), switch_event.getCPtr(ovars), flags, SWIGTYPE_p_switch_call_cause_t.getCPtr(cancel_cause));
+ public static switch_status_t switch_ivr_enterprise_originate(SWIGTYPE_p_switch_core_session session, SWIGTYPE_p_p_switch_core_session bleg, SWIGTYPE_p_switch_call_cause_t cause, string bridgeto, uint timelimit_sec, switch_state_handler_table table, string cid_name_override, string cid_num_override, switch_caller_profile caller_profile_override, switch_event ovars, uint flags, SWIGTYPE_p_switch_call_cause_t cancel_cause, SWIGTYPE_p_switch_dial_handle_list_s hl) {
+ switch_status_t ret = (switch_status_t)freeswitchPINVOKE.switch_ivr_enterprise_originate(SWIGTYPE_p_switch_core_session.getCPtr(session), SWIGTYPE_p_p_switch_core_session.getCPtr(bleg), SWIGTYPE_p_switch_call_cause_t.getCPtr(cause), bridgeto, timelimit_sec, switch_state_handler_table.getCPtr(table), cid_name_override, cid_num_override, switch_caller_profile.getCPtr(caller_profile_override), switch_event.getCPtr(ovars), flags, SWIGTYPE_p_switch_call_cause_t.getCPtr(cancel_cause), SWIGTYPE_p_switch_dial_handle_list_s.getCPtr(hl));
return ret;
}
@@ -13649,6 +13727,53 @@ else
return ret;
}
+ public static switch_status_t switch_dial_handle_list_serialize_json_obj(SWIGTYPE_p_switch_dial_handle_list_s hl, SWIGTYPE_p_p_cJSON json) {
+ switch_status_t ret = (switch_status_t)freeswitchPINVOKE.switch_dial_handle_list_serialize_json_obj(SWIGTYPE_p_switch_dial_handle_list_s.getCPtr(hl), SWIGTYPE_p_p_cJSON.getCPtr(json));
+ return ret;
+ }
+
+ public static switch_status_t switch_dial_handle_list_serialize_json(SWIGTYPE_p_switch_dial_handle_list_s hl, ref string str) {
+ switch_status_t ret = (switch_status_t)freeswitchPINVOKE.switch_dial_handle_list_serialize_json(SWIGTYPE_p_switch_dial_handle_list_s.getCPtr(hl), ref str);
+ return ret;
+ }
+
+ public static switch_status_t switch_dial_handle_list_create_json_obj(SWIGTYPE_p_p_switch_dial_handle_list_s handle, SWIGTYPE_p_cJSON json) {
+ switch_status_t ret = (switch_status_t)freeswitchPINVOKE.switch_dial_handle_list_create_json_obj(SWIGTYPE_p_p_switch_dial_handle_list_s.getCPtr(handle), SWIGTYPE_p_cJSON.getCPtr(json));
+ return ret;
+ }
+
+ public static switch_status_t switch_dial_handle_list_create_json(SWIGTYPE_p_p_switch_dial_handle_list_s handle, string handle_string) {
+ switch_status_t ret = (switch_status_t)freeswitchPINVOKE.switch_dial_handle_list_create_json(SWIGTYPE_p_p_switch_dial_handle_list_s.getCPtr(handle), handle_string);
+ return ret;
+ }
+
+ public static switch_status_t switch_dial_handle_list_create(SWIGTYPE_p_p_switch_dial_handle_list_s hl) {
+ switch_status_t ret = (switch_status_t)freeswitchPINVOKE.switch_dial_handle_list_create(SWIGTYPE_p_p_switch_dial_handle_list_s.getCPtr(hl));
+ return ret;
+ }
+
+ public static switch_status_t switch_dial_handle_list_create_handle(SWIGTYPE_p_switch_dial_handle_list_s hl, SWIGTYPE_p_p_switch_dial_handle_s handle) {
+ switch_status_t ret = (switch_status_t)freeswitchPINVOKE.switch_dial_handle_list_create_handle(SWIGTYPE_p_switch_dial_handle_list_s.getCPtr(hl), SWIGTYPE_p_p_switch_dial_handle_s.getCPtr(handle));
+ return ret;
+ }
+
+ public static void switch_dial_handle_list_destroy(SWIGTYPE_p_p_switch_dial_handle_list_s hl) {
+ freeswitchPINVOKE.switch_dial_handle_list_destroy(SWIGTYPE_p_p_switch_dial_handle_list_s.getCPtr(hl));
+ }
+
+ public static void switch_dial_handle_list_add_global_var(SWIGTYPE_p_switch_dial_handle_list_s hl, string var, string val) {
+ freeswitchPINVOKE.switch_dial_handle_list_add_global_var(SWIGTYPE_p_switch_dial_handle_list_s.getCPtr(hl), var, val);
+ }
+
+ public static void switch_dial_handle_list_add_global_var_printf(SWIGTYPE_p_switch_dial_handle_list_s hl, string var, string fmt) {
+ freeswitchPINVOKE.switch_dial_handle_list_add_global_var_printf(SWIGTYPE_p_switch_dial_handle_list_s.getCPtr(hl), var, fmt);
+ }
+
+ public static switch_status_t switch_ivr_enterprise_orig_and_bridge(SWIGTYPE_p_switch_core_session session, string data, SWIGTYPE_p_switch_dial_handle_list_s hl, SWIGTYPE_p_switch_call_cause_t cause) {
+ switch_status_t ret = (switch_status_t)freeswitchPINVOKE.switch_ivr_enterprise_orig_and_bridge(SWIGTYPE_p_switch_core_session.getCPtr(session), data, SWIGTYPE_p_switch_dial_handle_list_s.getCPtr(hl), SWIGTYPE_p_switch_call_cause_t.getCPtr(cause));
+ return ret;
+ }
+
public static switch_status_t switch_ivr_orig_and_bridge(SWIGTYPE_p_switch_core_session session, string data, SWIGTYPE_p_switch_dial_handle_s dh, SWIGTYPE_p_switch_call_cause_t cause) {
switch_status_t ret = (switch_status_t)freeswitchPINVOKE.switch_ivr_orig_and_bridge(SWIGTYPE_p_switch_core_session.getCPtr(session), data, SWIGTYPE_p_switch_dial_handle_s.getCPtr(dh), SWIGTYPE_p_switch_call_cause_t.getCPtr(cause));
return ret;
@@ -14626,6 +14751,12 @@ else
return ret;
}
+ public static uint switch_scheduler_add_task_ex(SWIGTYPE_p_time_t task_runtime, SWIGTYPE_p_f_p_switch_scheduler_task__void func, string desc, string group, uint cmd_id, SWIGTYPE_p_void cmd_arg, uint flags, SWIGTYPE_p_unsigned_long task_id) {
+ uint ret = freeswitchPINVOKE.switch_scheduler_add_task_ex(SWIGTYPE_p_time_t.getCPtr(task_runtime), SWIGTYPE_p_f_p_switch_scheduler_task__void.getCPtr(func), desc, group, cmd_id, SWIGTYPE_p_void.getCPtr(cmd_arg), flags, SWIGTYPE_p_unsigned_long.getCPtr(task_id));
+ if (freeswitchPINVOKE.SWIGPendingException.Pending) throw freeswitchPINVOKE.SWIGPendingException.Retrieve();
+ return ret;
+ }
+
public static uint switch_scheduler_del_task_id(uint task_id) {
uint ret = freeswitchPINVOKE.switch_scheduler_del_task_id(task_id);
return ret;
@@ -18830,6 +18961,9 @@ class freeswitchPINVOKE {
[global::System.Runtime.InteropServices.DllImport("mod_managed", EntryPoint="CSharp_FreeSWITCHfNative_switch_core_session_reset___")]
public static extern void switch_core_session_reset(global::System.Runtime.InteropServices.HandleRef jarg1, int jarg2, int jarg3);
+ [global::System.Runtime.InteropServices.DllImport("mod_managed", EntryPoint="CSharp_FreeSWITCHfNative_switch_core_session_try_reset___")]
+ public static extern int switch_core_session_try_reset(global::System.Runtime.InteropServices.HandleRef jarg1, int jarg2, int jarg3);
+
[global::System.Runtime.InteropServices.DllImport("mod_managed", EntryPoint="CSharp_FreeSWITCHfNative_switch_core_session_write_frame___")]
public static extern int switch_core_session_write_frame(global::System.Runtime.InteropServices.HandleRef jarg1, global::System.Runtime.InteropServices.HandleRef jarg2, uint jarg3, int jarg4);
@@ -19073,6 +19207,9 @@ class freeswitchPINVOKE {
[global::System.Runtime.InteropServices.DllImport("mod_managed", EntryPoint="CSharp_FreeSWITCHfNative_switch_core_file_pre_close___")]
public static extern int switch_core_file_pre_close(global::System.Runtime.InteropServices.HandleRef jarg1);
+ [global::System.Runtime.InteropServices.DllImport("mod_managed", EntryPoint="CSharp_FreeSWITCHfNative_switch_core_file_handle_dup___")]
+ public static extern int switch_core_file_handle_dup(global::System.Runtime.InteropServices.HandleRef jarg1, global::System.Runtime.InteropServices.HandleRef jarg2, global::System.Runtime.InteropServices.HandleRef jarg3);
+
[global::System.Runtime.InteropServices.DllImport("mod_managed", EntryPoint="CSharp_FreeSWITCHfNative_switch_core_file_close___")]
public static extern int switch_core_file_close(global::System.Runtime.InteropServices.HandleRef jarg1);
@@ -19742,6 +19879,9 @@ class freeswitchPINVOKE {
[global::System.Runtime.InteropServices.DllImport("mod_managed", EntryPoint="CSharp_FreeSWITCHfNative_switch_core_gen_certs___")]
public static extern int switch_core_gen_certs(string jarg1);
+ [global::System.Runtime.InteropServices.DllImport("mod_managed", EntryPoint="CSharp_FreeSWITCHfNative_switch_core_check_dtls_pem___")]
+ public static extern int switch_core_check_dtls_pem(string jarg1);
+
[global::System.Runtime.InteropServices.DllImport("mod_managed", EntryPoint="CSharp_FreeSWITCHfNative_switch_core_cert_gen_fingerprint___")]
public static extern int switch_core_cert_gen_fingerprint(string jarg1, global::System.Runtime.InteropServices.HandleRef jarg2);
@@ -25359,7 +25499,7 @@ class freeswitchPINVOKE {
public static extern int switch_ivr_originate(global::System.Runtime.InteropServices.HandleRef jarg1, global::System.Runtime.InteropServices.HandleRef jarg2, global::System.Runtime.InteropServices.HandleRef jarg3, string jarg4, uint jarg5, global::System.Runtime.InteropServices.HandleRef jarg6, string jarg7, string jarg8, global::System.Runtime.InteropServices.HandleRef jarg9, global::System.Runtime.InteropServices.HandleRef jarg10, uint jarg11, global::System.Runtime.InteropServices.HandleRef jarg12, global::System.Runtime.InteropServices.HandleRef jarg13);
[global::System.Runtime.InteropServices.DllImport("mod_managed", EntryPoint="CSharp_FreeSWITCHfNative_switch_ivr_enterprise_originate___")]
- public static extern int switch_ivr_enterprise_originate(global::System.Runtime.InteropServices.HandleRef jarg1, global::System.Runtime.InteropServices.HandleRef jarg2, global::System.Runtime.InteropServices.HandleRef jarg3, string jarg4, uint jarg5, global::System.Runtime.InteropServices.HandleRef jarg6, string jarg7, string jarg8, global::System.Runtime.InteropServices.HandleRef jarg9, global::System.Runtime.InteropServices.HandleRef jarg10, uint jarg11, global::System.Runtime.InteropServices.HandleRef jarg12);
+ public static extern int switch_ivr_enterprise_originate(global::System.Runtime.InteropServices.HandleRef jarg1, global::System.Runtime.InteropServices.HandleRef jarg2, global::System.Runtime.InteropServices.HandleRef jarg3, string jarg4, uint jarg5, global::System.Runtime.InteropServices.HandleRef jarg6, string jarg7, string jarg8, global::System.Runtime.InteropServices.HandleRef jarg9, global::System.Runtime.InteropServices.HandleRef jarg10, uint jarg11, global::System.Runtime.InteropServices.HandleRef jarg12, global::System.Runtime.InteropServices.HandleRef jarg13);
[global::System.Runtime.InteropServices.DllImport("mod_managed", EntryPoint="CSharp_FreeSWITCHfNative_switch_ivr_bridge_display___")]
public static extern void switch_ivr_bridge_display(global::System.Runtime.InteropServices.HandleRef jarg1, global::System.Runtime.InteropServices.HandleRef jarg2);
@@ -25706,6 +25846,36 @@ class freeswitchPINVOKE {
[global::System.Runtime.InteropServices.DllImport("mod_managed", EntryPoint="CSharp_FreeSWITCHfNative_switch_dial_handle_get_total___")]
public static extern int switch_dial_handle_get_total(global::System.Runtime.InteropServices.HandleRef jarg1);
+ [global::System.Runtime.InteropServices.DllImport("mod_managed", EntryPoint="CSharp_FreeSWITCHfNative_switch_dial_handle_list_serialize_json_obj___")]
+ public static extern int switch_dial_handle_list_serialize_json_obj(global::System.Runtime.InteropServices.HandleRef jarg1, global::System.Runtime.InteropServices.HandleRef jarg2);
+
+ [global::System.Runtime.InteropServices.DllImport("mod_managed", EntryPoint="CSharp_FreeSWITCHfNative_switch_dial_handle_list_serialize_json___")]
+ public static extern int switch_dial_handle_list_serialize_json(global::System.Runtime.InteropServices.HandleRef jarg1, ref string jarg2);
+
+ [global::System.Runtime.InteropServices.DllImport("mod_managed", EntryPoint="CSharp_FreeSWITCHfNative_switch_dial_handle_list_create_json_obj___")]
+ public static extern int switch_dial_handle_list_create_json_obj(global::System.Runtime.InteropServices.HandleRef jarg1, global::System.Runtime.InteropServices.HandleRef jarg2);
+
+ [global::System.Runtime.InteropServices.DllImport("mod_managed", EntryPoint="CSharp_FreeSWITCHfNative_switch_dial_handle_list_create_json___")]
+ public static extern int switch_dial_handle_list_create_json(global::System.Runtime.InteropServices.HandleRef jarg1, string jarg2);
+
+ [global::System.Runtime.InteropServices.DllImport("mod_managed", EntryPoint="CSharp_FreeSWITCHfNative_switch_dial_handle_list_create___")]
+ public static extern int switch_dial_handle_list_create(global::System.Runtime.InteropServices.HandleRef jarg1);
+
+ [global::System.Runtime.InteropServices.DllImport("mod_managed", EntryPoint="CSharp_FreeSWITCHfNative_switch_dial_handle_list_create_handle___")]
+ public static extern int switch_dial_handle_list_create_handle(global::System.Runtime.InteropServices.HandleRef jarg1, global::System.Runtime.InteropServices.HandleRef jarg2);
+
+ [global::System.Runtime.InteropServices.DllImport("mod_managed", EntryPoint="CSharp_FreeSWITCHfNative_switch_dial_handle_list_destroy___")]
+ public static extern void switch_dial_handle_list_destroy(global::System.Runtime.InteropServices.HandleRef jarg1);
+
+ [global::System.Runtime.InteropServices.DllImport("mod_managed", EntryPoint="CSharp_FreeSWITCHfNative_switch_dial_handle_list_add_global_var___")]
+ public static extern void switch_dial_handle_list_add_global_var(global::System.Runtime.InteropServices.HandleRef jarg1, string jarg2, string jarg3);
+
+ [global::System.Runtime.InteropServices.DllImport("mod_managed", EntryPoint="CSharp_FreeSWITCHfNative_switch_dial_handle_list_add_global_var_printf___")]
+ public static extern void switch_dial_handle_list_add_global_var_printf(global::System.Runtime.InteropServices.HandleRef jarg1, string jarg2, string jarg3);
+
+ [global::System.Runtime.InteropServices.DllImport("mod_managed", EntryPoint="CSharp_FreeSWITCHfNative_switch_ivr_enterprise_orig_and_bridge___")]
+ public static extern int switch_ivr_enterprise_orig_and_bridge(global::System.Runtime.InteropServices.HandleRef jarg1, string jarg2, global::System.Runtime.InteropServices.HandleRef jarg3, global::System.Runtime.InteropServices.HandleRef jarg4);
+
[global::System.Runtime.InteropServices.DllImport("mod_managed", EntryPoint="CSharp_FreeSWITCHfNative_switch_ivr_orig_and_bridge___")]
public static extern int switch_ivr_orig_and_bridge(global::System.Runtime.InteropServices.HandleRef jarg1, string jarg2, global::System.Runtime.InteropServices.HandleRef jarg3, global::System.Runtime.InteropServices.HandleRef jarg4);
@@ -27158,6 +27328,9 @@ class freeswitchPINVOKE {
[global::System.Runtime.InteropServices.DllImport("mod_managed", EntryPoint="CSharp_FreeSWITCHfNative_switch_scheduler_add_task___")]
public static extern uint switch_scheduler_add_task(global::System.Runtime.InteropServices.HandleRef jarg1, global::System.Runtime.InteropServices.HandleRef jarg2, string jarg3, string jarg4, uint jarg5, global::System.Runtime.InteropServices.HandleRef jarg6, uint jarg7);
+ [global::System.Runtime.InteropServices.DllImport("mod_managed", EntryPoint="CSharp_FreeSWITCHfNative_switch_scheduler_add_task_ex___")]
+ public static extern uint switch_scheduler_add_task_ex(global::System.Runtime.InteropServices.HandleRef jarg1, global::System.Runtime.InteropServices.HandleRef jarg2, string jarg3, string jarg4, uint jarg5, global::System.Runtime.InteropServices.HandleRef jarg6, uint jarg7, global::System.Runtime.InteropServices.HandleRef jarg8);
+
[global::System.Runtime.InteropServices.DllImport("mod_managed", EntryPoint="CSharp_FreeSWITCHfNative_switch_scheduler_del_task_id___")]
public static extern uint switch_scheduler_del_task_id(uint jarg1);
@@ -27416,6 +27589,9 @@ class freeswitchPINVOKE {
[global::System.Runtime.InteropServices.DllImport("mod_managed", EntryPoint="CSharp_FreeSWITCHfNative_Event_Fire___")]
public static extern bool Event_Fire(global::System.Runtime.InteropServices.HandleRef jarg1);
+ [global::System.Runtime.InteropServices.DllImport("mod_managed", EntryPoint="CSharp_FreeSWITCHfNative_Event_merge___")]
+ public static extern bool Event_merge(global::System.Runtime.InteropServices.HandleRef jarg1, global::System.Runtime.InteropServices.HandleRef jarg2);
+
[global::System.Runtime.InteropServices.DllImport("mod_managed", EntryPoint="CSharp_FreeSWITCHfNative_EventConsumer_events_set___")]
public static extern void EventConsumer_events_set(global::System.Runtime.InteropServices.HandleRef jarg1, global::System.Runtime.InteropServices.HandleRef jarg2);
@@ -31483,6 +31659,7 @@ public enum switch_channel_flag_t {
CF_SERVICE,
CF_TAGGED,
CF_WINNER,
+ CF_REUSE_CALLER_PROFILE,
CF_CONTROLLED,
CF_PROXY_MODE,
CF_PROXY_OFF,
@@ -36106,7 +36283,8 @@ namespace FreeSWITCH.Native {
ED_BRIDGE_READ = (1 << 4),
ED_BRIDGE_WRITE = (1 << 5),
ED_TAP_READ = (1 << 6),
- ED_TAP_WRITE = (1 << 7)
+ ED_TAP_WRITE = (1 << 7),
+ ED_STEREO = (1 << 8)
}
}
diff --git a/src/mod/languages/mod_perl/freeswitch.pm b/src/mod/languages/mod_perl/freeswitch.pm
index 3d511c9225..9717fbb944 100644
--- a/src/mod/languages/mod_perl/freeswitch.pm
+++ b/src/mod/languages/mod_perl/freeswitch.pm
@@ -311,6 +311,7 @@ sub DESTROY {
*addHeader = *freeswitchc::Event_addHeader;
*delHeader = *freeswitchc::Event_delHeader;
*fire = *freeswitchc::Event_fire;
+*merge = *freeswitchc::Event_merge;
sub DISOWN {
my $self = shift;
my $ptr = tied(%$self);
diff --git a/src/mod/languages/mod_perl/mod_perl_wrap.cpp b/src/mod/languages/mod_perl/mod_perl_wrap.cpp
index a6b48e7670..27e98ee3e6 100644
--- a/src/mod/languages/mod_perl/mod_perl_wrap.cpp
+++ b/src/mod/languages/mod_perl/mod_perl_wrap.cpp
@@ -4482,6 +4482,44 @@ XS(_wrap_Event_fire) {
}
+XS(_wrap_Event_merge) {
+ {
+ Event *arg1 = (Event *) 0 ;
+ Event *arg2 = (Event *) 0 ;
+ void *argp1 = 0 ;
+ int res1 = 0 ;
+ void *argp2 = 0 ;
+ int res2 = 0 ;
+ int argvi = 0;
+ bool result;
+ dXSARGS;
+
+ if ((items < 2) || (items > 2)) {
+ SWIG_croak("Usage: Event_merge(self,to_merge);");
+ }
+ res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_Event, 0 | 0 );
+ if (!SWIG_IsOK(res1)) {
+ SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Event_merge" "', argument " "1"" of type '" "Event *""'");
+ }
+ arg1 = reinterpret_cast< Event * >(argp1);
+ res2 = SWIG_ConvertPtr(ST(1), &argp2,SWIGTYPE_p_Event, 0 | 0 );
+ if (!SWIG_IsOK(res2)) {
+ SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Event_merge" "', argument " "2"" of type '" "Event *""'");
+ }
+ arg2 = reinterpret_cast< Event * >(argp2);
+ result = (bool)(arg1)->merge(arg2);
+ ST(argvi) = SWIG_From_bool SWIG_PERL_CALL_ARGS_1(static_cast< bool >(result)); argvi++ ;
+
+
+ XSRETURN(argvi);
+ fail:
+
+
+ SWIG_croak_null();
+ }
+}
+
+
XS(_wrap_EventConsumer_events_set) {
{
EventConsumer *arg1 = (EventConsumer *) 0 ;
@@ -10792,6 +10830,7 @@ static swig_command_info swig_commands[] = {
{"freeswitchc::Event_addHeader", _wrap_Event_addHeader},
{"freeswitchc::Event_delHeader", _wrap_Event_delHeader},
{"freeswitchc::Event_fire", _wrap_Event_fire},
+{"freeswitchc::Event_merge", _wrap_Event_merge},
{"freeswitchc::EventConsumer_events_set", _wrap_EventConsumer_events_set},
{"freeswitchc::EventConsumer_events_get", _wrap_EventConsumer_events_get},
{"freeswitchc::EventConsumer_e_event_id_set", _wrap_EventConsumer_e_event_id_set},
diff --git a/src/mod/languages/mod_python/freeswitch.py b/src/mod/languages/mod_python/freeswitch.py
index ac9f655ad9..48ccf472f1 100644
--- a/src/mod/languages/mod_python/freeswitch.py
+++ b/src/mod/languages/mod_python/freeswitch.py
@@ -327,6 +327,9 @@ class Event(_object):
def fire(self):
return _freeswitch.Event_fire(self)
+
+ def merge(self, to_merge):
+ return _freeswitch.Event_merge(self, to_merge)
Event_swigregister = _freeswitch.Event_swigregister
Event_swigregister(Event)
diff --git a/src/mod/languages/mod_python/mod_python_wrap.cpp b/src/mod/languages/mod_python/mod_python_wrap.cpp
index 31ec090c6a..227b441b59 100644
--- a/src/mod/languages/mod_python/mod_python_wrap.cpp
+++ b/src/mod/languages/mod_python/mod_python_wrap.cpp
@@ -5765,6 +5765,37 @@ fail:
}
+SWIGINTERN PyObject *_wrap_Event_merge(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+ PyObject *resultobj = 0;
+ Event *arg1 = (Event *) 0 ;
+ Event *arg2 = (Event *) 0 ;
+ void *argp1 = 0 ;
+ int res1 = 0 ;
+ void *argp2 = 0 ;
+ int res2 = 0 ;
+ PyObject * obj0 = 0 ;
+ PyObject * obj1 = 0 ;
+ bool result;
+
+ if (!PyArg_ParseTuple(args,(char *)"OO:Event_merge",&obj0,&obj1)) SWIG_fail;
+ res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_Event, 0 | 0 );
+ if (!SWIG_IsOK(res1)) {
+ SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Event_merge" "', argument " "1"" of type '" "Event *""'");
+ }
+ arg1 = reinterpret_cast< Event * >(argp1);
+ res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_Event, 0 | 0 );
+ if (!SWIG_IsOK(res2)) {
+ SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Event_merge" "', argument " "2"" of type '" "Event *""'");
+ }
+ arg2 = reinterpret_cast< Event * >(argp2);
+ result = (bool)(arg1)->merge(arg2);
+ resultobj = SWIG_From_bool(static_cast< bool >(result));
+ return resultobj;
+fail:
+ return NULL;
+}
+
+
SWIGINTERN PyObject *Event_swigregister(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
PyObject *obj;
if (!PyArg_ParseTuple(args,(char *)"O:swigregister", &obj)) return NULL;
@@ -10541,6 +10572,7 @@ static PyMethodDef SwigMethods[] = {
{ "Event_addHeader", _wrap_Event_addHeader, METH_VARARGS, NULL},
{ "Event_delHeader", _wrap_Event_delHeader, METH_VARARGS, NULL},
{ "Event_fire", _wrap_Event_fire, METH_VARARGS, NULL},
+ { "Event_merge", _wrap_Event_merge, METH_VARARGS, NULL},
{ "Event_swigregister", Event_swigregister, METH_VARARGS, NULL},
{ "EventConsumer_events_set", _wrap_EventConsumer_events_set, METH_VARARGS, NULL},
{ "EventConsumer_events_get", _wrap_EventConsumer_events_get, METH_VARARGS, NULL},
From 513b0fbf00c671b1ae6c416a06dd6a3d56e3fb66 Mon Sep 17 00:00:00 2001
From: Christian Glombek
Date: Wed, 24 Mar 2021 17:30:52 +0100
Subject: [PATCH 100/655] [mod_avmd, esl/python] Two build fixups (#611)
---
libs/esl/python/python-config | 14 +++++++-------
src/mod/applications/mod_avmd/mod_avmd.c | 4 +++-
2 files changed, 10 insertions(+), 8 deletions(-)
diff --git a/libs/esl/python/python-config b/libs/esl/python/python-config
index 71699916f5..1e60a89047 100644
--- a/libs/esl/python/python-config
+++ b/libs/esl/python/python-config
@@ -1,5 +1,6 @@
-#! /usr/bin/python2.5
+#!/usr/bin/env python
+from __future__ import print_function
import sys
import os
import getopt
@@ -9,8 +10,7 @@ valid_opts = ['prefix', 'exec-prefix', 'includes', 'libs', 'cflags',
'ldflags', 'help']
def exit_with_usage(code=1):
- print >>sys.stderr, "Usage: %s [%s]" % (sys.argv[0],
- '|'.join('--'+opt for opt in valid_opts))
+ print("Usage: %s [%s]" % (sys.argv[0], '|'.join('--'+opt for opt in valid_opts)), file=sys.stderr)
sys.exit(code)
try:
@@ -30,17 +30,17 @@ if opt == '--help':
exit_with_usage(0)
elif opt == '--prefix':
- print sysconfig.PREFIX
+ print(sysconfig.PREFIX)
elif opt == '--exec-prefix':
- print sysconfig.EXEC_PREFIX
+ print(sysconfig.EXEC_PREFIX)
elif opt in ('--includes', '--cflags'):
flags = ['-I' + sysconfig.get_python_inc(),
'-I' + sysconfig.get_python_inc(plat_specific=True)]
if opt == '--cflags':
flags.extend(getvar('CFLAGS').split())
- print ' '.join(flags)
+ print(' '.join(flags))
elif opt in ('--libs', '--ldflags'):
libs = getvar('LIBS').split() + getvar('SYSLIBS').split()
@@ -49,5 +49,5 @@ elif opt in ('--libs', '--ldflags'):
# shared library in prefix/lib/.
if opt == '--ldflags' and not getvar('Py_ENABLE_SHARED'):
libs.insert(0, '-L' + getvar('LIBPL'))
- print ' '.join(libs)
+ print(' '.join(libs))
diff --git a/src/mod/applications/mod_avmd/mod_avmd.c b/src/mod/applications/mod_avmd/mod_avmd.c
index a7a59d9289..ea1c5f483a 100644
--- a/src/mod/applications/mod_avmd/mod_avmd.c
+++ b/src/mod/applications/mod_avmd/mod_avmd.c
@@ -1343,8 +1343,10 @@ static switch_status_t avmd_parse_cmd_data(avmd_session_t *s, const char *cmd_da
switch_assert(argv[idx]);
status = avmd_parse_cmd_data_one_entry(argv[idx], &settings);
if (status != SWITCH_STATUS_SUCCESS) {
- switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(s->session), SWITCH_LOG_ERROR,
+ if (argv[idx]) {
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(s->session), SWITCH_LOG_ERROR,
"Error parsing option [%d] [%s]\n", idx + 1, argv[idx]); /* idx + 1 to report option 0 as 1 for users convenience */
+ }
switch (status)
{
case SWITCH_STATUS_TERM:
From 67cec5c3e80e653d4540b9ba2c4a0b38b92a9458 Mon Sep 17 00:00:00 2001
From: Andrey Volk
Date: Thu, 25 Mar 2021 18:52:56 +0300
Subject: [PATCH 101/655] version bump
---
build/next-release.txt | 2 +-
configure.ac | 4 ++--
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/build/next-release.txt b/build/next-release.txt
index defa9f0e12..ef3ef34409 100644
--- a/build/next-release.txt
+++ b/build/next-release.txt
@@ -1 +1 @@
-1.10.6-dev
+1.10.7-dev
diff --git a/configure.ac b/configure.ac
index 810003eda2..a74edfbc8b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -3,10 +3,10 @@
# Must change all of the below together
# For a release, set revision for that tagged release as well and uncomment
-AC_INIT([freeswitch], [1.10.6-dev], bugs@freeswitch.org)
+AC_INIT([freeswitch], [1.10.7-dev], bugs@freeswitch.org)
AC_SUBST(SWITCH_VERSION_MAJOR, [1])
AC_SUBST(SWITCH_VERSION_MINOR, [10])
-AC_SUBST(SWITCH_VERSION_MICRO, [6-dev])
+AC_SUBST(SWITCH_VERSION_MICRO, [7-dev])
AC_SUBST(SWITCH_VERSION_REVISION, [])
AC_SUBST(SWITCH_VERSION_REVISION_HUMAN, [])
From ec1a0215fedb56bcd6f73fb1e93f763ed5286cbb Mon Sep 17 00:00:00 2001
From: figaro2015
Date: Fri, 2 Apr 2021 12:18:16 -0700
Subject: [PATCH 102/655] [Core, mod_conference] Fixed oscillation in
conference AGC processing. Especially during volume reduction processing
(#1064)
* Fixed oscillation in conference AGC processing. Especially during volume reduction processing
* Re-scaled granular volume to +/- 50 dB level change. 10 = double loudness, -10 = half loudness, 0 = no change
Co-authored-by: Chris Rienzo
---
src/include/switch_resample.h | 7 ++--
.../mod_conference/conference_api.c | 9 -----
.../mod_conference/mod_conference.c | 8 ++---
src/switch_resample.c | 33 +++++++++++++++----
4 files changed, 35 insertions(+), 22 deletions(-)
diff --git a/src/include/switch_resample.h b/src/include/switch_resample.h
index 6656c205d7..462aa0629b 100644
--- a/src/include/switch_resample.h
+++ b/src/include/switch_resample.h
@@ -1,6 +1,6 @@
/*
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
- * Copyright (C) 2005-2014, Anthony Minessale II
+ * Copyright (C) 2005-2021, Anthony Minessale II
*
* Version: MPL 1.1
*
@@ -26,7 +26,7 @@
* Anthony Minessale II
*
*
- * switch_caller.h -- Caller Identification
+ * switch_resample.h
*
*/
/*! \file switch_resample.h
@@ -39,7 +39,8 @@
*/
#define switch_normalize_volume(x) if (x > 4) x = 4; if (x < -4) x = -4;
-#define switch_normalize_volume_granular(x) if (x > 13) x = 13; if (x < -13) x = -13;
+#define SWITCH_GRANULAR_VOLUME_MAX 50
+#define switch_normalize_volume_granular(x) if (x > SWITCH_GRANULAR_VOLUME_MAX) x = SWITCH_GRANULAR_VOLUME_MAX; if (x < -SWITCH_GRANULAR_VOLUME_MAX) x = -SWITCH_GRANULAR_VOLUME_MAX;
#ifndef SWITCH_RESAMPLE_H
#define SWITCH_RESAMPLE_H
diff --git a/src/mod/applications/mod_conference/conference_api.c b/src/mod/applications/mod_conference/conference_api.c
index 2c323d2b8d..ee74f2a371 100644
--- a/src/mod/applications/mod_conference/conference_api.c
+++ b/src/mod/applications/mod_conference/conference_api.c
@@ -1276,15 +1276,6 @@ void conference_api_set_agc(conference_member_t *member, const char *data)
}
- if (argv[0]) {
- tmp = atoi(argv[0]);
-
- if (tmp > 0) {
- member->agc_period_len = (1000 / member->conference->interval) * tmp;
- }
- }
-
-
if (!member->agc) {
switch_agc_create(&member->agc, member->agc_level, member->agc_low_energy_level, member->agc_margin,
member->agc_change_factor, member->agc_period_len);
diff --git a/src/mod/applications/mod_conference/mod_conference.c b/src/mod/applications/mod_conference/mod_conference.c
index d1ee467757..498de9fefc 100644
--- a/src/mod/applications/mod_conference/mod_conference.c
+++ b/src/mod/applications/mod_conference/mod_conference.c
@@ -3574,9 +3574,9 @@ conference_obj_t *conference_new(char *name, conference_xml_cfg_t cfg, switch_co
conference->agc_level = 0;
conference->agc_low_energy_level = 0;
- conference->agc_margin = 20;
- conference->agc_change_factor = 3;
- conference->agc_period_len = (1000 / conference->interval) * 2;
+ conference->agc_margin = 100;
+ conference->agc_change_factor = 2;
+ conference->agc_period_len = 500 / conference->interval;
if (agc_level) {
@@ -3610,7 +3610,7 @@ conference_obj_t *conference_new(char *name, conference_xml_cfg_t cfg, switch_co
if (agc_period_len) {
tmp = atoi(agc_period_len);
if (tmp > 0) {
- conference->agc_period_len = (1000 / conference->interval) * tmp;
+ conference->agc_period_len = tmp;
}
}
diff --git a/src/switch_resample.c b/src/switch_resample.c
index 866acdd99c..ca14a221ab 100644
--- a/src/switch_resample.c
+++ b/src/switch_resample.c
@@ -345,9 +345,23 @@ SWITCH_DECLARE(void) switch_mux_channels(int16_t *data, switch_size_t samples, u
SWITCH_DECLARE(void) switch_change_sln_volume_granular(int16_t *data, uint32_t samples, int32_t vol)
{
double newrate = 0;
- double pos[13] = {1.25, 1.50, 1.75, 2.0, 2.25, 2.50, 2.75, 3.0, 3.25, 3.50, 3.75, 4.0, 4.5};
- double neg[13] = {.917, .834, .751, .668, .585, .502, .419, .336, .253, .087, .017, .004, 0.0};
- double *chart;
+ // change in dB mapped to ratio for output sample
+ // computed as (powf(10.0f, (float)(change_in_dB) / 20.0f))
+ static const double pos[SWITCH_GRANULAR_VOLUME_MAX] = {
+ 1.122018, 1.258925, 1.412538, 1.584893, 1.778279, 1.995262, 2.238721, 2.511887, 2.818383, 3.162278,
+ 3.548134, 3.981072, 4.466835, 5.011872, 5.623413, 6.309574, 7.079458, 7.943282, 8.912509, 10.000000,
+ 11.220183, 12.589254, 14.125375, 15.848933, 17.782795, 19.952621, 22.387213, 25.118862, 28.183832, 31.622776,
+ 35.481335, 39.810719, 44.668358, 50.118729, 56.234131, 63.095726, 70.794586, 79.432816, 89.125107, 100.000000,
+ 112.201836, 125.892517, 141.253784, 158.489334, 177.827942, 199.526215, 223.872070, 251.188705, 281.838318, 316.227753
+ };
+ static const double neg[SWITCH_GRANULAR_VOLUME_MAX] = {
+ 0.891251, 0.794328, 0.707946, 0.630957, 0.562341, 0.501187, 0.446684, 0.398107, 0.354813, 0.316228,
+ 0.281838, 0.251189, 0.223872, 0.199526, 0.177828, 0.158489, 0.141254, 0.125893, 0.112202, 0.100000,
+ 0.089125, 0.079433, 0.070795, 0.063096, 0.056234, 0.050119, 0.044668, 0.039811, 0.035481, 0.031623,
+ 0.028184, 0.025119, 0.022387, 0.019953, 0.017783, 0.015849, 0.014125, 0.012589, 0.011220, 0.010000,
+ 0.008913, 0.007943, 0.007079, 0.006310, 0.005623, 0.005012, 0.004467, 0.003981, 0.003548, 0.000000 // NOTE mapped -50 dB ratio to total silence instead of 0.003162
+ };
+ const double *chart;
uint32_t i;
if (vol == 0) return;
@@ -362,7 +376,7 @@ SWITCH_DECLARE(void) switch_change_sln_volume_granular(int16_t *data, uint32_t s
i = abs(vol) - 1;
- switch_assert(i < 13);
+ switch_assert(i < SWITCH_GRANULAR_VOLUME_MAX);
newrate = chart[i];
@@ -444,6 +458,13 @@ SWITCH_DECLARE(void) switch_agc_set(switch_agc_t *agc, uint32_t energy_avg,
agc->change_factor = change_factor;
agc->period_len = period_len;
agc->low_energy_point = low_energy_point;
+
+ agc->score = 0;
+ agc->score_count = 0;
+ agc->score_sum = 0;
+ agc->score_avg = 0;
+ agc->score_over = 0;
+ agc->score_under = 0;
}
SWITCH_DECLARE(switch_status_t) switch_agc_create(switch_agc_t **agcP, uint32_t energy_avg,
@@ -539,6 +560,8 @@ SWITCH_DECLARE(switch_status_t) switch_agc_feed(switch_agc_t *agc, int16_t *data
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "[%s] OVER++ SCORE AVG: %d ENERGY AVG: %d MARGIN: %d\n",
agc->token, agc->score_avg, agc->energy_avg, agc->margin);
agc->score_over++;
+ } else {
+ agc->score_over = 0;
}
} else {
agc->score_over = 0;
@@ -549,8 +572,6 @@ SWITCH_DECLARE(switch_status_t) switch_agc_feed(switch_agc_t *agc, int16_t *data
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "[%s] BELOW LOW POINT, SCORE AVG: %d ENERGY AVG: %d MARGIN: %d\n",
agc->token, agc->score_avg, agc->energy_avg, agc->margin);
} else if (((agc->score_avg < agc->energy_avg) && (agc->energy_avg - agc->score_avg > agc->margin))) {
- //&& (agc->vol < 0 || agc->score_avg > agc->low_energy_point)) {
-
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "[%s] UNDER++ SCORE AVG: %d ENERGY AVG: %d MARGIN: %d\n",
agc->token, agc->score_avg, agc->energy_avg, agc->margin);
agc->score_under++;
From fd27504a7dc4561b5f7f2ff27762f8e5c362f3bd Mon Sep 17 00:00:00 2001
From: Andrey Volk
Date: Fri, 9 Apr 2021 00:55:52 +0300
Subject: [PATCH 103/655] [Core] Add switch_digest(), switch_digest_string()
APIs. Add unit-tests.
---
src/include/switch_utils.h | 3 +
src/switch_core.c | 2 +
src/switch_utils.c | 87 ++++++++++++++++++++++++
tests/unit/switch_core.c | 50 ++++++++++++++
tests/unit/test_switch_core.2017.vcxproj | 1 +
5 files changed, 143 insertions(+)
diff --git a/src/include/switch_utils.h b/src/include/switch_utils.h
index 1c40975908..20655ecd4e 100644
--- a/src/include/switch_utils.h
+++ b/src/include/switch_utils.h
@@ -1460,6 +1460,9 @@ SWITCH_DECLARE(char *)switch_html_strip(const char *str);
SWITCH_DECLARE(unsigned long) switch_getpid(void);
+SWITCH_DECLARE(switch_status_t) switch_digest(const char *digest_name, unsigned char **digest, const void *input, switch_size_t inputLen, unsigned int *outputlen);
+SWITCH_DECLARE(switch_status_t) switch_digest_string(const char *digest_name, char **digest_str, const void *input, switch_size_t inputLen, unsigned int *outputlen);
+
SWITCH_END_EXTERN_C
#endif
/* For Emacs:
diff --git a/src/switch_core.c b/src/switch_core.c
index 2a27b57ea3..d4507aa49c 100644
--- a/src/switch_core.c
+++ b/src/switch_core.c
@@ -1945,6 +1945,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_init(switch_core_flag_t flags, switc
SSL_library_init();
switch_ssl_init_ssl_locks();
+ OpenSSL_add_all_algorithms();
switch_curl_init();
switch_core_set_variable("hostname", runtime.hostname);
@@ -3037,6 +3038,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_destroy(void)
switch_curl_destroy();
switch_ssl_destroy_ssl_locks();
+ EVP_cleanup();
switch_scheduler_task_thread_stop();
diff --git a/src/switch_utils.c b/src/switch_utils.c
index 5d6b8f2aaf..0fee81551b 100644
--- a/src/switch_utils.c
+++ b/src/switch_utils.c
@@ -51,6 +51,10 @@
#include "gumbo.h"
#endif
+#if defined(HAVE_OPENSSL)
+#include
+#endif
+
struct switch_network_node {
ip_t ip;
ip_t mask;
@@ -4549,6 +4553,89 @@ SWITCH_DECLARE(unsigned long) switch_getpid(void)
return (unsigned long)pid;
}
+SWITCH_DECLARE(switch_status_t) switch_digest(const char *digest_name, unsigned char **digest, const void *input, switch_size_t inputLen, unsigned int *outputlen)
+{
+#if defined(HAVE_OPENSSL)
+ EVP_MD_CTX *mdctx;
+ const EVP_MD *md;
+ int size;
+
+ switch_assert(digest);
+
+ if (!digest_name) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Message digest is not set\n");
+ return SWITCH_STATUS_FALSE;
+ }
+
+ md = EVP_get_digestbyname(digest_name);
+
+ if (!md) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unknown message digest %s\n", digest_name);
+ return SWITCH_STATUS_FALSE;
+ }
+
+ size = EVP_MD_size(md);
+ if (!size || !(*digest = malloc(size))) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Zero digest size or can't allocate memory to store results %s\n", digest_name);
+ return SWITCH_STATUS_FALSE;
+ }
+
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+ mdctx = EVP_MD_CTX_new();
+#else
+ mdctx = EVP_MD_CTX_create();
+#endif
+
+ if (!mdctx) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "EVP_MD_CTX_new error\n");
+ switch_safe_free(*digest);
+ return SWITCH_STATUS_FALSE;
+ }
+
+ EVP_MD_CTX_init(mdctx);
+ EVP_DigestInit_ex(mdctx, md, NULL);
+ EVP_DigestUpdate(mdctx, input, inputLen);
+ EVP_DigestFinal_ex(mdctx, *digest, outputlen);
+
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+ EVP_MD_CTX_free(mdctx);
+#else
+ EVP_MD_CTX_destroy(mdctx);
+#endif
+
+ return SWITCH_STATUS_SUCCESS;
+#else
+ return SWITCH_STATUS_FALSE;
+#endif
+}
+
+SWITCH_DECLARE(switch_status_t) switch_digest_string(const char *digest_name, char **digest_str, const void *input, switch_size_t inputLen, unsigned int *outputlen)
+{
+ unsigned char *digest = NULL;
+ switch_status_t status;
+ short i = 0, x;
+ uint8_t b;
+
+ status = switch_digest(digest_name, &digest, input, inputLen, outputlen);
+
+ if (status == SWITCH_STATUS_SUCCESS) {
+ if ((*digest_str = malloc(*outputlen * 2 + 1))) {
+ for (x = i = 0; x < *outputlen; x++) {
+ b = (digest[x] >> 4) & 15;
+ (*digest_str)[i++] = b + (b > 9 ? 'a' - 10 : '0');
+ b = digest[x] & 15;
+ (*digest_str)[i++] = b + (b > 9 ? 'a' - 10 : '0');
+ }
+
+ (*digest_str)[i] = '\0';
+ }
+ }
+
+ switch_safe_free(digest);
+ *outputlen = i;
+
+ return status;
+}
/* For Emacs:
* Local Variables:
diff --git a/tests/unit/switch_core.c b/tests/unit/switch_core.c
index 9f58969a6f..d0d6bacef2 100644
--- a/tests/unit/switch_core.c
+++ b/tests/unit/switch_core.c
@@ -34,6 +34,10 @@
#include
+#if defined(HAVE_OPENSSL)
+#include
+#endif
+
FST_CORE_BEGIN("./conf")
{
FST_SUITE_BEGIN(switch_ivr_originate)
@@ -48,6 +52,52 @@ FST_CORE_BEGIN("./conf")
}
FST_TEARDOWN_END()
+#ifdef HAVE_OPENSSL
+ FST_TEST_BEGIN(test_md5)
+ {
+ char *digest_name = "md5";
+ char *digest_str = NULL;
+ const char *str = "test data";
+ unsigned int outputlen;
+
+ switch_status_t status = switch_digest_string(digest_name, &digest_str, str, strlen(str), &outputlen);
+ fst_check_int_equals(status, SWITCH_STATUS_SUCCESS);
+ fst_check_string_equals(digest_str, "eb733a00c0c9d336e65691a37ab54293");
+ switch_safe_free(digest_str);
+ }
+ FST_TEST_END()
+
+ FST_TEST_BEGIN(test_sha256)
+ {
+ char *digest_name = "sha256";
+ char *digest_str = NULL;
+ const char *str = "test data";
+ unsigned int outputlen;
+
+ switch_status_t status = switch_digest_string(digest_name, &digest_str, str, strlen(str), &outputlen);
+ fst_check_int_equals(status, SWITCH_STATUS_SUCCESS);
+ fst_check_string_equals(digest_str, "916f0027a575074ce72a331777c3478d6513f786a591bd892da1a577bf2335f9");
+ switch_safe_free(digest_str);
+ }
+ FST_TEST_END()
+#endif
+
+#if OPENSSL_VERSION_NUMBER >= 0x10101000L
+ FST_TEST_BEGIN(test_sha512_256)
+ {
+ char *digest_name = "sha512-256";
+ char *digest_str = NULL;
+ const char *str = "test data";
+ unsigned int outputlen;
+
+ switch_status_t status = switch_digest_string(digest_name, &digest_str, str, strlen(str), &outputlen);
+ fst_check_int_equals(status, SWITCH_STATUS_SUCCESS);
+ fst_check_string_equals(digest_str, "9fe875600168548c1954aed4f03974ce06b3e17f03a70980190da2d7ef937a43");
+ switch_safe_free(digest_str);
+ }
+ FST_TEST_END()
+#endif
+
#ifndef WIN32
FST_TEST_BEGIN(test_fork)
{
diff --git a/tests/unit/test_switch_core.2017.vcxproj b/tests/unit/test_switch_core.2017.vcxproj
index 922fb9b51f..c9e1cd5423 100644
--- a/tests/unit/test_switch_core.2017.vcxproj
+++ b/tests/unit/test_switch_core.2017.vcxproj
@@ -47,6 +47,7 @@
$(DefaultPlatformToolset)
+
From 833235b94139bdf43991eb0a5dd59046ef6bb3ac Mon Sep 17 00:00:00 2001
From: Dragos Oancea
Date: Fri, 9 Apr 2021 15:45:17 +0000
Subject: [PATCH 104/655] [mod_sofia] Add RFC8760 (sha-256, sha-512) enable on
the sip profile, eg:
---
src/mod/endpoints/mod_sofia/mod_sofia.h | 13 ++
src/mod/endpoints/mod_sofia/sofia.c | 11 ++
src/mod/endpoints/mod_sofia/sofia_reg.c | 162 ++++++++++++++++++++++--
3 files changed, 172 insertions(+), 14 deletions(-)
diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.h b/src/mod/endpoints/mod_sofia/mod_sofia.h
index db709b9721..3c2d02a5a7 100644
--- a/src/mod/endpoints/mod_sofia/mod_sofia.h
+++ b/src/mod/endpoints/mod_sofia/mod_sofia.h
@@ -369,6 +369,8 @@ typedef enum {
#define SOFIA_MAX_MSG_QUEUE 64
#define SOFIA_MSG_QUEUE_SIZE 1000
+#define SOFIA_MAX_REG_ALGS 7 /* rfc8760 */
+
struct mod_sofia_globals {
switch_memory_pool_t *pool;
switch_hash_t *profile_hash;
@@ -599,6 +601,13 @@ typedef enum {
KA_INFO
} ka_type_t;
+typedef enum {
+ ALG_MD5 = (1 << 0),
+ ALG_SHA256 = (1 << 1),
+ ALG_SHA512 = (1 << 2),
+ ALG_NONE = (1 << 3),
+} sofia_auth_algs_t;
+
struct sofia_profile {
int debug;
int parse_invite_tel_params;
@@ -789,6 +798,8 @@ struct sofia_profile {
char *rfc7989_filter;
char *acl_inbound_x_token_header;
char *acl_proxy_x_token_header;
+ uint8_t rfc8760_algs_count;
+ sofia_auth_algs_t auth_algs[SOFIA_MAX_REG_ALGS];
};
@@ -1260,6 +1271,8 @@ void sofia_reg_close_handles(sofia_profile_t *profile);
void write_csta_xml_chunk(switch_event_t *event, switch_stream_handle_t stream, const char *csta_event, char *fwd_type);
void sofia_glue_clear_soa(switch_core_session_t *session, switch_bool_t partner);
+sofia_auth_algs_t sofia_alg_str2id(char *algorithm, switch_bool_t permissive);
+switch_status_t sofia_make_digest(sofia_auth_algs_t use_alg, char **digest, const void *input, unsigned int *outputlen);
/* For Emacs:
* Local Variables:
diff --git a/src/mod/endpoints/mod_sofia/sofia.c b/src/mod/endpoints/mod_sofia/sofia.c
index b76a804e8e..82fb6471c9 100644
--- a/src/mod/endpoints/mod_sofia/sofia.c
+++ b/src/mod/endpoints/mod_sofia/sofia.c
@@ -6039,6 +6039,17 @@ switch_status_t config_sofia(sofia_config_t reload, char *profile_name)
profile->proxy_notify_events = switch_core_strdup(profile->pool, val);
} else if (!strcasecmp(var, "proxy-info-content-types")) {
profile->proxy_info_content_types = switch_core_strdup(profile->pool, val);
+ } else if (!strcasecmp(var, "rfc8760-auth-algorithms")) {
+ /* the order in which algorithms are allowed matters */
+ char *algs_arr[100] = { 0 };
+ uint8_t algs = switch_separate_string(val, ',', algs_arr, (sizeof(algs_arr) / sizeof(algs_arr[0])));
+ if (algs && algs < SOFIA_MAX_REG_ALGS) {
+ int i;
+ for (i = 0; i < algs && algs_arr[i]; i++) {
+ profile->auth_algs[i] = sofia_alg_str2id(algs_arr[i], SWITCH_TRUE);
+ }
+ profile->rfc8760_algs_count = algs;
+ }
}
}
diff --git a/src/mod/endpoints/mod_sofia/sofia_reg.c b/src/mod/endpoints/mod_sofia/sofia_reg.c
index 582de54cb4..6263e05170 100644
--- a/src/mod/endpoints/mod_sofia/sofia_reg.c
+++ b/src/mod/endpoints/mod_sofia/sofia_reg.c
@@ -1123,13 +1123,22 @@ switch_console_callback_match_t *sofia_reg_find_reg_url_with_positive_expires_mu
return cbt.list;
}
+static char * sofia_alg_to_str(sofia_auth_algs_t alg)
+{
+ if (alg == ALG_SHA256)
+ return "SHA-256";
+ if (alg == ALG_SHA512)
+ return "SHA-512-256";
+ return "MD5";
+}
void sofia_reg_auth_challenge(sofia_profile_t *profile, nua_handle_t *nh, sofia_dispatch_event_t *de,
sofia_regtype_t regtype, const char *realm, int stale, long exptime)
{
switch_uuid_t uuid;
char uuid_str[SWITCH_UUID_FORMATTED_LENGTH + 1];
- char *sql, *auth_str;
+ char *sql, *auth_str = NULL;
+ char *auth_str_rfc8760[SOFIA_MAX_REG_ALGS] = {0};
msg_t *msg = NULL;
@@ -1147,14 +1156,53 @@ void sofia_reg_auth_challenge(sofia_profile_t *profile, nua_handle_t *nh, sofia_
switch_assert(sql != NULL);
sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE);
- auth_str = switch_mprintf("Digest realm=\"%q\", nonce=\"%q\",%s algorithm=MD5, qop=\"auth\"", realm, uuid_str, stale ? " stale=true," : "");
+ if (!profile->rfc8760_algs_count) {
+ auth_str = switch_mprintf("Digest realm=\"%q\", nonce=\"%q\",%s algorithm=MD5, qop=\"auth\"", realm, uuid_str, stale ? " stale=true," : "");
+ } else {
+ int i;
+ for (i = 0 ; i < profile->rfc8760_algs_count; i++) {
+ if (profile->auth_algs[i] != ALG_NONE) {
+ auth_str_rfc8760[i] = switch_mprintf("Digest realm=\"%q\", nonce=\"%q\",%s algorithm=%s, qop=\"auth\"", realm, uuid_str, stale ? " stale=true," : "", sofia_alg_to_str(profile->auth_algs[i]));
+ }
+ }
+ }
if (regtype == REG_REGISTER) {
- nua_respond(nh, SIP_401_UNAUTHORIZED, TAG_IF(msg, NUTAG_WITH_THIS_MSG(msg)), SIPTAG_WWW_AUTHENTICATE_STR(auth_str), TAG_END());
+ if (!profile->rfc8760_algs_count) {
+ nua_respond(nh, SIP_401_UNAUTHORIZED, TAG_IF(msg, NUTAG_WITH_THIS_MSG(msg)), SIPTAG_WWW_AUTHENTICATE_STR(auth_str), TAG_END());
+ } else {
+ int i;
+ nua_respond(nh, SIP_401_UNAUTHORIZED, TAG_IF(msg, NUTAG_WITH_THIS_MSG(msg)),
+ TAG_IF(auth_str_rfc8760[0], SIPTAG_WWW_AUTHENTICATE_STR(auth_str_rfc8760[0])), TAG_IF(auth_str_rfc8760[1], SIPTAG_WWW_AUTHENTICATE_STR(auth_str_rfc8760[1])),
+ TAG_IF(auth_str_rfc8760[2], SIPTAG_WWW_AUTHENTICATE_STR(auth_str_rfc8760[2])), TAG_IF(auth_str_rfc8760[3], SIPTAG_WWW_AUTHENTICATE_STR(auth_str_rfc8760[3])),
+ TAG_IF(auth_str_rfc8760[4], SIPTAG_WWW_AUTHENTICATE_STR(auth_str_rfc8760[4])), TAG_IF(auth_str_rfc8760[5], SIPTAG_WWW_AUTHENTICATE_STR(auth_str_rfc8760[5])),
+ TAG_IF(auth_str_rfc8760[6], SIPTAG_WWW_AUTHENTICATE_STR(auth_str_rfc8760[6])), TAG_END());
+ for (i = 0 ; i < profile->rfc8760_algs_count; i++) {
+ switch_safe_free(auth_str_rfc8760[i]);
+ }
+ }
} else if (regtype == REG_INVITE) {
- nua_respond(nh, SIP_407_PROXY_AUTH_REQUIRED,
+ if (!profile->rfc8760_algs_count) {
+ nua_respond(nh, SIP_407_PROXY_AUTH_REQUIRED,
+ TAG_IF(msg, NUTAG_WITH_THIS_MSG(msg)),
+ SIPTAG_PROXY_AUTHENTICATE_STR(auth_str), TAG_END());
+ } else {
+ int i;
+ nua_respond(nh, SIP_407_PROXY_AUTH_REQUIRED,
TAG_IF(msg, NUTAG_WITH_THIS_MSG(msg)),
- SIPTAG_PROXY_AUTHENTICATE_STR(auth_str), TAG_END());
+ TAG_IF(auth_str_rfc8760[0], SIPTAG_PROXY_AUTHENTICATE_STR(auth_str_rfc8760[0])),
+ TAG_IF(auth_str_rfc8760[1], SIPTAG_PROXY_AUTHENTICATE_STR(auth_str_rfc8760[1])),
+ TAG_IF(auth_str_rfc8760[2], SIPTAG_PROXY_AUTHENTICATE_STR(auth_str_rfc8760[2])),
+ TAG_IF(auth_str_rfc8760[3], SIPTAG_PROXY_AUTHENTICATE_STR(auth_str_rfc8760[3])),
+ TAG_IF(auth_str_rfc8760[4], SIPTAG_PROXY_AUTHENTICATE_STR(auth_str_rfc8760[4])),
+ TAG_IF(auth_str_rfc8760[5], SIPTAG_PROXY_AUTHENTICATE_STR(auth_str_rfc8760[5])),
+ TAG_IF(auth_str_rfc8760[6], SIPTAG_PROXY_AUTHENTICATE_STR(auth_str_rfc8760[6])),
+ TAG_END());
+ for (i = 0 ; i < profile->rfc8760_algs_count; i++) {
+ switch_safe_free(auth_str_rfc8760[i]);
+ }
+ }
+
}
switch_safe_free(auth_str);
@@ -2710,6 +2758,54 @@ static int sofia_reg_regcount_callback(void *pArg, int argc, char **argv, char *
return 0;
}
+static switch_bool_t sofia_alg_is_allowed(sofia_profile_t *profile, sofia_auth_algs_t alg)
+{
+ int i;
+
+ for (i = 0 ; i < SOFIA_MAX_REG_ALGS; i++) {
+ if (profile->auth_algs[i] == alg) {
+ return SWITCH_TRUE;
+ }
+ }
+ return SWITCH_FALSE;
+}
+
+/*we are more permissive with the alg names that come from cfg */
+sofia_auth_algs_t sofia_alg_str2id(char *algorithm, switch_bool_t permissive)
+{
+ if (!strcasecmp(algorithm, "MD5") || (permissive && !strcasecmp(algorithm, "MD-5"))) {
+ return ALG_MD5;
+ }
+ if (!strcasecmp(algorithm, "SHA-256") || (permissive && !strcasecmp(algorithm, "SHA256"))) {
+ return ALG_SHA256;
+ }
+ if (!strcasecmp(algorithm, "SHA-512-256") || (permissive && !strcasecmp(algorithm, "SHA512"))
+ || (permissive && !strcasecmp(algorithm, "SHA512-256")) || (permissive && !strcasecmp(algorithm, "SHA-512"))) {
+ return ALG_SHA512;
+ }
+
+ return ALG_NONE;
+}
+
+switch_status_t sofia_make_digest(sofia_auth_algs_t use_alg, char **digest, const void *input, unsigned int *outputlen)
+{
+ switch (use_alg)
+ {
+ case ALG_MD5:
+ switch_digest_string("md5", digest, input, strlen((char *)input), outputlen);
+ break;
+ case ALG_SHA256:
+ switch_digest_string("sha256", digest, input, strlen((char *)input), outputlen);
+ break;
+ case ALG_SHA512:
+ switch_digest_string("sha512-256", digest, input, strlen((char *)input), outputlen);
+ break;
+ default:
+ return SWITCH_STATUS_FALSE;
+ }
+ return SWITCH_STATUS_SUCCESS;
+}
+
auth_res_t sofia_reg_parse_auth(sofia_profile_t *profile,
sip_authorization_t const *authorization,
sip_t const *sip,
@@ -2724,9 +2820,8 @@ auth_res_t sofia_reg_parse_auth(sofia_profile_t *profile,
{
int indexnum;
const char *cur;
- char uridigest[SWITCH_MD5_DIGEST_STRING_SIZE];
- char bigdigest[SWITCH_MD5_DIGEST_STRING_SIZE];
- char *username, *realm, *nonce, *uri, *qop, *cnonce, *nc, *response, *input = NULL, *input2 = NULL;
+ char *uridigest = NULL, *bigdigest = NULL, *hexdigest = NULL;
+ char *username, *realm, *nonce, *uri, *qop, *cnonce, *nc, *response, *algorithm, *input = NULL, *input2 = NULL;
auth_res_t ret = AUTH_FORBIDDEN;
int first = 0;
const char *passwd = NULL;
@@ -2737,7 +2832,6 @@ auth_res_t sofia_reg_parse_auth(sofia_profile_t *profile,
char *sql;
char *number_alias = NULL;
switch_xml_t user = NULL, param, uparams;
- char hexdigest[SWITCH_MD5_DIGEST_STRING_SIZE] = "";
char *domain_name = NULL;
switch_event_t *params = NULL;
const char *auth_acl = NULL;
@@ -2747,9 +2841,12 @@ auth_res_t sofia_reg_parse_auth(sofia_profile_t *profile,
const char *user_agent_filter = profile->user_agent_filter;
uint32_t max_registrations_perext = profile->max_registrations_perext;
char client_port[16];
+ uint8_t use_alg;
+ unsigned int digest_outputlen;
+
snprintf(client_port, 15, "%d", network_port);
- username = realm = nonce = uri = qop = cnonce = nc = response = NULL;
+ username = realm = nonce = uri = qop = cnonce = nc = response = algorithm = NULL;
if (authorization->au_params) {
for (indexnum = 0; (cur = authorization->au_params[indexnum]); indexnum++) {
@@ -2782,7 +2879,10 @@ auth_res_t sofia_reg_parse_auth(sofia_profile_t *profile,
response = strdup(val);
} else if (!strcasecmp(var, "nc") && !nc) {
nc = strdup(val);
+ } else if (!strcasecmp(var, "algorithm") && !algorithm) {
+ algorithm = strdup(val);
}
+
}
free(work);
@@ -2807,6 +2907,26 @@ auth_res_t sofia_reg_parse_auth(sofia_profile_t *profile,
}
}
+ if (algorithm) {
+ if (profile->rfc8760_algs_count) {
+ switch_bool_t not_allowed = SWITCH_FALSE;
+ sofia_auth_algs_t alg_id = sofia_alg_str2id(algorithm, SWITCH_FALSE);
+ if ((alg_id == ALG_NONE) || !sofia_alg_is_allowed(profile, alg_id)) {
+ not_allowed = SWITCH_TRUE;
+ } else {
+ use_alg = alg_id;
+ }
+ if (not_allowed) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "SIP auth hash algorithm explicitly not allowed. [%s]\n", algorithm);
+ goto end;
+ }
+ } else {
+ use_alg = ALG_MD5;
+ }
+ } else {
+ use_alg = ALG_MD5;
+ }
+
user_agent = (sip && sip->sip_user_agent) ? sip->sip_user_agent->g_string : "unknown";
if (zstr(np)) {
@@ -3059,10 +3179,14 @@ auth_res_t sofia_reg_parse_auth(sofia_profile_t *profile,
if (!a1_hash) {
input = switch_mprintf("%s:%s:%s", username, realm, passwd);
- switch_md5_string(hexdigest, (void *) input, strlen(input));
+
+ if (sofia_make_digest(use_alg, &hexdigest, (void *)input, &digest_outputlen) != SWITCH_STATUS_SUCCESS) {
+ switch_safe_free(input);
+ goto end;
+ }
+
switch_safe_free(input);
a1_hash = hexdigest;
-
}
if (user_agent_filter) {
@@ -3110,7 +3234,10 @@ auth_res_t sofia_reg_parse_auth(sofia_profile_t *profile,
for_the_sake_of_interop:
if ((input = switch_mprintf("%s:%q", regstr, uri))) {
- switch_md5_string(uridigest, (void *) input, strlen(input));
+ if (sofia_make_digest(use_alg, &uridigest, (void *)input, &digest_outputlen) != SWITCH_STATUS_SUCCESS) {
+ switch_safe_free(input);
+ goto end;
+ }
}
if (nc && cnonce && qop) {
@@ -3120,7 +3247,10 @@ auth_res_t sofia_reg_parse_auth(sofia_profile_t *profile,
}
if (input2) {
- switch_md5_string(bigdigest, (void *) input2, strlen(input2));
+ if (sofia_make_digest(use_alg, &bigdigest, (void *)input2, &digest_outputlen) != SWITCH_STATUS_SUCCESS) {
+ switch_safe_free(input2);
+ goto end;
+ }
}
if (input2 && !strcasecmp(bigdigest, response)) {
@@ -3286,6 +3416,10 @@ auth_res_t sofia_reg_parse_auth(sofia_profile_t *profile,
switch_safe_free(cnonce);
switch_safe_free(nc);
switch_safe_free(response);
+ switch_safe_free(algorithm);
+ switch_safe_free(uridigest);
+ switch_safe_free(bigdigest);
+ switch_safe_free(hexdigest);
if (reg_count && !*reg_count) {
if ((ret == AUTH_OK || ret == AUTH_RENEWED)) {
From e6b6aea6ff906e8567e3b0dedf7d28be32b8b368 Mon Sep 17 00:00:00 2001
From: Andrey Volk
Date: Wed, 10 Mar 2021 20:08:20 +0300
Subject: [PATCH 105/655] [mod_sofia] Add basic INVITE test
---
.../mod_sofia/test/conf/freeswitch.xml | 102 ++++++++++++++++++
.../mod_sofia/test/test_sofia_funcs.c | 28 ++++-
2 files changed, 125 insertions(+), 5 deletions(-)
create mode 100644 src/mod/endpoints/mod_sofia/test/conf/freeswitch.xml
diff --git a/src/mod/endpoints/mod_sofia/test/conf/freeswitch.xml b/src/mod/endpoints/mod_sofia/test/conf/freeswitch.xml
new file mode 100644
index 0000000000..c654a84ebc
--- /dev/null
+++ b/src/mod/endpoints/mod_sofia/test/conf/freeswitch.xml
@@ -0,0 +1,102 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/mod/endpoints/mod_sofia/test/test_sofia_funcs.c b/src/mod/endpoints/mod_sofia/test/test_sofia_funcs.c
index e5b1baa932..0c03d232d1 100644
--- a/src/mod/endpoints/mod_sofia/test/test_sofia_funcs.c
+++ b/src/mod/endpoints/mod_sofia/test/test_sofia_funcs.c
@@ -1,6 +1,6 @@
/*
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
- * Copyright (C) 2005-2018, Anthony Minessale II
+ * Copyright (C) 2005-2021, Anthony Minessale II
*
* Version: MPL 1.1
*
@@ -33,9 +33,9 @@
#include
#include "../mod_sofia.c"
-FST_MINCORE_BEGIN("./conf")
+FST_CORE_EX_BEGIN("./conf", SCF_VG | SCF_USE_SQL)
-FST_SUITE_BEGIN(switch_hash)
+FST_MODULE_BEGIN(mod_sofia, sofia)
FST_SETUP_BEGIN()
{
@@ -94,9 +94,27 @@ FST_TEST_BEGIN(test_protect_url)
}
FST_TEST_END()
-FST_SUITE_END()
+FST_TEST_BEGIN(originate_test)
+{
+ switch_core_session_t *session = NULL;
+ switch_channel_t *channel = NULL;
+ switch_status_t status;
+ switch_call_cause_t cause;
+ const char *local_ip_v4 = switch_core_get_variable("local_ip_v4");
+ status = switch_ivr_originate(NULL, &session, &cause, switch_core_sprintf(fst_pool, "{ignore_early_media=true}sofia/internal/park@%s:53060", local_ip_v4), 2, NULL, NULL, NULL, NULL, NULL, SOF_NONE, NULL, NULL);
+ fst_requires(session);
+ fst_check(status == SWITCH_STATUS_SUCCESS);
+ channel = switch_core_session_get_channel(session);
+ fst_requires(channel);
+ switch_channel_hangup(channel, SWITCH_CAUSE_NORMAL_CLEARING);
+ switch_core_session_rwunlock(session);
+ switch_sleep(1 * 1000 * 1000);
+}
+FST_TEST_END()
-FST_MINCORE_END()
+FST_MODULE_END()
+
+FST_CORE_END()
/* For Emacs:
From 73569bb1f79fb2d8349f957c582c84dcd5dd4f5d Mon Sep 17 00:00:00 2001
From: Dragos Oancea
Date: Tue, 13 Apr 2021 10:30:15 +0000
Subject: [PATCH 106/655] [mod_sofia] rfc8760: reorder hash algorithms by
priority (strength), no matter the order provided in the cfg
---
src/mod/endpoints/mod_sofia/sofia.c | 23 +++++++++++++++++++----
1 file changed, 19 insertions(+), 4 deletions(-)
diff --git a/src/mod/endpoints/mod_sofia/sofia.c b/src/mod/endpoints/mod_sofia/sofia.c
index 82fb6471c9..dbd9f94343 100644
--- a/src/mod/endpoints/mod_sofia/sofia.c
+++ b/src/mod/endpoints/mod_sofia/sofia.c
@@ -6040,15 +6040,30 @@ switch_status_t config_sofia(sofia_config_t reload, char *profile_name)
} else if (!strcasecmp(var, "proxy-info-content-types")) {
profile->proxy_info_content_types = switch_core_strdup(profile->pool, val);
} else if (!strcasecmp(var, "rfc8760-auth-algorithms")) {
- /* the order in which algorithms are allowed matters */
char *algs_arr[100] = { 0 };
uint8_t algs = switch_separate_string(val, ',', algs_arr, (sizeof(algs_arr) / sizeof(algs_arr[0])));
if (algs && algs < SOFIA_MAX_REG_ALGS) {
- int i;
+ sofia_auth_algs_t temp;
+ int i, j = 0;
for (i = 0; i < algs && algs_arr[i]; i++) {
- profile->auth_algs[i] = sofia_alg_str2id(algs_arr[i], SWITCH_TRUE);
+ temp = sofia_alg_str2id(algs_arr[i], SWITCH_TRUE);
+ if (temp != ALG_NONE) {
+ profile->auth_algs[j] = temp;
+ j++;
+ }
+ }
+ profile->rfc8760_algs_count = j;
+ for (i = 0; i < profile->rfc8760_algs_count; i++) {
+ for (j = i + 1; j < profile->rfc8760_algs_count; j++) {
+ /* when adding algs: algs must be kept in priority order in the enum */
+ if (profile->auth_algs[i] < profile->auth_algs[j])
+ {
+ temp = profile->auth_algs[i];
+ profile->auth_algs[i] = profile->auth_algs[j];
+ profile->auth_algs[j] = temp;
+ }
+ }
}
- profile->rfc8760_algs_count = algs;
}
}
}
From 7fc5d9a7c36337b15a5c7044bdaecdc82d95d94b Mon Sep 17 00:00:00 2001
From: Dragos Oancea
Date: Wed, 31 Mar 2021 13:49:59 +0000
Subject: [PATCH 107/655] [core] RTP: handle flush for incoming stream with DTX
or packet loss.
---
src/switch_rtp.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/src/switch_rtp.c b/src/switch_rtp.c
index d75219c6cf..e879436206 100644
--- a/src/switch_rtp.c
+++ b/src/switch_rtp.c
@@ -390,6 +390,7 @@ struct switch_rtp {
//uint32_t last_clock_ts;
uint32_t last_write_ts;
uint32_t last_read_ts;
+ uint32_t prev_read_ts;
uint32_t last_cng_ts;
uint32_t last_write_samplecount;
uint32_t delay_samples;
@@ -6413,6 +6414,7 @@ static switch_status_t read_rtp_packet(switch_rtp_t *rtp_session, switch_size_t
}
if (ts) {
+ rtp_session->prev_read_ts = rtp_session->last_read_ts;
rtp_session->last_read_ts = ts;
}
@@ -6488,7 +6490,8 @@ static switch_status_t read_rtp_packet(switch_rtp_t *rtp_session, switch_size_t
}
} else {
if (rtp_session->last_rtp_hdr.m && rtp_session->last_rtp_hdr.pt != rtp_session->recv_te &&
- !rtp_session->flags[SWITCH_RTP_FLAG_VIDEO] && !(rtp_session->rtp_bugs & RTP_BUG_IGNORE_MARK_BIT)) {
+ !rtp_session->flags[SWITCH_RTP_FLAG_VIDEO] && !(rtp_session->rtp_bugs & RTP_BUG_IGNORE_MARK_BIT) &&
+ rtp_session->last_read_ts - rtp_session->prev_read_ts < rtp_session->samples_per_interval * 3) {
switch_rtp_set_flag(rtp_session, SWITCH_RTP_FLAG_FLUSH);
} else if (rtp_session->last_jb_read_ssrc && rtp_session->last_jb_read_ssrc != read_ssrc) {
switch_rtp_set_flag(rtp_session, SWITCH_RTP_FLAG_FLUSH);
From 0877bd5770b8853dc81132c64b971bdb81b56d8c Mon Sep 17 00:00:00 2001
From: Norm Brandinger
Date: Fri, 16 Apr 2021 10:24:51 -0400
Subject: [PATCH 108/655] [Core] switch_rtp: fix
switch_rtp_set_max_missed_packets logging
Warning message about missed packets is misleading.
Message indicates greater (>) however, the conditional is greater than or equals (>=).
The message prints the value of rtp_sesstion->missed_count twice instead of printing the value of rtp_session->max_missed_packets.
---
src/switch_rtp.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/switch_rtp.c b/src/switch_rtp.c
index e879436206..1b0d407dec 100644
--- a/src/switch_rtp.c
+++ b/src/switch_rtp.c
@@ -2913,11 +2913,11 @@ SWITCH_DECLARE(void) switch_rtp_set_max_missed_packets(switch_rtp_t *rtp_session
return;
}
- if (rtp_session->missed_count >= max) {
+ if (rtp_session->missed_count > max) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_WARNING,
"new max missed packets(%d->%d) greater than current missed packets(%d). RTP will timeout.\n",
- rtp_session->missed_count, max, rtp_session->missed_count);
+ rtp_session->max_missed_packets, max, rtp_session->missed_count);
}
rtp_session->max_missed_packets = max;
From b7316ba557e6e30e5f12f9ac8c797e947c8d8dca Mon Sep 17 00:00:00 2001
From: sergey-safarov
Date: Mon, 26 Apr 2021 17:46:26 +0300
Subject: [PATCH 109/655] [Build-System] Use a fresher gcc on RHEL based dists
---
freeswitch.spec | 32 ++++++++++++++++++++++++++++++++
1 file changed, 32 insertions(+)
diff --git a/freeswitch.spec b/freeswitch.spec
index 3bbc518119..a62776b1cc 100644
--- a/freeswitch.spec
+++ b/freeswitch.spec
@@ -170,6 +170,19 @@ Requires: zlib
Requires: libxml2
Requires: libsndfile
+%if 0%{?rhel} == 7
+# to build mariadb module required gcc >= 4.9 (more details GH #1046)
+# On CentOS 7 dist you can install fresh gcc using command
+# yum install centos-release-scl && yum install devtoolset-9
+BuildRequires: devtoolset-9
+%endif
+%if 0%{?rhel} == 8
+# we want use fresh gcc on RHEL 8 based dists
+# On CentOS 8 dist you can install fresh gcc using command
+# dnf install gcc-toolset-9
+BuildRequires: gcc-toolset-9
+%endif
+
%if 0%{?suse_version} > 800
PreReq: %insserv_prereq %fillup_prereq
%endif
@@ -1575,6 +1588,16 @@ export DESTDIR=%{buildroot}/
export PKG_CONFIG_PATH=/usr/bin/pkg-config:$PKG_CONFIG_PATH
export ACLOCAL_FLAGS="-I /usr/share/aclocal"
+%if 0%{?rhel} == 7
+# to build mod_mariadb we need gcc >= 4.9 (more details GH #1046)
+export CFLAGS="$CFLAGS -Wno-error=expansion-to-defined"
+. /opt/rh/devtoolset-9/enable
+%endif
+%if 0%{?rhel} == 8
+# we want use fresh gcc on RHEL 8 based dists
+. /opt/rh/gcc-toolset-9/enable
+%endif
+
######################################################################################################################
#
# Bootstrap, Configure and Build the whole enchilada
@@ -1635,6 +1658,15 @@ cd libs/esl
#
######################################################################################################################
%install
+%if 0%{?rhel} == 7
+# to build mod_mariadb we need gcc >= 4.9
+. /opt/rh/devtoolset-9/enable
+%endif
+%if 0%{?rhel} == 8
+# we want use fresh gcc on RHEL 8 based dists
+. /opt/rh/gcc-toolset-9/enable
+%endif
+
%{__make} DESTDIR=%{buildroot} install
From deecaae870dc0caf14bfc421c871bb6660f5e602 Mon Sep 17 00:00:00 2001
From: Chris Rienzo
Date: Tue, 27 Apr 2021 15:54:32 -0400
Subject: [PATCH 110/655] STIR/SHAKEN (#1160)
* [core] Add SWITCH_CAUSEs for STIR/SHAKEN.
[mod_sofia] Add sofia_verify_identity dialplan APP as a STIR/SHAKEN verification service. Set sip_hangup_on_verify_identity_fail=true to end calls that fail verification, otherwise check sip_verstat and sip_verstat_detailed channel variables for verification result.
* [mod_sofia] Fix stir shaken implementation issues on fail.
* fix build
* Fix given comments
* stir_shaken_passport_get_grant return does not require to be freed.
* reworked things
* [core] add switch_rfc822_datetime_to_epoch()
* [mod_sofia] fix test return code
* [mod_sofia] Add Date header when signing Identity
* [mod_sofia] Check Date - WIP doesn't work
* [mod_sofia] STIR/SHAKEN check SIP Date header
* Try to give time for sofia to clean up calls
Co-authored-by: Andrey Volk
---
configure.ac | 4 +
src/include/switch_types.h | 7 +-
src/mod/endpoints/mod_sofia/Makefile.am | 16 +-
src/mod/endpoints/mod_sofia/mod_sofia.c | 426 +++++++++++++++++-
src/mod/endpoints/mod_sofia/mod_sofia.h | 7 +
src/mod/endpoints/mod_sofia/sofia.c | 20 +
src/mod/endpoints/mod_sofia/sofia_glue.c | 29 +-
.../mod_sofia/test/conf/freeswitch.xml | 44 ++
.../mod_sofia/test/stir-shaken/priv.pem | 5 +
.../mod_sofia/test/stir-shaken/pub.pem | 4 +
.../mod_sofia/test/stir-shaken/www/cert.pem | 13 +
.../mod_sofia/test/stir-shaken/www/pub.pem | 13 +
.../mod_sofia/test/test_sofia_funcs.c | 144 ++++++
.../mod_sofia/test/test_sofia_funcs.sh | 11 +
src/switch_channel.c | 5 +
tests/unit/switch_vad.c | 3 +-
16 files changed, 742 insertions(+), 9 deletions(-)
create mode 100644 src/mod/endpoints/mod_sofia/test/stir-shaken/priv.pem
create mode 100644 src/mod/endpoints/mod_sofia/test/stir-shaken/pub.pem
create mode 100644 src/mod/endpoints/mod_sofia/test/stir-shaken/www/cert.pem
create mode 100644 src/mod/endpoints/mod_sofia/test/stir-shaken/www/pub.pem
create mode 100755 src/mod/endpoints/mod_sofia/test/test_sofia_funcs.sh
diff --git a/configure.ac b/configure.ac
index a74edfbc8b..73c260f311 100644
--- a/configure.ac
+++ b/configure.ac
@@ -838,6 +838,10 @@ PKG_CHECK_MODULES([AMRWB], [opencore-amrwb >= 0.1.0 vo-amrwbenc >= 0.1.0],[
AM_CONDITIONAL([HAVE_AMRWB],[true])],[
AC_MSG_RESULT([no]); AM_CONDITIONAL([HAVE_AMRWB],[false])])
+PKG_CHECK_MODULES([STIRSHAKEN], [stirshaken],[
+ AM_CONDITIONAL([HAVE_STIRSHAKEN],[true])],[
+ AC_MSG_RESULT([no]); AM_CONDITIONAL([HAVE_STIRSHAKEN],[false])])
+
AC_CHECK_LIB(apr-1, apr_pool_mutex_set, use_system_apr=yes, use_system_apr=no)
AM_CONDITIONAL([SYSTEM_APR],[test "${use_system_apr}" = "yes"])
AC_CHECK_LIB(aprutil-1, apr_queue_pop_timeout, use_system_aprutil=yes, use_system_aprutil=no)
diff --git a/src/include/switch_types.h b/src/include/switch_types.h
index 58f708729d..fafc508823 100644
--- a/src/include/switch_types.h
+++ b/src/include/switch_types.h
@@ -2235,7 +2235,12 @@ typedef enum {
SWITCH_CAUSE_DECLINE = 616,
SWITCH_CAUSE_DOES_NOT_EXIST_ANYWHERE = 617,
SWITCH_CAUSE_NOT_ACCEPTABLE = 618,
- SWITCH_CAUSE_UNWANTED = 619
+ SWITCH_CAUSE_UNWANTED = 619,
+ SWITCH_CAUSE_NO_IDENTITY = 620,
+ SWITCH_CAUSE_BAD_IDENTITY_INFO = 621,
+ SWITCH_CAUSE_UNSUPPORTED_CERTIFICATE = 622,
+ SWITCH_CAUSE_INVALID_IDENTITY = 623,
+ SWITCH_CAUSE_STALE_DATE = 624
} switch_call_cause_t;
typedef enum {
diff --git a/src/mod/endpoints/mod_sofia/Makefile.am b/src/mod/endpoints/mod_sofia/Makefile.am
index 0e4346e237..4bd1749175 100644
--- a/src/mod/endpoints/mod_sofia/Makefile.am
+++ b/src/mod/endpoints/mod_sofia/Makefile.am
@@ -5,21 +5,27 @@ MODNAME=mod_sofia
noinst_LTLIBRARIES = libsofiamod.la
libsofiamod_la_SOURCES = mod_sofia.c sofia.c sofia_json_api.c sofia_glue.c sofia_presence.c sofia_reg.c sofia_media.c sip-dig.c rtp.c mod_sofia.h
libsofiamod_la_LDFLAGS = -static
-libsofiamod_la_CFLAGS = $(AM_CFLAGS) -I. $(SOFIA_SIP_CFLAGS)
+libsofiamod_la_CFLAGS = $(AM_CFLAGS) -I. $(SOFIA_SIP_CFLAGS) $(STIRSHAKEN_CFLAGS)
+if HAVE_STIRSHAKEN
+libsofiamod_la_CFLAGS += -DHAVE_STIRSHAKEN
+endif
mod_LTLIBRARIES = mod_sofia.la
mod_sofia_la_SOURCES =
mod_sofia_la_LIBADD = $(switch_builddir)/libfreeswitch.la libsofiamod.la
-mod_sofia_la_LDFLAGS = -avoid-version -module -no-undefined -shared $(SOFIA_SIP_LIBS)
+mod_sofia_la_LDFLAGS = -avoid-version -module -no-undefined -shared $(SOFIA_SIP_LIBS) $(STIRSHAKEN_LIBS)
noinst_PROGRAMS = test/test_sofia_funcs
test_test_sofia_funcs_SOURCES = test/test_sofia_funcs.c
-test_test_sofia_funcs_CFLAGS = $(AM_CFLAGS) $(SOFIA_SIP_CFLAGS) -DSWITCH_TEST_BASE_DIR_FOR_CONF=\"${abs_builddir}/test\" -DSWITCH_TEST_BASE_DIR_OVERRIDE=\"${abs_builddir}/test\"
-test_test_sofia_funcs_LDFLAGS = $(AM_LDFLAGS) -avoid-version -no-undefined $(freeswitch_LDFLAGS) $(switch_builddir)/libfreeswitch.la $(CORE_LIBS) $(APR_LIBS)
+test_test_sofia_funcs_CFLAGS = $(AM_CFLAGS) $(SOFIA_SIP_CFLAGS) $(STIRSHAKEN_CFLAGS) -DSWITCH_TEST_BASE_DIR_FOR_CONF=\"${abs_builddir}/test\" -DSWITCH_TEST_BASE_DIR_OVERRIDE=\"${abs_builddir}/test\"
+if HAVE_STIRSHAKEN
+test_test_sofia_funcs_CFLAGS += -DHAVE_STIRSHAKEN
+endif
+test_test_sofia_funcs_LDFLAGS = $(AM_LDFLAGS) -avoid-version -no-undefined $(freeswitch_LDFLAGS) $(switch_builddir)/libfreeswitch.la $(CORE_LIBS) $(APR_LIBS) $(STIRSHAKEN_LIBS)
test_test_sofia_funcs_LDADD = libsofiamod.la $(SOFIA_SIP_LIBS)
-TESTS = $(noinst_PROGRAMS)
+TESTS = test/test_sofia_funcs.sh
if ISMAC
mod_sofia_la_LDFLAGS += -framework CoreFoundation -framework SystemConfiguration
diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.c b/src/mod/endpoints/mod_sofia/mod_sofia.c
index 8c1b7fd325..ce9d520ba8 100644
--- a/src/mod/endpoints/mod_sofia/mod_sofia.c
+++ b/src/mod/endpoints/mod_sofia/mod_sofia.c
@@ -1,6 +1,6 @@
/*
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
- * Copyright (C) 2005-2014, Anthony Minessale II
+ * Copyright (C) 2005-2021, Anthony Minessale II
*
* Version: MPL 1.1
*
@@ -41,6 +41,10 @@
#include "mod_sofia.h"
#include "sofia-sip/sip_extra.h"
+#if HAVE_STIRSHAKEN
+#include
+#endif
+
SWITCH_MODULE_LOAD_FUNCTION(mod_sofia_load);
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_sofia_shutdown);
SWITCH_MODULE_DEFINITION(mod_sofia, mod_sofia_load, mod_sofia_shutdown, NULL);
@@ -351,6 +355,17 @@ static int hangup_cause_to_sip(switch_call_cause_t cause)
return 606;
case SWITCH_CAUSE_UNWANTED:
return 607;
+ /* STIR/SHAKEN */
+ case SWITCH_CAUSE_NO_IDENTITY:
+ return 428;
+ case SWITCH_CAUSE_BAD_IDENTITY_INFO:
+ return 429;
+ case SWITCH_CAUSE_UNSUPPORTED_CERTIFICATE:
+ return 437;
+ case SWITCH_CAUSE_INVALID_IDENTITY:
+ return 438;
+ case SWITCH_CAUSE_STALE_DATE:
+ return 403;
default:
return 480;
}
@@ -6109,6 +6124,409 @@ SWITCH_STANDARD_APP(sofia_sla_function)
switch_ivr_eavesdrop_session(session, data, NULL, ED_MUX_READ | ED_MUX_WRITE | ED_COPY_DISPLAY);
}
+#if HAVE_STIRSHAKEN
+static stir_shaken_as_t *sofia_stir_shaken_as = NULL;
+static stir_shaken_vs_t *sofia_stir_shaken_vs = NULL;
+
+static switch_status_t sofia_stir_shaken_vs_create(stir_shaken_context_t *context)
+{
+ sofia_stir_shaken_vs = stir_shaken_vs_create(context);
+ if (!sofia_stir_shaken_vs) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to create Identity verification service!\n");
+ return SWITCH_STATUS_FALSE;
+ }
+ if (mod_sofia_globals.stir_shaken_vs_ca_dir) {
+ stir_shaken_vs_load_ca_dir(context, sofia_stir_shaken_vs, mod_sofia_globals.stir_shaken_vs_ca_dir);
+ }
+ stir_shaken_vs_set_x509_cert_path_check(context, sofia_stir_shaken_vs, mod_sofia_globals.stir_shaken_vs_cert_path_check);
+ stir_shaken_vs_set_connect_timeout(context, sofia_stir_shaken_vs, 3);
+ //stir_shaken_vs_set_callback(context, sofia_stir_shaken_vs, shaken_callback);
+ return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t sofia_stir_shaken_as_create(stir_shaken_context_t *context)
+{
+ if (mod_sofia_globals.stir_shaken_as_key && mod_sofia_globals.stir_shaken_as_url) {
+ sofia_stir_shaken_as = stir_shaken_as_create(context);
+ if (!sofia_stir_shaken_as) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to create Identity authentication service!\n");
+ return SWITCH_STATUS_FALSE;
+ }
+ if (stir_shaken_as_load_private_key(context, sofia_stir_shaken_as, mod_sofia_globals.stir_shaken_as_key) != STIR_SHAKEN_STATUS_OK) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to load key for Identity authentication service: %s", mod_sofia_globals.stir_shaken_as_key);
+ stir_shaken_as_destroy(&sofia_stir_shaken_as);
+ return SWITCH_STATUS_FALSE;
+ }
+ }
+ return SWITCH_STATUS_SUCCESS;
+}
+#endif
+
+static void sofia_stir_shaken_create_services(void)
+{
+#if HAVE_STIRSHAKEN
+ stir_shaken_context_t context = { 0 };
+ if (stir_shaken_init(&context, STIR_SHAKEN_LOGLEVEL_NOTHING) != STIR_SHAKEN_STATUS_OK) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Failed to initialize stirshaken library!\n");
+ return;
+ }
+ sofia_stir_shaken_vs_create(&context);
+ sofia_stir_shaken_as_create(&context);
+#endif
+}
+
+static void sofia_stir_shaken_destroy_services(void)
+{
+#if HAVE_STIRSHAKEN
+ stir_shaken_vs_destroy(&sofia_stir_shaken_vs);
+ stir_shaken_as_destroy(&sofia_stir_shaken_as);
+ stir_shaken_deinit();
+#endif
+}
+
+#if HAVE_STIRSHAKEN
+static char *canonicalize_phone_number(const char *number)
+{
+ // remove all characters except for digits, *, and # from the phone number
+ // TODO determine if dial number and remove dial codes or add country code
+ char *canonicalized_number = strdup(number ? number : "");
+ size_t i = 0, j = 0;
+ size_t number_len = strlen(canonicalized_number);
+ for (i = 0; i < number_len; i++) {
+ if (isdigit(canonicalized_number[i]) || canonicalized_number[i] == '#' || canonicalized_number[i] == '*') {
+ canonicalized_number[j] = canonicalized_number[i];
+ j++;
+ }
+ }
+ canonicalized_number[j] = '\0';
+ return canonicalized_number;
+}
+
+static switch_status_t sofia_stir_shaken_validate_passport_claims(switch_core_session_t *session, long iat, const char *orig, int orig_is_tn, const char *dest, int dest_is_tn)
+{
+ switch_channel_t *channel = switch_core_session_get_channel(session);
+ const char *from = NULL;
+ const char *to = NULL;
+ char *canonicalized_from = NULL;
+ char *canonicalized_to = NULL;
+ switch_status_t status = SWITCH_STATUS_FALSE;
+ switch_time_t now = switch_epoch_time_now(NULL);
+
+ if (iat > now) {
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "PASSporT iat is in the future\n");
+ return SWITCH_STATUS_FALSE;
+ } else if (now - iat > 60) {
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "PASSporT iat is too old\n");
+ return SWITCH_STATUS_FALSE;
+ }
+
+ if (mod_sofia_globals.stir_shaken_vs_require_date || switch_true(switch_channel_get_variable(channel, "sip_stir_shaken_vs_require_date"))) {
+ const char *sip_epoch_time_var = switch_channel_get_variable(channel, "sip_date_epoch_time");
+ switch_time_t sip_epoch_time;
+
+ if (zstr(sip_epoch_time_var)) {
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Missing required SIP Date\n");
+ return SWITCH_STATUS_FALSE;
+ }
+ sip_epoch_time = strtol(sip_epoch_time_var, NULL, 10);
+ if (sip_epoch_time > now) {
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "SIP Date %s is in the future\n", sip_epoch_time_var);
+ return SWITCH_STATUS_FALSE;
+ }
+ if (now - sip_epoch_time > 60) {
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "SIP Date %s is too old\n", sip_epoch_time_var);
+ return SWITCH_STATUS_FALSE;
+ }
+ if ((iat > sip_epoch_time && iat - sip_epoch_time > 60) || (iat < sip_epoch_time && sip_epoch_time - iat > 60)) {
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "SIP Date %s is too far from PASSporT iat %ld\n", sip_epoch_time_var, iat);
+ return SWITCH_STATUS_FALSE;
+ }
+ // Date is within 60 seconds of now and within 60 seconds of iat
+ }
+
+ if (orig_is_tn) {
+ from = switch_channel_get_variable(channel, "sip_from_user");
+ from = canonicalized_from = canonicalize_phone_number(from);
+ } else {
+ from = switch_channel_get_variable(channel, "sip_from_uri");
+ }
+ if (dest_is_tn) {
+ to = switch_channel_get_variable(channel, "sip_to_user");
+ to = canonicalized_to = canonicalize_phone_number(to);
+ } else {
+ to = switch_channel_get_variable(channel, "sip_to_uri");
+ }
+
+ if (zstr(from) || zstr(to) || zstr(orig) || zstr(dest)) {
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Missing data to verify SIP From/To matches PASSporT claims. From=%s, To=%s, orig=%s, dest=%s\n", from, to, orig, dest);
+ status = SWITCH_STATUS_FALSE;
+ } else if (strcmp(orig, from) || strcmp(dest, to)) {
+ status = SWITCH_STATUS_FALSE;
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "SIP From/To does not match PASSporT claims. From=%s, To=%s, orig=%s, dest=%s\n", from, to, orig, dest);
+ } else {
+ status = SWITCH_STATUS_SUCCESS;
+ }
+ switch_safe_free(canonicalized_from);
+ switch_safe_free(canonicalized_to);
+ return status;
+}
+
+/**
+ * Returns first dest if found. Must be freed by caller.
+ */
+static char* sofia_stir_shaken_passport_get_dest(stir_shaken_passport_t *passport, int *is_tn)
+{
+ char *id = NULL;
+ char *dest = NULL;
+ int tn_form = 0;
+ int id_int = 0;
+ cJSON *item = NULL;
+ cJSON *destjson = NULL;
+ stir_shaken_context_t ss = { 0 };
+
+ if (!passport) return NULL;
+
+ dest = stir_shaken_passport_get_grants_json(&ss, passport, "dest");
+ if (!dest) {
+ return NULL;
+ }
+
+ destjson = cJSON_Parse(dest);
+ if (!destjson) {
+ free(dest);
+ return NULL;
+ }
+
+ if ((item = cJSON_GetObjectItem(destjson, "tn"))) {
+ tn_form = 1;
+ } else if ((item = cJSON_GetObjectItem(destjson, "uri"))) {
+ tn_form = 0;
+ } else {
+ cJSON_Delete(destjson);
+ free(dest);
+ return NULL;
+ }
+
+ if (cJSON_IsArray(item)) {
+ item = cJSON_GetArrayItem(item, 0);
+ if (!item) {
+ cJSON_Delete(destjson);
+ free(dest);
+ return NULL;
+ }
+ } else {
+ item = destjson;
+ }
+
+ if (cJSON_IsString(item)) {
+ id = strdup(item->valuestring);
+ } else if (cJSON_IsNumber(item)) {
+ id_int = item->valueint;
+ id = malloc(20);
+ if (!id) {
+ cJSON_Delete(destjson);
+ free(dest);
+ return NULL;
+ }
+ snprintf(id, 20, "%d", id_int);
+ } else {
+ cJSON_Delete(destjson);
+ free(dest);
+ return NULL;
+ }
+
+ if (is_tn) *is_tn = tn_form;
+ cJSON_Delete(destjson);
+ free(dest);
+ return id;
+}
+
+
+#endif
+
+// TODO Date header must be present
+// Date header must be < (expiration policy) age
+// Date header must be within 1 minute of iat
+
+
+/* Check signature in Identity header and save result to sip_verstat */
+SWITCH_STANDARD_APP(sofia_stir_shaken_vs_function)
+{
+ switch_channel_t *channel = switch_core_session_get_channel(session);
+#if HAVE_STIRSHAKEN
+ stir_shaken_status_t verify_signature_status = STIR_SHAKEN_STATUS_FALSE;
+ stir_shaken_context_t verify_signature_context = { 0 };
+ stir_shaken_status_t validate_passport_status = STIR_SHAKEN_STATUS_FALSE;
+ stir_shaken_context_t validate_passport_context = { 0 };
+ stir_shaken_context_t get_grant_context = { 0 };
+ stir_shaken_passport_t *passport = NULL;
+ stir_shaken_cert_t *cert = NULL;
+ stir_shaken_error_t stir_error = { 0 };
+ switch_status_t claim_status = SWITCH_STATUS_FALSE;
+ const char *identity_header = switch_channel_get_variable(channel, "sip_h_identity");
+ const char *attestation = NULL;
+ int orig_is_tn = 0;
+ switch_bool_t hangup_on_fail = switch_true(switch_channel_get_variable(channel, "sip_stir_shaken_vs_hangup_on_fail"));
+
+ // TODO: compact Identity header is not supported - this will require construction of PASSporT from SIP headers in order to check signature
+
+ if (zstr(identity_header)) {
+ // Nothing to do
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "No-TN-Validation: no SIP Identity\n");
+ switch_channel_set_variable(channel, "sip_verstat_detailed", "No-TN-Validation");
+ switch_channel_set_variable(channel, "sip_verstat", "No-TN-Validation");
+ if (hangup_on_fail) {
+ switch_channel_hangup(channel, SWITCH_CAUSE_NO_IDENTITY);
+ }
+ goto done;
+ }
+
+ // verify the JWT signature in the SIP Identity header
+ verify_signature_status = stir_shaken_vs_sih_verify(&verify_signature_context, sofia_stir_shaken_vs, identity_header, &cert, &passport);
+ if (verify_signature_status != STIR_SHAKEN_STATUS_OK) {
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "PASSporT failed signature verification: %s\n", stir_shaken_get_error(&verify_signature_context, &stir_error));
+ if (hangup_on_fail) {
+ switch_channel_hangup(channel, SWITCH_CAUSE_INVALID_IDENTITY);
+ goto done;
+ }
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "PASSporT passed signature verification\n");
+ }
+
+ if (passport) {
+ // validate the PASSporT is not expired
+ int timeout = 60;
+ const char *timeout_str = switch_channel_get_variable(channel, "sip_stir_shaken_vs_max_age");
+ if (timeout_str && switch_is_number(timeout_str)) {
+ int new_timeout = atoi(timeout_str);
+ if (new_timeout > 0) {
+ timeout = new_timeout;
+ }
+ }
+ validate_passport_status = stir_shaken_passport_validate_iat_against_freshness(&validate_passport_context, passport, timeout);
+ if (validate_passport_status != STIR_SHAKEN_STATUS_OK) {
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "PASSporT failed stale check: %s\n", stir_shaken_get_error(&validate_passport_context, &stir_error));
+ if (hangup_on_fail) {
+ switch_channel_hangup(channel, SWITCH_CAUSE_STALE_DATE);
+ goto done;
+ }
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "PASSporT passed stale check\n");
+ }
+
+ // validate the required PASSporT headers and grants are set
+ validate_passport_status = stir_shaken_passport_validate_headers_and_grants(&validate_passport_context, passport);
+ if (validate_passport_status != STIR_SHAKEN_STATUS_OK) {
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "PASSporT failed header and grant validation: %s\n", stir_shaken_get_error(&validate_passport_context, &stir_error));
+ if (hangup_on_fail) {
+ switch_channel_hangup(channel, SWITCH_CAUSE_INVALID_IDENTITY);
+ if (validate_passport_status == STIR_SHAKEN_STATUS_OK && verify_signature_status == STIR_SHAKEN_STATUS_OK) {
+ switch_channel_hangup(channel, SWITCH_CAUSE_INCOMING_CALL_BARRED);
+ } else {
+ switch_channel_hangup(channel, SWITCH_CAUSE_INVALID_IDENTITY);
+ }
+ goto done;
+ }
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "PASSporT passed header and grant validation\n");
+ }
+ }
+
+ if (passport) {
+ // validate the PASSporT claims match the SIP headers
+ stir_shaken_context_t validate_claims_context = { 0 };
+ int dest_is_tn = 0;
+ char *orig = stir_shaken_passport_get_identity(&validate_claims_context, passport, &orig_is_tn);
+ char *dest = sofia_stir_shaken_passport_get_dest(passport, &dest_is_tn); // TODO libstirshaken should provide helper for 'dest' values
+ long iat = stir_shaken_passport_get_grant_int(&validate_claims_context, passport, "iat");
+ claim_status = sofia_stir_shaken_validate_passport_claims(session, iat, orig, orig_is_tn, dest, dest_is_tn);
+ if (claim_status != SWITCH_STATUS_SUCCESS) {
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "PASSporT claims do not match SIP request\n");
+ if (hangup_on_fail) {
+ switch_channel_hangup(channel, SWITCH_CAUSE_INVALID_IDENTITY);
+ switch_safe_free(orig);
+ switch_safe_free(dest);
+ goto done;
+ }
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "PASSporT claims match SIP request\n");
+ }
+ switch_safe_free(orig);
+ switch_safe_free(dest);
+ }
+
+ attestation = stir_shaken_passport_get_grant(&get_grant_context, passport, "attest");
+
+ if (!zstr(attestation) && verify_signature_status == STIR_SHAKEN_STATUS_OK && validate_passport_status == STIR_SHAKEN_STATUS_OK && claim_status == SWITCH_STATUS_SUCCESS) {
+ if (orig_is_tn) {
+ switch_channel_set_variable_printf(channel, "sip_verstat_detailed", "TN-Validation-Passed-%s", attestation);
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "No-TN-Validation: PASSporT orig is not a telephone number\n");
+ switch_channel_set_variable(channel, "sip_verstat", "No-TN-Validation");
+ }
+ if (orig_is_tn && !strcmp(attestation, "A")) {
+ // Signature is valid and call has "A" attestation
+ switch_channel_set_variable(channel, "sip_verstat", "TN-Validation-Passed");
+ } else {
+ // Signature is valid and call has "B" or "C" attestation or is not from a phone number
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "No-TN-Validation: PASSporT only has \"%s\" attestation\n", attestation);
+ switch_channel_set_variable(channel, "sip_verstat", "No-TN-Validation");
+ }
+ } else if (!passport || !cert || zstr(attestation) || verify_signature_status == STIR_SHAKEN_STATUS_OK) {
+ // failed to get cert / bad passport / no attestation / claims don't match SIP
+ switch_channel_set_variable(channel, "sip_verstat_detailed", "No-TN-Validation");
+ switch_channel_set_variable(channel, "sip_verstat", "No-TN-Validation");
+ } else {
+ // bad signature
+ switch_channel_set_variable_printf(channel, "sip_verstat_detailed", "TN-Validation-Failed-%s", attestation);
+ switch_channel_set_variable(channel, "sip_verstat", "TN-Validation-Failed");
+ }
+
+
+done:
+ stir_shaken_passport_destroy(&passport);
+ stir_shaken_cert_destroy(&cert);
+
+#else
+ switch_channel_set_variable(channel, "sip_verstat_detailed", "No-TN-Validation");
+ switch_channel_set_variable(channel, "sip_verstat", "No-TN-Validation");
+#endif
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "verstat=%s, verstat_detailed=%s\n", switch_channel_get_variable(channel, "sip_verstat"), switch_channel_get_variable(channel, "sip_verstat_detailed"));
+}
+
+/* This assumes TN attestation for orig and dest only */
+char *sofia_stir_shaken_as_create_identity_header(switch_core_session_t *session, const char *attest, const char *orig, const char *dest)
+{
+#if HAVE_STIRSHAKEN
+ stir_shaken_context_t as_context = { 0 };
+ stir_shaken_passport_params_t passport_params = { 0 };
+ char *canonical_desttn = NULL;
+ char *canonical_origtn = NULL;
+ char *passport = NULL;
+
+ if (zstr(attest) || zstr(orig) || zstr(dest) || !mod_sofia_globals.stir_shaken_as_url) {
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Missing required parameter to create PASSporT\n");
+ return NULL;
+ }
+
+ passport_params.attest = attest;
+ passport_params.x5u = mod_sofia_globals.stir_shaken_as_url;
+ passport_params.desttn_key = "tn";
+ passport_params.desttn_val = canonical_desttn = canonicalize_phone_number(dest);
+ passport_params.iat = switch_epoch_time_now(NULL);
+ passport_params.origtn_key = "tn";
+ passport_params.origtn_val = canonical_origtn = canonicalize_phone_number(orig);
+ passport_params.origid = switch_core_session_get_uuid(session);
+
+ passport = stir_shaken_as_authenticate_to_sih(&as_context, sofia_stir_shaken_as, &passport_params, NULL);
+ switch_safe_free(canonical_desttn);
+ switch_safe_free(canonical_origtn);
+ return passport;
+#else
+ return NULL;
+#endif
+}
+
SWITCH_MODULE_LOAD_FUNCTION(mod_sofia_load)
{
@@ -6367,6 +6785,8 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_sofia_load)
SWITCH_ADD_APP(app_interface, "sofia_sla", "private sofia sla function",
"private sofia sla function", sofia_sla_function, "", SAF_NONE);
+ SWITCH_ADD_APP(app_interface, "sofia_stir_shaken_vs", "Verify SIP Identity header and store result in sip_verstat channel variable",
+ "Verify SIP Identity header and store result in sip_verstat channel variable", sofia_stir_shaken_vs_function, "", SAF_SUPPORT_NOMEDIA);
SWITCH_ADD_API(api_interface, "sofia", "Sofia Controls", sofia_function, "");
SWITCH_ADD_API(api_interface, "sofia_gateway_data", "Get data from a sofia gateway", sofia_gateway_data_function, " [ivar|ovar|var] ");
@@ -6410,6 +6830,8 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_sofia_load)
crtp_init(*module_interface);
+ sofia_stir_shaken_create_services();
+
/* indicate that the module should continue to be loaded */
return SWITCH_STATUS_SUCCESS;
@@ -6496,6 +6918,8 @@ void mod_sofia_shutdown_cleanup() {
switch_core_hash_destroy(&mod_sofia_globals.profile_hash);
switch_core_hash_destroy(&mod_sofia_globals.gateway_hash);
switch_mutex_unlock(mod_sofia_globals.hash_mutex);
+
+ sofia_stir_shaken_destroy_services();
}
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_sofia_shutdown)
diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.h b/src/mod/endpoints/mod_sofia/mod_sofia.h
index 3c2d02a5a7..e91d849913 100644
--- a/src/mod/endpoints/mod_sofia/mod_sofia.h
+++ b/src/mod/endpoints/mod_sofia/mod_sofia.h
@@ -407,6 +407,11 @@ struct mod_sofia_globals {
time_t presence_epoch;
int presence_year;
int abort_on_empty_external_ip;
+ const char *stir_shaken_as_key;
+ const char *stir_shaken_as_url;
+ const char *stir_shaken_vs_ca_dir;
+ int stir_shaken_vs_cert_path_check;
+ int stir_shaken_vs_require_date;
};
extern struct mod_sofia_globals mod_sofia_globals;
@@ -1274,6 +1279,8 @@ void sofia_glue_clear_soa(switch_core_session_t *session, switch_bool_t partner)
sofia_auth_algs_t sofia_alg_str2id(char *algorithm, switch_bool_t permissive);
switch_status_t sofia_make_digest(sofia_auth_algs_t use_alg, char **digest, const void *input, unsigned int *outputlen);
+char *sofia_stir_shaken_as_create_identity_header(switch_core_session_t *session, const char *attest, const char *orig, const char *dest);
+
/* For Emacs:
* Local Variables:
* mode:c
diff --git a/src/mod/endpoints/mod_sofia/sofia.c b/src/mod/endpoints/mod_sofia/sofia.c
index dbd9f94343..dd46fb4c0f 100644
--- a/src/mod/endpoints/mod_sofia/sofia.c
+++ b/src/mod/endpoints/mod_sofia/sofia.c
@@ -4547,6 +4547,19 @@ switch_status_t config_sofia(sofia_config_t reload, char *profile_name)
}
} else if (!strcasecmp(var, "capture-server")) {
mod_sofia_globals.capture_server = switch_core_strdup(mod_sofia_globals.pool, val);
+ } else if (!strcasecmp(var, "stir-shaken-as-key")) {
+ /* The private key to authenticate SIP Identity when sip_identity_attest is set */
+ mod_sofia_globals.stir_shaken_as_key = switch_core_strdup(mod_sofia_globals.pool, val);
+ } else if (!strcasecmp(var, "stir-shaken-as-url")) {
+ /* The x5u URL to advertise when sip_identity_attest is set */
+ mod_sofia_globals.stir_shaken_as_url = switch_core_strdup(mod_sofia_globals.pool, val);
+ } else if (!strcasecmp(var, "stir-shaken-vs-ca-dir")) {
+ /* The dir that contains the trusted CA root certs. */
+ mod_sofia_globals.stir_shaken_vs_ca_dir = switch_core_strdup(mod_sofia_globals.pool, val);
+ } else if (!strcasecmp(var, "stir-shaken-vs-cert-path-check")) {
+ mod_sofia_globals.stir_shaken_vs_cert_path_check = switch_true(val);
+ } else if (!strcasecmp(var, "stir-shaken-vs-require-date")) {
+ mod_sofia_globals.stir_shaken_vs_require_date = switch_true(val);
}
}
}
@@ -11426,6 +11439,13 @@ void sofia_handle_sip_i_invite(switch_core_session_t *session, nua_t *nua, sofia
if (sip->sip_identity && sip->sip_identity->id_value) {
switch_channel_set_variable(channel, "sip_h_identity", sip->sip_identity->id_value);
}
+ if (sip->sip_date && sip->sip_date->d_time > 0) {
+ // This INVITE has a SIP Date header.
+ // sofia-sip stores the Date header value in sip_date->d_time as seconds since January 1, 1900 0:00:00.
+ // Unix epoch time is seconds since January 1, 1970 0:00:00, making d_time larger by 2208988800.
+ // Convert to Unix epoch time and save it.
+ switch_channel_set_variable_printf(channel, "sip_date_epoch_time", "%ld", sip->sip_date->d_time - 2208988800);
+ }
/* Loop thru unknown Headers Here so we can do something with them */
for (un = sip->sip_unknown; un; un = un->un_next) {
diff --git a/src/mod/endpoints/mod_sofia/sofia_glue.c b/src/mod/endpoints/mod_sofia/sofia_glue.c
index 0c0035412f..10282383d2 100644
--- a/src/mod/endpoints/mod_sofia/sofia_glue.c
+++ b/src/mod/endpoints/mod_sofia/sofia_glue.c
@@ -1064,6 +1064,9 @@ switch_status_t sofia_glue_do_invite(switch_core_session_t *session)
uint8_t is_t38 = 0;
const char *hold_char = "*";
const char *session_id_header = sofia_glue_session_id_header(session, tech_pvt->profile);
+ const char *stir_shaken_attest = NULL;
+ char *identity_to_free = NULL;
+ const char *date = NULL;
if (sofia_test_flag(tech_pvt, TFLAG_SIP_HOLD_INACTIVE) ||
@@ -1123,7 +1126,20 @@ switch_status_t sofia_glue_do_invite(switch_core_session_t *session)
alert_info = switch_core_session_sprintf(tech_pvt->session, "Alert-Info: %s", alertbuf);
}
- identity = switch_channel_get_variable(channel, "sip_h_identity");
+ if ((stir_shaken_attest = switch_channel_get_variable(tech_pvt->channel, "sip_stir_shaken_attest"))) {
+ char date_buf[80] = "";
+ char *dest = caller_profile->destination_number;
+ check_decode(dest, session);
+ switch_rfc822_date(date_buf, switch_micro_time_now());
+ date = switch_core_session_strdup(tech_pvt->session, date_buf);
+ identity = identity_to_free = sofia_stir_shaken_as_create_identity_header(tech_pvt->session, stir_shaken_attest, cid_num, dest);
+ }
+ if (!identity) {
+ identity = switch_channel_get_variable(channel, "sip_h_identity");
+ }
+ if (!date) {
+ date = switch_channel_get_variable(channel, "sip_h_date");
+ }
max_forwards = switch_channel_get_variable(channel, SWITCH_MAX_FORWARDS_VARIABLE);
@@ -1658,6 +1674,7 @@ switch_status_t sofia_glue_do_invite(switch_core_session_t *session)
TAG_IF(!zstr(tech_pvt->asserted_id), SIPTAG_P_ASSERTED_IDENTITY_STR(tech_pvt->asserted_id)),
TAG_IF(!zstr(tech_pvt->privacy), SIPTAG_PRIVACY_STR(tech_pvt->privacy)),
TAG_IF(!zstr(identity), SIPTAG_IDENTITY_STR(identity)),
+ TAG_IF(!zstr(date), SIPTAG_DATE_STR(date)),
TAG_IF(!zstr(alert_info), SIPTAG_HEADER_STR(alert_info)),
TAG_IF(!zstr(extra_headers), SIPTAG_HEADER_STR(extra_headers)),
TAG_IF(sofia_test_pflag(tech_pvt->profile, PFLAG_PASS_CALLEE_ID), SIPTAG_HEADER_STR("X-FS-Support: " FREESWITCH_SUPPORT)),
@@ -1725,6 +1742,8 @@ end:
sofia_glue_free_destination(dst);
}
+ switch_safe_free(identity_to_free);
+
return status;
}
@@ -1832,6 +1851,14 @@ switch_call_cause_t sofia_glue_sip_cause_to_freeswitch(int status)
return SWITCH_CAUSE_EXCHANGE_ROUTING_ERROR;
case 487:
return SWITCH_CAUSE_ORIGINATOR_CANCEL;
+ case 428:
+ return SWITCH_CAUSE_NO_IDENTITY;
+ case 429:
+ return SWITCH_CAUSE_BAD_IDENTITY_INFO;
+ case 437:
+ return SWITCH_CAUSE_UNSUPPORTED_CERTIFICATE;
+ case 438:
+ return SWITCH_CAUSE_INVALID_IDENTITY;
default:
return SWITCH_CAUSE_NORMAL_UNSPECIFIED;
}
diff --git a/src/mod/endpoints/mod_sofia/test/conf/freeswitch.xml b/src/mod/endpoints/mod_sofia/test/conf/freeswitch.xml
index c654a84ebc..d58f45b983 100644
--- a/src/mod/endpoints/mod_sofia/test/conf/freeswitch.xml
+++ b/src/mod/endpoints/mod_sofia/test/conf/freeswitch.xml
@@ -31,6 +31,11 @@
+
+
+
+
+
@@ -97,6 +102,45 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/mod/endpoints/mod_sofia/test/stir-shaken/priv.pem b/src/mod/endpoints/mod_sofia/test/stir-shaken/priv.pem
new file mode 100644
index 0000000000..0e812f09b6
--- /dev/null
+++ b/src/mod/endpoints/mod_sofia/test/stir-shaken/priv.pem
@@ -0,0 +1,5 @@
+-----BEGIN EC PRIVATE KEY-----
+MHcCAQEEIKigooZBuy0XvaeIEFPkuvOehEbhrqFIKdeBZAJaZIawoAoGCCqGSM49
+AwEHoUQDQgAEnqiYijyOLEo9hJ/x2oVYIQT12XL3YREF2XS+cWmabEtjJpfAPmS+
+1f+fg3APWD+owNyaDV54r3YTHqkvTK/5mA==
+-----END EC PRIVATE KEY-----
diff --git a/src/mod/endpoints/mod_sofia/test/stir-shaken/pub.pem b/src/mod/endpoints/mod_sofia/test/stir-shaken/pub.pem
new file mode 100644
index 0000000000..96c90cbeeb
--- /dev/null
+++ b/src/mod/endpoints/mod_sofia/test/stir-shaken/pub.pem
@@ -0,0 +1,4 @@
+-----BEGIN PUBLIC KEY-----
+MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEnqiYijyOLEo9hJ/x2oVYIQT12XL3
+YREF2XS+cWmabEtjJpfAPmS+1f+fg3APWD+owNyaDV54r3YTHqkvTK/5mA==
+-----END PUBLIC KEY-----
diff --git a/src/mod/endpoints/mod_sofia/test/stir-shaken/www/cert.pem b/src/mod/endpoints/mod_sofia/test/stir-shaken/www/cert.pem
new file mode 100644
index 0000000000..f364baa301
--- /dev/null
+++ b/src/mod/endpoints/mod_sofia/test/stir-shaken/www/cert.pem
@@ -0,0 +1,13 @@
+-----BEGIN CERTIFICATE-----
+MIIB6DCCAY6gAwIBAgIBATAKBggqhkjOPQQDAjAlMQswCQYDVQQGEwJVUzEWMBQG
+A1UEAwwNbGlic3RpcnNoYWtlbjAeFw0yMTA0MTMwMTA1MDBaFw0zMTA0MTEwMTA1
+MDBaMCUxCzAJBgNVBAYTAlVTMRYwFAYDVQQDDA1saWJzdGlyc2hha2VuMFkwEwYH
+KoZIzj0CAQYIKoZIzj0DAQcDQgAEnqiYijyOLEo9hJ/x2oVYIQT12XL3YREF2XS+
+cWmabEtjJpfAPmS+1f+fg3APWD+owNyaDV54r3YTHqkvTK/5mKOBrjCBqzAdBgNV
+HQ4EFgQUdCtIqcHHdpzTxT0uZ3BUo7f+IhYwHwYDVR0jBBgwFoAUdCtIqcHHdpzT
+xT0uZ3BUo7f+IhYwNQYJYIZIAYb4QgENBCgWJkFsd2F5cyBsb29rIG9uIHRoZSBi
+cmlnaHQgc2lkZSBvZiBsaWZlMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQD
+AgEGMBEGCWCGSAGG+EIBAQQEAwICBDAKBggqhkjOPQQDAgNIADBFAiAN2YS+x4Nb
+fWAwiLKlQV141PkFQ7KbjVYeHHjPO7u1dgIhAI7N+vW2BdFzhH65xcHn/nWv1HXe
+5NfoHbhDS+cC7Bet
+-----END CERTIFICATE-----
diff --git a/src/mod/endpoints/mod_sofia/test/stir-shaken/www/pub.pem b/src/mod/endpoints/mod_sofia/test/stir-shaken/www/pub.pem
new file mode 100644
index 0000000000..f364baa301
--- /dev/null
+++ b/src/mod/endpoints/mod_sofia/test/stir-shaken/www/pub.pem
@@ -0,0 +1,13 @@
+-----BEGIN CERTIFICATE-----
+MIIB6DCCAY6gAwIBAgIBATAKBggqhkjOPQQDAjAlMQswCQYDVQQGEwJVUzEWMBQG
+A1UEAwwNbGlic3RpcnNoYWtlbjAeFw0yMTA0MTMwMTA1MDBaFw0zMTA0MTEwMTA1
+MDBaMCUxCzAJBgNVBAYTAlVTMRYwFAYDVQQDDA1saWJzdGlyc2hha2VuMFkwEwYH
+KoZIzj0CAQYIKoZIzj0DAQcDQgAEnqiYijyOLEo9hJ/x2oVYIQT12XL3YREF2XS+
+cWmabEtjJpfAPmS+1f+fg3APWD+owNyaDV54r3YTHqkvTK/5mKOBrjCBqzAdBgNV
+HQ4EFgQUdCtIqcHHdpzTxT0uZ3BUo7f+IhYwHwYDVR0jBBgwFoAUdCtIqcHHdpzT
+xT0uZ3BUo7f+IhYwNQYJYIZIAYb4QgENBCgWJkFsd2F5cyBsb29rIG9uIHRoZSBi
+cmlnaHQgc2lkZSBvZiBsaWZlMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQD
+AgEGMBEGCWCGSAGG+EIBAQQEAwICBDAKBggqhkjOPQQDAgNIADBFAiAN2YS+x4Nb
+fWAwiLKlQV141PkFQ7KbjVYeHHjPO7u1dgIhAI7N+vW2BdFzhH65xcHn/nWv1HXe
+5NfoHbhDS+cC7Bet
+-----END CERTIFICATE-----
diff --git a/src/mod/endpoints/mod_sofia/test/test_sofia_funcs.c b/src/mod/endpoints/mod_sofia/test/test_sofia_funcs.c
index 0c03d232d1..e769057363 100644
--- a/src/mod/endpoints/mod_sofia/test/test_sofia_funcs.c
+++ b/src/mod/endpoints/mod_sofia/test/test_sofia_funcs.c
@@ -112,6 +112,150 @@ FST_TEST_BEGIN(originate_test)
}
FST_TEST_END()
+FST_TEST_BEGIN(sofia_verify_identity_test_no_identity)
+{
+ switch_core_session_t *session = NULL;
+ switch_channel_t *channel = NULL;
+ switch_status_t status;
+ switch_call_cause_t cause;
+ const char *local_ip_v4 = switch_core_get_variable("local_ip_v4");
+ status = switch_ivr_originate(NULL, &session, &cause, switch_core_sprintf(fst_pool, "{ignore_early_media=true}sofia/internal/verifyidentity@%s:53060", local_ip_v4), 2, NULL, NULL, NULL, NULL, NULL, SOF_NONE, NULL, NULL);
+ fst_check(status != SWITCH_STATUS_SUCCESS);
+ fst_check(cause == SWITCH_CAUSE_NO_IDENTITY);
+ if (session) {
+ channel = switch_core_session_get_channel(session);
+ switch_channel_hangup(channel, SWITCH_CAUSE_NORMAL_CLEARING);
+ switch_core_session_rwunlock(session);
+ switch_sleep(1 * 1000 * 1000);
+ }
+}
+FST_TEST_END()
+
+FST_TEST_BEGIN(sofia_verify_identity_test_bad_identity)
+{
+ switch_core_session_t *session = NULL;
+ switch_channel_t *channel = NULL;
+ switch_status_t status;
+ switch_call_cause_t cause;
+ const char *local_ip_v4 = switch_core_get_variable("local_ip_v4");
+ status = switch_ivr_originate(NULL, &session, &cause, switch_core_sprintf(fst_pool, "{ignore_early_media=true,sip_h_identity=foo;info=bar}sofia/internal/verifyidentity@%s:53060", local_ip_v4), 2, NULL, NULL, NULL, NULL, NULL, SOF_NONE, NULL, NULL);
+ fst_check(status != SWITCH_STATUS_SUCCESS);
+ fst_check(cause == SWITCH_CAUSE_INVALID_IDENTITY);
+ if (session) {
+ channel = switch_core_session_get_channel(session);
+ switch_channel_hangup(channel, SWITCH_CAUSE_NORMAL_CLEARING);
+ switch_core_session_rwunlock(session);
+ switch_sleep(1 * 1000 * 1000);
+ }
+}
+FST_TEST_END()
+
+FST_TEST_BEGIN(sofia_verify_identity_test_valid_identity_no_cert_available)
+{
+ switch_core_session_t *session = NULL;
+ switch_channel_t *channel = NULL;
+ switch_status_t status;
+ switch_call_cause_t cause;
+ const char *local_ip_v4 = switch_core_get_variable("local_ip_v4");
+ status = switch_ivr_originate(NULL, &session, &cause, switch_core_sprintf(fst_pool, "{origination_caller_id_number=+15551231234,ignore_early_media=true,sip_h_identity=eyJhbGciOiJFUzI1NiIsInBwdCI6InNoYWtlbiIsInR5cCI6InBhc3Nwb3J0IiwieDV1IjoiaHR0cDovLzEyNy4wLjAuMS80MDQucGVtIn0.eyJhdHRlc3QiOiJBIiwiZGVzdCI6eyJ0biI6WyIxNTU1MzIxNDMyMSJdfSwiaWF0IjoxNjE4Mjc5OTYzLCJvcmlnIjp7InRuIjoiMTU1NTEyMzEyMzQifSwib3JpZ2lkIjoiMTMxMzEzMTMifQ.Cm34sISkFWYB6ohtjjJEO71Hyz4TQ5qrTDyYmCXBj-ni5Fe7IbNjmMyvY_lD_Go0u2csWQNe8n03fHSO7Z7nNw;info=;alg=ES256;ppt=shaken}sofia/internal/+15553214321@%s:53060", local_ip_v4), 2, NULL, NULL, NULL, NULL, NULL, SOF_NONE, NULL, NULL);
+ fst_check(status != SWITCH_STATUS_SUCCESS);
+ fst_check(cause == SWITCH_CAUSE_INVALID_IDENTITY);
+ if (session) {
+ channel = switch_core_session_get_channel(session);
+ switch_channel_hangup(channel, SWITCH_CAUSE_NORMAL_CLEARING);
+ switch_core_session_rwunlock(session);
+ switch_sleep(1 * 1000 * 1000);
+ }
+}
+FST_TEST_END()
+
+FST_TEST_BEGIN(sofia_auth_identity_test_attest_a)
+{
+ switch_core_session_t *session = NULL;
+ switch_channel_t *channel = NULL;
+ switch_status_t status;
+ switch_call_cause_t cause;
+ const char *local_ip_v4 = switch_core_get_variable("local_ip_v4");
+ status = switch_ivr_originate(NULL, &session, &cause, switch_core_sprintf(fst_pool, "{origination_caller_id_number=+15551231234,ignore_early_media=true,sip_stir_shaken_attest=A}sofia/internal/+15553214322@%s:53060", local_ip_v4), 2, NULL, NULL, NULL, NULL, NULL, SOF_NONE, NULL, NULL);
+ fst_check(status == SWITCH_STATUS_SUCCESS);
+ fst_requires(session);
+ channel = switch_core_session_get_channel(session);
+ switch_channel_hangup(channel, SWITCH_CAUSE_NORMAL_CLEARING);
+ switch_core_session_rwunlock(session);
+ switch_sleep(1 * 1000 * 1000);
+}
+FST_TEST_END()
+
+FST_TEST_BEGIN(sofia_auth_identity_test_attest_b)
+{
+ switch_core_session_t *session = NULL;
+ switch_channel_t *channel = NULL;
+ switch_status_t status;
+ switch_call_cause_t cause;
+ const char *local_ip_v4 = switch_core_get_variable("local_ip_v4");
+ status = switch_ivr_originate(NULL, &session, &cause, switch_core_sprintf(fst_pool, "{origination_caller_id_number=+15551231234,ignore_early_media=true,sip_stir_shaken_attest=B}sofia/internal/+15553214322@%s:53060", local_ip_v4), 2, NULL, NULL, NULL, NULL, NULL, SOF_NONE, NULL, NULL);
+ fst_check(status == SWITCH_STATUS_SUCCESS);
+ fst_requires(session);
+ channel = switch_core_session_get_channel(session);
+ switch_channel_hangup(channel, SWITCH_CAUSE_NORMAL_CLEARING);
+ switch_core_session_rwunlock(session);
+ switch_sleep(1 * 1000 * 1000);
+}
+FST_TEST_END()
+
+FST_TEST_BEGIN(sofia_auth_identity_test_attest_c)
+{
+ switch_core_session_t *session = NULL;
+ switch_channel_t *channel = NULL;
+ switch_status_t status;
+ switch_call_cause_t cause;
+ const char *local_ip_v4 = switch_core_get_variable("local_ip_v4");
+ status = switch_ivr_originate(NULL, &session, &cause, switch_core_sprintf(fst_pool, "{origination_caller_id_number=+15551231234,ignore_early_media=true,sip_stir_shaken_attest=C}sofia/internal/+15553214322@%s:53060", local_ip_v4), 2, NULL, NULL, NULL, NULL, NULL, SOF_NONE, NULL, NULL);
+ fst_check(status == SWITCH_STATUS_SUCCESS);
+ fst_requires(session);
+ channel = switch_core_session_get_channel(session);
+ switch_channel_hangup(channel, SWITCH_CAUSE_NORMAL_CLEARING);
+ switch_core_session_rwunlock(session);
+ switch_sleep(1 * 1000 * 1000);
+}
+FST_TEST_END()
+
+FST_TEST_BEGIN(sofia_verify_identity_test_verified_attest_a_expired)
+{
+ switch_core_session_t *session = NULL;
+ switch_channel_t *channel = NULL;
+ switch_status_t status;
+ switch_call_cause_t cause;
+ const char *local_ip_v4 = switch_core_get_variable("local_ip_v4");
+ status = switch_ivr_originate(NULL, &session, &cause, switch_core_sprintf(fst_pool, "{origination_caller_id_number=+15551231234,ignore_early_media=true,sip_h_identity=eyJhbGciOiJFUzI1NiIsInBwdCI6InNoYWtlbiIsInR5cCI6InBhc3Nwb3J0IiwieDV1IjoiaHR0cDovLzEyNy4wLjAuMTo4MDgwL2NlcnQucGVtIn0.eyJhdHRlc3QiOiJBIiwiZGVzdCI6eyJ0biI6WyIxNTU1MzIxNDMyMiJdfSwiaWF0IjoxNjE4MzczMTc0LCJvcmlnIjp7InRuIjoiMTU1NTEyMzEyMzQifSwib3JpZ2lkIjoiMzliZDYzZDQtOTE1Mi00MzU0LWFkNjctNjg5NjQ2NmI4ZDI3In0.mUaikwHSOb8RVPwwMZTsqBe57MZY29CgbIqmiiEmyq9DzKZO-y4qShiIVT3serg-xHgC9SCMjUOBWaDfeXnEvA;info=;alg=ES256;ppt=shaken}sofia/internal/+15553214322@%s:53060", local_ip_v4), 2, NULL, NULL, NULL, NULL, NULL, SOF_NONE, NULL, NULL);
+ fst_check(status != SWITCH_STATUS_SUCCESS);
+ fst_check(cause == SWITCH_CAUSE_CALL_REJECTED);
+ if (session) {
+ channel = switch_core_session_get_channel(session);
+ switch_channel_hangup(channel, SWITCH_CAUSE_NORMAL_CLEARING);
+ switch_core_session_rwunlock(session);
+ switch_sleep(1 * 1000 * 1000);
+ }
+}
+FST_TEST_END()
+
+FST_TEST_BEGIN(sofia_auth_identity_test_attest_a_date)
+{
+ switch_core_session_t *session = NULL;
+ switch_channel_t *channel = NULL;
+ switch_status_t status;
+ switch_call_cause_t cause;
+ const char *local_ip_v4 = switch_core_get_variable("local_ip_v4");
+ status = switch_ivr_originate(NULL, &session, &cause, switch_core_sprintf(fst_pool, "{origination_caller_id_number=+15551231235,ignore_early_media=true,sip_stir_shaken_attest=A}sofia/internal/+15553214323@%s:53060", local_ip_v4), 2, NULL, NULL, NULL, NULL, NULL, SOF_NONE, NULL, NULL);
+ fst_check(status == SWITCH_STATUS_SUCCESS);
+ fst_requires(session);
+ channel = switch_core_session_get_channel(session);
+ switch_channel_hangup(channel, SWITCH_CAUSE_NORMAL_CLEARING);
+ switch_core_session_rwunlock(session);
+ switch_sleep(10 * 1000 * 1000);
+}
+FST_TEST_END()
+
FST_MODULE_END()
FST_CORE_END()
diff --git a/src/mod/endpoints/mod_sofia/test/test_sofia_funcs.sh b/src/mod/endpoints/mod_sofia/test/test_sofia_funcs.sh
new file mode 100755
index 0000000000..3ef117ee52
--- /dev/null
+++ b/src/mod/endpoints/mod_sofia/test/test_sofia_funcs.sh
@@ -0,0 +1,11 @@
+#/bin/sh
+cd test
+pushd stir-shaken/www
+python -m SimpleHTTPServer 8080 &
+ppid=$!
+popd
+./test_sofia_funcs $@
+test=$?
+kill $ppid
+wait $ppid
+exit $test
diff --git a/src/switch_channel.c b/src/switch_channel.c
index 09a0697f9f..1beeaef4c4 100644
--- a/src/switch_channel.c
+++ b/src/switch_channel.c
@@ -130,6 +130,11 @@ static struct switch_cause_table CAUSE_CHART[] = {
{"DOES_NOT_EXIST_ANYWHERE", SWITCH_CAUSE_DOES_NOT_EXIST_ANYWHERE},
{"NOT_ACCEPTABLE", SWITCH_CAUSE_NOT_ACCEPTABLE},
{"UNWANTED", SWITCH_CAUSE_UNWANTED},
+ {"NO_IDENTITY", SWITCH_CAUSE_NO_IDENTITY},
+ {"BAD_IDENTITY_INFO", SWITCH_CAUSE_BAD_IDENTITY_INFO},
+ {"UNSUPPORTED_CERTIFICATE", SWITCH_CAUSE_UNSUPPORTED_CERTIFICATE},
+ {"INVALID_IDENTITY", SWITCH_CAUSE_INVALID_IDENTITY},
+ {"STALE_DATE", SWITCH_CAUSE_STALE_DATE},
{NULL, 0}
};
diff --git a/tests/unit/switch_vad.c b/tests/unit/switch_vad.c
index 8b0f85bb1f..95519c7b92 100644
--- a/tests/unit/switch_vad.c
+++ b/tests/unit/switch_vad.c
@@ -75,11 +75,12 @@ FST_CORE_BEGIN("./conf")
int duration;
float pos = 0.0;
int got_transition = 0;
+ int res;
switch_vad_state_t cur_state = SWITCH_VAD_STATE_NONE;
switch_vad_t *vad = switch_vad_init(8000, 1);
fst_requires(vad);
- int res = switch_vad_set_mode(vad, 0); // tone is detected as speech in mode 0
+ res = switch_vad_set_mode(vad, 0); // tone is detected as speech in mode 0
fst_requires(res == 0);
switch_vad_set_param(vad, "silence_ms", 400);
switch_vad_set_param(vad, "voice_ms", 80);
From 583443e384c3b05f35c461265ad930825a9254b8 Mon Sep 17 00:00:00 2001
From: Clarence
Date: Wed, 28 Apr 2021 19:59:52 +0800
Subject: [PATCH 111/655] [mod_sofia] release nat mapping when nua create
failed
---
src/mod/endpoints/mod_sofia/sofia.c | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/src/mod/endpoints/mod_sofia/sofia.c b/src/mod/endpoints/mod_sofia/sofia.c
index dd46fb4c0f..d152a12810 100644
--- a/src/mod/endpoints/mod_sofia/sofia.c
+++ b/src/mod/endpoints/mod_sofia/sofia.c
@@ -3188,7 +3188,7 @@ void *SWITCH_THREAD_FUNC sofia_profile_thread_run(switch_thread_t *thread, void
if (!sofia_glue_init_sql(profile)) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Cannot Open SQL Database [%s]!\n", profile->name);
sofia_profile_start_failure(profile, profile->name);
- goto end;
+ goto db_fail;
}
supported = switch_core_sprintf(profile->pool, "%s%s%spath, replaces", use_100rel ? "100rel, " : "", use_timer ? "timer, " : "", use_rfc_5626 ? "outbound, " : "");
@@ -3339,7 +3339,7 @@ void *SWITCH_THREAD_FUNC sofia_profile_thread_run(switch_thread_t *thread, void
}
sofia_profile_start_failure(profile, profile->name);
- goto end;
+ goto nua_fail;
}
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Created agent for %s\n", profile->name);
@@ -3570,6 +3570,7 @@ void *SWITCH_THREAD_FUNC sofia_profile_thread_run(switch_thread_t *thread, void
switch_event_fire(&s_event);
}
+ nua_fail:
if (sofia_test_pflag(profile, PFLAG_AUTO_NAT) && switch_nat_get_type()) {
if (switch_nat_del_mapping(profile->sip_port, SWITCH_NAT_UDP) == SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Deleted UDP nat mapping for %s port %d\n", profile->name, profile->sip_port);
@@ -3582,7 +3583,7 @@ void *SWITCH_THREAD_FUNC sofia_profile_thread_run(switch_thread_t *thread, void
}
}
- end:
+ db_fail:
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Write lock %s\n", profile->name);
switch_thread_rwlock_wrlock(profile->rwlock);
From fc054360b70e026122249c834b28d95248c881b5 Mon Sep 17 00:00:00 2001
From: sergey-safarov
Date: Thu, 6 May 2021 20:51:54 +0300
Subject: [PATCH 112/655] [Build-System] Rename package format-mod-opusfile to
format-opusfile on CentOS
---
freeswitch.spec | 16 ++++++----------
1 file changed, 6 insertions(+), 10 deletions(-)
diff --git a/freeswitch.spec b/freeswitch.spec
index a62776b1cc..9e5f368fe6 100644
--- a/freeswitch.spec
+++ b/freeswitch.spec
@@ -37,7 +37,6 @@
%define build_mod_esl 0
%define build_mod_rayo 1
%define build_mod_ssml 1
-%define build_mod_opusfile 0
%define build_mod_v8 0
%{?with_sang_tc:%define build_sng_tc 1 }
@@ -46,7 +45,6 @@
%{?with_py26_esl:%define build_py26_esl 1 }
%{?with_timerfd:%define build_timerfd 1 }
%{?with_mod_esl:%define build_mod_esl 1 }
-%{?with_mod_opusfile:%define build_mod_opusfile 1 }
%{?with_mod_v8:%define build_mod_v8 1 }
%define nonparsedversion 1.7.0
@@ -1107,17 +1105,15 @@ BuildRequires: lame-devel
Mod Shout is a FreeSWITCH module to allow you to stream audio from MP3s or a i
shoutcast stream.
-%if %{build_mod_opusfile}
-%package format-mod-opusfile
+%package format-opusfile
Summary: Plays Opus encoded files
Group: System/Libraries
Requires: %{name} = %{version}-%{release}
Requires: opusfile >= 0.5
BuildRequires: opusfile-devel >= 0.5
-%description format-mod-opusfile
+%description format-opusfile
Mod Opusfile is a FreeSWITCH module to allow you to play Opus encoded files
-%endif
%if %{build_mod_ssml}
%package format-ssml
@@ -1514,14 +1510,11 @@ EVENT_HANDLERS_MODULES+=" event_handlers/mod_rayo"
# File and Audio Format Handlers
#
######################################################################################################################
-FORMATS_MODULES="formats/mod_local_stream formats/mod_native_file formats/mod_portaudio_stream \
+FORMATS_MODULES="formats/mod_local_stream formats/mod_native_file formats/mod_opusfile formats/mod_portaudio_stream \
formats/mod_shell_stream formats/mod_shout formats/mod_sndfile formats/mod_tone_stream"
%if %{build_mod_ssml}
FORMATS_MODULES+=" formats/mod_ssml"
%endif
-%if %{build_mod_opusfile}
-FORMATS_MODULES+=" formats/mod_opusfile"
-%endif
######################################################################################################################
#
@@ -2349,6 +2342,9 @@ fi
%files format-native-file
%{MODINSTDIR}/mod_native_file.so*
+%files format-opusfile
+%{MODINSTDIR}/mod_opusfile.so*
+
%files format-portaudio-stream
%{MODINSTDIR}/mod_portaudio_stream.so*
From 2915d3aba8f52e34a7fd258fbd4182fddfa42879 Mon Sep 17 00:00:00 2001
From: Dragos Oancea
Date: Fri, 7 May 2021 14:17:15 +0000
Subject: [PATCH 113/655] [mod_amrwb] add cfg setting mode-set-overwrite (it
will answer with just one mode-set value) - fixes audio quality issues in
mod_conference with some UEs.
---
conf/testing/autoload_configs/amrwb.conf.xml | 2 ++
conf/vanilla/autoload_configs/amrwb.conf.xml | 2 ++
src/mod/codecs/mod_amrwb/mod_amrwb.c | 6 +++++-
3 files changed, 9 insertions(+), 1 deletion(-)
diff --git a/conf/testing/autoload_configs/amrwb.conf.xml b/conf/testing/autoload_configs/amrwb.conf.xml
index 0bd8e6b733..1163ffd1a6 100644
--- a/conf/testing/autoload_configs/amrwb.conf.xml
+++ b/conf/testing/autoload_configs/amrwb.conf.xml
@@ -18,5 +18,7 @@
+
+
diff --git a/conf/vanilla/autoload_configs/amrwb.conf.xml b/conf/vanilla/autoload_configs/amrwb.conf.xml
index 0bd8e6b733..1163ffd1a6 100644
--- a/conf/vanilla/autoload_configs/amrwb.conf.xml
+++ b/conf/vanilla/autoload_configs/amrwb.conf.xml
@@ -18,5 +18,7 @@
+
+
diff --git a/src/mod/codecs/mod_amrwb/mod_amrwb.c b/src/mod/codecs/mod_amrwb/mod_amrwb.c
index ef7891cde6..8be5f4d541 100644
--- a/src/mod/codecs/mod_amrwb/mod_amrwb.c
+++ b/src/mod/codecs/mod_amrwb/mod_amrwb.c
@@ -88,6 +88,7 @@ static struct {
switch_byte_t volte;
switch_byte_t adjust_bitrate;
switch_byte_t force_oa; /*force OA when originating*/
+ switch_byte_t mode_set_overwrite;
int debug;
} globals;
@@ -273,7 +274,7 @@ static switch_status_t switch_amrwb_init(switch_codec_t *codec, switch_codec_fla
}
}
- if (context->enc_modes) {
+ if (context->enc_modes && !globals.mode_set_overwrite) {
/* choose the highest mode (bitrate) for high audio quality. */
for (i = SWITCH_AMRWB_MODES-2; i > -1; i--) {
if (context->enc_modes & (1 << i)) {
@@ -572,6 +573,9 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_amrwb_load)
if (!strcasecmp(var, "force-oa")) {
globals.force_oa = (switch_byte_t) atoi(val);
}
+ if (!strcasecmp(var, "mode-set-overwrite")) {
+ globals.mode_set_overwrite = (switch_byte_t) atoi(val);
+ }
}
}
}
From 954056c009482d8093b37c26d6e2fbda33d85383 Mon Sep 17 00:00:00 2001
From: Aron Podrigal
Date: Mon, 10 May 2021 14:32:48 -0500
Subject: [PATCH 114/655] [mod_curl] Added PATCH method, add insecure and
secure options to verify SSL certs, add proxy option.
* mod_curl: hanlde PATCH method
* mod_curl: verify ssl with an option `insecure` to not verify
* mod_curl: added option to use proxy
* mod_curl: use assert(options)
* [mod_curl] default certificate validation secure/insecure controlled by `validate-certs` config option.
* [mod_curl] Added option secure to force https certs validation
---
src/mod/applications/mod_curl/mod_curl.c | 105 ++++++++++++-----------
1 file changed, 56 insertions(+), 49 deletions(-)
diff --git a/src/mod/applications/mod_curl/mod_curl.c b/src/mod/applications/mod_curl/mod_curl.c
index f0c952a215..2da7d4e1ea 100644
--- a/src/mod/applications/mod_curl/mod_curl.c
+++ b/src/mod/applications/mod_curl/mod_curl.c
@@ -50,7 +50,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_curl_load);
*/
SWITCH_MODULE_DEFINITION(mod_curl, mod_curl_load, mod_curl_shutdown, NULL);
-static char *SYNTAX = "curl url [headers|json|content-type |connect-timeout |timeout |append_headers [|append_headers ]] [get|head|post|delete|put [data]]";
+static char *SYNTAX = "curl url [headers|json|content-type |connect-timeout |timeout |append_headers [|append_headers ]|insecure|secure|[proxy ]] [get|head|post|delete|put [data]]";
#define HTTP_SENDFILE_ACK_EVENT "curl_sendfile::ack"
#define HTTP_SENDFILE_RESPONSE_SIZE 32768
@@ -61,11 +61,13 @@ static struct {
switch_memory_pool_t *pool;
switch_event_node_t *node;
int max_bytes;
+ switch_bool_t validate_certs;
} globals;
static switch_xml_config_item_t instructions[] = {
/* parameter name type reloadable pointer default value options structure */
SWITCH_CONFIG_ITEM("max-bytes", SWITCH_CONFIG_INT, CONFIG_RELOADABLE, &globals.max_bytes, (void *) HTTP_DEFAULT_MAX_BYTES, NULL,NULL, NULL),
+ SWITCH_CONFIG_ITEM("validate-certs", SWITCH_CONFIG_BOOL, CONFIG_RELOADABLE, &globals.validate_certs, SWITCH_FALSE, NULL, NULL, NULL),
SWITCH_CONFIG_ITEM_END()
};
@@ -124,6 +126,8 @@ typedef struct callback_obj callback_t;
struct curl_options_obj {
long connect_timeout;
long timeout;
+ int insecure;
+ char *proxy;
};
typedef struct curl_options_obj curl_options_t;
@@ -178,6 +182,8 @@ static http_data_t *do_lookup_url(switch_memory_pool_t *pool, const char *url, c
switch_curl_slist_t *headers = NULL;
struct data_stream dstream = { NULL };
+ assert(options);
+
http_data = switch_core_alloc(pool, sizeof(http_data_t));
memset(http_data, 0, sizeof(http_data_t));
http_data->pool = pool;
@@ -192,20 +198,27 @@ static http_data_t *do_lookup_url(switch_memory_pool_t *pool, const char *url, c
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "method: %s, url: %s, content-type: %s\n", method, url, content_type);
curl_handle = switch_curl_easy_init();
- if (options) {
- if (options->connect_timeout) {
- switch_curl_easy_setopt(curl_handle, CURLOPT_CONNECTTIMEOUT, options->connect_timeout);
- }
+ if (options->connect_timeout) {
+ switch_curl_easy_setopt(curl_handle, CURLOPT_CONNECTTIMEOUT, options->connect_timeout);
+ }
- if (options->timeout) {
- switch_curl_easy_setopt(curl_handle, CURLOPT_TIMEOUT, options->timeout);
- }
+ if (options->timeout) {
+ switch_curl_easy_setopt(curl_handle, CURLOPT_TIMEOUT, options->timeout);
+ }
+
+ if (options->proxy) {
+ switch_curl_easy_setopt(curl_handle, CURLOPT_PROXY, options->proxy);
}
if (!strncasecmp(url, "https", 5)) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Not verifying TLS cert for %s; connection is not secure\n", url);
- switch_curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, 0);
- switch_curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYHOST, 0);
+ if (options->insecure) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Not verifying TLS cert for %s; connection is not secure\n", url);
+ switch_curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, 0);
+ switch_curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYHOST, 0);
+ } else {
+ switch_curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, 1);
+ switch_curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYHOST, 1);
+ }
}
if (append_headers) {
@@ -228,6 +241,16 @@ static http_data_t *do_lookup_url(switch_memory_pool_t *pool, const char *url, c
switch_safe_free(ct);
}
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Post data: %s\n", data);
+ } else if (!strcasecmp(method, "patch")) {
+ switch_curl_easy_setopt(curl_handle, CURLOPT_CUSTOMREQUEST, "PATCH");
+ switch_curl_easy_setopt(curl_handle, CURLOPT_POSTFIELDSIZE, strlen(data));
+ switch_curl_easy_setopt(curl_handle, CURLOPT_POSTFIELDS, (void *) data);
+ if (content_type) {
+ char *ct = switch_mprintf("Content-Type: %s", content_type);
+ headers = switch_curl_slist_append(headers, ct);
+ switch_safe_free(ct);
+ }
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "PATCH data: %s\n", data);
} else if (!strcasecmp(method, "delete")) {
switch_curl_easy_setopt(curl_handle, CURLOPT_CUSTOMREQUEST, "DELETE");
switch_curl_easy_setopt(curl_handle, CURLOPT_POSTFIELDSIZE, strlen(data));
@@ -807,7 +830,7 @@ SWITCH_STANDARD_APP(curl_app_function)
switch_curl_slist_t *slist = NULL;
switch_stream_handle_t stream = { 0 };
int i = 0;
- curl_options_t options = { 0 };
+ curl_options_t options = { .insecure = !globals.validate_certs };
const char *curl_timeout;
char *append_headers[HTTP_MAX_APPEND_HEADERS + 1] = { 0 };
int ah_index = 0;
@@ -830,24 +853,8 @@ SWITCH_STANDARD_APP(curl_app_function)
do_json = SWITCH_TRUE;
} else if (!strcasecmp("get", argv[i]) || !strcasecmp("head", argv[i])) {
method = switch_core_strdup(pool, argv[i]);
- } else if (!strcasecmp("post", argv[i])) {
- method = "post";
- if (++i < argc) {
- postdata = switch_core_strdup(pool, argv[i]);
- switch_url_decode(postdata);
- } else {
- postdata = "";
- }
- } else if (!strcasecmp("delete", argv[i])) {
- method = "delete";
- if (++i < argc) {
- postdata = switch_core_strdup(pool, argv[i]);
- switch_url_decode(postdata);
- } else {
- postdata = "";
- }
- } else if (!strcasecmp("put", argv[i])) {
- method = "put";
+ } else if (!strcasecmp("post", argv[i]) || !strcasecmp("patch", argv[i]) || !strcasecmp("put", argv[i]) || !strcasecmp("delete", argv[i])) {
+ method = argv[i];
if (++i < argc) {
postdata = switch_core_strdup(pool, argv[i]);
switch_url_decode(postdata);
@@ -863,6 +870,14 @@ SWITCH_STANDARD_APP(curl_app_function)
if (ah_index == HTTP_MAX_APPEND_HEADERS) continue;
append_headers[ah_index++] = argv[i];
}
+ } else if (!strcasecmp("insecure", argv[i])) {
+ options.insecure = 1;
+ } else if (!strcasecmp("secure", argv[i])) {
+ options.insecure = 0;
+ } else if (!strcasecmp("proxy", argv[i])) {
+ if (++i < argc) {
+ options.proxy = argv[i];
+ }
}
}
}
@@ -931,7 +946,7 @@ SWITCH_STANDARD_API(curl_function)
int ah_index = 0;
switch_memory_pool_t *pool = NULL;
- curl_options_t options = { 0 };
+ curl_options_t options = { .insecure = !globals.validate_certs };
if (zstr(cmd)) {
switch_goto_status(SWITCH_STATUS_SUCCESS, usage);
@@ -958,24 +973,8 @@ SWITCH_STANDARD_API(curl_function)
do_json = SWITCH_TRUE;
} else if (!strcasecmp("get", argv[i]) || !strcasecmp("head", argv[i])) {
method = switch_core_strdup(pool, argv[i]);
- } else if (!strcasecmp("post", argv[i])) {
- method = "post";
- if (++i < argc) {
- postdata = switch_core_strdup(pool, argv[i]);
- switch_url_decode(postdata);
- } else {
- postdata = "";
- }
- } else if (!strcasecmp("delete", argv[i])) {
- method = "delete";
- if (++i < argc) {
- postdata = switch_core_strdup(pool, argv[i]);
- switch_url_decode(postdata);
- } else {
- postdata = "";
- }
- } else if (!strcasecmp("put", argv[i])) {
- method = "put";
+ } else if (!strcasecmp("post", argv[i]) || !strcasecmp("patch", argv[i]) || !strcasecmp("put", argv[i]) || !strcasecmp("delete", argv[i])) {
+ method = argv[i];
if (++i < argc) {
postdata = switch_core_strdup(pool, argv[i]);
switch_url_decode(postdata);
@@ -1011,6 +1010,14 @@ SWITCH_STANDARD_API(curl_function)
if (ah_index == HTTP_MAX_APPEND_HEADERS) continue;
append_headers[ah_index++] = argv[i];
}
+ } else if (!strcasecmp("insecure", argv[i])) {
+ options.insecure = 1;
+ } else if (!strcasecmp("secure", argv[i])) {
+ options.insecure = 0;
+ } else if (!strcasecmp("proxy", argv[i])) {
+ if (++i < argc) {
+ options.proxy = argv[i];
+ }
}
}
From 21c113ba2c07b3328d2d3cfc41cb005d06dfd3da Mon Sep 17 00:00:00 2001
From: Anthony Minessale
Date: Sat, 11 Apr 2020 22:37:04 +0000
Subject: [PATCH 115/655] [mod_curl] look for cacert in certs dir
---
src/mod/applications/mod_curl/mod_curl.c | 34 +++++++++++++++++-------
1 file changed, 25 insertions(+), 9 deletions(-)
diff --git a/src/mod/applications/mod_curl/mod_curl.c b/src/mod/applications/mod_curl/mod_curl.c
index 2da7d4e1ea..02079d6767 100644
--- a/src/mod/applications/mod_curl/mod_curl.c
+++ b/src/mod/applications/mod_curl/mod_curl.c
@@ -85,6 +85,7 @@ struct http_data_obj {
int err;
long http_response_code;
char *http_response;
+ char *cacert;
switch_curl_slist_t *headers;
};
typedef struct http_data_obj http_data_t;
@@ -102,6 +103,7 @@ struct http_sendfile_data_obj {
char *filename_element_name;
char *extrapost_elements;
switch_CURL *curl_handle;
+ char *cacert;
struct curl_httppost *formpost;
struct curl_httppost *lastptr;
uint8_t flags; /* This is for where to send output of the curl_sendfile commands */
@@ -211,13 +213,20 @@ static http_data_t *do_lookup_url(switch_memory_pool_t *pool, const char *url, c
}
if (!strncasecmp(url, "https", 5)) {
- if (options->insecure) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Not verifying TLS cert for %s; connection is not secure\n", url);
- switch_curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, 0);
- switch_curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYHOST, 0);
+ http_data->cacert = switch_core_sprintf(http_data->pool, "%s%scacert.pem", SWITCH_GLOBAL_dirs.certs_dir, SWITCH_PATH_SEPARATOR);
+
+ if (switch_file_exists(http_data->cacert, http_data->pool) == SWITCH_STATUS_SUCCESS) {
+ switch_curl_easy_setopt(curl_handle, CURLOPT_CAINFO, http_data->cacert);
} else {
- switch_curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, 1);
- switch_curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYHOST, 1);
+ http_data->cacert = NULL;
+ if (options->insecure) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Not verifying TLS cert for %s; connection is not secure\n", url);
+ switch_curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, 0);
+ switch_curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYHOST, 0);
+ } else {
+ switch_curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, 1);
+ switch_curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYHOST, 1);
+ }
}
}
@@ -413,9 +422,16 @@ static void http_sendfile_initialize_curl(http_sendfile_data_t *http_data)
if (!strncasecmp(http_data->url, "https", 5))
{
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Not verifying TLS cert for %s; connection is not secure\n", http_data->url);
- curl_easy_setopt(http_data->curl_handle, CURLOPT_SSL_VERIFYPEER, 0);
- curl_easy_setopt(http_data->curl_handle, CURLOPT_SSL_VERIFYHOST, 0);
+ http_data->cacert = switch_core_sprintf(http_data->pool, "%s%scacert.pem", SWITCH_GLOBAL_dirs.certs_dir, SWITCH_PATH_SEPARATOR);
+
+ if (switch_file_exists(http_data->cacert, http_data->pool) == SWITCH_STATUS_SUCCESS) {
+ switch_curl_easy_setopt(http_data->curl_handle, CURLOPT_CAINFO, http_data->cacert);
+ } else {
+ http_data->cacert = NULL;
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Not verifying TLS cert for %s; connection is not secure\n", http_data->url);
+ curl_easy_setopt(http_data->curl_handle, CURLOPT_SSL_VERIFYPEER, 0);
+ curl_easy_setopt(http_data->curl_handle, CURLOPT_SSL_VERIFYHOST, 0);
+ }
}
/* From the docs:
From a562db760c8a9247d35d353ed98331b835ca3636 Mon Sep 17 00:00:00 2001
From: Dragos Oancea
Date: Fri, 14 May 2021 18:36:30 +0300
Subject: [PATCH 116/655] [mod_opus] add cfg setting to overwrite the fmtp
stereo param coming from remote. Eg: incoming SDP has stereo=1 but we want a
mono call so we answer with stereo=0.
* [mod_opus] add cfg setting to overwrite the fmtp stereo param coming from remote. Eg: incoming SDP has stereo=1 but we want a mono call so we answer with stereo=0.
sprop-stereo will be set to 0 too.
* [core] opus: use switch_core_max_audio_channels() with remote fmtp stereo=1 to allow disabling of stereo.
---
conf/testing/autoload_configs/opus.conf.xml | 3 ++-
conf/vanilla/autoload_configs/opus.conf.xml | 4 +++-
src/mod/codecs/mod_opus/mod_opus.c | 10 +++++++++-
src/switch_core_media.c | 8 +++++++-
4 files changed, 21 insertions(+), 4 deletions(-)
diff --git a/conf/testing/autoload_configs/opus.conf.xml b/conf/testing/autoload_configs/opus.conf.xml
index e187a0a6c5..1154797dce 100644
--- a/conf/testing/autoload_configs/opus.conf.xml
+++ b/conf/testing/autoload_configs/opus.conf.xml
@@ -6,6 +6,7 @@
-
+
+
diff --git a/conf/vanilla/autoload_configs/opus.conf.xml b/conf/vanilla/autoload_configs/opus.conf.xml
index 94aaede471..8494c2d3c7 100644
--- a/conf/vanilla/autoload_configs/opus.conf.xml
+++ b/conf/vanilla/autoload_configs/opus.conf.xml
@@ -28,6 +28,8 @@
-
+
+
+
diff --git a/src/mod/codecs/mod_opus/mod_opus.c b/src/mod/codecs/mod_opus/mod_opus.c
index 2081ef1b88..a90aba346a 100644
--- a/src/mod/codecs/mod_opus/mod_opus.c
+++ b/src/mod/codecs/mod_opus/mod_opus.c
@@ -160,6 +160,7 @@ struct {
int debuginfo;
uint32_t use_jb_lookahead;
switch_mutex_t *mutex;
+ int mono;
} opus_prefs;
static struct {
@@ -283,7 +284,7 @@ static switch_status_t switch_opus_fmtp_parse(const char *fmtp, switch_codec_fmt
}
if (!strcasecmp(data, "stereo")) {
- codec_settings->stereo = atoi(arg);
+ codec_settings->stereo = opus_prefs.mono ? 0 : atoi(arg);
codec_fmtp->stereo = codec_settings->stereo;
}
@@ -563,6 +564,11 @@ static switch_status_t switch_opus_init(switch_codec_t *codec, switch_codec_flag
opus_codec_settings.usedtx = opus_prefs.use_dtx;
+ if (opus_prefs.mono) {
+ opus_codec_settings.stereo = 0;
+ opus_codec_settings.sprop_stereo = 0;
+ }
+
codec->fmtp_out = gen_fmtp(&opus_codec_settings, codec->memory_pool);
if (encoding) {
@@ -1080,6 +1086,8 @@ static switch_status_t opus_load_config(switch_bool_t reload)
if (!switch_opus_acceptable_rate(opus_prefs.sprop_maxcapturerate)) {
opus_prefs.sprop_maxcapturerate = 0; /* value not supported */
}
+ } else if (!strcasecmp(key, "mono")) {
+ opus_prefs.mono = atoi(val);
}
}
}
diff --git a/src/switch_core_media.c b/src/switch_core_media.c
index ac8b9b9f71..686bc344f7 100644
--- a/src/switch_core_media.c
+++ b/src/switch_core_media.c
@@ -5774,7 +5774,13 @@ SWITCH_DECLARE(uint8_t) switch_core_media_negotiate_sdp(switch_core_session_t *s
pmap->adv_channels = 2; /* IKR ???*/
}
if (!zstr((char *) mmap->rm_fmtp) && switch_stristr("stereo=1", (char *) mmap->rm_fmtp)) {
- pmap->channels = 2;
+ uint32_t allow_channels = switch_core_max_audio_channels(0);
+ if (!allow_channels || allow_channels >= 2) { /*default*/
+ pmap->channels = 2;
+ } else { /* allow_channels == 1 */
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Opus: setting 1 audio channel via config.\n");
+ pmap->channels = 1;
+ }
} else {
pmap->channels = 1;
}
From 5a9eabca8e085451c259ea06c580aae74753fe15 Mon Sep 17 00:00:00 2001
From: Chris Rienzo
Date: Sun, 16 May 2021 23:12:28 +0000
Subject: [PATCH 117/655] [core] Fix read of uninitialized buffer in
switch_simple_email().
---
src/switch_utils.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/src/switch_utils.c b/src/switch_utils.c
index 0fee81551b..85e12f0488 100644
--- a/src/switch_utils.c
+++ b/src/switch_utils.c
@@ -1128,6 +1128,8 @@ SWITCH_DECLARE(switch_bool_t) switch_simple_email(const char *to,
switch_bool_t rval = SWITCH_FALSE;
const char *err = NULL;
+ filename[0] = '\0';
+
if (zstr(to)) {
err = "No to address specified";
goto end;
@@ -1323,7 +1325,7 @@ SWITCH_DECLARE(switch_bool_t) switch_simple_email(const char *to,
close(fd);
}
- if (unlink(filename) != 0) {
+ if (!zstr_buf(filename) && unlink(filename) != 0) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Failed to delete file [%s]\n", filename);
}
From 189f6f8db256bca8ef63683104247e4b85c81f93 Mon Sep 17 00:00:00 2001
From: Andrey Volk
Date: Fri, 28 May 2021 21:26:56 +0300
Subject: [PATCH 118/655] [apr] error: use of undeclared identifier 'NSIG'
---
libs/apr/include/apr_general.h | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/libs/apr/include/apr_general.h b/libs/apr/include/apr_general.h
index 42eec83ce4..3a956288e3 100644
--- a/libs/apr/include/apr_general.h
+++ b/libs/apr/include/apr_general.h
@@ -29,6 +29,10 @@
#include "apr_pools.h"
#include "apr_errno.h"
+#if !defined(_ANSI_SOURCE) && defined(_DARWIN_C_SOURCE)
+#define NSIG __DARWIN_NSIG
+#endif
+
#if APR_HAVE_SIGNAL_H
#include
#endif
From 81fff857c5455167d807179ff5621d62d9a137f8 Mon Sep 17 00:00:00 2001
From: Andrey Volk
Date: Mon, 7 Jun 2021 20:46:58 +0300
Subject: [PATCH 119/655] [mod_sofia] sofia_process_dispatch_event() should
unref all handles via sofia stack
---
src/mod/endpoints/mod_sofia/mod_sofia.c | 2 +-
src/mod/endpoints/mod_sofia/mod_sofia.h | 2 +-
src/mod/endpoints/mod_sofia/sofia.c | 20 +++++++-------------
3 files changed, 9 insertions(+), 15 deletions(-)
diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.c b/src/mod/endpoints/mod_sofia/mod_sofia.c
index ce9d520ba8..79a3c06795 100644
--- a/src/mod/endpoints/mod_sofia/mod_sofia.c
+++ b/src/mod/endpoints/mod_sofia/mod_sofia.c
@@ -1343,7 +1343,7 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi
de->session = session;
}
- sofia_process_dispatch_event(&de, SWITCH_FALSE);
+ sofia_process_dispatch_event(&de);
switch_mutex_unlock(tech_pvt->sofia_mutex);
diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.h b/src/mod/endpoints/mod_sofia/mod_sofia.h
index e91d849913..02128bf2fd 100644
--- a/src/mod/endpoints/mod_sofia/mod_sofia.h
+++ b/src/mod/endpoints/mod_sofia/mod_sofia.h
@@ -1253,7 +1253,7 @@ uint32_t sofia_presence_get_cseq(sofia_profile_t *profile);
void sofia_glue_build_vid_refresh_message(switch_core_session_t *session, const char *pl);
char *sofia_glue_gen_contact_str(sofia_profile_t *profile, sip_t const *sip, nua_handle_t *nh, sofia_dispatch_event_t *de, sofia_nat_parse_t *np);
void sofia_glue_pause_jitterbuffer(switch_core_session_t *session, switch_bool_t on);
-void sofia_process_dispatch_event(sofia_dispatch_event_t **dep, switch_bool_t stack_thread);
+void sofia_process_dispatch_event(sofia_dispatch_event_t **dep);
void sofia_process_dispatch_event_in_thread(sofia_dispatch_event_t **dep);
char *sofia_glue_get_host(const char *str, switch_memory_pool_t *pool);
void sofia_presence_check_subscriptions(sofia_profile_t *profile, time_t now);
diff --git a/src/mod/endpoints/mod_sofia/sofia.c b/src/mod/endpoints/mod_sofia/sofia.c
index d152a12810..9ebd0ee35f 100644
--- a/src/mod/endpoints/mod_sofia/sofia.c
+++ b/src/mod/endpoints/mod_sofia/sofia.c
@@ -2230,7 +2230,7 @@ void *SWITCH_THREAD_FUNC sofia_msg_thread_run_once(switch_thread_t *thread, void
if (de) {
pool = de->pool;
de->pool = NULL;
- sofia_process_dispatch_event(&de, SWITCH_FALSE);
+ sofia_process_dispatch_event(&de);
}
if (pool) {
@@ -2263,7 +2263,7 @@ void sofia_process_dispatch_event_in_thread(sofia_dispatch_event_t **dep)
switch_thread_pool_launch_thread(&td);
}
-void sofia_process_dispatch_event(sofia_dispatch_event_t **dep, switch_bool_t stack_thread)
+void sofia_process_dispatch_event(sofia_dispatch_event_t **dep)
{
sofia_dispatch_event_t *de = *dep;
nua_handle_t *nh = de->nh;
@@ -2282,15 +2282,9 @@ void sofia_process_dispatch_event(sofia_dispatch_event_t **dep, switch_bool_t st
profile->queued_events--;
switch_mutex_unlock(profile->flag_mutex);
- if (stack_thread) {
- /* Safe to unref directly */
- if (nh) nua_handle_unref(nh);
- nua_unref(nua);
- } else {
- /* This is not a stack thread, need to call via stack (_user) using events */
- if (nh) nua_handle_unref_user(nh);
- nua_unref_user(nua);
- }
+ /* This is not a stack thread, need to call via stack (_user) using events */
+ if (nh) nua_handle_unref_user(nh);
+ nua_unref_user(nua);
}
@@ -2327,7 +2321,7 @@ void *SWITCH_THREAD_FUNC sofia_msg_thread_run(switch_thread_t *thread, void *obj
if (pop) {
sofia_dispatch_event_t *de = (sofia_dispatch_event_t *) pop;
- sofia_process_dispatch_event(&de, SWITCH_FALSE);
+ sofia_process_dispatch_event(&de);
} else {
break;
}
@@ -2382,7 +2376,7 @@ void sofia_queue_message(sofia_dispatch_event_t *de)
if (mod_sofia_globals.running == 0 || !mod_sofia_globals.msg_queue) {
/* Calling with SWITCH_TRUE as we are sure this is the stack's thread */
- sofia_process_dispatch_event(&de, SWITCH_TRUE);
+ sofia_process_dispatch_event(&de);
return;
}
From 9b91e82fa8fa0c11eee2c7ce03f14be7eb47816c Mon Sep 17 00:00:00 2001
From: Andrey Volk
Date: Tue, 15 Jun 2021 20:51:03 +0300
Subject: [PATCH 120/655] Bump sofia-sip library requirement to version 1.13.4
---
configure.ac | 2 +-
debian/bootstrap.sh | 2 +-
freeswitch.spec | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/configure.ac b/configure.ac
index 73c260f311..ccbf0ed3e1 100644
--- a/configure.ac
+++ b/configure.ac
@@ -725,7 +725,7 @@ PKG_CHECK_MODULES([SPANDSP], [spandsp >= 3.0],[
AC_MSG_ERROR([no usable spandsp; please install spandsp3 devel package or equivalent])
])
-PKG_CHECK_MODULES([SOFIA_SIP], [sofia-sip-ua >= 1.13.3],[
+PKG_CHECK_MODULES([SOFIA_SIP], [sofia-sip-ua >= 1.13.4],[
AM_CONDITIONAL([HAVE_SOFIA_SIP],[true])],[
AC_MSG_ERROR([no usable sofia-sip; please install sofia-sip-ua devel package or equivalent])
])
diff --git a/debian/bootstrap.sh b/debian/bootstrap.sh
index 594e7adb7c..53db0f9499 100755
--- a/debian/bootstrap.sh
+++ b/debian/bootstrap.sh
@@ -332,7 +332,7 @@ Build-Depends:
uuid-dev, libexpat1-dev, libgdbm-dev, libdb-dev,
# used by many modules
libcurl4-openssl-dev | libcurl4-gnutls-dev | libcurl-dev,
- bison, zlib1g-dev, libsofia-sip-ua-dev (>= 1.13.3),
+ bison, zlib1g-dev, libsofia-sip-ua-dev (>= 1.13.4),
libspandsp3-dev,
# used to format the private freeswitch apt-repo key properly
gnupg,
diff --git a/freeswitch.spec b/freeswitch.spec
index 9e5f368fe6..c9c7a447f3 100644
--- a/freeswitch.spec
+++ b/freeswitch.spec
@@ -140,7 +140,7 @@ BuildRequires: curl-devel >= 7.19
BuildRequires: gcc-c++
BuildRequires: libtool >= 1.5.17
BuildRequires: openssl-devel >= 1.0.1e
-BuildRequires: sofia-sip-devel >= 1.13.3
+BuildRequires: sofia-sip-devel >= 1.13.4
BuildRequires: spandsp3-devel >= 3.0
BuildRequires: pcre-devel
BuildRequires: speex-devel
From 65d0665a95daf1b030d8dc24d5838305403a2c57 Mon Sep 17 00:00:00 2001
From: Andrey Volk
Date: Wed, 16 Jun 2021 11:18:15 +0300
Subject: [PATCH 121/655] [mod_sofia] Calling direct _unref() functions in
sofia_event_callback() is unsafe.
---
src/mod/endpoints/mod_sofia/sofia.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/src/mod/endpoints/mod_sofia/sofia.c b/src/mod/endpoints/mod_sofia/sofia.c
index 9ebd0ee35f..70ed479ab5 100644
--- a/src/mod/endpoints/mod_sofia/sofia.c
+++ b/src/mod/endpoints/mod_sofia/sofia.c
@@ -2581,8 +2581,8 @@ void sofia_event_callback(nua_event_t event,
profile->queued_events--;
switch_mutex_unlock(profile->flag_mutex);
- nua_handle_unref(nh);
- nua_unref(nua);
+ nua_handle_unref_user(nh);
+ nua_unref_user(nua);
goto end;
}
@@ -2619,8 +2619,8 @@ void sofia_event_callback(nua_event_t event,
profile->queued_events--;
switch_mutex_unlock(profile->flag_mutex);
- nua_handle_unref(nh);
- nua_unref(nua);
+ nua_handle_unref_user(nh);
+ nua_unref_user(nua);
goto end;
}
From f275f416b399afb443087916e9e1ad8097ca9513 Mon Sep 17 00:00:00 2001
From: Andrey Volk
Date: Fri, 25 Jun 2021 00:26:51 +0300
Subject: [PATCH 122/655] [FreeSwitchConsole] Fix build with Visual Studio 2022
---
w32/Console/FreeSwitchConsole.2017.vcxproj | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/w32/Console/FreeSwitchConsole.2017.vcxproj b/w32/Console/FreeSwitchConsole.2017.vcxproj
index 5e29a6f52d..5f636c96b3 100644
--- a/w32/Console/FreeSwitchConsole.2017.vcxproj
+++ b/w32/Console/FreeSwitchConsole.2017.vcxproj
@@ -99,7 +99,7 @@
trueProgramDatabasetrue
- 6031;6340;6246;6011;6387;%(DisableSpecificWarnings)
+ 28251;6031;6340;6246;6011;6387;%(DisableSpecificWarnings)$(OutDir);%(AdditionalLibraryDirectories)
@@ -129,7 +129,7 @@
trueProgramDatabasetrue
- 6031;6340;6246;6011;6387;%(DisableSpecificWarnings)
+ 28251;6031;6340;6246;6011;6387;%(DisableSpecificWarnings)$(OutDir);%(AdditionalLibraryDirectories)
@@ -152,7 +152,7 @@
Level4trueProgramDatabase
- 6031;6340;6246;6011;6387;%(DisableSpecificWarnings)
+ 28251;6031;6340;6246;6011;6387;%(DisableSpecificWarnings)$(OutDir);%(AdditionalLibraryDirectories)
@@ -180,7 +180,7 @@
Level4trueProgramDatabase
- 6031;6340;6246;6011;6387;%(DisableSpecificWarnings)
+ 28251;6031;6340;6246;6011;6387;%(DisableSpecificWarnings)$(OutDir);%(AdditionalLibraryDirectories)
From f6f3f38d252511dd6203cec2fc561cf2e8c7834d Mon Sep 17 00:00:00 2001
From: Andrey Volk
Date: Fri, 9 Jul 2021 14:52:00 +0300
Subject: [PATCH 123/655] [Core] Fix bridge_early_media
---
src/switch_ivr_originate.c | 28 ++++++++++++++++------------
1 file changed, 16 insertions(+), 12 deletions(-)
diff --git a/src/switch_ivr_originate.c b/src/switch_ivr_originate.c
index d81ffcc357..9785d0b7aa 100644
--- a/src/switch_ivr_originate.c
+++ b/src/switch_ivr_originate.c
@@ -124,6 +124,7 @@ typedef struct {
uint8_t early_media;
uint8_t answered;
uint8_t tagged;
+ uint8_t array_pos;
uint32_t per_channel_timelimit_sec;
uint32_t per_channel_progress_timelimit_sec;
uint32_t per_channel_delay_start;
@@ -1862,7 +1863,8 @@ typedef struct early_state early_state_t;
static void *SWITCH_THREAD_FUNC early_thread_run(switch_thread_t *thread, void *obj)
{
early_state_t *state = (early_state_t *) obj;
- //originate_status_t originate_status[MAX_PEERS] = { {0} };
+ originate_status_t originate_status[MAX_PEERS] = { {0} };
+ uint8_t array_pos = 0;
int16_t mux_data[SWITCH_RECOMMENDED_BUFFER_SIZE / 2] = { 0 };
int32_t sample;
switch_codec_t read_codecs[MAX_PEERS] = { {0} };
@@ -1873,9 +1875,8 @@ static void *SWITCH_THREAD_FUNC early_thread_run(switch_thread_t *thread, void *
switch_frame_t *read_frame = NULL;
switch_codec_implementation_t read_impl = { 0 };
-#if 0
for (i = 0; i < MAX_PEERS && i < state->ttl; i++) {
- switch_core_session_t *session = state->originate_status[i].peer_session;
+ switch_core_session_t *session = state->oglobals->originate_status[i].peer_session;
switch_channel_t *channel = NULL;
if (session) channel = switch_core_session_get_channel(session);
@@ -1885,11 +1886,12 @@ static void *SWITCH_THREAD_FUNC early_thread_run(switch_thread_t *thread, void *
}
if (switch_core_session_read_lock(session) == SWITCH_STATUS_SUCCESS) {
- originate_status[i].peer_session = session;
- originate_status[i].peer_channel = channel;
+ originate_status[array_pos].peer_session = session;
+ originate_status[array_pos].peer_channel = channel;
+ originate_status[array_pos].array_pos = (uint8_t) i;
+ array_pos++;
}
}
-#endif
if (state->oglobals->session) {
switch_core_session_get_read_impl(state->oglobals->session, &read_impl);
@@ -1901,9 +1903,10 @@ static void *SWITCH_THREAD_FUNC early_thread_run(switch_thread_t *thread, void *
ready = 0;
answered = 0;
- for (i = 0; i < MAX_PEERS && i < state->ttl; i++) {
- switch_core_session_t *session = state->oglobals->originate_status[i].peer_session;
- switch_channel_t *channel = state->oglobals->originate_status[i].peer_channel;
+ for (array_pos = 0; array_pos < MAX_PEERS && originate_status[array_pos].peer_session; array_pos++) {
+ switch_core_session_t *session = originate_status[array_pos].peer_session;
+ switch_channel_t *channel = originate_status[array_pos].peer_channel;
+ i = originate_status[array_pos].array_pos;
if (!session || !channel || !switch_channel_up(channel)) {
continue;
@@ -1981,9 +1984,10 @@ static void *SWITCH_THREAD_FUNC early_thread_run(switch_thread_t *thread, void *
}
- for (i = 0; i < MAX_PEERS && i < state->ttl; i++) {
- switch_core_session_t *session = state->oglobals->originate_status[i].peer_session;
- switch_channel_t *channel = state->oglobals->originate_status[i].peer_channel;
+ for (array_pos = 0; array_pos < MAX_PEERS && originate_status[array_pos].peer_session; array_pos++) {
+ switch_core_session_t *session = originate_status[array_pos].peer_session;
+ switch_channel_t *channel = originate_status[array_pos].peer_channel;
+ i = originate_status[array_pos].array_pos;
if (!session) continue;
From d03100661e0d73fad1986de5ed2ab1a5c8d520ef Mon Sep 17 00:00:00 2001
From: bmlkc
Date: Fri, 9 Jul 2021 20:44:43 +0200
Subject: [PATCH 124/655] [mod_opusfile] not draining before destroying encoder
causes loss on encoded file
---
src/mod/formats/mod_opusfile/mod_opusfile.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/mod/formats/mod_opusfile/mod_opusfile.c b/src/mod/formats/mod_opusfile/mod_opusfile.c
index 25246a7ced..ae6eebed15 100644
--- a/src/mod/formats/mod_opusfile/mod_opusfile.c
+++ b/src/mod/formats/mod_opusfile/mod_opusfile.c
@@ -316,6 +316,7 @@ static switch_status_t switch_opusfile_close(switch_file_handle_t *handle)
}
#ifdef HAVE_OPUSFILE_ENCODE
if (context->enc) {
+ ope_encoder_drain(context->enc);
ope_encoder_destroy(context->enc);
}
if (context->comments) {
From a4d09d26359d15ed3b6831b37200204d0b647472 Mon Sep 17 00:00:00 2001
From: Andrey Volk
Date: Wed, 14 Jul 2021 19:03:58 +0300
Subject: [PATCH 125/655] [Testing] Update Drone CI signature.
---
.drone.yml | 20 ++++++++++----------
1 file changed, 10 insertions(+), 10 deletions(-)
diff --git a/.drone.yml b/.drone.yml
index 45cbab5880..d8b61ec59b 100644
--- a/.drone.yml
+++ b/.drone.yml
@@ -5,14 +5,14 @@ name: unit-tests
steps:
- name: bootstrap
image: signalwire/freeswitch-public-base
- pull: true
+ pull: always
commands:
- cat /proc/sys/kernel/core_pattern
- ./bootstrap.sh -j
- name: configure
image: signalwire/freeswitch-public-base
- pull: true
+ pull: always
commands:
- apt-get update && DEBIAN_FRONTEND=noninteractive apt-get -yq remove libspandsp-dev
- DEBIAN_FRONTEND=noninteractive apt-get -yq install libsofia-sip-ua-dev libspandsp3-dev
@@ -27,7 +27,7 @@ steps:
- name: build
image: signalwire/freeswitch-public-base
- pull: true
+ pull: always
commands:
- apt-get update && DEBIAN_FRONTEND=noninteractive apt-get -yq remove libspandsp-dev
- DEBIAN_FRONTEND=noninteractive apt-get -yq install libsofia-sip-ua-dev libspandsp3-dev
@@ -37,7 +37,7 @@ steps:
- name: run-tests
image: signalwire/freeswitch-public-base
- pull: true
+ pull: always
commands:
- apt-get update && DEBIAN_FRONTEND=noninteractive apt-get -yq remove libspandsp-dev
- DEBIAN_FRONTEND=noninteractive apt-get -yq install libsofia-sip-ua-dev libspandsp3-dev
@@ -53,7 +53,7 @@ steps:
- name: notify
image: signalwire/drone-notify
- pull: true
+ pull: always
environment:
SLACK_WEBHOOK_URL:
from_secret: slack_webhook_url
@@ -76,13 +76,13 @@ name: scan-build
steps:
- name: bootstrap
image: signalwire/freeswitch-public-base:stretch
- pull: true
+ pull: always
commands:
- ./bootstrap.sh -j
- name: configure
image: signalwire/freeswitch-public-base:stretch
- pull: true
+ pull: always
commands:
- apt-get update && DEBIAN_FRONTEND=noninteractive apt-get -yq remove libspandsp-dev
- DEBIAN_FRONTEND=noninteractive apt-get -yq install libsofia-sip-ua-dev libspandsp3-dev
@@ -113,7 +113,7 @@ steps:
- name: scan-build
image: signalwire/freeswitch-public-base:stretch
- pull: true
+ pull: always
commands:
- apt-get update && DEBIAN_FRONTEND=noninteractive apt-get -yq remove libspandsp-dev
- DEBIAN_FRONTEND=noninteractive apt-get -yq install libsofia-sip-ua-dev libspandsp3-dev
@@ -126,7 +126,7 @@ steps:
- name: notify
image: signalwire/drone-notify
- pull: true
+ pull: always
environment:
SLACK_WEBHOOK_URL:
from_secret: slack_webhook_url
@@ -145,6 +145,6 @@ trigger:
---
kind: signature
-hmac: af77439b382612b49140cb95f04d6d695e0a188c411ae227abcba205bf96bab9
+hmac: bc24832140c40a8fde4bb04bd6bcce43029bf1641ed4acc3585fe52049ae24dc
...
From 9aee9b8e24b1106973e62f58b78100fb34e5acc0 Mon Sep 17 00:00:00 2001
From: Andrey Volk
Date: Sat, 6 Feb 2021 00:38:51 +0300
Subject: [PATCH 126/655] [Core, mod_commands] Add posix_spawn replacement for
the system call. Add unit-tests.
---
src/include/switch_core.h | 2 +
src/mod/applications/mod_commands/Makefile.am | 7 +
.../applications/mod_commands/mod_commands.c | 50 +++++
.../applications/mod_commands/test/.gitignore | 5 +
.../mod_commands/test/conf/freeswitch.xml | 37 ++++
.../mod_commands/test/test_mod_commands.c | 72 +++++++
src/switch_core.c | 200 ++++++++++++++++--
tests/unit/switch_core.c | 34 +++
8 files changed, 392 insertions(+), 15 deletions(-)
create mode 100644 src/mod/applications/mod_commands/test/.gitignore
create mode 100644 src/mod/applications/mod_commands/test/conf/freeswitch.xml
create mode 100644 src/mod/applications/mod_commands/test/test_mod_commands.c
diff --git a/src/include/switch_core.h b/src/include/switch_core.h
index 6299e09c52..e2dfa57afc 100644
--- a/src/include/switch_core.h
+++ b/src/include/switch_core.h
@@ -2842,6 +2842,8 @@ SWITCH_DECLARE(int) switch_system(const char *cmd, switch_bool_t wait);
SWITCH_DECLARE(int) switch_stream_system_fork(const char *cmd, switch_stream_handle_t *stream);
SWITCH_DECLARE(int) switch_stream_system(const char *cmd, switch_stream_handle_t *stream);
+SWITCH_DECLARE(int) switch_spawn(const char *cmd, switch_bool_t wait);
+SWITCH_DECLARE(int) switch_stream_spawn(const char *cmd, switch_bool_t wait, switch_stream_handle_t *stream);
SWITCH_DECLARE(void) switch_core_session_debug_pool(switch_stream_handle_t *stream);
diff --git a/src/mod/applications/mod_commands/Makefile.am b/src/mod/applications/mod_commands/Makefile.am
index 82cfe69a4d..60d4aa13bd 100644
--- a/src/mod/applications/mod_commands/Makefile.am
+++ b/src/mod/applications/mod_commands/Makefile.am
@@ -6,3 +6,10 @@ mod_commands_la_SOURCES = mod_commands.c
mod_commands_la_CFLAGS = $(AM_CFLAGS)
mod_commands_la_LIBADD = $(switch_builddir)/libfreeswitch.la
mod_commands_la_LDFLAGS = -avoid-version -module -no-undefined -shared
+
+noinst_PROGRAMS = test/test_mod_commands
+test_test_mod_commands_CFLAGS = $(SWITCH_AM_CFLAGS) -I../ -DSWITCH_TEST_BASE_DIR_FOR_CONF=\"${abs_builddir}/test\" -DSWITCH_TEST_BASE_DIR_OVERRIDE=\"${abs_builddir}/test\"
+test_test_mod_commands_LDFLAGS = -avoid-version -no-undefined $(SWITCH_AM_LDFLAGS)
+test_test_mod_commands_LDADD = mod_commands.la $(switch_builddir)/libfreeswitch.la
+
+TESTS = $(noinst_PROGRAMS)
diff --git a/src/mod/applications/mod_commands/mod_commands.c b/src/mod/applications/mod_commands/mod_commands.c
index 37eda79929..6c36d26d2a 100644
--- a/src/mod/applications/mod_commands/mod_commands.c
+++ b/src/mod/applications/mod_commands/mod_commands.c
@@ -6522,6 +6522,53 @@ SWITCH_STANDARD_API(bg_system_function)
return SWITCH_STATUS_SUCCESS;
}
+#define SPAWN_SYNTAX ""
+SWITCH_STANDARD_API(spawn_stream_function)
+{
+ if (zstr(cmd)) {
+ stream->write_function(stream, "-USAGE: %s\n", SPAWN_SYNTAX);
+ return SWITCH_STATUS_SUCCESS;
+ }
+
+ if (switch_stream_spawn(cmd, SWITCH_TRUE, stream) < 0) {
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_NOTICE, "Failed to execute command: %s\n", cmd);
+ }
+
+ return SWITCH_STATUS_SUCCESS;
+}
+
+#define SPAWN_SYNTAX ""
+SWITCH_STANDARD_API(spawn_function)
+{
+ if (zstr(cmd)) {
+ stream->write_function(stream, "-USAGE: %s\n", SPAWN_SYNTAX);
+ return SWITCH_STATUS_SUCCESS;
+ }
+
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_NOTICE, "Executing command: %s\n", cmd);
+ if (switch_spawn(cmd, SWITCH_TRUE) < 0) {
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_NOTICE, "Failed to execute command: %s\n", cmd);
+ }
+ stream->write_function(stream, "+OK\n");
+ return SWITCH_STATUS_SUCCESS;
+}
+
+#define SPAWN_SYNTAX ""
+SWITCH_STANDARD_API(bg_spawn_function)
+{
+ if (zstr(cmd)) {
+ stream->write_function(stream, "-USAGE: %s\n", SPAWN_SYNTAX);
+ return SWITCH_STATUS_SUCCESS;
+ }
+
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_NOTICE, "Executing command: %s\n", cmd);
+ if (switch_spawn(cmd, SWITCH_FALSE) < 0) {
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_NOTICE, "Failed to execute command: %s\n", cmd);
+ }
+ stream->write_function(stream, "+OK\n");
+ return SWITCH_STATUS_SUCCESS;
+}
+
SWITCH_STANDARD_API(strftime_tz_api_function)
{
char *format = NULL;
@@ -7456,6 +7503,9 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_commands_load)
if (use_system_commands) {
SWITCH_ADD_API(commands_api_interface, "bg_system", "Execute a system command in the background", bg_system_function, SYSTEM_SYNTAX);
SWITCH_ADD_API(commands_api_interface, "system", "Execute a system command", system_function, SYSTEM_SYNTAX);
+ SWITCH_ADD_API(commands_api_interface, "bg_spawn", "Execute a spawn command in the background", bg_spawn_function, SPAWN_SYNTAX);
+ SWITCH_ADD_API(commands_api_interface, "spawn", "Execute a spawn command without capturing it's output", spawn_function, SPAWN_SYNTAX);
+ SWITCH_ADD_API(commands_api_interface, "spawn_stream", "Execute a spawn command and capture it's output", spawn_stream_function, SPAWN_SYNTAX);
}
SWITCH_ADD_API(commands_api_interface, "acl", "Compare an ip to an acl list", acl_function, "");
diff --git a/src/mod/applications/mod_commands/test/.gitignore b/src/mod/applications/mod_commands/test/.gitignore
new file mode 100644
index 0000000000..b752c84499
--- /dev/null
+++ b/src/mod/applications/mod_commands/test/.gitignore
@@ -0,0 +1,5 @@
+.dirstamp
+.libs/
+.deps/
+test_mod_commands*.o
+test_mod_commands
diff --git a/src/mod/applications/mod_commands/test/conf/freeswitch.xml b/src/mod/applications/mod_commands/test/conf/freeswitch.xml
new file mode 100644
index 0000000000..9369d4e918
--- /dev/null
+++ b/src/mod/applications/mod_commands/test/conf/freeswitch.xml
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/mod/applications/mod_commands/test/test_mod_commands.c b/src/mod/applications/mod_commands/test/test_mod_commands.c
new file mode 100644
index 0000000000..d12535e430
--- /dev/null
+++ b/src/mod/applications/mod_commands/test/test_mod_commands.c
@@ -0,0 +1,72 @@
+/*
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ * Copyright (C) 2005-2018, Anthony Minessale II
+ *
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ *
+ * The Initial Developer of the Original Code is
+ * Andrey Volk
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Andrey Volk
+ *
+ * mod_commands_test -- mod_commands tests
+ *
+ */
+
+#include
+
+FST_CORE_BEGIN("conf")
+{
+ FST_MODULE_BEGIN(mod_commands, mod_commands_test)
+ {
+ FST_SETUP_BEGIN()
+ {
+ }
+ FST_SETUP_END()
+
+ FST_TEST_BEGIN(spawn_test)
+ {
+#ifdef __linux__
+ switch_stream_handle_t stream = { 0 };
+
+ SWITCH_STANDARD_STREAM(stream);
+ switch_api_execute("bg_spawn", "echo TEST_BG_SPAWN", NULL, &stream);
+ fst_check_string_equals(stream.data, "+OK\n");
+ switch_safe_free(stream.data);
+
+ SWITCH_STANDARD_STREAM(stream);
+ switch_api_execute("spawn_stream", "echo DEADBEEF", NULL, &stream);
+ fst_check_string_equals(stream.data, "DEADBEEF\n");
+ switch_safe_free(stream.data);
+
+ SWITCH_STANDARD_STREAM(stream);
+ switch_api_execute("spawn", "echo TEST_NO_OUTPUT", NULL, &stream);
+ fst_check_string_equals(stream.data, "+OK\n");
+ switch_safe_free(stream.data);
+#endif
+ }
+ FST_TEST_END()
+
+ FST_TEARDOWN_BEGIN()
+ {
+ }
+ FST_TEARDOWN_END()
+ }
+ FST_MODULE_END()
+}
+FST_CORE_END()
diff --git a/src/switch_core.c b/src/switch_core.c
index d4507aa49c..617b623753 100644
--- a/src/switch_core.c
+++ b/src/switch_core.c
@@ -59,6 +59,15 @@
#include
#endif
+#ifdef __linux__
+#include
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE /* Required for POSIX_SPAWN_USEVFORK */
+#endif
+#include
+#include
+#endif
+
#ifdef WIN32
#define popen _popen
#define pclose _pclose
@@ -2282,6 +2291,17 @@ static void switch_load_core_config(const char *file)
} else {
switch_clear_flag((&runtime), SCF_THREADED_SYSTEM_EXEC);
}
+#endif
+ } else if (!strcasecmp(var, "spawn-instead-of-system") && !zstr(val)) {
+#ifdef WIN32
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "spawn-instead-of-system is not implemented on this platform\n");
+#else
+ int v = switch_true(val);
+ if (v) {
+ switch_core_set_variable("spawn_instead_of_system", "true");
+ } else {
+ switch_core_set_variable("spawn_instead_of_system", "false");
+ }
#endif
} else if (!strcasecmp(var, "min-idle-cpu") && !zstr(val)) {
switch_core_min_idle_cpu(atof(val));
@@ -3341,9 +3361,14 @@ static int switch_system_fork(const char *cmd, switch_bool_t wait)
SWITCH_DECLARE(int) switch_system(const char *cmd, switch_bool_t wait)
{
+#ifdef __linux__
+ switch_bool_t spawn_instead_of_system = switch_true(switch_core_get_variable("spawn_instead_of_system"));
+#else
+ switch_bool_t spawn_instead_of_system = SWITCH_FALSE;
+#endif
int (*sys_p)(const char *cmd, switch_bool_t wait);
- sys_p = switch_test_flag((&runtime), SCF_THREADED_SYSTEM_EXEC) ? switch_system_thread : switch_system_fork;
+ sys_p = spawn_instead_of_system ? switch_spawn : switch_test_flag((&runtime), SCF_THREADED_SYSTEM_EXEC) ? switch_system_thread : switch_system_fork;
return sys_p(cmd, wait);
@@ -3356,6 +3381,141 @@ SWITCH_DECLARE(int) switch_stream_system_fork(const char *cmd, switch_stream_han
return switch_stream_system(cmd, stream);
}
+#ifdef __linux__
+extern char **environ;
+#endif
+
+SWITCH_DECLARE(int) switch_stream_spawn(const char *cmd, switch_bool_t wait, switch_stream_handle_t *stream)
+{
+#ifndef __linux__
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "posix_spawn is unsupported on current platform\n");
+ return 1;
+#else
+ int status = 0, rval;
+ char buffer[1024];
+ pid_t pid;
+ char *pdata = NULL, *argv[64];
+ posix_spawn_file_actions_t action;
+ posix_spawnattr_t *attr;
+ int cout_pipe[2];
+ int cerr_pipe[2];
+ struct pollfd pfds[2] = { {0} };
+
+ if (zstr(cmd)) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Failed to execute switch_spawn_stream because of empty command\n");
+ return 1;
+ }
+
+ if (!(pdata = strdup(cmd))) {
+ return 1;
+ }
+
+ if (!switch_separate_string(pdata, ' ', argv, (sizeof(argv) / sizeof(argv[0])))) {
+ free(pdata);
+ return 1;
+ }
+
+ if (!(attr = malloc(sizeof(posix_spawnattr_t)))) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to execute switch_spawn_stream because of a memory error: %s\n", cmd);
+ free(pdata);
+ return 1;
+ }
+
+ if (stream) {
+ if (pipe(cout_pipe)) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to execute switch_spawn_stream because of a pipe error: %s\n", cmd);
+ free(attr);
+ free(pdata);
+ return 1;
+ }
+
+ if (pipe(cerr_pipe)) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to execute switch_spawn_stream because of a pipe error: %s\n", cmd);
+ close(cout_pipe[0]);
+ close(cout_pipe[1]);
+ free(attr);
+ free(pdata);
+ return 1;
+ }
+ }
+
+ memset(attr, 0, sizeof(posix_spawnattr_t));
+ posix_spawnattr_init(attr);
+ posix_spawnattr_setflags(attr, POSIX_SPAWN_USEVFORK);
+
+ posix_spawn_file_actions_init(&action);
+
+ if (stream) {
+ posix_spawn_file_actions_addclose(&action, cout_pipe[0]);
+ posix_spawn_file_actions_addclose(&action, cerr_pipe[0]);
+ posix_spawn_file_actions_adddup2(&action, cout_pipe[1], 1);
+ posix_spawn_file_actions_adddup2(&action, cerr_pipe[1], 2);
+
+ posix_spawn_file_actions_addclose(&action, cout_pipe[1]);
+ posix_spawn_file_actions_addclose(&action, cerr_pipe[1]);
+ }
+
+ if (posix_spawnp(&pid, argv[0], &action, attr, argv, environ) != 0) {
+ status = 1;
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Failed to execute posix_spawnp: %s\n", cmd);
+ if (stream) {
+ close(cout_pipe[0]), close(cerr_pipe[0]);
+ close(cout_pipe[1]), close(cerr_pipe[1]);
+ }
+ } else {
+ if (stream) {
+ close(cout_pipe[1]), close(cerr_pipe[1]); /* close child-side of pipes */
+
+ pfds[0] = (struct pollfd) {
+ .fd = cout_pipe[0],
+ .events = POLLIN,
+ .revents = 0
+ };
+
+ pfds[1] = (struct pollfd) {
+ .fd = cerr_pipe[0],
+ .events = POLLIN,
+ .revents = 0
+ };
+
+ while ((rval = poll(pfds, 2, /*timeout*/-1)) > 0) {
+ if (pfds[0].revents & POLLIN) {
+ int bytes_read = read(cout_pipe[0], buffer, sizeof(buffer));
+ stream->raw_write_function(stream, (unsigned char *)buffer, bytes_read);
+ } else if (pfds[1].revents & POLLIN) {
+ int bytes_read = read(cerr_pipe[0], buffer, sizeof(buffer));
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "STDERR of cmd (%s): %.*s\n", cmd, bytes_read, buffer);
+ } else {
+ break; /* nothing left to read */
+ }
+ }
+
+ close(cout_pipe[0]), close(cerr_pipe[0]);
+ }
+
+ if (wait) {
+ if (waitpid(pid, &status, 0) != pid) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "waitpid failed: %s\n", cmd);
+ } else if (status != 0) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Exit status (%d): %s\n", status, cmd);
+ }
+ }
+ }
+
+ posix_spawnattr_destroy(attr);
+ free(attr);
+ posix_spawn_file_actions_destroy(&action);
+ free(pdata);
+
+ return status;
+#endif
+}
+
+SWITCH_DECLARE(int) switch_spawn(const char *cmd, switch_bool_t wait)
+{
+ return switch_stream_spawn(cmd, wait, NULL);
+}
+
SWITCH_DECLARE(switch_status_t) switch_core_get_stacksizes(switch_size_t *cur, switch_size_t *max)
{
#ifdef HAVE_SETRLIMIT
@@ -3382,26 +3542,36 @@ SWITCH_DECLARE(switch_status_t) switch_core_get_stacksizes(switch_size_t *cur, s
SWITCH_DECLARE(int) switch_stream_system(const char *cmd, switch_stream_handle_t *stream)
{
- char buffer[128];
- size_t bytes;
- FILE* pipe = popen(cmd, "r");
- if (!pipe) return 1;
+#ifdef __linux__
+ switch_bool_t spawn_instead_of_system = switch_true(switch_core_get_variable("spawn_instead_of_system"));
+#else
+ switch_bool_t spawn_instead_of_system = SWITCH_FALSE;
+#endif
- while (!feof(pipe)) {
- while ((bytes = fread(buffer, 1, 128, pipe)) > 0) {
- if (stream != NULL) {
- stream->raw_write_function(stream, (unsigned char *)buffer, bytes);
+ if (spawn_instead_of_system){
+ return switch_stream_spawn(cmd, SWITCH_TRUE, stream);
+ } else {
+ char buffer[128];
+ size_t bytes;
+ FILE* pipe = popen(cmd, "r");
+ if (!pipe) return 1;
+
+ while (!feof(pipe)) {
+ while ((bytes = fread(buffer, 1, 128, pipe)) > 0) {
+ if (stream != NULL) {
+ stream->raw_write_function(stream, (unsigned char *)buffer, bytes);
+ }
}
}
- }
- if (ferror(pipe)) {
+ if (ferror(pipe)) {
+ pclose(pipe);
+ return 1;
+ }
+
pclose(pipe);
- return 1;
+ return 0;
}
-
- pclose(pipe);
- return 0;
}
SWITCH_DECLARE(uint16_t) switch_core_get_rtp_port_range_start_port()
diff --git a/tests/unit/switch_core.c b/tests/unit/switch_core.c
index d0d6bacef2..44cfe148bf 100644
--- a/tests/unit/switch_core.c
+++ b/tests/unit/switch_core.c
@@ -160,6 +160,40 @@ FST_CORE_BEGIN("./conf")
fst_check_int_equals(r, SWITCH_TRUE);
}
FST_TEST_END()
+
+ FST_TEST_BEGIN(test_switch_spawn)
+ {
+#ifdef __linux__
+ int status;
+ switch_stream_handle_t stream = { 0 };
+
+ status = switch_spawn("echo CHECKING_BAD_FILE_DESCRIPTOR", SWITCH_TRUE);
+ fst_check_int_equals(status, 0);
+
+ SWITCH_STANDARD_STREAM(stream);
+ status = switch_stream_spawn("echo DEADBEEF", SWITCH_TRUE, &stream);
+ fst_check_int_equals(status, 0);
+ fst_check_string_equals(stream.data, "DEADBEEF\n");
+ switch_safe_free(stream.data);
+
+ SWITCH_STANDARD_STREAM(stream);
+ status = switch_stream_spawn("echo DEADBEEF", SWITCH_FALSE, &stream);
+ fst_check_int_equals(status, 0);
+ fst_check_string_equals(stream.data, "DEADBEEF\n");
+ switch_safe_free(stream.data);
+
+ printf("\nExpected warning check ... ");
+ status = switch_spawn("false", SWITCH_TRUE);
+ fct_chk_neq_int(status, 0);
+
+ status = switch_spawn("false", SWITCH_FALSE);
+ fct_chk_eq_int(status, 0);
+
+ status = switch_spawn("true", SWITCH_TRUE);
+ fct_chk_eq_int(status, 0);
+#endif
+ }
+ FST_TEST_END()
}
FST_SUITE_END()
}
From 311e932df5ac30f7fdb8b31f3579f6a012b964cf Mon Sep 17 00:00:00 2001
From: Chris Rienzo
Date: Tue, 9 Feb 2021 13:19:22 -0500
Subject: [PATCH 127/655] [core, mod_commands] Execute command under shell when
using spawn in switch_system().
---
src/include/switch_core.h | 2 +-
.../applications/mod_commands/mod_commands.c | 2 +-
src/switch_core.c | 53 ++++++++++++-------
tests/unit/conf/freeswitch.xml | 3 ++
tests/unit/switch_core.c | 53 ++++++++++++++-----
5 files changed, 79 insertions(+), 34 deletions(-)
diff --git a/src/include/switch_core.h b/src/include/switch_core.h
index e2dfa57afc..4f172a928e 100644
--- a/src/include/switch_core.h
+++ b/src/include/switch_core.h
@@ -2843,7 +2843,7 @@ SWITCH_DECLARE(int) switch_stream_system_fork(const char *cmd, switch_stream_han
SWITCH_DECLARE(int) switch_stream_system(const char *cmd, switch_stream_handle_t *stream);
SWITCH_DECLARE(int) switch_spawn(const char *cmd, switch_bool_t wait);
-SWITCH_DECLARE(int) switch_stream_spawn(const char *cmd, switch_bool_t wait, switch_stream_handle_t *stream);
+SWITCH_DECLARE(int) switch_stream_spawn(const char *cmd, switch_bool_t shell, switch_bool_t wait, switch_stream_handle_t *stream);
SWITCH_DECLARE(void) switch_core_session_debug_pool(switch_stream_handle_t *stream);
diff --git a/src/mod/applications/mod_commands/mod_commands.c b/src/mod/applications/mod_commands/mod_commands.c
index 6c36d26d2a..ad5bd51ce9 100644
--- a/src/mod/applications/mod_commands/mod_commands.c
+++ b/src/mod/applications/mod_commands/mod_commands.c
@@ -6530,7 +6530,7 @@ SWITCH_STANDARD_API(spawn_stream_function)
return SWITCH_STATUS_SUCCESS;
}
- if (switch_stream_spawn(cmd, SWITCH_TRUE, stream) < 0) {
+ if (switch_stream_spawn(cmd, SWITCH_FALSE, SWITCH_TRUE, stream) < 0) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_NOTICE, "Failed to execute command: %s\n", cmd);
}
diff --git a/src/switch_core.c b/src/switch_core.c
index 617b623753..2589d276a4 100644
--- a/src/switch_core.c
+++ b/src/switch_core.c
@@ -3361,17 +3361,21 @@ static int switch_system_fork(const char *cmd, switch_bool_t wait)
SWITCH_DECLARE(int) switch_system(const char *cmd, switch_bool_t wait)
{
+ int retval = 0;
#ifdef __linux__
switch_bool_t spawn_instead_of_system = switch_true(switch_core_get_variable("spawn_instead_of_system"));
#else
switch_bool_t spawn_instead_of_system = SWITCH_FALSE;
#endif
- int (*sys_p)(const char *cmd, switch_bool_t wait);
-
- sys_p = spawn_instead_of_system ? switch_spawn : switch_test_flag((&runtime), SCF_THREADED_SYSTEM_EXEC) ? switch_system_thread : switch_system_fork;
-
- return sys_p(cmd, wait);
-
+
+ if (spawn_instead_of_system) {
+ retval = switch_stream_spawn(cmd, SWITCH_TRUE, wait, NULL);
+ } else if (switch_test_flag((&runtime), SCF_THREADED_SYSTEM_EXEC)) {
+ retval = switch_system_thread(cmd, wait);
+ } else {
+ retval = switch_system_fork(cmd, wait);
+ }
+ return retval;
}
@@ -3385,7 +3389,7 @@ SWITCH_DECLARE(int) switch_stream_system_fork(const char *cmd, switch_stream_han
extern char **environ;
#endif
-SWITCH_DECLARE(int) switch_stream_spawn(const char *cmd, switch_bool_t wait, switch_stream_handle_t *stream)
+SWITCH_DECLARE(int) switch_stream_spawn(const char *cmd, switch_bool_t shell, switch_bool_t wait, switch_stream_handle_t *stream)
{
#ifndef __linux__
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "posix_spawn is unsupported on current platform\n");
@@ -3406,18 +3410,27 @@ SWITCH_DECLARE(int) switch_stream_spawn(const char *cmd, switch_bool_t wait, swi
return 1;
}
- if (!(pdata = strdup(cmd))) {
- return 1;
- }
-
- if (!switch_separate_string(pdata, ' ', argv, (sizeof(argv) / sizeof(argv[0])))) {
- free(pdata);
- return 1;
+ if (shell) {
+ argv[0] = switch_core_get_variable("spawn_system_shell");
+ argv[1] = "-c";
+ argv[2] = (char *)cmd;
+ argv[3] = NULL;
+ if (zstr(argv[0])) {
+ argv[0] = "/bin/sh";
+ }
+ } else {
+ if (!(pdata = strdup(cmd))) {
+ return 1;
+ }
+ if (!switch_separate_string(pdata, ' ', argv, (sizeof(argv) / sizeof(argv[0])))) {
+ free(pdata);
+ return 1;
+ }
}
if (!(attr = malloc(sizeof(posix_spawnattr_t)))) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to execute switch_spawn_stream because of a memory error: %s\n", cmd);
- free(pdata);
+ switch_safe_free(pdata);
return 1;
}
@@ -3425,7 +3438,7 @@ SWITCH_DECLARE(int) switch_stream_spawn(const char *cmd, switch_bool_t wait, swi
if (pipe(cout_pipe)) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to execute switch_spawn_stream because of a pipe error: %s\n", cmd);
free(attr);
- free(pdata);
+ switch_safe_free(pdata);
return 1;
}
@@ -3434,7 +3447,7 @@ SWITCH_DECLARE(int) switch_stream_spawn(const char *cmd, switch_bool_t wait, swi
close(cout_pipe[0]);
close(cout_pipe[1]);
free(attr);
- free(pdata);
+ switch_safe_free(pdata);
return 1;
}
}
@@ -3505,7 +3518,7 @@ SWITCH_DECLARE(int) switch_stream_spawn(const char *cmd, switch_bool_t wait, swi
posix_spawnattr_destroy(attr);
free(attr);
posix_spawn_file_actions_destroy(&action);
- free(pdata);
+ switch_safe_free(pdata);
return status;
#endif
@@ -3513,7 +3526,7 @@ SWITCH_DECLARE(int) switch_stream_spawn(const char *cmd, switch_bool_t wait, swi
SWITCH_DECLARE(int) switch_spawn(const char *cmd, switch_bool_t wait)
{
- return switch_stream_spawn(cmd, wait, NULL);
+ return switch_stream_spawn(cmd, SWITCH_FALSE, wait, NULL);
}
SWITCH_DECLARE(switch_status_t) switch_core_get_stacksizes(switch_size_t *cur, switch_size_t *max)
@@ -3549,7 +3562,7 @@ SWITCH_DECLARE(int) switch_stream_system(const char *cmd, switch_stream_handle_t
#endif
if (spawn_instead_of_system){
- return switch_stream_spawn(cmd, SWITCH_TRUE, stream);
+ return switch_stream_spawn(cmd, SWITCH_TRUE, SWITCH_TRUE, stream);
} else {
char buffer[128];
size_t bytes;
diff --git a/tests/unit/conf/freeswitch.xml b/tests/unit/conf/freeswitch.xml
index 578a4fe2b7..3dcb33198b 100644
--- a/tests/unit/conf/freeswitch.xml
+++ b/tests/unit/conf/freeswitch.xml
@@ -1,6 +1,9 @@
+
+
+
diff --git a/tests/unit/switch_core.c b/tests/unit/switch_core.c
index 44cfe148bf..bba7272cac 100644
--- a/tests/unit/switch_core.c
+++ b/tests/unit/switch_core.c
@@ -40,10 +40,11 @@
FST_CORE_BEGIN("./conf")
{
- FST_SUITE_BEGIN(switch_ivr_originate)
+ FST_SUITE_BEGIN(switch_core)
{
FST_SETUP_BEGIN()
{
+ switch_core_set_variable("spawn_instead_of_system", "false");
}
FST_SETUP_END()
@@ -101,17 +102,17 @@ FST_CORE_BEGIN("./conf")
#ifndef WIN32
FST_TEST_BEGIN(test_fork)
{
- switch_stream_handle_t exec_result = { 0 };
- SWITCH_STANDARD_STREAM(exec_result);
- fst_requires(switch_stream_system_fork("ip ad sh", &exec_result) == 0);
- fst_requires(!zstr(exec_result.data));
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "%s\n", (char *)exec_result.data);
+ switch_stream_handle_t exec_result = { 0 };
+ SWITCH_STANDARD_STREAM(exec_result);
+ fst_requires(switch_stream_system_fork("ip ad sh", &exec_result) == 0);
+ fst_requires(!zstr(exec_result.data));
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "%s\n", (char *)exec_result.data);
- fst_requires(switch_stream_system_fork("ip ad sh | grep link", &exec_result) == 0);
- fst_requires(!zstr(exec_result.data));
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "%s\n", (char *)exec_result.data);
+ fst_requires(switch_stream_system_fork("ip ad sh | grep link", &exec_result) == 0);
+ fst_requires(!zstr(exec_result.data));
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "%s\n", (char *)exec_result.data);
- switch_safe_free(exec_result.data);
+ switch_safe_free(exec_result.data);
}
FST_TEST_END()
#endif
@@ -171,13 +172,13 @@ FST_CORE_BEGIN("./conf")
fst_check_int_equals(status, 0);
SWITCH_STANDARD_STREAM(stream);
- status = switch_stream_spawn("echo DEADBEEF", SWITCH_TRUE, &stream);
+ status = switch_stream_spawn("echo DEADBEEF", SWITCH_FALSE, SWITCH_TRUE, &stream);
fst_check_int_equals(status, 0);
fst_check_string_equals(stream.data, "DEADBEEF\n");
switch_safe_free(stream.data);
SWITCH_STANDARD_STREAM(stream);
- status = switch_stream_spawn("echo DEADBEEF", SWITCH_FALSE, &stream);
+ status = switch_stream_spawn("echo DEADBEEF", SWITCH_FALSE, SWITCH_FALSE, &stream);
fst_check_int_equals(status, 0);
fst_check_string_equals(stream.data, "DEADBEEF\n");
switch_safe_free(stream.data);
@@ -191,6 +192,34 @@ FST_CORE_BEGIN("./conf")
status = switch_spawn("true", SWITCH_TRUE);
fct_chk_eq_int(status, 0);
+#endif
+ }
+ FST_TEST_END()
+
+ FST_TEST_BEGIN(test_switch_spawn_instead_of_system)
+ {
+#ifdef __linux__
+ int status;
+ char file_uuid[SWITCH_UUID_FORMATTED_LENGTH + 1] = { 0 };
+ const char *filename = NULL;
+ const char *cmd = NULL;
+
+ // tell FS core to use posix_spawn() instead of popen() and friends
+ switch_core_set_variable("spawn_instead_of_system", "true");
+
+ // echo text to a file using shell redirection- this will ensure the command was executed in a shell, as expected
+ switch_uuid_str(file_uuid, sizeof(file_uuid));
+ filename = switch_core_sprintf(fst_pool, "%s" SWITCH_PATH_SEPARATOR "%s", SWITCH_GLOBAL_dirs.temp_dir, file_uuid);
+ cmd = switch_core_sprintf(fst_pool, "echo test_switch_spawn_instead_of_system with spaces > %s", filename);
+ status = switch_system(cmd, SWITCH_TRUE);
+
+ fst_check_int_equals(status, 0);
+ fst_xcheck(status == 0, "Expect switch_system() command to return 0");
+ fst_xcheck(switch_file_exists(filename, fst_pool) == SWITCH_STATUS_SUCCESS, "Expect switch_system() to use shell to create file via > redirection");
+ unlink(filename);
+
+ // verify exec-set works- see conf/freeswitch.xml for test setup of shell_exec_set_test global variable
+ fst_check_string_equals(switch_core_get_variable("shell_exec_set_test"), "usr");
#endif
}
FST_TEST_END()
From ba8aff571e5d61c63bf7e28ae8b73836c7b8b402 Mon Sep 17 00:00:00 2001
From: nrensen
Date: Mon, 19 Jul 2021 23:57:13 +0800
Subject: [PATCH 128/655] [mod_commands] OpenBSD compat
---
src/mod/applications/mod_commands/Makefile.am | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/src/mod/applications/mod_commands/Makefile.am b/src/mod/applications/mod_commands/Makefile.am
index 60d4aa13bd..18d5832063 100644
--- a/src/mod/applications/mod_commands/Makefile.am
+++ b/src/mod/applications/mod_commands/Makefile.am
@@ -7,9 +7,13 @@ mod_commands_la_CFLAGS = $(AM_CFLAGS)
mod_commands_la_LIBADD = $(switch_builddir)/libfreeswitch.la
mod_commands_la_LDFLAGS = -avoid-version -module -no-undefined -shared
+noinst_LTLIBRARIES = libmodcommands.la
+libmodcommands_la_SOURCES = $(mod_commands_la_SOURCES)
+libmodcommands_la_CFLAGS = $(mod_commands_la_CFLAGS)
+
noinst_PROGRAMS = test/test_mod_commands
test_test_mod_commands_CFLAGS = $(SWITCH_AM_CFLAGS) -I../ -DSWITCH_TEST_BASE_DIR_FOR_CONF=\"${abs_builddir}/test\" -DSWITCH_TEST_BASE_DIR_OVERRIDE=\"${abs_builddir}/test\"
test_test_mod_commands_LDFLAGS = -avoid-version -no-undefined $(SWITCH_AM_LDFLAGS)
-test_test_mod_commands_LDADD = mod_commands.la $(switch_builddir)/libfreeswitch.la
+test_test_mod_commands_LDADD = libmodcommands.la $(switch_builddir)/libfreeswitch.la
TESTS = $(noinst_PROGRAMS)
From 1311a84ee20fe6e476bc2848faccbdd08c65ebbd Mon Sep 17 00:00:00 2001
From: Andrey Volk
Date: Tue, 20 Jul 2021 20:39:58 +0300
Subject: [PATCH 129/655] [mod_signalwire] When SignalWire SIP Gateway is in
unregistered state it's DOWN and can not be NOREG.
---
src/mod/applications/mod_signalwire/mod_signalwire.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/mod/applications/mod_signalwire/mod_signalwire.c b/src/mod/applications/mod_signalwire/mod_signalwire.c
index 15e0672984..445de3744b 100644
--- a/src/mod/applications/mod_signalwire/mod_signalwire.c
+++ b/src/mod/applications/mod_signalwire/mod_signalwire.c
@@ -869,7 +869,7 @@ static void on_sofia_gateway_state(switch_event_t *event)
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "SignalWire SIP Gateway registered to %s:%s\n", ip, port);
switch_set_string(globals.gateway_ip, ip);
switch_set_string(globals.gateway_port, port);
- } else if (!strcmp(state, "NOREG")) {
+ } else if (!strcmp(state, "DOWN")) {
globals.gateway_ip[0] = '\0';
globals.gateway_port[0] = '\0';
}
From f631ac800c1a697806f4898a6c97fcc499ba5b17 Mon Sep 17 00:00:00 2001
From: Andrey Volk
Date: Mon, 24 May 2021 17:17:28 +0300
Subject: [PATCH 130/655] [Unit-tests] Build sofia-sip on the fly on Drone CI
so backtraces are more informative in ASAN reports.
---
.drone.yml | 21 ++++++++++++---------
1 file changed, 12 insertions(+), 9 deletions(-)
diff --git a/.drone.yml b/.drone.yml
index d8b61ec59b..d7bcb8a7d9 100644
--- a/.drone.yml
+++ b/.drone.yml
@@ -14,8 +14,10 @@ steps:
image: signalwire/freeswitch-public-base
pull: always
commands:
- - apt-get update && DEBIAN_FRONTEND=noninteractive apt-get -yq remove libspandsp-dev
- - DEBIAN_FRONTEND=noninteractive apt-get -yq install libsofia-sip-ua-dev libspandsp3-dev
+ - apt-get update && DEBIAN_FRONTEND=noninteractive apt-get -yq remove libsofia-sip-ua0 libspandsp-dev
+ - DEBIAN_FRONTEND=noninteractive apt-get -yq install libspandsp3-dev
+ - git clone https://github.com/freeswitch/sofia-sip.git
+ - cd sofia-sip && ./autogen.sh && ./configure.gnu && make -j`nproc` && make install && cd ..
- echo "applications/mod_test" >> modules.conf
- echo 'codecs/mod_openh264' >> modules.conf
- sed -i '/applications\\/mod_http_cache/s/^#//g' modules.conf
@@ -29,8 +31,9 @@ steps:
image: signalwire/freeswitch-public-base
pull: always
commands:
- - apt-get update && DEBIAN_FRONTEND=noninteractive apt-get -yq remove libspandsp-dev
- - DEBIAN_FRONTEND=noninteractive apt-get -yq install libsofia-sip-ua-dev libspandsp3-dev
+ - apt-get update && DEBIAN_FRONTEND=noninteractive apt-get -yq remove libsofia-sip-ua0 libspandsp-dev
+ - DEBIAN_FRONTEND=noninteractive apt-get -yq install libspandsp3-dev
+ - cd sofia-sip && make install && cd ..
- echo '#!/bin/bash\nmake -j`nproc --all` |& tee ./unit-tests-build-result.txt\nexitstatus=$${PIPESTATUS[0]}\necho $$exitstatus > ./build-status.txt\n' > build.sh
- chmod +x build.sh
- ./build.sh
@@ -39,8 +42,9 @@ steps:
image: signalwire/freeswitch-public-base
pull: always
commands:
- - apt-get update && DEBIAN_FRONTEND=noninteractive apt-get -yq remove libspandsp-dev
- - DEBIAN_FRONTEND=noninteractive apt-get -yq install libsofia-sip-ua-dev libspandsp3-dev
+ - apt-get update && DEBIAN_FRONTEND=noninteractive apt-get -yq remove libsofia-sip-ua0 libspandsp-dev
+ - DEBIAN_FRONTEND=noninteractive apt-get -yq install libspandsp3-dev
+ - cd sofia-sip && make install && cd ..
- make install || true
- cd tests/unit
- ./run-tests.sh
@@ -61,7 +65,7 @@ steps:
from_secret: notify_env
commands:
- /root/unit-tests-notify.sh
-
+
trigger:
branch:
- master
@@ -135,7 +139,6 @@ steps:
commands:
- /root/scan-build-notify.sh
-
trigger:
branch:
- master
@@ -145,6 +148,6 @@ trigger:
---
kind: signature
-hmac: bc24832140c40a8fde4bb04bd6bcce43029bf1641ed4acc3585fe52049ae24dc
+hmac: 5d5cfb225053294d7cf1a4fed88eaf9a3a53c99a7bad4dc7164eece336c8861a
...
From dd1e0c160555e50774395fa7350dd851c3146b05 Mon Sep 17 00:00:00 2001
From: tomeeo
Date: Fri, 23 Jul 2021 17:04:59 -0400
Subject: [PATCH 131/655] [mod_http_cache] Fix the query string not included
for HTTP PUT requests to s3
---
src/mod/applications/mod_http_cache/aws.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/mod/applications/mod_http_cache/aws.c b/src/mod/applications/mod_http_cache/aws.c
index cc02b4e5b5..264756eda7 100644
--- a/src/mod/applications/mod_http_cache/aws.c
+++ b/src/mod/applications/mod_http_cache/aws.c
@@ -47,7 +47,7 @@
*/
static char *hmac256(char* buffer, unsigned int buffer_length, const char* key, unsigned int key_length, const char* message)
{
- if (zstr(key) || zstr(message) || buffer_length < SHA256_DIGEST_LENGTH) {
+ if (!key || zstr(message) || buffer_length < SHA256_DIGEST_LENGTH) {
return NULL;
}
From 73571bf9c6b66f3a18838e25e8506e0e63e50327 Mon Sep 17 00:00:00 2001
From: Mario G
Date: Mon, 5 Jul 2021 14:46:00 -0700
Subject: [PATCH 132/655] [libvpx] configure: macos release independence for
sse
---
libs/libvpx/build/make/configure.sh | 96 +++--------------------------
libs/libvpx/configure | 27 +-------
2 files changed, 9 insertions(+), 114 deletions(-)
diff --git a/libs/libvpx/build/make/configure.sh b/libs/libvpx/build/make/configure.sh
index 1b52c053c1..728c3e2568 100644
--- a/libs/libvpx/build/make/configure.sh
+++ b/libs/libvpx/build/make/configure.sh
@@ -767,49 +767,9 @@ process_common_toolchain() {
# detect tgt_os
case "$gcctarget" in
- *darwin10*)
+ *darwin*)
tgt_isa=x86_64
- tgt_os=darwin10
- ;;
- *darwin11*)
- tgt_isa=x86_64
- tgt_os=darwin11
- ;;
- *darwin12*)
- tgt_isa=x86_64
- tgt_os=darwin12
- ;;
- *darwin13*)
- tgt_isa=x86_64
- tgt_os=darwin13
- ;;
- *darwin14*)
- tgt_isa=x86_64
- tgt_os=darwin14
- ;;
- *darwin15*)
- tgt_isa=x86_64
- tgt_os=darwin15
- ;;
- *darwin16*)
- tgt_isa=x86_64
- tgt_os=darwin16
- ;;
- *darwin17*)
- tgt_isa=x86_64
- tgt_os=darwin17
- ;;
- *darwin18*)
- tgt_isa=x86_64
- tgt_os=darwin18
- ;;
- *darwin19*)
- tgt_isa=x86_64
- tgt_os=darwin19
- ;;
- *darwin20*)
- tgt_isa=x86_64
- tgt_os=darwin20
+ tgt_os=darwin
;;
x86_64*mingw32*)
tgt_os=win64
@@ -903,53 +863,11 @@ process_common_toolchain() {
esac
case ${toolchain} in
- *-darwin8-*)
- add_cflags "-mmacosx-version-min=10.4"
- add_ldflags "-mmacosx-version-min=10.4"
- ;;
- *-darwin9-*)
- add_cflags "-mmacosx-version-min=10.5"
- add_ldflags "-mmacosx-version-min=10.5"
- ;;
- *-darwin10-*)
- add_cflags "-mmacosx-version-min=10.6"
- add_ldflags "-mmacosx-version-min=10.6"
- ;;
- *-darwin11-*)
- add_cflags "-mmacosx-version-min=10.7"
- add_ldflags "-mmacosx-version-min=10.7"
- ;;
- *-darwin12-*)
- add_cflags "-mmacosx-version-min=10.8"
- add_ldflags "-mmacosx-version-min=10.8"
- ;;
- *-darwin13-*)
- add_cflags "-mmacosx-version-min=10.9"
- add_ldflags "-mmacosx-version-min=10.9"
- ;;
- *-darwin14-*)
- add_cflags "-mmacosx-version-min=10.10"
- add_ldflags "-mmacosx-version-min=10.10"
- ;;
- *-darwin15-*)
- add_cflags "-mmacosx-version-min=10.11"
- add_ldflags "-mmacosx-version-min=10.11"
- ;;
- *-darwin16-*)
- add_cflags "-mmacosx-version-min=10.12"
- add_ldflags "-mmacosx-version-min=10.12"
- ;;
- *-darwin17-*)
- add_cflags "-mmacosx-version-min=10.13"
- add_ldflags "-mmacosx-version-min=10.13"
- ;;
- *-darwin18-*)
- add_cflags "-mmacosx-version-min=10.14"
- add_ldflags "-mmacosx-version-min=10.14"
- ;;
- *-darwin19-*)
- add_cflags "-mmacosx-version-min=10.15"
- add_ldflags "-mmacosx-version-min=10.15"
+ *-darwin-*)
+ mvmin=$(sw_vers -productVersion)
+ mvmin="-mmacosx-version-min="${mvmin%.*}
+ add_cflags $mvmin
+ add_ldflags $mvmin
;;
*-iphonesimulator-*)
add_cflags "-miphoneos-version-min=${IOS_VERSION_MIN}"
diff --git a/libs/libvpx/configure b/libs/libvpx/configure
index 731bcb5bc8..354f03d525 100755
--- a/libs/libvpx/configure
+++ b/libs/libvpx/configure
@@ -117,19 +117,7 @@ all_platforms="${all_platforms} mips64-linux-gcc"
all_platforms="${all_platforms} ppc64le-linux-gcc"
all_platforms="${all_platforms} sparc-solaris-gcc"
all_platforms="${all_platforms} x86-android-gcc"
-all_platforms="${all_platforms} x86-darwin8-gcc"
-all_platforms="${all_platforms} x86-darwin8-icc"
-all_platforms="${all_platforms} x86-darwin9-gcc"
-all_platforms="${all_platforms} x86-darwin9-icc"
-all_platforms="${all_platforms} x86-darwin10-gcc"
-all_platforms="${all_platforms} x86-darwin11-gcc"
-all_platforms="${all_platforms} x86-darwin12-gcc"
-all_platforms="${all_platforms} x86-darwin13-gcc"
-all_platforms="${all_platforms} x86-darwin14-gcc"
-all_platforms="${all_platforms} x86-darwin15-gcc"
-all_platforms="${all_platforms} x86-darwin16-gcc"
-all_platforms="${all_platforms} x86-darwin17-gcc"
-all_platforms="${all_platforms} x86-darwin18-gcc"
+all_platforms="${all_platforms} x86-darwin-gcc"
all_platforms="${all_platforms} x86-iphonesimulator-gcc"
all_platforms="${all_platforms} x86-linux-gcc"
all_platforms="${all_platforms} x86-linux-icc"
@@ -139,18 +127,7 @@ all_platforms="${all_platforms} x86-win32-gcc"
all_platforms="${all_platforms} x86-win32-vs14"
all_platforms="${all_platforms} x86-win32-vs15"
all_platforms="${all_platforms} x86_64-android-gcc"
-all_platforms="${all_platforms} x86_64-darwin9-gcc"
-all_platforms="${all_platforms} x86_64-darwin10-gcc"
-all_platforms="${all_platforms} x86_64-darwin11-gcc"
-all_platforms="${all_platforms} x86_64-darwin12-gcc"
-all_platforms="${all_platforms} x86_64-darwin13-gcc"
-all_platforms="${all_platforms} x86_64-darwin14-gcc"
-all_platforms="${all_platforms} x86_64-darwin15-gcc"
-all_platforms="${all_platforms} x86_64-darwin16-gcc"
-all_platforms="${all_platforms} x86_64-darwin17-gcc"
-all_platforms="${all_platforms} x86_64-darwin18-gcc"
-all_platforms="${all_platforms} x86_64-darwin19-gcc"
-all_platforms="${all_platforms} x86_64-darwin20-gcc"
+all_platforms="${all_platforms} x86_64-darwin-gcc"
all_platforms="${all_platforms} x86_64-iphonesimulator-gcc"
all_platforms="${all_platforms} x86_64-linux-gcc"
all_platforms="${all_platforms} x86_64-linux-icc"
From bd87b8892c260753af5672b6f865684036f157dc Mon Sep 17 00:00:00 2001
From: xiaobaozidi
Date: Tue, 29 Jun 2021 20:08:16 -0500
Subject: [PATCH 133/655] [mod_sofia] Fixed a few Usage-of-uninitialized value
bugs which may cause information discolsure and bypass ACL check
---
src/mod/endpoints/mod_sofia/sofia.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/src/mod/endpoints/mod_sofia/sofia.c b/src/mod/endpoints/mod_sofia/sofia.c
index 70ed479ab5..79deb3e08a 100644
--- a/src/mod/endpoints/mod_sofia/sofia.c
+++ b/src/mod/endpoints/mod_sofia/sofia.c
@@ -856,7 +856,7 @@ void sofia_handle_sip_i_notify(switch_core_session_t *session, int status,
if (sofia_test_pflag(profile, PFLAG_FORWARD_MWI_NOTIFY)) {
const char *mwi_status = NULL;
- char network_ip[80];
+ char network_ip[80] = "";
uint32_t x = 0;
int acl_ok = 1;
char *last_acl = NULL;
@@ -1616,7 +1616,7 @@ static void our_sofia_event_callback(nua_event_t event,
}
if (authorization) {
- char network_ip[80];
+ char network_ip[80] = "";
int network_port;
sofia_glue_get_addr(de->data->e_msg, network_ip, sizeof(network_ip), &network_port);
auth_res = sofia_reg_parse_auth(profile, authorization, sip, de,
@@ -10192,7 +10192,7 @@ void sofia_handle_sip_i_reinvite(switch_core_session_t *session,
if (session && profile && sip && sofia_test_pflag(profile, PFLAG_TRACK_CALLS)) {
switch_channel_t *channel = switch_core_session_get_channel(session);
private_object_t *tech_pvt = (private_object_t *) switch_core_session_get_private(session);
- char network_ip[80];
+ char network_ip[80] = "";
int network_port = 0;
char via_space[2048];
char branch[16] = "";
@@ -10308,7 +10308,7 @@ void sofia_handle_sip_i_invite(switch_core_session_t *session, nua_t *nua, sofia
const char *referred_by_user = NULL;//, *referred_by_host = NULL;
const char *context = NULL;
const char *dialplan = NULL;
- char network_ip[80];
+ char network_ip[80] = "";
char proxied_client_ip[80];
switch_event_t *v_event = NULL;
switch_xml_t x_user = NULL;
From 9376db0aae8422787ba9e688fd263814c16d9ed5 Mon Sep 17 00:00:00 2001
From: Andrey Volk
Date: Thu, 15 Jul 2021 17:26:20 +0300
Subject: [PATCH 134/655] [Core] Fix FreeSWITCH crashes caused by race
conditions when working with Secure RTP.
---
src/switch_rtp.c | 20 ++++++++++++--------
1 file changed, 12 insertions(+), 8 deletions(-)
diff --git a/src/switch_rtp.c b/src/switch_rtp.c
index 1b0d407dec..d4e3f10218 100644
--- a/src/switch_rtp.c
+++ b/src/switch_rtp.c
@@ -64,9 +64,9 @@
#define JITTER_LEAD_FRAMES 10
#define READ_INC(rtp_session) switch_mutex_lock(rtp_session->read_mutex); rtp_session->reading++
-#define READ_DEC(rtp_session) switch_mutex_unlock(rtp_session->read_mutex); rtp_session->reading--
-#define WRITE_INC(rtp_session) switch_mutex_lock(rtp_session->write_mutex); rtp_session->writing++
-#define WRITE_DEC(rtp_session) switch_mutex_unlock(rtp_session->write_mutex); rtp_session->writing--
+#define READ_DEC(rtp_session) rtp_session->reading--; switch_mutex_unlock(rtp_session->read_mutex)
+#define WRITE_INC(rtp_session) switch_mutex_lock(rtp_session->write_mutex); rtp_session->writing++
+#define WRITE_DEC(rtp_session) rtp_session->writing--; switch_mutex_unlock(rtp_session->write_mutex)
#define RTP_STUN_FREQ 1000000
#define rtp_header_len 12
@@ -2387,6 +2387,7 @@ static int check_rtcp_and_ice(switch_rtp_t *rtp_session)
#ifdef ENABLE_SRTP
+ switch_mutex_lock(rtp_session->ice_mutex);
if (rtp_session->flags[SWITCH_RTP_FLAG_SECURE_SEND]) {
int stat = 0;
int sbytes = (int) rtcp_bytes;
@@ -2399,12 +2400,13 @@ static int check_rtcp_and_ice(switch_rtp_t *rtp_session)
if (stat) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_ERROR, "Error: SRTP RTCP protection failed with code %d\n", stat);
+ switch_mutex_unlock(rtp_session->ice_mutex);
goto end;
} else {
rtcp_bytes = sbytes;
}
-
}
+ switch_mutex_unlock(rtp_session->ice_mutex);
#endif
#ifdef ENABLE_ZRTP
@@ -7099,9 +7101,6 @@ static switch_status_t read_rtcp_packet(switch_rtp_t *rtp_session, switch_size_t
*bytes = 0;
}
}
- switch_mutex_unlock(rtp_session->ice_mutex);
-
-
#ifdef ENABLE_SRTP
if (rtp_session->flags[SWITCH_RTP_FLAG_SECURE_RECV] && rtp_session->rtcp_recv_msg_p->header.version == 2) {
@@ -7128,6 +7127,7 @@ static switch_status_t read_rtcp_packet(switch_rtp_t *rtp_session, switch_size_t
}
#endif
+ switch_mutex_unlock(rtp_session->ice_mutex);
#ifdef ENABLE_ZRTP
if (zrtp_on && !rtp_session->flags[SWITCH_RTP_FLAG_PROXY_MEDIA] && rtp_session->rtcp_recv_msg_p->header.version == 2) {
@@ -7606,6 +7606,7 @@ static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_
other_rtp_session->rtcp_send_msg = rtp_session->rtcp_recv_msg;
#ifdef ENABLE_SRTP
+ switch_mutex_lock(other_rtp_session->ice_mutex);
if (switch_rtp_test_flag(other_rtp_session, SWITCH_RTP_FLAG_SECURE_SEND)) {
int stat = 0;
int sbytes = (int) rtcp_bytes;
@@ -7620,8 +7621,8 @@ static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_ERROR, "Error: SRTP RTCP protection failed with code %d\n", stat);
}
rtcp_bytes = sbytes;
-
}
+ switch_mutex_unlock(other_rtp_session->ice_mutex);
#endif
#ifdef ENABLE_ZRTP
@@ -9237,6 +9238,7 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_write_raw(switch_rtp_t *rtp_session,
if (process_encryption) {
#ifdef ENABLE_SRTP
+ switch_mutex_lock(rtp_session->ice_mutex);
if (rtp_session->flags[SWITCH_RTP_FLAG_SECURE_SEND]) {
int sbytes = (int) *bytes;
@@ -9251,6 +9253,7 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_write_raw(switch_rtp_t *rtp_session,
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_ERROR, "Error! RE-Activating Secure RTP SEND\n");
rtp_session->flags[SWITCH_RTP_FLAG_SECURE_SEND] = 0;
status = SWITCH_STATUS_FALSE;
+ switch_mutex_unlock(rtp_session->ice_mutex);
goto end;
} else {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_INFO, "RE-Activating Secure RTP SEND\n");
@@ -9268,6 +9271,7 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_write_raw(switch_rtp_t *rtp_session,
}
*bytes = sbytes;
}
+ switch_mutex_unlock(rtp_session->ice_mutex);
#endif
#ifdef ENABLE_ZRTP
/* ZRTP Send */
From 432bfc0c45de62cdf146ad3870f8b8d351c5c22b Mon Sep 17 00:00:00 2001
From: dhruvecosmob
Date: Tue, 20 Jul 2021 16:02:52 +0300
Subject: [PATCH 135/655] [mod_sofia] Deprecate the auth-messages profile param
by setting it to be enabled by default and introducing the new
disable-auth-messages param with a higher priority when set.
---
.../endpoints/mod_sofia/conf/sofia.conf.xml | 8 +++++++-
src/mod/endpoints/mod_sofia/sofia.c | 18 ++++++++++++++++--
2 files changed, 23 insertions(+), 3 deletions(-)
diff --git a/src/mod/endpoints/mod_sofia/conf/sofia.conf.xml b/src/mod/endpoints/mod_sofia/conf/sofia.conf.xml
index 7c802aa43b..3166094a27 100644
--- a/src/mod/endpoints/mod_sofia/conf/sofia.conf.xml
+++ b/src/mod/endpoints/mod_sofia/conf/sofia.conf.xml
@@ -317,12 +317,18 @@
register for nat handling -->
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/mod/endpoints/mod_sofia/test/sipp-based-tests.c b/src/mod/endpoints/mod_sofia/test/sipp-based-tests.c
new file mode 100644
index 0000000000..382dbc2970
--- /dev/null
+++ b/src/mod/endpoints/mod_sofia/test/sipp-based-tests.c
@@ -0,0 +1,295 @@
+
+/*
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ * Copyright (C) 2005-2021, Anthony Minessale II
+ *
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ *
+ * The Initial Developer of the Original Code is
+ * Anthony Minessale II
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Dragos Oancea
+ *
+ *
+ * sipp-based-tests.c - Test FreeSwitch using sipp (https://github.com/SIPp/sipp)
+ *
+ */
+
+#include
+#include
+#include
+
+int test_success = 0;
+int test_sofia_debug = 1;
+
+static switch_bool_t has_ipv6()
+{
+ switch_stream_handle_t stream = { 0 };
+ SWITCH_STANDARD_STREAM(stream);
+ switch_api_execute("sofia", "status profile external-ipv6", NULL, &stream);
+
+ if (strstr((char *)stream.data, "Invalid Profile")) {
+
+ switch_safe_free(stream.data);
+
+ return SWITCH_FALSE;
+ }
+
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "STATUS PROFILE: %s\n", (char *) stream.data);
+
+ switch_safe_free(stream.data);
+
+ return SWITCH_TRUE;
+}
+
+static int start_sipp_uac(const char *ip, int remote_port,const char *scenario_uac, const char *extra)
+{
+ char *cmd = switch_mprintf("sipp %s:%d -nr -p 5062 -m 1 -s 1001 -recv_timeout 10000 -timeout 10s -sf %s -bg %s", ip, remote_port, scenario_uac, extra);
+ int sys_ret = switch_system(cmd, SWITCH_TRUE);
+
+ printf("%s\n", cmd);
+ switch_safe_free(cmd);
+ switch_sleep(1000 * 1000);
+ return sys_ret;
+}
+
+static void kill_sipp(void)
+{
+ switch_system("pkill -x sipp", SWITCH_TRUE);
+ switch_sleep(1000 * 1000);
+}
+
+static void event_handler(switch_event_t *event)
+{
+ const char *new_ev = switch_event_get_header(event, "Event-Subclass");
+ char *str;
+
+ if (new_ev && !strcmp(new_ev, "sofia::gateway_invalid_digest_req")) {
+ test_success = 1;
+ }
+
+ /*print the event*/
+ switch_event_serialize_json(event, &str);
+ if (str) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "%s\n", str);
+ switch_safe_free(str);
+ }
+}
+
+FST_CORE_EX_BEGIN("./conf-sipp", SCF_VG | SCF_USE_SQL)
+{
+ FST_MODULE_BEGIN(mod_sofia, uac-uas)
+ {
+ FST_SETUP_BEGIN()
+ {
+ switch_stream_handle_t stream = { 0 };
+ SWITCH_STANDARD_STREAM(stream);
+ switch_api_execute("sofia", "global siptrace on", NULL, &stream);
+ if (test_sofia_debug) {
+ switch_api_execute("sofia", "loglevel all 9", NULL, &stream);
+ switch_api_execute("sofia", "tracelevel debug", NULL, &stream);
+ }
+ switch_safe_free(stream.data);
+
+ switch_core_set_variable("spawn_instead_of_system", "true");
+
+ fst_requires_module("mod_sndfile");
+ fst_requires_module("mod_voicemail");
+ fst_requires_module("mod_sofia");
+ fst_requires_module("mod_loopback");
+ fst_requires_module("mod_console");
+ fst_requires_module("mod_dptools");
+ fst_requires_module("mod_dialplan_xml");
+ fst_requires_module("mod_commands");
+ fst_requires_module("mod_say_en");
+ fst_requires_module("mod_tone_stream");
+
+ }
+ FST_SETUP_END()
+
+ FST_TEARDOWN_BEGIN()
+ {
+ }
+ FST_TEARDOWN_END()
+
+ FST_TEST_BEGIN(uac_digest_leak_udp)
+ {
+ switch_core_session_t *session;
+ switch_call_cause_t cause;
+ switch_status_t status;
+ switch_channel_t *channel;
+ const char *local_ip_v4 = switch_core_get_variable("local_ip_v4");
+ int sipp_ret;
+
+ switch_event_bind("sofia", SWITCH_EVENT_CUSTOM, NULL, event_handler, NULL);
+
+ status = switch_ivr_originate(NULL, &session, &cause, "loopback/+15553334444", 2, NULL, NULL, NULL, NULL, NULL, SOF_NONE, NULL, NULL);
+ sipp_ret = start_sipp_uac(local_ip_v4, 5080, "sipp-scenarios/uac_digest_leak.xml", "");
+ if (sipp_ret < 0 || sipp_ret == 127) {
+ fst_requires(0); /* sipp not found */
+ }
+
+ fst_check(status == SWITCH_STATUS_SUCCESS);
+ if (!session) {
+ fst_requires(session);
+ }
+
+ channel = switch_core_session_get_channel(session);
+ fst_xcheck(switch_channel_get_state(channel) < CS_HANGUP, "Expect call not to be hung up");
+
+ while (1) {
+ int ret;
+ switch_sleep(1000 * 1000);
+ ret = switch_system("pidof sipp", SWITCH_TRUE);
+ if (!ret) {
+ break;
+ }
+ }
+
+ switch_sleep(5000 * 1000);
+
+ switch_channel_hangup(channel, SWITCH_CAUSE_NORMAL_CLEARING);
+
+ switch_core_session_rwunlock(session);
+ switch_sleep(1000 * 1000);
+
+ switch_event_unbind_callback(event_handler);
+ /* sipp should timeout, attempt kill, just in case.*/
+ kill_sipp();
+ fst_check(test_success);
+ test_success = 0;
+ }
+ FST_TEST_END()
+
+ FST_TEST_BEGIN(uac_digest_leak_tcp)
+ {
+ switch_core_session_t *session;
+ switch_call_cause_t cause;
+ switch_status_t status;
+ switch_channel_t *channel;
+ const char *local_ip_v4 = switch_core_get_variable("local_ip_v4");
+ int sipp_ret;
+
+ switch_event_bind("sofia", SWITCH_EVENT_CUSTOM, NULL, event_handler, NULL);
+
+ status = switch_ivr_originate(NULL, &session, &cause, "loopback/+15553334444", 2, NULL, NULL, NULL, NULL, NULL, SOF_NONE, NULL, NULL);
+ sipp_ret = start_sipp_uac(local_ip_v4, 5080, "sipp-scenarios/uac_digest_leak-tcp.xml", "-t t1");
+ if (sipp_ret < 0 || sipp_ret == 127) {
+ fst_requires(0); /* sipp not found */
+ }
+
+ fst_check(status == SWITCH_STATUS_SUCCESS);
+ if (!session) {
+ fst_requires(session);
+ }
+
+ channel = switch_core_session_get_channel(session);
+ fst_xcheck(switch_channel_get_state(channel) < CS_HANGUP, "Expect call not to be hung up");
+
+ while (1) {
+ int ret;
+ switch_sleep(1000 * 1000);
+ ret = switch_system("pidof sipp", SWITCH_TRUE);
+ if (!ret) {
+ break;
+ }
+ }
+
+ switch_sleep(5000 * 1000);
+
+ switch_channel_hangup(channel, SWITCH_CAUSE_NORMAL_CLEARING);
+
+ switch_core_session_rwunlock(session);
+ switch_sleep(1000 * 1000);
+
+ switch_event_unbind_callback(event_handler);
+ /* sipp should timeout, attempt kill, just in case.*/
+ kill_sipp();
+ fst_check(test_success);
+ test_success = 0;
+ }
+ FST_TEST_END()
+
+ FST_TEST_BEGIN(uac_digest_leak_udp_ipv6)
+ {
+ switch_core_session_t *session;
+ switch_call_cause_t cause;
+ switch_status_t status;
+ switch_channel_t *channel;
+ const char *local_ip_v6 = switch_core_get_variable("local_ip_v6");
+ int sipp_ret;
+ char *ipv6 = NULL;
+
+ if (!has_ipv6()) {
+ goto skiptest;
+ }
+ switch_event_bind("sofia", SWITCH_EVENT_CUSTOM, NULL, event_handler, NULL);
+
+ if (!strchr(local_ip_v6,'[')) {
+ ipv6 = switch_mprintf("[%s]", local_ip_v6);
+ }
+ status = switch_ivr_originate(NULL, &session, &cause, "loopback/+15553334444", 2, NULL, NULL, NULL, NULL, NULL, SOF_NONE, NULL, NULL);
+
+ if (!ipv6) {
+ sipp_ret = start_sipp_uac(local_ip_v6, 6060, "sipp-scenarios/uac_digest_leak-ipv6.xml", "-i [::1]");
+ } else {
+ sipp_ret = start_sipp_uac(ipv6, 6060, "sipp-scenarios/uac_digest_leak-ipv6.xml", "-i [::1] -mi [::1]");
+ }
+
+ if (sipp_ret < 0 || sipp_ret == 127) {
+ fst_requires(0); /* sipp not found */
+ }
+
+ fst_check(status == SWITCH_STATUS_SUCCESS);
+ if (!session) {
+ fst_requires(session);
+ }
+
+ channel = switch_core_session_get_channel(session);
+ fst_xcheck(switch_channel_get_state(channel) < CS_HANGUP, "Expect call not to be hung up");
+
+ while (1) {
+ int ret;
+ switch_sleep(1000 * 1000);
+ ret = switch_system("pidof sipp", SWITCH_TRUE);
+ if (!ret) {
+ break;
+ }
+ }
+
+ switch_sleep(5000 * 1000);
+
+ switch_channel_hangup(channel, SWITCH_CAUSE_NORMAL_CLEARING);
+
+ switch_core_session_rwunlock(session);
+ switch_sleep(1000 * 1000);
+
+ switch_event_unbind_callback(event_handler);
+ /* sipp should timeout, attempt kill, just in case.*/
+ kill_sipp();
+ switch_safe_free(ipv6);
+ fst_check(test_success);
+skiptest:
+ test_success = 0;
+ }
+ FST_TEST_END()
+
+ }
+ FST_MODULE_END()
+}
+FST_CORE_END()
diff --git a/src/mod/endpoints/mod_sofia/test/sipp-scenarios/uac_digest_leak-ipv6.xml b/src/mod/endpoints/mod_sofia/test/sipp-scenarios/uac_digest_leak-ipv6.xml
new file mode 100644
index 0000000000..6ddbe069da
--- /dev/null
+++ b/src/mod/endpoints/mod_sofia/test/sipp-scenarios/uac_digest_leak-ipv6.xml
@@ -0,0 +1,100 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ;tag=[call_number]
+ To: sut
+ Call-ID: [call_id]
+ CSeq: 1 INVITE
+ Contact: sip:1001@[local_ip]:[local_port]
+ Max-Forwards: 70
+ Subject: Performance Test
+ Content-Type: application/sdp
+ Content-Length: [len]
+
+ v=0
+ o=user1 53655765 2353687637 IN IP[local_ip_type] 0000:0000:0000:0000:0000:0000:0000:0001
+ s=-
+ c=IN IP6 0000:0000:0000:0000:0000:0000:0000:0001
+ t=0 0
+ m=audio [media_port] RTP/AVP 0
+ a=rtpmap:0 PCMU/8000
+
+ ]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ;tag=[call_number]
+ To: sut [peer_tag_param]
+ Call-ID: [call_id]
+ CSeq: 1 ACK
+ Contact: sip:1001@[local_ip]:[local_port]
+ Max-Forwards: 70
+ Subject: Performance Test
+ Content-Length: 0
+
+ ]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/mod/endpoints/mod_sofia/test/sipp-scenarios/uac_digest_leak-tcp.xml b/src/mod/endpoints/mod_sofia/test/sipp-scenarios/uac_digest_leak-tcp.xml
new file mode 100644
index 0000000000..7276fa1d46
--- /dev/null
+++ b/src/mod/endpoints/mod_sofia/test/sipp-scenarios/uac_digest_leak-tcp.xml
@@ -0,0 +1,99 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ ;tag=[call_number]
+ To: sut
+ Call-ID: [call_id]
+ CSeq: 1 INVITE
+ Contact:
+ Max-Forwards: 70
+ Subject: Performance Test
+ Content-Type: application/sdp
+ Content-Length: [len]
+
+ v=0
+ o=user1 53655765 2353687637 IN IP[local_ip_type] 127.0.0.1
+ s=-
+ c=IN IP[media_ip_type] 127.0.0.1
+ t=0 0
+ m=audio [media_port] RTP/AVP 0
+ a=rtpmap:0 PCMU/8000
+
+ ]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ;tag=[call_number]
+ To: sut [peer_tag_param]
+ Call-ID: [call_id]
+ CSeq: 1 ACK
+ Contact:
+ Max-Forwards: 70
+ Subject: Performance Test
+ Content-Length: 0
+
+ ]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/mod/endpoints/mod_sofia/test/sipp-scenarios/uac_digest_leak.xml b/src/mod/endpoints/mod_sofia/test/sipp-scenarios/uac_digest_leak.xml
new file mode 100644
index 0000000000..7c1e9ebd62
--- /dev/null
+++ b/src/mod/endpoints/mod_sofia/test/sipp-scenarios/uac_digest_leak.xml
@@ -0,0 +1,98 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ ;tag=[call_number]
+ To: sut
+ Call-ID: [call_id]
+ CSeq: 1 INVITE
+ Contact: sip:1001@127.0.0.1:[local_port]
+ Max-Forwards: 70
+ Subject: Performance Test
+ Content-Type: application/sdp
+ Content-Length: [len]
+
+ v=0
+ o=user1 53655765 2353687637 IN IP[local_ip_type] [local_ip]
+ s=-
+ c=IN IP[media_ip_type] [media_ip]
+ t=0 0
+ m=audio [media_port] RTP/AVP 0
+ a=rtpmap:0 PCMU/8000
+
+ ]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ;tag=[call_number]
+ To: sut [peer_tag_param]
+ Call-ID: [call_id]
+ CSeq: 1 ACK
+ Contact: sip:1001@127.0.0.1:[local_port]
+ Max-Forwards: 70
+ Subject: Performance Test
+ Content-Length: 0
+
+ ]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/mod/endpoints/mod_sofia/test/test_run_sipp.sh b/src/mod/endpoints/mod_sofia/test/test_run_sipp.sh
new file mode 100755
index 0000000000..fbe01c144d
--- /dev/null
+++ b/src/mod/endpoints/mod_sofia/test/test_run_sipp.sh
@@ -0,0 +1,3 @@
+#/bin/sh
+./sipp-based-tests
+
diff --git a/src/mod/endpoints/mod_sofia/test/voicemail/vm-goodbye.wav b/src/mod/endpoints/mod_sofia/test/voicemail/vm-goodbye.wav
new file mode 100644
index 0000000000000000000000000000000000000000..b656226bf1de91d745587532a4c22fc0c0db3f49
GIT binary patch
literal 7606
zcmXw81(X!W*1lEUJu^FNNEUZ@7JCrff&_O0!FdE(B)G%FB@mqONN@=YfyHe}aCd^c
zOBP*rq`Rx`|MAZGPo0_F?yj!u_D#!%_3CZSNz|@Z+i!aHADSl}5eclCxrruLCz6zo
zdUhMyZ5H+jioho`?!4w0%KN{o51gBd(;JSaNHTH%J$tYxnafcfzT#%#BsrWCRTq9E
zM)E_>E04QNoH#ONg4XUT(O)L(JUmA35Lx&YSC*Tpyk3ZX#Z(h@p6Ajge#CoeG6h*v
zcQKOgbAHM|-*FPJB`@$hoqSoFE?XbUj6laz{CNoqhID`<*@7dFd9{
znW%`EWJFl^JoSAGBD+NQv6g#|MU;|xRB7_LBZA@Jwm@=P^|WDu$nZSpl6_ZYrd6V}
z^qbO??8)JYj!cc5F4CJre6={2bDMWK$)QQ%Mq#oWhbD(kxCh*lPLk@wr}P?qMZXdU
zL>qb1T;k8_XG-$Sk7!Azj+QO-1-rhz!ft3^4!#Z6a0|F&?Q$xT&*-*#KW8(B$)mD~
z)hjYjWI1urDjzXX{7W?uH#wiv#Lnz2ar%aago?WR+&E{Gvs4e(^Hh7CD4WYP@v9XT
zbvf!^vWw@p$bv=_wOeeXADxJBFzjS1VesHU?f^fa*7?xWhd+nf!msHnmo{al8P&hoX{BjT6Xn^sVk
zkKE)vt#j~Iv02XyR}GbR%7qUFehc|jH}|-`$h}0v`J*}}lFS!!keSYx5+fpt%L5Us
zBbtbKy!>Qr&}*twl({()NS5j@XKHVzs+JQbr;qbAA(Z`H_L
zR%xy&KG7&07rGOiYbOS?q)iS@a8}x;eaOuxzT?I`UCy$C#xyHq#QB&}J`8E8f{aSSwz4Z>7XcRK*nlaXEUxvt9MmKY*KgBF;
z%#bX8mEWij;qGou=WK9yXrq14PH;lbAvKzI>VkTzSV^sDy*MUV?lVl;L~gZ)n-Am|
zGmm*eR24g@3jd-@>&&W=d)>X@e(kn*FS{q)S#Eh1P@mNnT@w*>luC$!qA5IJfLtJ_
z$wjiRtR@S|KSdSsp2kr=y23wlG0w^_^)NkIchL{kpQ@+Iq2g4GYM?f$m#VqW$NRYf
zDLNxs$>Xx4k!;*E&KjGHMMiPsXBjJ33BRaC34BtQ(Ir$X_m)%JS!@4hU$qN3Z=Cb)
zCFSFM^p(gX!*Z^X$4oRInvcyh=1en}+1pquUyGN>EY-P&UZ7q3sT`nxi_ZwyL>m
zrFyHM)g@H`vb}}nuX1%tqEsp?x``2DmRKQv!&;9_(Hr?Chj>8is23Ha_q>~@aYtkp
zrElpSdb;kRYwL=-h%T#J=s|jeeyQVmCZ|9vdnl(EDej0uvV$BeCqmCPWGYUsERIkE
zy1*^?f$pb;UaP)Wg;li5tZJ$0>YeJXKk6Br1r&>l)xwZ%qwO9Y8W~hN`kea5Bs?2(%PSry>#3Sh+Y6=-13Mu1cj0}rwV!7xna*B)e
zANm));8pxR=i*m7SufW!VB@*q|EzX(86Lpf_%$rk4*7RI{Y97P2K`OvXg{r`*)$lr
zv^qG5BZEHkbN-u;^B!Kui+BnT<=)(dzr*T?zkPW$|HK>k7@xqNm#7yVXbLT+m9zqD
zBl7n$no0esE%=E;roYI)^HiMBimP!ctm0gTYvH7E@Ypk)#@VPQbqDvWX*V6CGjxbH
z(^49bd(|ilrSdu6%yZ$l-*ZE}SA*+uYwpG)cp>Du&SAX&HDad^jizZd2a-&pA@n_c
zgDRE*)bI02-oa~m8TQY|S_YZ6@&TNB2igd+m%gGr*jtt=g5UD^Tbv3|F3O7gvE+rP
zny8r)HSo(KV%Av94pxW*;6If=W2JGBZ5DVV78Nx&6`^?WRRer{S@ozkRmJJWK`SHq
zP|x1+3%<)&_%b-TfbZ-402T8yo0J}vI3By}Q*+qrJ7~8(HN#a^DupLskwqcA{gm&)
zMwj^#&bWnlUxODD66d87R0$NDKqqanTH};@uxvSSlpVa8Wb;StehK<7LGd5{1W5>1
z&w%Ios3?`B($K;eU6cXEqErYxXNM&-Pz)-u7xWEi!XOX+kHm?w;5a>=X2d5wdWk69
ziN+_2{8<10JTqmZOjMY1K)Z!tS%&l`>dSrJ1P@5QKYWTS!++xue`RSNboLGseFeEYLHhQ%ssexf
z#OtUh{Q!UV!uLmshv4-zwGx@cQd&jDgjZyyL-4c&_*M`RAH~(-B}wq`3tSTK&q2(r
zfPe0x7gQP9WUqK3>d1w%zVyl!;tBjEmQSdn>am;TesnXde(IS@Q&KDXa=tFp)+mfI0P&LLqqlWV%T~>{9CaL%Ov96{s>IGu5
zXSMH*zgd)F&7uG5?Cw*iy>m0v-=3o+Kc;y+M<;R-9<8=Gb?u(cKozNasZ=$R)|mm2{#YraI5eHdC;gxH*{fLN_BTWhkJxuxMkFB)k|;S6yvTh
zL)6%qg|Tr~1GO*wHdxg8;N-IX>Z-_PHn8&2827ld!g*|W4tEW;b$0M?ltWynQ^p4G
z_{eKf4`N38ZnzxkAJ`tQshUEP*2Ybw4@Jp$?%$dz8J*eZzx959-79^j+D-
zn7x4UEmTvqq}}?ctGKgO
zBVtkH@ykB1`$(`u9d=;pc%ypBkrC5(!pzZ!J#=qng<0wn{6QmJ}$X4#`jAjX1A_N_EaV
zb9j}x*0;}J+n2|0Mr!wd;NZtKft5xTZysMRtEt${iFVzzEP>gfDfGlBC*SZbr=#1|
z>8E1ER_mg#SwsPEX8#5MLpL?8*vF0`vYz|C@$E2v;^VrP-5`)NcqW`xJ~Q@-kg8#C
zck;XAwMTw3cX*%r2BOQ2h-|1I1{QxT7us%K_AT;_HhS|XHP`0AoM2C@SOW%lu%^vyJ;@vo|>voV-0o~jYWJ-Mi(D&Ph}x$GkL
zk2*n?6$kX5aJ1dcovk;DMA6Pbe0Xwu@Lk@MyxO&>l~^CI^T2X
zXjkY(;(M`3y$I#7J*o=r6|o|(d}p4tih2%upZMdALeA*4F`;box%Zy;tf-*(xE0-N
zc0T)O=N^;%o8Q|vLXYf9Tv*f;cPQF$%@ucY7e_y%6sg%ay^u`wNPo9I6pl-S~
z-B@R&eZU!kPV&62hc35@dyxx>pHSa>8Qm@N)UrzWn)$EG;!cY+WEg^72
zJ#J&ibXvLHP`?Z4&EYBGXw{E?75!0@ry6g}8dj3o!dE=9lzGF6P8$~fM_%&|_nhI8
z?s0dOyTDmxzj9XbNgARZSSqWEr*@(#=(aYVo7Jrz=1NbksHvVc>TOym&|D1gHuPSg
zdhSs7oEzmnwd*)V`2gkP2ll~mqWhSuixRYpHp-!9Su@I%UF&gZDo_Q%9^x
z-k)T=+U+h?J=`O99ebwQNol;zmG&`b4Ja+F;dzXr#ms9~7$RQ^fH;h$gRx8rK&%aaFw>PH!
z;?yv{@f0(L=!b3z)yAC#8&^`BQCnuI1$Gw4uj|qSbWr_7TUo#uVeB(wJ&XO
z@Xo+vx3>{(y%U-Ak7}{1>h87kIuFz-^amZ(b9;+ZQ&y0wU
z{!?wXr-t?Fe#M4i_w2qrFpuh9;mWA%j{Hl2=ZkyuIM&&N~(c83>}A}Q(~c5B1aqF
zTH0Fad+R$RrrFtpJDhk~6VZNOE7eVZaJ|kgCs}V1TdBFq@4Rx3>(z9E#-bm6M}5U#
zva0#LRo}9FN#15+pgle4bL+`8V~Y5QnPZlI<^JRhbL;bHk&gVTzSG`)qD!NLOs2Es
zkfsJQqnX{hX%_L`^sW~(@%~#UgWPZQ6ww@wK61F~?R0Sm@j8)#&bkeph3*FJa5tJt
z{b(5dMBT(9_4xJ6fv4e>Uw&MB}#{s9b(@e#QexjwmifY_dl>{1*
ziq0aM*78AqBGwv}%n!yxtDA44sok$a9qejU(P$}O(++r7l=eHFofOpeXzHS-J560y
zevYFn=wAl&0n7>^F%jO^*XU_}@*eUG*1v@Q4*x=P&H8dN`s8xrvwmg=?HxK<{7i;g
z;S6*`>Xx3*Td5m;)>qV3O=65ZE#r;X#*dcv*0!GM+ICK-7UeX~$b#~Ks7<%sI`$r?
zGM5v-ac?!;z2q)X9rY_-Pj`5*&Y~ys2Gp;8;%_;`ykj=@tnwZ;>gg1Fr27ZGlG%;-
zm;=k|O-^rTgxbL0(q4@j(!J*7}UR7t&y$5D{>BS*I}&2>x#d4fcYxt
z@V4~bGJEJpw&85h17(acS{|oXdWzf0ndY9;<>@UyQ+wQ-i19;u5%4QP3-n9%N&Tj;
zb1xFIixF!UGk-LTSam!(t&$XhDRL~QP-*e4h!RShDyN$Z@22Q2I$r0}=hRuXRqsPT
z*pSEQ%6gO@i)W4LzA%hyGD-d|hZ!%-8P+CitbCx>xPx>PdV|Sm3Odbs`i@)2-KJLP
z{OszTx|zPK2I>kt8xze?T|tl2yLEr?SW;XNm&H}F2s7d(xxlDk4lx^<>qKSUN4-OY
z4#r%x3mxA!;Az{`LEQq=*+p)ptEt!Owf==O@-3a4H|YktmHrx@+5z}j3hl$xI86jZ
z1*zm#qm>z9b&?BovU2r%u7?S*vq+@*`izRxH{p3b_z>sj%IIM0X$#X{DelD&^>uYX
z)z?2@>bSu(G3(8TP4|d+M0*r6)mP>_bDy!0-st-9gIt(CDu@^{fwRGO`!IoC)y*+&
z?9qiW%bw8_^(NgE(_aF3Xsnj!nXbgykR=vz442^iJVGa7dN%pB
zE`XEs>0-K;&aeNgt6^q&$&r|A;^`pG#nj}Lh2>gN(eRiTjes#;RuCPi5*NkHdrC7g+PJD$LQl8#cKF$Kl}=~Wrc83(2ioLBg>FOEo#B(xjaywbUYqd)=D6C?|~r9
z0up%`-~Hel-$Cns-p+nZg*~Vtv@?v(@kYuhexXO=lB_Nd%TAG=
zXHBPb)~E4l`5gL)YkMjp>Enuv+y@_Ih2>q8T#wTU=+#>pJg
zVNh)kRNYV)&~@NfQ{b}?^eY|EgMog`
z!sHqat2d?qkEh2#PUefMKx5{}PDV9jq_IPOqWhG{UqSZ$KvDKW@+hDjFMvc$h26`*
z>bCwjaEvI(%18P-a$Z~h0a1H^v;Plo
zstKfF4Xn}!)_O#lgjXIz2Dpdp7h~j;KZ?4jkZEkuH^7UoASzEF-;F~K+Rnp~J!=Ea
z?7$LI=3xh3@)`bkAD<7}0Dswm78L-sIf%Icm!X`P((6(k_+o$f`#Q=X%89Asx+o&E
z%UZIw%qjm8>42rR2a*s$Z83t;r8kS8|icaSVM(6f<1?n
zh1V7V1;KeZA8J(=Zh*Ue!O>>K<4yb?^d5LjEg)GLkvB3zqy3OyzXj^n2f1f1a?n&-
zj{1On0t!bcjUFOG*3s|C8jX<6$^iW`DGaP|;dodR~s52ay3!
z10%c#&f@4Le6$L*P#@G<&=}}^B&MZJw3p5!M_&gA1He~SU~Hw46R#rY-2jH>qPibI
zBpv6S;N}WW-iw&}6}e&usHZ?b0-k#n2=EJFyesguKk~v+aJvK5;sz?2q^IC95A=}-
z7VQQ-xB4IDX7n>K+{(D~1MJipeC3C>N`eCuHPWOfYyf+_gL>?R=1Kx1jR9i#5z^en
z=Ll%tM_&0G5pW6|ZH24{!RZZ1d>5JhD)7~p_?s10%nZ3}!X|YwuapCo%J|NT>nNa<
z*--!T0)_m7YQBT#JO!30LEXZ=FSvF9TDuDU<)d5t26g`iXr$u56F`!4AR;m$GVb9`
z2UY7OuF@fw<^l}?nTi7kE&>X1@Q4iXjO;iuJ!<+pXyzZ}s8}Gg7BJ^D*zXN0{%6?k
d6XN9yLTrPUgL^jC7Zlcm6HNHi7ay|u{{YPU)KmZf
literal 0
HcmV?d00001
diff --git a/src/mod/endpoints/mod_sofia/test/voicemail/vm-not_available.wav b/src/mod/endpoints/mod_sofia/test/voicemail/vm-not_available.wav
new file mode 100644
index 0000000000000000000000000000000000000000..fc5358332f08445eace117f1467414c0c5b3ac70
GIT binary patch
literal 15658
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