diff options
62 files changed, 2726 insertions, 1061 deletions
@@ -364,13 +364,41 @@ cdr_csv --- Functionality changes from Asterisk 13.10.0 to Asterisk 13.11.0 ---------- ------------------------------------------------------------------------------ +chan_dahdi +------------------ + * Added "faxdetect_timeout" option. + The option determines how many seconds into a call before faxdetect + is disabled for the call. Setting the value to zero disables the timeout. + res_pjsip ------------------ + * Added "fax_detect_timeout" to endpoint. + The option determines how many seconds into a call before fax_detect + is disabled for the call. Setting the value to zero disables the timeout. + * Added "subscribe_context" to endpoint. If specified, incoming SUBSCRIBE requests will be searched for the matching extension in the indicated context. If no "subscribe_context" is specified, then the "context" setting is used. +res_rtp_asterisk +------------------ + * The DTLS part in Asterisk now supports Perfect Forward Secrecy (PFS). + Enabling PFS is attempted by default, and is dependent on the configuration + of the module using TLS. + - Ephemeral ECDH (ECDHE) is enabled by default. To disable it, do not + specify a ECDHE cipher suite in sip.conf, for example: + dtlscipher=AES128-SHA + - Ephemeral DH (DHE) is disabled by default. To enable it, add DH parameters + into the private key file, e.g., sip.conf dtlsprivatekey. For example: + openssl dhparam -out ./dh.pem 2048 + - Because clients expect the server to prefer PFS, and because OpenSSL sorts + its cipher suites by bit strength, see "openssl ciphers -v DEFAULT". + Consider re-ordering your cipher suites in the respective configuration + file. For example: + dtlscipher=ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256 + which forces PFS and requires at least DTLS 1.2. + ------------------------------------------------------------------------------ --- Functionality changes from Asterisk 13.9.0 to Asterisk 13.10.0 ----------- ------------------------------------------------------------------------------ @@ -408,8 +436,6 @@ res_pjsip "contact_deny" - List of Contact header addresses to deny "contact_permit" - List of Contact header addresses to permit - * Added new status Updated to AMI event ContactStatus on update registration - * Added "reg_server" to contacts. If the Asterisk system name is set in asterisk.conf, it will be stored into the "reg_server" field in the ps_contacts table to facilitate @@ -491,7 +491,7 @@ doc/core-en_US.xml: makeopts .lastclean $(XML_core_en_US) @printf "Building Documentation For: " @echo "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" > $@ @echo "<!DOCTYPE docs SYSTEM \"appdocsxml.dtd\">" >> $@ - @echo "<?xml-stylesheet type=\"text/xsl\" href=\"appdocsxml.xslt\"?>" > $@ + @echo "<?xml-stylesheet type=\"text/xsl\" href=\"appdocsxml.xslt\"?>" >> $@ @echo "<docs xmlns:xi=\"http://www.w3.org/2001/XInclude\">" >> $@ @for x in $(MOD_SUBDIRS); do \ printf "$$x " ; \ @@ -515,7 +515,7 @@ else @printf "Building Documentation For: " @echo "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" > $@ @echo "<!DOCTYPE docs SYSTEM \"appdocsxml.dtd\">" >> $@ - @echo "<?xml-stylesheet type=\"text/xsl\" href=\"appdocsxml.xslt\"?>" > $@ + @echo "<?xml-stylesheet type=\"text/xsl\" href=\"appdocsxml.xslt\"?>" >> $@ @echo "<docs xmlns:xi=\"http://www.w3.org/2001/XInclude\">" >> $@ @for x in $(MOD_SUBDIRS); do \ printf "$$x " ; \ @@ -824,7 +824,7 @@ install-logrotate: rm -f contrib/scripts/asterisk.logrotate.tmp config: - if [ -f /etc/redhat-release -o -f /etc/fedora-release ]; then \ + @if [ -f /etc/redhat-release -o -f /etc/fedora-release ]; then \ ./build_tools/install_subst contrib/init.d/rc.redhat.asterisk "$(DESTDIR)/etc/rc.d/init.d/asterisk"; \ if [ ! -f "$(DESTDIR)/etc/sysconfig/asterisk" ] ; then \ $(INSTALL) -m 644 contrib/init.d/etc_default_asterisk "$(DESTDIR)/etc/sysconfig/asterisk" ; \ diff --git a/apps/app_macro.c b/apps/app_macro.c index d2da16523..26e4262b1 100644 --- a/apps/app_macro.c +++ b/apps/app_macro.c @@ -190,8 +190,8 @@ static void macro_fixup(void *data, struct ast_channel *old_chan, struct ast_cha static struct ast_exten *find_matching_priority(struct ast_context *c, const char *exten, int priority, const char *callerid) { struct ast_exten *e; - struct ast_include *i; struct ast_context *c2; + int idx; for (e=ast_walk_context_extensions(c, NULL); e; e=ast_walk_context_extensions(c, e)) { if (ast_extension_match(ast_get_extension_name(e), exten)) { @@ -210,7 +210,9 @@ static struct ast_exten *find_matching_priority(struct ast_context *c, const cha } /* No match; run through includes */ - for (i=ast_walk_context_includes(c, NULL); i; i=ast_walk_context_includes(c, i)) { + for (idx = 0; idx < ast_context_includes_count(c); idx++) { + const struct ast_include *i = ast_context_includes_get(c, idx); + for (c2=ast_walk_contexts(NULL); c2; c2=ast_walk_contexts(c2)) { if (!strcmp(ast_get_context_name(c2), ast_get_include_name(i))) { e = find_matching_priority(c2, exten, priority, callerid); diff --git a/apps/app_queue.c b/apps/app_queue.c index 8f949635d..39413f9a6 100644 --- a/apps/app_queue.c +++ b/apps/app_queue.c @@ -2359,10 +2359,17 @@ static void pending_members_remove(struct member *mem) */ static void update_status(struct call_queue *q, struct member *m, const int status) { - m->status = status; - - /* Whatever the status is clear the member from the pending members pool */ - pending_members_remove(m); + if (m->status != status) { + m->status = status; + + /* Remove the member from the pending members pool only when the status changes. + * This is not done unconditionally because we can occasionally see multiple + * device state notifications of not in use after a previous call has ended, + * including after we have initiated a new call. This is more likely to + * happen when there is latency in the connection to the member. + */ + pending_members_remove(m); + } queue_publish_member_blob(queue_member_status_type(), queue_member_blob_create(q, m)); } diff --git a/apps/app_voicemail.c b/apps/app_voicemail.c index 6607f529e..894038bdb 100644 --- a/apps/app_voicemail.c +++ b/apps/app_voicemail.c @@ -12307,6 +12307,7 @@ static int append_mailbox(const char *context, const char *box, const char *data return 0; } +#ifdef TEST_FRAMEWORK AST_TEST_DEFINE(test_voicemail_vmuser) { int res = 0; @@ -12494,6 +12495,7 @@ AST_TEST_DEFINE(test_voicemail_vmuser) free_user(vmu); return res ? AST_TEST_FAIL : AST_TEST_PASS; } +#endif static int vm_box_exists(struct ast_channel *chan, const char *data) { diff --git a/apps/app_while.c b/apps/app_while.c index 273b46678..cc048dfb3 100644 --- a/apps/app_while.c +++ b/apps/app_while.c @@ -117,8 +117,8 @@ static const char *get_index(struct ast_channel *chan, const char *prefix, int i static struct ast_exten *find_matching_priority(struct ast_context *c, const char *exten, int priority, const char *callerid) { struct ast_exten *e; - struct ast_include *i; struct ast_context *c2; + int idx; for (e=ast_walk_context_extensions(c, NULL); e; e=ast_walk_context_extensions(c, e)) { if (ast_extension_match(ast_get_extension_name(e), exten)) { @@ -137,7 +137,9 @@ static struct ast_exten *find_matching_priority(struct ast_context *c, const cha } /* No match; run through includes */ - for (i=ast_walk_context_includes(c, NULL); i; i=ast_walk_context_includes(c, i)) { + for (idx = 0; idx < ast_context_includes_count(c); idx++) { + const struct ast_include *i = ast_context_includes_get(c, idx); + for (c2=ast_walk_contexts(NULL); c2; c2=ast_walk_contexts(c2)) { if (!strcmp(ast_get_context_name(c2), ast_get_include_name(i))) { e = find_matching_priority(c2, exten, priority, callerid); diff --git a/autoconf/acx_pthread.m4 b/autoconf/acx_pthread.m4 deleted file mode 100644 index b7ee73ddb..000000000 --- a/autoconf/acx_pthread.m4 +++ /dev/null @@ -1,243 +0,0 @@ -dnl @synopsis ACX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]]) -dnl -dnl @summary figure out how to build C programs using POSIX threads -dnl -dnl This macro figures out how to build C programs using POSIX threads. -dnl It sets the PTHREAD_LIBS output variable to the threads library and -dnl linker flags, and the PTHREAD_CFLAGS output variable to any special -dnl C compiler flags that are needed. (The user can also force certain -dnl compiler flags/libs to be tested by setting these environment -dnl variables.) -dnl -dnl Also sets PTHREAD_CC to any special C compiler that is needed for -dnl multi-threaded programs (defaults to the value of CC otherwise). -dnl (This is necessary on AIX to use the special cc_r compiler alias.) -dnl -dnl NOTE: You are assumed to not only compile your program with these -dnl flags, but also link it with them as well. e.g. you should link -dnl with $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS -dnl $LIBS -dnl -dnl If you are only building threads programs, you may wish to use -dnl these variables in your default LIBS, CFLAGS, and CC: -dnl -dnl LIBS="$PTHREAD_LIBS $LIBS" -dnl CFLAGS="$CFLAGS $PTHREAD_CFLAGS" -dnl CC="$PTHREAD_CC" -dnl -dnl In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute -dnl constant has a nonstandard name, defines PTHREAD_CREATE_JOINABLE to -dnl that name (e.g. PTHREAD_CREATE_UNDETACHED on AIX). -dnl -dnl ACTION-IF-FOUND is a list of shell commands to run if a threads -dnl library is found, and ACTION-IF-NOT-FOUND is a list of commands to -dnl run it if it is not found. If ACTION-IF-FOUND is not specified, the -dnl default action will define HAVE_PTHREAD. -dnl -dnl Please let the authors know if this macro fails on any platform, or -dnl if you have any other suggestions or comments. This macro was based -dnl on work by SGJ on autoconf scripts for FFTW (www.fftw.org) (with -dnl help from M. Frigo), as well as ac_pthread and hb_pthread macros -dnl posted by Alejandro Forero Cuervo to the autoconf macro repository. -dnl We are also grateful for the helpful feedback of numerous users. -dnl -dnl @category InstalledPackages -dnl @author Steven G. Johnson <stevenj@alum.mit.edu> -dnl @version 2006-05-29 -dnl @license GPLWithACException - -AC_DEFUN([ACX_PTHREAD], -[ -AC_REQUIRE([AC_CANONICAL_HOST]) -AC_LANG_SAVE -AC_LANG_C -acx_pthread_ok=no - -# We used to check for pthread.h first, but this fails if pthread.h -# requires special compiler flags (e.g. on True64 or Sequent). -# It gets checked for in the link test anyway. - -# First of all, check if the user has set any of the PTHREAD_LIBS, -# etcetera environment variables, and if threads linking works using -# them: -if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then - save_CFLAGS="$CFLAGS" - CFLAGS="$CFLAGS $PTHREAD_CFLAGS" - save_LIBS="$LIBS" - LIBS="$PTHREAD_LIBS $LIBS" - AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS]) - AC_TRY_LINK_FUNC(pthread_join, acx_pthread_ok=yes) - AC_MSG_RESULT($acx_pthread_ok) - if test x"$acx_pthread_ok" = xno; then - PTHREAD_LIBS="" - PTHREAD_CFLAGS="" - fi - LIBS="$save_LIBS" - CFLAGS="$save_CFLAGS" -fi - -# We must check for the threads library under a number of different -# names; the ordering is very important because some systems -# (e.g. DEC) have both -lpthread and -lpthreads, where one of the -# libraries is broken (non-POSIX). - -# Create a list of thread flags to try. Items starting with a "-" are -# C compiler flags, and other items are library names, except for "none" -# which indicates that we try without any flags at all, and "pthread-config" -# which is a program returning the flags for the Pth emulation library. - -acx_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config" - -# The ordering *is* (sometimes) important. Some notes on the -# individual items follow: - -# pthreads: AIX (must check this before -lpthread) -# none: in case threads are in libc; should be tried before -Kthread and -# other compiler flags to prevent continual compiler warnings -# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h) -# -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able) -# lthread: LinuxThreads port on FreeBSD (also preferred to -pthread) -# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads) -# -pthreads: Solaris/gcc -# -mthreads: Mingw32/gcc, Lynx/gcc -# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it -# doesn't hurt to check since this sometimes defines pthreads too; -# also defines -D_REENTRANT) -# ... -mt is also the pthreads flag for HP/aCC -# pthread: Linux, etcetera -# --thread-safe: KAI C++ -# pthread-config: use pthread-config program (for GNU Pth library) - -case "${host_cpu}-${host_os}" in - *solaris*) - - # On Solaris (at least, for some versions), libc contains stubbed - # (non-functional) versions of the pthreads routines, so link-based - # tests will erroneously succeed. (We need to link with -pthreads/-mt/ - # -lpthread.) (The stubs are missing pthread_cleanup_push, or rather - # a function called by this macro, so we could check for that, but - # who knows whether they'll stub that too in a future libc.) So, - # we'll just look for -pthreads and -lpthread first: - - acx_pthread_flags="-pthreads pthread -mt -pthread $acx_pthread_flags" - ;; -esac - -if test x"$acx_pthread_ok" = xno; then -for flag in $acx_pthread_flags; do - - case $flag in - none) - AC_MSG_CHECKING([whether pthreads work without any flags]) - ;; - - -*) - AC_MSG_CHECKING([whether pthreads work with $flag]) - PTHREAD_CFLAGS="$flag" - ;; - - pthread-config) - AC_CHECK_PROG(acx_pthread_config, pthread-config, yes, no) - if test x"$acx_pthread_config" = xno; then continue; fi - PTHREAD_CFLAGS="`pthread-config --cflags`" - PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`" - ;; - - *) - AC_MSG_CHECKING([for the pthreads library -l$flag]) - PTHREAD_LIBS="-l$flag" - ;; - esac - - save_LIBS="$LIBS" - save_CFLAGS="$CFLAGS" - LIBS="$PTHREAD_LIBS $LIBS" - CFLAGS="$CFLAGS $PTHREAD_CFLAGS" - - # Check for various functions. We must include pthread.h, - # since some functions may be macros. (On the Sequent, we - # need a special flag -Kthread to make this header compile.) - # We check for pthread_join because it is in -lpthread on IRIX - # while pthread_create is in libc. We check for pthread_attr_init - # due to DEC craziness with -lpthreads. We check for - # pthread_cleanup_push because it is one of the few pthread - # functions on Solaris that doesn't have a non-functional libc stub. - # We try pthread_create on general principles. - AC_TRY_LINK([#include <pthread.h>], - [pthread_t th; pthread_join(th, 0); - pthread_attr_init(0); pthread_cleanup_push(0, 0); - pthread_create(0,0,0,0); pthread_cleanup_pop(0); ], - [acx_pthread_ok=yes]) - - LIBS="$save_LIBS" - CFLAGS="$save_CFLAGS" - - AC_MSG_RESULT($acx_pthread_ok) - if test "x$acx_pthread_ok" = xyes; then - break; - fi - - PTHREAD_LIBS="" - PTHREAD_CFLAGS="" -done -fi - -# Various other checks: -if test "x$acx_pthread_ok" = xyes; then - save_LIBS="$LIBS" - LIBS="$PTHREAD_LIBS $LIBS" - save_CFLAGS="$CFLAGS" - CFLAGS="$CFLAGS $PTHREAD_CFLAGS" - - # Detect AIX lossage: JOINABLE attribute is called UNDETACHED. - AC_MSG_CHECKING([for joinable pthread attribute]) - attr_name=unknown - for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do - AC_TRY_LINK([#include <pthread.h>], [int attr=$attr; return attr;], - [attr_name=$attr; break]) - done - AC_MSG_RESULT($attr_name) - if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then - AC_DEFINE_UNQUOTED(PTHREAD_CREATE_JOINABLE, $attr_name, - [Define to necessary symbol if this constant - uses a non-standard name on your system.]) - fi - - AC_MSG_CHECKING([if more special flags are required for pthreads]) - flag=no - case "${host_cpu}-${host_os}" in - *-aix* | *-freebsd* | *-darwin*) flag="-D_THREAD_SAFE";; - *solaris* | *-osf* | *-hpux*) flag="-D_REENTRANT";; - esac - AC_MSG_RESULT(${flag}) - if test "x$flag" != xno; then - PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS" - fi - - LIBS="$save_LIBS" - CFLAGS="$save_CFLAGS" - - # More AIX lossage: must compile with xlc_r or cc_r - if test x"$GCC" != xyes; then - AC_CHECK_PROGS(PTHREAD_CC, xlc_r cc_r, ${CC}) - else - PTHREAD_CC=$CC - fi -else - PTHREAD_CC="$CC" -fi - -AC_SUBST(PTHREAD_LIBS) -AC_SUBST(PTHREAD_CFLAGS) -AC_SUBST(PTHREAD_CC) - -# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND: -if test x"$acx_pthread_ok" = xyes; then - ifelse([$1],,AC_DEFINE(HAVE_PTHREAD,1,[Define if you have POSIX threads libraries and header files.]),[$1]) - : -else - acx_pthread_ok=no - $2 -fi -AC_LANG_RESTORE -])dnl ACX_PTHREAD diff --git a/autoconf/ax_pthread.m4 b/autoconf/ax_pthread.m4 new file mode 100644 index 000000000..4c4051ea3 --- /dev/null +++ b/autoconf/ax_pthread.m4 @@ -0,0 +1,485 @@ +# =========================================================================== +# http://www.gnu.org/software/autoconf-archive/ax_pthread.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]]) +# +# DESCRIPTION +# +# This macro figures out how to build C programs using POSIX threads. It +# sets the PTHREAD_LIBS output variable to the threads library and linker +# flags, and the PTHREAD_CFLAGS output variable to any special C compiler +# flags that are needed. (The user can also force certain compiler +# flags/libs to be tested by setting these environment variables.) +# +# Also sets PTHREAD_CC to any special C compiler that is needed for +# multi-threaded programs (defaults to the value of CC otherwise). (This +# is necessary on AIX to use the special cc_r compiler alias.) +# +# NOTE: You are assumed to not only compile your program with these flags, +# but also to link with them as well. For example, you might link with +# $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS $LIBS +# +# If you are only building threaded programs, you may wish to use these +# variables in your default LIBS, CFLAGS, and CC: +# +# LIBS="$PTHREAD_LIBS $LIBS" +# CFLAGS="$CFLAGS $PTHREAD_CFLAGS" +# CC="$PTHREAD_CC" +# +# In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute constant +# has a nonstandard name, this macro defines PTHREAD_CREATE_JOINABLE to +# that name (e.g. PTHREAD_CREATE_UNDETACHED on AIX). +# +# Also HAVE_PTHREAD_PRIO_INHERIT is defined if pthread is found and the +# PTHREAD_PRIO_INHERIT symbol is defined when compiling with +# PTHREAD_CFLAGS. +# +# ACTION-IF-FOUND is a list of shell commands to run if a threads library +# is found, and ACTION-IF-NOT-FOUND is a list of commands to run it if it +# is not found. If ACTION-IF-FOUND is not specified, the default action +# will define HAVE_PTHREAD. +# +# Please let the authors know if this macro fails on any platform, or if +# you have any other suggestions or comments. This macro was based on work +# by SGJ on autoconf scripts for FFTW (http://www.fftw.org/) (with help +# from M. Frigo), as well as ac_pthread and hb_pthread macros posted by +# Alejandro Forero Cuervo to the autoconf macro repository. We are also +# grateful for the helpful feedback of numerous users. +# +# Updated for Autoconf 2.68 by Daniel Richard G. +# +# LICENSE +# +# Copyright (c) 2008 Steven G. Johnson <stevenj@alum.mit.edu> +# Copyright (c) 2011 Daniel Richard G. <skunk@iSKUNK.ORG> +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation, either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program. If not, see <http://www.gnu.org/licenses/>. +# +# As a special exception, the respective Autoconf Macro's copyright owner +# gives unlimited permission to copy, distribute and modify the configure +# scripts that are the output of Autoconf when processing the Macro. You +# need not follow the terms of the GNU General Public License when using +# or distributing such scripts, even though portions of the text of the +# Macro appear in them. The GNU General Public License (GPL) does govern +# all other use of the material that constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the Autoconf +# Macro released by the Autoconf Archive. When you make and distribute a +# modified version of the Autoconf Macro, you may extend this special +# exception to the GPL to apply to your modified version as well. + +#serial 23 + +AU_ALIAS([ACX_PTHREAD], [AX_PTHREAD]) +AC_DEFUN([AX_PTHREAD], [ +AC_REQUIRE([AC_CANONICAL_HOST]) +AC_REQUIRE([AC_PROG_CC]) +AC_REQUIRE([AC_PROG_SED]) +AC_LANG_PUSH([C]) +ax_pthread_ok=no + +# We used to check for pthread.h first, but this fails if pthread.h +# requires special compiler flags (e.g. on Tru64 or Sequent). +# It gets checked for in the link test anyway. + +# First of all, check if the user has set any of the PTHREAD_LIBS, +# etcetera environment variables, and if threads linking works using +# them: +if test "x$PTHREAD_CFLAGS$PTHREAD_LIBS" != "x"; then + ax_pthread_save_CC="$CC" + ax_pthread_save_CFLAGS="$CFLAGS" + ax_pthread_save_LIBS="$LIBS" + AS_IF([test "x$PTHREAD_CC" != "x"], [CC="$PTHREAD_CC"]) + CFLAGS="$CFLAGS $PTHREAD_CFLAGS" + LIBS="$PTHREAD_LIBS $LIBS" + AC_MSG_CHECKING([for pthread_join using $CC $PTHREAD_CFLAGS $PTHREAD_LIBS]) + AC_LINK_IFELSE([AC_LANG_CALL([], [pthread_join])], [ax_pthread_ok=yes]) + AC_MSG_RESULT([$ax_pthread_ok]) + if test "x$ax_pthread_ok" = "xno"; then + PTHREAD_LIBS="" + PTHREAD_CFLAGS="" + fi + CC="$ax_pthread_save_CC" + CFLAGS="$ax_pthread_save_CFLAGS" + LIBS="$ax_pthread_save_LIBS" +fi + +# We must check for the threads library under a number of different +# names; the ordering is very important because some systems +# (e.g. DEC) have both -lpthread and -lpthreads, where one of the +# libraries is broken (non-POSIX). + +# Create a list of thread flags to try. Items starting with a "-" are +# C compiler flags, and other items are library names, except for "none" +# which indicates that we try without any flags at all, and "pthread-config" +# which is a program returning the flags for the Pth emulation library. + +ax_pthread_flags="pthreads none -Kthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config" + +# The ordering *is* (sometimes) important. Some notes on the +# individual items follow: + +# pthreads: AIX (must check this before -lpthread) +# none: in case threads are in libc; should be tried before -Kthread and +# other compiler flags to prevent continual compiler warnings +# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h) +# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads), Tru64 +# (Note: HP C rejects this with "bad form for `-t' option") +# -pthreads: Solaris/gcc (Note: HP C also rejects) +# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it +# doesn't hurt to check since this sometimes defines pthreads and +# -D_REENTRANT too), HP C (must be checked before -lpthread, which +# is present but should not be used directly; and before -mthreads, +# because the compiler interprets this as "-mt" + "-hreads") +# -mthreads: Mingw32/gcc, Lynx/gcc +# pthread: Linux, etcetera +# --thread-safe: KAI C++ +# pthread-config: use pthread-config program (for GNU Pth library) + +case $host_os in + + freebsd*) + + # -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able) + # lthread: LinuxThreads port on FreeBSD (also preferred to -pthread) + + ax_pthread_flags="-kthread lthread $ax_pthread_flags" + ;; + + hpux*) + + # From the cc(1) man page: "[-mt] Sets various -D flags to enable + # multi-threading and also sets -lpthread." + + ax_pthread_flags="-mt -pthread pthread $ax_pthread_flags" + ;; + + openedition*) + + # IBM z/OS requires a feature-test macro to be defined in order to + # enable POSIX threads at all, so give the user a hint if this is + # not set. (We don't define these ourselves, as they can affect + # other portions of the system API in unpredictable ways.) + + AC_EGREP_CPP([AX_PTHREAD_ZOS_MISSING], + [ +# if !defined(_OPEN_THREADS) && !defined(_UNIX03_THREADS) + AX_PTHREAD_ZOS_MISSING +# endif + ], + [AC_MSG_WARN([IBM z/OS requires -D_OPEN_THREADS or -D_UNIX03_THREADS to enable pthreads support.])]) + ;; + + solaris*) + + # On Solaris (at least, for some versions), libc contains stubbed + # (non-functional) versions of the pthreads routines, so link-based + # tests will erroneously succeed. (N.B.: The stubs are missing + # pthread_cleanup_push, or rather a function called by this macro, + # so we could check for that, but who knows whether they'll stub + # that too in a future libc.) So we'll check first for the + # standard Solaris way of linking pthreads (-mt -lpthread). + + ax_pthread_flags="-mt,pthread pthread $ax_pthread_flags" + ;; +esac + +# GCC generally uses -pthread, or -pthreads on some platforms (e.g. SPARC) + +AS_IF([test "x$GCC" = "xyes"], + [ax_pthread_flags="-pthread -pthreads $ax_pthread_flags"]) + +# The presence of a feature test macro requesting re-entrant function +# definitions is, on some systems, a strong hint that pthreads support is +# correctly enabled + +case $host_os in + darwin* | hpux* | linux* | osf* | solaris*) + ax_pthread_check_macro="_REENTRANT" + ;; + + aix*) + ax_pthread_check_macro="_THREAD_SAFE" + ;; + + *) + ax_pthread_check_macro="--" + ;; +esac +AS_IF([test "x$ax_pthread_check_macro" = "x--"], + [ax_pthread_check_cond=0], + [ax_pthread_check_cond="!defined($ax_pthread_check_macro)"]) + +# Are we compiling with Clang? + +AC_CACHE_CHECK([whether $CC is Clang], + [ax_cv_PTHREAD_CLANG], + [ax_cv_PTHREAD_CLANG=no + # Note that Autoconf sets GCC=yes for Clang as well as GCC + if test "x$GCC" = "xyes"; then + AC_EGREP_CPP([AX_PTHREAD_CC_IS_CLANG], + [/* Note: Clang 2.7 lacks __clang_[a-z]+__ */ +# if defined(__clang__) && defined(__llvm__) + AX_PTHREAD_CC_IS_CLANG +# endif + ], + [ax_cv_PTHREAD_CLANG=yes]) + fi + ]) +ax_pthread_clang="$ax_cv_PTHREAD_CLANG" + +ax_pthread_clang_warning=no + +# Clang needs special handling, because older versions handle the -pthread +# option in a rather... idiosyncratic way + +if test "x$ax_pthread_clang" = "xyes"; then + + # Clang takes -pthread; it has never supported any other flag + + # (Note 1: This will need to be revisited if a system that Clang + # supports has POSIX threads in a separate library. This tends not + # to be the way of modern systems, but it's conceivable.) + + # (Note 2: On some systems, notably Darwin, -pthread is not needed + # to get POSIX threads support; the API is always present and + # active. We could reasonably leave PTHREAD_CFLAGS empty. But + # -pthread does define _REENTRANT, and while the Darwin headers + # ignore this macro, third-party headers might not.) + + PTHREAD_CFLAGS="-pthread" + PTHREAD_LIBS= + + ax_pthread_ok=yes + + # However, older versions of Clang make a point of warning the user + # that, in an invocation where only linking and no compilation is + # taking place, the -pthread option has no effect ("argument unused + # during compilation"). They expect -pthread to be passed in only + # when source code is being compiled. + # + # Problem is, this is at odds with the way Automake and most other + # C build frameworks function, which is that the same flags used in + # compilation (CFLAGS) are also used in linking. Many systems + # supported by AX_PTHREAD require exactly this for POSIX threads + # support, and in fact it is often not straightforward to specify a + # flag that is used only in the compilation phase and not in + # linking. Such a scenario is extremely rare in practice. + # + # Even though use of the -pthread flag in linking would only print + # a warning, this can be a nuisance for well-run software projects + # that build with -Werror. So if the active version of Clang has + # this misfeature, we search for an option to squash it. + + AC_CACHE_CHECK([whether Clang needs flag to prevent "argument unused" warning when linking with -pthread], + [ax_cv_PTHREAD_CLANG_NO_WARN_FLAG], + [ax_cv_PTHREAD_CLANG_NO_WARN_FLAG=unknown + # Create an alternate version of $ac_link that compiles and + # links in two steps (.c -> .o, .o -> exe) instead of one + # (.c -> exe), because the warning occurs only in the second + # step + ax_pthread_save_ac_link="$ac_link" + ax_pthread_sed='s/conftest\.\$ac_ext/conftest.$ac_objext/g' + ax_pthread_link_step=`$as_echo "$ac_link" | sed "$ax_pthread_sed"` + ax_pthread_2step_ac_link="($ac_compile) && (echo ==== >&5) && ($ax_pthread_link_step)" + ax_pthread_save_CFLAGS="$CFLAGS" + for ax_pthread_try in '' -Qunused-arguments -Wno-unused-command-line-argument unknown; do + AS_IF([test "x$ax_pthread_try" = "xunknown"], [break]) + CFLAGS="-Werror -Wunknown-warning-option $ax_pthread_try -pthread $ax_pthread_save_CFLAGS" + ac_link="$ax_pthread_save_ac_link" + AC_LINK_IFELSE([AC_LANG_SOURCE([[int main(void){return 0;}]])], + [ac_link="$ax_pthread_2step_ac_link" + AC_LINK_IFELSE([AC_LANG_SOURCE([[int main(void){return 0;}]])], + [break]) + ]) + done + ac_link="$ax_pthread_save_ac_link" + CFLAGS="$ax_pthread_save_CFLAGS" + AS_IF([test "x$ax_pthread_try" = "x"], [ax_pthread_try=no]) + ax_cv_PTHREAD_CLANG_NO_WARN_FLAG="$ax_pthread_try" + ]) + + case "$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG" in + no | unknown) ;; + *) PTHREAD_CFLAGS="$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG $PTHREAD_CFLAGS" ;; + esac + +fi # $ax_pthread_clang = yes + +if test "x$ax_pthread_ok" = "xno"; then +for ax_pthread_try_flag in $ax_pthread_flags; do + + case $ax_pthread_try_flag in + none) + AC_MSG_CHECKING([whether pthreads work without any flags]) + ;; + + -mt,pthread) + AC_MSG_CHECKING([whether pthreads work with -mt -lpthread]) + PTHREAD_CFLAGS="-mt" + PTHREAD_LIBS="-lpthread" + ;; + + -*) + AC_MSG_CHECKING([whether pthreads work with $ax_pthread_try_flag]) + PTHREAD_CFLAGS="$ax_pthread_try_flag" + ;; + + pthread-config) + AC_CHECK_PROG([ax_pthread_config], [pthread-config], [yes], [no]) + AS_IF([test "x$ax_pthread_config" = "xno"], [continue]) + PTHREAD_CFLAGS="`pthread-config --cflags`" + PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`" + ;; + + *) + AC_MSG_CHECKING([for the pthreads library -l$ax_pthread_try_flag]) + PTHREAD_LIBS="-l$ax_pthread_try_flag" + ;; + esac + + ax_pthread_save_CFLAGS="$CFLAGS" + ax_pthread_save_LIBS="$LIBS" + CFLAGS="$CFLAGS $PTHREAD_CFLAGS" + LIBS="$PTHREAD_LIBS $LIBS" + + # Check for various functions. We must include pthread.h, + # since some functions may be macros. (On the Sequent, we + # need a special flag -Kthread to make this header compile.) + # We check for pthread_join because it is in -lpthread on IRIX + # while pthread_create is in libc. We check for pthread_attr_init + # due to DEC craziness with -lpthreads. We check for + # pthread_cleanup_push because it is one of the few pthread + # functions on Solaris that doesn't have a non-functional libc stub. + # We try pthread_create on general principles. + + AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <pthread.h> +# if $ax_pthread_check_cond +# error "$ax_pthread_check_macro must be defined" +# endif + static void routine(void *a) { a = 0; } + static void *start_routine(void *a) { return a; }], + [pthread_t th; pthread_attr_t attr; + pthread_create(&th, 0, start_routine, 0); + pthread_join(th, 0); + pthread_attr_init(&attr); + pthread_cleanup_push(routine, 0); + pthread_cleanup_pop(0) /* ; */])], + [ax_pthread_ok=yes], + []) + + CFLAGS="$ax_pthread_save_CFLAGS" + LIBS="$ax_pthread_save_LIBS" + + AC_MSG_RESULT([$ax_pthread_ok]) + AS_IF([test "x$ax_pthread_ok" = "xyes"], [break]) + + PTHREAD_LIBS="" + PTHREAD_CFLAGS="" +done +fi + +# Various other checks: +if test "x$ax_pthread_ok" = "xyes"; then + ax_pthread_save_CFLAGS="$CFLAGS" + ax_pthread_save_LIBS="$LIBS" + CFLAGS="$CFLAGS $PTHREAD_CFLAGS" + LIBS="$PTHREAD_LIBS $LIBS" + + # Detect AIX lossage: JOINABLE attribute is called UNDETACHED. + AC_CACHE_CHECK([for joinable pthread attribute], + [ax_cv_PTHREAD_JOINABLE_ATTR], + [ax_cv_PTHREAD_JOINABLE_ATTR=unknown + for ax_pthread_attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do + AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <pthread.h>], + [int attr = $ax_pthread_attr; return attr /* ; */])], + [ax_cv_PTHREAD_JOINABLE_ATTR=$ax_pthread_attr; break], + []) + done + ]) + AS_IF([test "x$ax_cv_PTHREAD_JOINABLE_ATTR" != "xunknown" && \ + test "x$ax_cv_PTHREAD_JOINABLE_ATTR" != "xPTHREAD_CREATE_JOINABLE" && \ + test "x$ax_pthread_joinable_attr_defined" != "xyes"], + [AC_DEFINE_UNQUOTED([PTHREAD_CREATE_JOINABLE], + [$ax_cv_PTHREAD_JOINABLE_ATTR], + [Define to necessary symbol if this constant + uses a non-standard name on your system.]) + ax_pthread_joinable_attr_defined=yes + ]) + + AC_CACHE_CHECK([whether more special flags are required for pthreads], + [ax_cv_PTHREAD_SPECIAL_FLAGS], + [ax_cv_PTHREAD_SPECIAL_FLAGS=no + case $host_os in + solaris*) + ax_cv_PTHREAD_SPECIAL_FLAGS="-D_POSIX_PTHREAD_SEMANTICS" + ;; + esac + ]) + AS_IF([test "x$ax_cv_PTHREAD_SPECIAL_FLAGS" != "xno" && \ + test "x$ax_pthread_special_flags_added" != "xyes"], + [PTHREAD_CFLAGS="$ax_cv_PTHREAD_SPECIAL_FLAGS $PTHREAD_CFLAGS" + ax_pthread_special_flags_added=yes]) + + AC_CACHE_CHECK([for PTHREAD_PRIO_INHERIT], + [ax_cv_PTHREAD_PRIO_INHERIT], + [AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <pthread.h>]], + [[int i = PTHREAD_PRIO_INHERIT;]])], + [ax_cv_PTHREAD_PRIO_INHERIT=yes], + [ax_cv_PTHREAD_PRIO_INHERIT=no]) + ]) + AS_IF([test "x$ax_cv_PTHREAD_PRIO_INHERIT" = "xyes" && \ + test "x$ax_pthread_prio_inherit_defined" != "xyes"], + [AC_DEFINE([HAVE_PTHREAD_PRIO_INHERIT], [1], [Have PTHREAD_PRIO_INHERIT.]) + ax_pthread_prio_inherit_defined=yes + ]) + + CFLAGS="$ax_pthread_save_CFLAGS" + LIBS="$ax_pthread_save_LIBS" + + # More AIX lossage: compile with *_r variant + if test "x$GCC" != "xyes"; then + case $host_os in + aix*) + AS_CASE(["x/$CC"], + [x*/c89|x*/c89_128|x*/c99|x*/c99_128|x*/cc|x*/cc128|x*/xlc|x*/xlc_v6|x*/xlc128|x*/xlc128_v6], + [#handle absolute path differently from PATH based program lookup + AS_CASE(["x$CC"], + [x/*], + [AS_IF([AS_EXECUTABLE_P([${CC}_r])],[PTHREAD_CC="${CC}_r"])], + [AC_CHECK_PROGS([PTHREAD_CC],[${CC}_r],[$CC])])]) + ;; + esac + fi +fi + +test -n "$PTHREAD_CC" || PTHREAD_CC="$CC" + +AC_SUBST([PTHREAD_LIBS]) +AC_SUBST([PTHREAD_CFLAGS]) +AC_SUBST([PTHREAD_CC]) + +# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND: +if test "x$ax_pthread_ok" = "xyes"; then + ifelse([$1],,[AC_DEFINE([HAVE_PTHREAD],[1],[Define if you have POSIX threads libraries and header files.])],[$1]) + : +else + ax_pthread_ok=no + $2 +fi +AC_LANG_POP +])dnl AX_PTHREAD diff --git a/channels/chan_dahdi.c b/channels/chan_dahdi.c index e4b7c0ee8..7a3c31fd5 100644 --- a/channels/chan_dahdi.c +++ b/channels/chan_dahdi.c @@ -1693,26 +1693,28 @@ static void my_handle_dtmf(void *pvt, struct ast_channel *ast, enum analog_sub a if (strcmp(ast_channel_exten(ast), "fax")) { const char *target_context = S_OR(ast_channel_macrocontext(ast), ast_channel_context(ast)); - /* We need to unlock 'ast' here because ast_exists_extension has the + /* + * We need to unlock 'ast' here because ast_exists_extension has the * potential to start autoservice on the channel. Such action is prone - * to deadlock. + * to deadlock if the channel is locked. + * + * ast_async_goto() has its own restriction on not holding the + * channel lock. */ ast_mutex_unlock(&p->lock); ast_channel_unlock(ast); if (ast_exists_extension(ast, target_context, "fax", 1, S_COR(ast_channel_caller(ast)->id.number.valid, ast_channel_caller(ast)->id.number.str, NULL))) { - ast_channel_lock(ast); - ast_mutex_lock(&p->lock); ast_verb(3, "Redirecting %s to fax extension\n", ast_channel_name(ast)); /* Save the DID/DNIS when we transfer the fax call to a "fax" extension */ pbx_builtin_setvar_helper(ast, "FAXEXTEN", ast_channel_exten(ast)); if (ast_async_goto(ast, target_context, "fax", 1)) ast_log(LOG_WARNING, "Failed to async goto '%s' into fax of '%s'\n", ast_channel_name(ast), target_context); } else { - ast_channel_lock(ast); - ast_mutex_lock(&p->lock); ast_log(LOG_NOTICE, "Fax detected, but no fax extension\n"); } + ast_channel_lock(ast); + ast_mutex_lock(&p->lock); } else { ast_debug(1, "Already in a fax extension, not redirecting\n"); } @@ -2345,7 +2347,6 @@ static void my_pri_ss7_open_media(void *p) if (pvt->dsp_features && pvt->dsp) { ast_dsp_set_features(pvt->dsp, pvt->dsp_features); - pvt->dsp_features = 0; } } #endif /* defined(HAVE_PRI) || defined(HAVE_SS7) */ @@ -7200,26 +7201,28 @@ static void dahdi_handle_dtmf(struct ast_channel *ast, int idx, struct ast_frame if (strcmp(ast_channel_exten(ast), "fax")) { const char *target_context = S_OR(ast_channel_macrocontext(ast), ast_channel_context(ast)); - /* We need to unlock 'ast' here because ast_exists_extension has the + /* + * We need to unlock 'ast' here because ast_exists_extension has the * potential to start autoservice on the channel. Such action is prone - * to deadlock. + * to deadlock if the channel is locked. + * + * ast_async_goto() has its own restriction on not holding the + * channel lock. */ ast_mutex_unlock(&p->lock); ast_channel_unlock(ast); if (ast_exists_extension(ast, target_context, "fax", 1, S_COR(ast_channel_caller(ast)->id.number.valid, ast_channel_caller(ast)->id.number.str, NULL))) { - ast_channel_lock(ast); - ast_mutex_lock(&p->lock); ast_verb(3, "Redirecting %s to fax extension\n", ast_channel_name(ast)); /* Save the DID/DNIS when we transfer the fax call to a "fax" extension */ pbx_builtin_setvar_helper(ast, "FAXEXTEN", ast_channel_exten(ast)); if (ast_async_goto(ast, target_context, "fax", 1)) ast_log(LOG_WARNING, "Failed to async goto '%s' into fax of '%s'\n", ast_channel_name(ast), target_context); } else { - ast_channel_lock(ast); - ast_mutex_lock(&p->lock); ast_log(LOG_NOTICE, "Fax detected, but no fax extension\n"); } + ast_channel_lock(ast); + ast_mutex_lock(&p->lock); } else { ast_debug(1, "Already in a fax extension, not redirecting\n"); } @@ -8640,6 +8643,15 @@ static struct ast_frame *dahdi_read(struct ast_channel *ast) /* Perform busy detection etc on the dahdi line */ int mute; + if ((p->dsp_features & DSP_FEATURE_FAX_DETECT) + && p->faxdetect_timeout + && p->faxdetect_timeout <= ast_channel_get_up_time(ast)) { + p->dsp_features &= ~DSP_FEATURE_FAX_DETECT; + ast_dsp_set_features(p->dsp, p->dsp_features); + ast_debug(1, "Channel driver fax CNG detection timeout on %s\n", + ast_channel_name(ast)); + } + f = ast_dsp_process(ast, p->dsp, &p->subs[idx].f); /* Check if DSP code thinks we should be muting this frame and mute the conference if so */ @@ -12539,6 +12551,7 @@ static struct dahdi_pvt *mkintf(int channel, const struct dahdi_chan_conf *conf, tmp->callprogress = conf->chan.callprogress; tmp->waitfordialtone = conf->chan.waitfordialtone; tmp->dialtone_detect = conf->chan.dialtone_detect; + tmp->faxdetect_timeout = conf->chan.faxdetect_timeout; tmp->cancallforward = conf->chan.cancallforward; tmp->dtmfrelax = conf->chan.dtmfrelax; tmp->callwaiting = tmp->permcallwaiting; @@ -17790,6 +17803,10 @@ static int process_dahdi(struct dahdi_chan_conf *confp, const char *cat, struct confp->chan.callprogress |= CALLPROGRESS_FAX_OUTGOING; } else if (!strcasecmp(v->value, "both") || ast_true(v->value)) confp->chan.callprogress |= CALLPROGRESS_FAX_INCOMING | CALLPROGRESS_FAX_OUTGOING; + } else if (!strcasecmp(v->name, "faxdetect_timeout")) { + if (sscanf(v->value, "%30u", &confp->chan.faxdetect_timeout) != 1) { + confp->chan.faxdetect_timeout = 0; + } } else if (!strcasecmp(v->name, "echocancel")) { process_echocancel(confp, v->value, v->lineno); } else if (!strcasecmp(v->name, "echotraining")) { diff --git a/channels/chan_dahdi.h b/channels/chan_dahdi.h index 4bb5d19a2..ab5c1eba9 100644 --- a/channels/chan_dahdi.h +++ b/channels/chan_dahdi.h @@ -612,6 +612,11 @@ struct dahdi_pvt { */ int dialtone_detect; int dialtone_scanning_time_elapsed; /*!< Amount of audio scanned for dialtone, in frames */ + /*! + * \brief The number of seconds into call to disable fax detection. (0 = disabled) + * \note Set from the "faxdetect_timeout" value read in from chan_dahdi.conf + */ + unsigned int faxdetect_timeout; struct timeval waitingfordt; /*!< Time we started waiting for dialtone */ struct timeval flashtime; /*!< Last flash-hook time */ /*! \brief Opaque DSP configuration structure. */ diff --git a/channels/chan_pjsip.c b/channels/chan_pjsip.c index 5ad117404..2e87393a6 100644 --- a/channels/chan_pjsip.c +++ b/channels/chan_pjsip.c @@ -612,10 +612,12 @@ static struct ast_frame *chan_pjsip_cng_tone_detected(struct ast_sip_session *se { const char *target_context; int exists; + int dsp_features; - /* If we only needed this DSP for fax detection purposes we can just drop it now */ - if (session->endpoint->dtmf == AST_SIP_DTMF_INBAND || session->endpoint->dtmf == AST_SIP_DTMF_AUTO) { - ast_dsp_set_features(session->dsp, DSP_FEATURE_DIGIT_DETECT); + dsp_features = ast_dsp_get_features(session->dsp); + dsp_features &= ~DSP_FEATURE_FAX_DETECT; + if (dsp_features) { + ast_dsp_set_features(session->dsp, dsp_features); } else { ast_dsp_free(session->dsp); session->dsp = NULL; @@ -628,16 +630,19 @@ static struct ast_frame *chan_pjsip_cng_tone_detected(struct ast_sip_session *se target_context = S_OR(ast_channel_macrocontext(session->channel), ast_channel_context(session->channel)); - /* We need to unlock the channel here because ast_exists_extension has the + /* + * We need to unlock the channel here because ast_exists_extension has the * potential to start and stop an autoservice on the channel. Such action * is prone to deadlock if the channel is locked. + * + * ast_async_goto() has its own restriction on not holding the channel lock. */ ast_channel_unlock(session->channel); + ast_frfree(f); + f = &ast_null_frame; exists = ast_exists_extension(session->channel, target_context, "fax", 1, S_COR(ast_channel_caller(session->channel)->id.number.valid, ast_channel_caller(session->channel)->id.number.str, NULL)); - ast_channel_lock(session->channel); - if (exists) { ast_verb(2, "Redirecting '%s' to fax extension due to CNG detection\n", ast_channel_name(session->channel)); @@ -646,12 +651,11 @@ static struct ast_frame *chan_pjsip_cng_tone_detected(struct ast_sip_session *se ast_log(LOG_ERROR, "Failed to async goto '%s' into fax extension in '%s'\n", ast_channel_name(session->channel), target_context); } - ast_frfree(f); - f = &ast_null_frame; } else { ast_log(LOG_NOTICE, "FAX CNG detected on '%s' but no fax extension in '%s'\n", ast_channel_name(session->channel), target_context); } + ast_channel_lock(session->channel); return f; } @@ -660,6 +664,7 @@ static struct ast_frame *chan_pjsip_cng_tone_detected(struct ast_sip_session *se static struct ast_frame *chan_pjsip_read(struct ast_channel *ast) { struct ast_sip_channel_pvt *channel = ast_channel_tech_pvt(ast); + struct ast_sip_session *session; struct chan_pjsip_pvt *pvt = channel->pvt; struct ast_frame *f; struct ast_sip_session_media *media = NULL; @@ -697,22 +702,42 @@ static struct ast_frame *chan_pjsip_read(struct ast_channel *ast) return f; } - if (ast_format_cap_iscompatible_format(channel->session->endpoint->media.codecs, f->subclass.format) == AST_FORMAT_CMP_NOT_EQUAL) { + session = channel->session; + + if (ast_format_cap_iscompatible_format(session->endpoint->media.codecs, f->subclass.format) == AST_FORMAT_CMP_NOT_EQUAL) { ast_debug(1, "Oooh, got a frame with format of %s on channel '%s' when endpoint '%s' is not configured for it\n", ast_format_get_name(f->subclass.format), ast_channel_name(ast), - ast_sorcery_object_get_id(channel->session->endpoint)); + ast_sorcery_object_get_id(session->endpoint)); ast_frfree(f); return &ast_null_frame; } - if (channel->session->dsp) { - f = ast_dsp_process(ast, channel->session->dsp, f); + if (session->dsp) { + int dsp_features; + dsp_features = ast_dsp_get_features(session->dsp); + if ((dsp_features & DSP_FEATURE_FAX_DETECT) + && session->endpoint->faxdetect_timeout + && session->endpoint->faxdetect_timeout <= ast_channel_get_up_time(ast)) { + dsp_features &= ~DSP_FEATURE_FAX_DETECT; + if (dsp_features) { + ast_dsp_set_features(session->dsp, dsp_features); + } else { + ast_dsp_free(session->dsp); + session->dsp = NULL; + } + ast_debug(3, "Channel driver fax CNG detection timeout on %s\n", + ast_channel_name(ast)); + } + } + if (session->dsp) { + f = ast_dsp_process(ast, session->dsp, f); if (f && (f->frametype == AST_FRAME_DTMF)) { if (f->subclass.integer == 'f') { - ast_debug(3, "Fax CNG detected on %s\n", ast_channel_name(ast)); - f = chan_pjsip_cng_tone_detected(channel->session, f); + ast_debug(3, "Channel driver fax CNG detected on %s\n", + ast_channel_name(ast)); + f = chan_pjsip_cng_tone_detected(session, f); } else { ast_debug(3, "* Detected inband DTMF '%c' on '%s'\n", f->subclass.integer, ast_channel_name(ast)); diff --git a/channels/chan_sip.c b/channels/chan_sip.c index ca8c0fdf2..7a48cd8cd 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -8610,29 +8610,31 @@ static struct ast_frame *sip_read(struct ast_channel *ast) if (faxdetected && ast_test_flag(&p->flags[1], SIP_PAGE2_FAX_DETECT_CNG)) { if (strcmp(ast_channel_exten(ast), "fax")) { const char *target_context = S_OR(ast_channel_macrocontext(ast), ast_channel_context(ast)); - /* We need to unlock 'ast' here because + /* + * We need to unlock 'ast' here because * ast_exists_extension has the potential to start and * stop an autoservice on the channel. Such action is * prone to deadlock if the channel is locked. + * + * ast_async_goto() has its own restriction on not holding + * the channel lock. */ sip_pvt_unlock(p); ast_channel_unlock(ast); + ast_frfree(fr); + fr = &ast_null_frame; if (ast_exists_extension(ast, target_context, "fax", 1, S_COR(ast_channel_caller(ast)->id.number.valid, ast_channel_caller(ast)->id.number.str, NULL))) { - ast_channel_lock(ast); - sip_pvt_lock(p); ast_verb(2, "Redirecting '%s' to fax extension due to CNG detection\n", ast_channel_name(ast)); pbx_builtin_setvar_helper(ast, "FAXEXTEN", ast_channel_exten(ast)); if (ast_async_goto(ast, target_context, "fax", 1)) { ast_log(LOG_NOTICE, "Failed to async goto '%s' into fax of '%s'\n", ast_channel_name(ast), target_context); } - ast_frfree(fr); - fr = &ast_null_frame; } else { - ast_channel_lock(ast); - sip_pvt_lock(p); ast_log(LOG_NOTICE, "FAX CNG detected but no fax extension\n"); } + ast_channel_lock(ast); + sip_pvt_lock(p); } } @@ -17243,10 +17245,8 @@ static void mwi_event_cb(void *userdata, struct stasis_subscription *sub, struct struct sip_peer *peer = sip_find_peer(peer_name, NULL, TRUE, FINDALLDEVICES, FALSE, 0); if (stasis_subscription_final_message(sub, msg)) { - if (peer) { - /* configuration reloaded */ - return; - } + /* peer can be non-NULL during reload. */ + ao2_cleanup(peer); ast_free(peer_name); return; } diff --git a/channels/sip/config_parser.c b/channels/sip/config_parser.c index 56d04b260..036f7f7d2 100644 --- a/channels/sip/config_parser.c +++ b/channels/sip/config_parser.c @@ -274,6 +274,7 @@ int sip_parse_register_line(struct sip_registry *reg, int default_expiry, const return 0; } +#ifdef TEST_FRAMEWORK AST_TEST_DEFINE(sip_parse_register_line_test) { int res = AST_TEST_PASS; @@ -643,6 +644,7 @@ alloc_fail: ast_test_status_update(test, "Out of memory. \n"); return res; } +#endif int sip_parse_host(char *line, int lineno, char **hostname, int *portnum, enum ast_transport *transport) { @@ -708,6 +710,7 @@ int sip_parse_host(char *line, int lineno, char **hostname, int *portnum, enum a return 0; } +#ifdef TEST_FRAMEWORK AST_TEST_DEFINE(sip_parse_host_line_test) { int res = AST_TEST_PASS; @@ -787,6 +790,7 @@ AST_TEST_DEFINE(sip_parse_host_line_test) return res; } +#endif /*! \brief Parse the comma-separated nat= option values */ void sip_parse_nat_option(const char *value, struct ast_flags *mask, struct ast_flags *flags) @@ -834,6 +838,7 @@ void sip_parse_nat_option(const char *value, struct ast_flags *mask, struct ast_ } } +#ifdef TEST_FRAMEWORK #define TEST_FORCE_RPORT 1 << 0 #define TEST_COMEDIA 1 << 1 #define TEST_AUTO_FORCE_RPORT 1 << 2 @@ -904,6 +909,8 @@ AST_TEST_DEFINE(sip_parse_nat_test) return res; } +#endif + /*! \brief SIP test registration */ void sip_config_parser_register_tests(void) { diff --git a/channels/sip/reqresp_parser.c b/channels/sip/reqresp_parser.c index 298b8cb95..358d6e568 100644 --- a/channels/sip/reqresp_parser.c +++ b/channels/sip/reqresp_parser.c @@ -258,7 +258,7 @@ int parse_uri_full(char *uri, const char *scheme, char **user, char **pass, return error; } - +#ifdef TEST_FRAMEWORK AST_TEST_DEFINE(sip_parse_uri_full_test) { int res = AST_TEST_PASS; @@ -514,7 +514,7 @@ AST_TEST_DEFINE(sip_parse_uri_full_test) return res; } - +#endif int parse_uri(char *uri, const char *scheme, char **user, char **pass, char **hostport, char **transport) { @@ -530,6 +530,7 @@ int parse_uri(char *uri, const char *scheme, char **user, char **pass, return ret; } +#ifdef TEST_FRAMEWORK AST_TEST_DEFINE(sip_parse_uri_test) { int res = AST_TEST_PASS; @@ -687,6 +688,7 @@ AST_TEST_DEFINE(sip_parse_uri_test) return res; } +#endif /*! \brief Get caller id name from SIP headers, copy into output buffer * @@ -817,6 +819,7 @@ const char *get_calleridname(const char *input, char *output, size_t outputsize) return input; } +#ifdef TEST_FRAMEWORK AST_TEST_DEFINE(get_calleridname_test) { int res = AST_TEST_PASS; @@ -899,6 +902,7 @@ AST_TEST_DEFINE(get_calleridname_test) return res; } +#endif int get_name_and_number(const char *hdr, char **name, char **number) { @@ -940,6 +944,7 @@ int get_name_and_number(const char *hdr, char **name, char **number) return 0; } +#ifdef TEST_FRAMEWORK AST_TEST_DEFINE(get_name_and_number_test) { int res = AST_TEST_PASS; @@ -1044,6 +1049,7 @@ AST_TEST_DEFINE(get_name_and_number_test) return res; } +#endif int get_in_brackets_const(const char *src,const char **start,int *length) { @@ -1176,6 +1182,7 @@ char *get_in_brackets(char *tmp) return out; } +#ifdef TEST_FRAMEWORK AST_TEST_DEFINE(get_in_brackets_test) { int res = AST_TEST_PASS; @@ -1252,7 +1259,7 @@ AST_TEST_DEFINE(get_in_brackets_test) return res; } - +#endif int parse_name_andor_addr(char *uri, const char *scheme, char **name, char **user, char **pass, char **hostport, @@ -1298,6 +1305,7 @@ int parse_name_andor_addr(char *uri, const char *scheme, char **name, return parse_uri_full(uri, scheme, user, pass, hostport, params, headers, residue2); } +#ifdef TEST_FRAMEWORK AST_TEST_DEFINE(parse_name_andor_addr_test) { int res = AST_TEST_PASS; @@ -1427,6 +1435,7 @@ AST_TEST_DEFINE(parse_name_andor_addr_test) return res; } +#endif int get_comma(char *in, char **out) { @@ -1523,6 +1532,7 @@ int parse_contact_header(char *contactheader, struct contactliststruct *contactl return last; } +#ifdef TEST_FRAMEWORK AST_TEST_DEFINE(parse_contact_header_test) { int res = AST_TEST_PASS; @@ -1668,6 +1678,7 @@ AST_TEST_DEFINE(parse_contact_header_test) return res; } +#endif /*! * \brief Parse supported header in incoming packet @@ -1755,6 +1766,7 @@ unsigned int parse_sip_options(const char *options, char *unsupported, size_t un return profile; } +#ifdef TEST_FRAMEWORK AST_TEST_DEFINE(sip_parse_options_test) { int res = AST_TEST_PASS; @@ -1892,6 +1904,7 @@ AST_TEST_DEFINE(sip_parse_options_test) return res; } +#endif /*! \brief helper routine for sip_uri_cmp to compare URI parameters * @@ -2246,6 +2259,7 @@ int sip_uri_cmp(const char *input1, const char *input2) #define URI_CMP_MATCH 0 #define URI_CMP_NOMATCH 1 +#ifdef TEST_FRAMEWORK AST_TEST_DEFINE(sip_uri_cmp_test) { static const struct { @@ -2362,6 +2376,7 @@ AST_TEST_DEFINE(sip_uri_cmp_test) return test_res; } +#endif void free_via(struct sip_via *v) { @@ -2448,6 +2463,7 @@ struct sip_via *parse_via(const char *header) return v; } +#ifdef TEST_FRAMEWORK AST_TEST_DEFINE(parse_via_test) { int res = AST_TEST_PASS; @@ -2625,6 +2641,7 @@ AST_TEST_DEFINE(parse_via_test) } return res; } +#endif void sip_request_parser_register_tests(void) { diff --git a/configs/samples/chan_dahdi.conf.sample b/configs/samples/chan_dahdi.conf.sample index e0c69ebef..a0c729c11 100644 --- a/configs/samples/chan_dahdi.conf.sample +++ b/configs/samples/chan_dahdi.conf.sample @@ -1119,6 +1119,15 @@ pickupgroup=1 ;faxdetect=outgoing ;faxdetect=no ; +; When 'faxdetect' is enabled, one could use 'faxdetect_timeout' to disable fax +; detection after the specified number of seconds into a call. Be aware that +; outgoing analog channels may consider the channel is answered immediately +; when dialing completes. Analog does not have a reliable method of detecting +; when the far end answers. Zero disables the timeout. +; Default is 0 to disable the timeout. +; +;faxdetect_timeout=30 +; ; When 'faxdetect' is used, one could use 'faxbuffers' to configure the DAHDI ; transmit buffer policy. The default is *OFF*. When this configuration ; option is used, the faxbuffer policy will be used for the life of the call diff --git a/configs/samples/pjsip.conf.sample b/configs/samples/pjsip.conf.sample index 9069a669f..4c42e8a5f 100644 --- a/configs/samples/pjsip.conf.sample +++ b/configs/samples/pjsip.conf.sample @@ -693,6 +693,10 @@ ;t38_udptl_maxdatagram=0 ; T 38 UDPTL maximum datagram size (default: ; "0") ;fax_detect=no ; Whether CNG tone detection is enabled (default: "no") +;fax_detect_timeout=30 ; How many seconds into a call before fax_detect is + ; disabled for the call. + ; Zero disables the timeout. + ; (default: "0") ;t38_udptl_nat=no ; Whether NAT support is enabled on UDPTL sessions ; (default: "no") ;t38_udptl_ipv6=no ; Whether IPv6 is used for UDPTL Sessions (default: @@ -1136,10 +1136,6 @@ PBX_DAHDI DAHDI_DIR DAHDI_INCLUDE DAHDI_LIB -PBX_OPENSSL_ECDH_AUTO -OPENSSL_ECDH_AUTO_DIR -OPENSSL_ECDH_AUTO_INCLUDE -OPENSSL_ECDH_AUTO_LIB PBX_OPENSSL_EC OPENSSL_EC_DIR OPENSSL_EC_INCLUDE @@ -1199,7 +1195,7 @@ NOISY_BUILD PTHREAD_CFLAGS PTHREAD_LIBS PTHREAD_CC -acx_pthread_config +ax_pthread_config MD5 SOXMIX PBX_FLEX @@ -7939,6 +7935,76 @@ if test "${MD5}" = "digest" ; then MD5="${MD5} -a md5" fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5 +$as_echo_n "checking for a sed that does not truncate output... " >&6; } +if ${ac_cv_path_SED+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ + for ac_i in 1 2 3 4 5 6 7; do + ac_script="$ac_script$as_nl$ac_script" + done + echo "$ac_script" 2>/dev/null | sed 99q >conftest.sed + { ac_script=; unset ac_script;} + if test -z "$SED"; then + ac_path_SED_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in sed gsed; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_SED="$as_dir/$ac_prog$ac_exec_ext" + as_fn_executable_p "$ac_path_SED" || continue +# Check for GNU ac_path_SED and select it if it is found. + # Check for GNU $ac_path_SED +case `"$ac_path_SED" --version 2>&1` in +*GNU*) + ac_cv_path_SED="$ac_path_SED" ac_path_SED_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo '' >> "conftest.nl" + "$ac_path_SED" -f conftest.sed < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_SED_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_SED="$ac_path_SED" + ac_path_SED_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_SED_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_SED"; then + as_fn_error $? "no acceptable sed could be found in \$PATH" "$LINENO" 5 + fi +else + ac_cv_path_SED=$SED +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5 +$as_echo "$ac_cv_path_SED" >&6; } + SED="$ac_cv_path_SED" + rm -f conftest.sed + + @@ -7948,22 +8014,26 @@ ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu -acx_pthread_ok=no +ax_pthread_ok=no # We used to check for pthread.h first, but this fails if pthread.h -# requires special compiler flags (e.g. on True64 or Sequent). +# requires special compiler flags (e.g. on Tru64 or Sequent). # It gets checked for in the link test anyway. # First of all, check if the user has set any of the PTHREAD_LIBS, # etcetera environment variables, and if threads linking works using # them: -if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then - save_CFLAGS="$CFLAGS" +if test "x$PTHREAD_CFLAGS$PTHREAD_LIBS" != "x"; then + ax_pthread_save_CC="$CC" + ax_pthread_save_CFLAGS="$CFLAGS" + ax_pthread_save_LIBS="$LIBS" + if test "x$PTHREAD_CC" != "x"; then : + CC="$PTHREAD_CC" +fi CFLAGS="$CFLAGS $PTHREAD_CFLAGS" - save_LIBS="$LIBS" LIBS="$PTHREAD_LIBS $LIBS" - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS" >&5 -$as_echo_n "checking for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS... " >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_join using $CC $PTHREAD_CFLAGS $PTHREAD_LIBS" >&5 +$as_echo_n "checking for pthread_join using $CC $PTHREAD_CFLAGS $PTHREAD_LIBS... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -7983,18 +8053,19 @@ return pthread_join (); } _ACEOF if ac_fn_c_try_link "$LINENO"; then : - acx_pthread_ok=yes + ax_pthread_ok=yes fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $acx_pthread_ok" >&5 -$as_echo "$acx_pthread_ok" >&6; } - if test x"$acx_pthread_ok" = xno; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_pthread_ok" >&5 +$as_echo "$ax_pthread_ok" >&6; } + if test "x$ax_pthread_ok" = "xno"; then PTHREAD_LIBS="" PTHREAD_CFLAGS="" fi - LIBS="$save_LIBS" - CFLAGS="$save_CFLAGS" + CC="$ax_pthread_save_CC" + CFLAGS="$ax_pthread_save_CFLAGS" + LIBS="$ax_pthread_save_LIBS" fi # We must check for the threads library under a number of different @@ -8007,7 +8078,7 @@ fi # which indicates that we try without any flags at all, and "pthread-config" # which is a program returning the flags for the Pth emulation library. -acx_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config" +ax_pthread_flags="pthreads none -Kthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config" # The ordering *is* (sometimes) important. Some notes on the # individual items follow: @@ -8016,59 +8087,269 @@ acx_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -m # none: in case threads are in libc; should be tried before -Kthread and # other compiler flags to prevent continual compiler warnings # -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h) -# -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able) -# lthread: LinuxThreads port on FreeBSD (also preferred to -pthread) -# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads) -# -pthreads: Solaris/gcc -# -mthreads: Mingw32/gcc, Lynx/gcc +# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads), Tru64 +# (Note: HP C rejects this with "bad form for `-t' option") +# -pthreads: Solaris/gcc (Note: HP C also rejects) # -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it -# doesn't hurt to check since this sometimes defines pthreads too; -# also defines -D_REENTRANT) -# ... -mt is also the pthreads flag for HP/aCC +# doesn't hurt to check since this sometimes defines pthreads and +# -D_REENTRANT too), HP C (must be checked before -lpthread, which +# is present but should not be used directly; and before -mthreads, +# because the compiler interprets this as "-mt" + "-hreads") +# -mthreads: Mingw32/gcc, Lynx/gcc # pthread: Linux, etcetera # --thread-safe: KAI C++ # pthread-config: use pthread-config program (for GNU Pth library) -case "${host_cpu}-${host_os}" in - *solaris*) +case $host_os in + + freebsd*) + + # -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able) + # lthread: LinuxThreads port on FreeBSD (also preferred to -pthread) + + ax_pthread_flags="-kthread lthread $ax_pthread_flags" + ;; + + hpux*) + + # From the cc(1) man page: "[-mt] Sets various -D flags to enable + # multi-threading and also sets -lpthread." + + ax_pthread_flags="-mt -pthread pthread $ax_pthread_flags" + ;; + + openedition*) + + # IBM z/OS requires a feature-test macro to be defined in order to + # enable POSIX threads at all, so give the user a hint if this is + # not set. (We don't define these ourselves, as they can affect + # other portions of the system API in unpredictable ways.) + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +# if !defined(_OPEN_THREADS) && !defined(_UNIX03_THREADS) + AX_PTHREAD_ZOS_MISSING +# endif + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "AX_PTHREAD_ZOS_MISSING" >/dev/null 2>&1; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: IBM z/OS requires -D_OPEN_THREADS or -D_UNIX03_THREADS to enable pthreads support." >&5 +$as_echo "$as_me: WARNING: IBM z/OS requires -D_OPEN_THREADS or -D_UNIX03_THREADS to enable pthreads support." >&2;} +fi +rm -f conftest* + + ;; + + solaris*) # On Solaris (at least, for some versions), libc contains stubbed # (non-functional) versions of the pthreads routines, so link-based - # tests will erroneously succeed. (We need to link with -pthreads/-mt/ - # -lpthread.) (The stubs are missing pthread_cleanup_push, or rather - # a function called by this macro, so we could check for that, but - # who knows whether they'll stub that too in a future libc.) So, - # we'll just look for -pthreads and -lpthread first: + # tests will erroneously succeed. (N.B.: The stubs are missing + # pthread_cleanup_push, or rather a function called by this macro, + # so we could check for that, but who knows whether they'll stub + # that too in a future libc.) So we'll check first for the + # standard Solaris way of linking pthreads (-mt -lpthread). + + ax_pthread_flags="-mt,pthread pthread $ax_pthread_flags" + ;; +esac + +# GCC generally uses -pthread, or -pthreads on some platforms (e.g. SPARC) + +if test "x$GCC" = "xyes"; then : + ax_pthread_flags="-pthread -pthreads $ax_pthread_flags" +fi + +# The presence of a feature test macro requesting re-entrant function +# definitions is, on some systems, a strong hint that pthreads support is +# correctly enabled - acx_pthread_flags="-pthreads pthread -mt -pthread $acx_pthread_flags" +case $host_os in + darwin* | hpux* | linux* | osf* | solaris*) + ax_pthread_check_macro="_REENTRANT" + ;; + + aix*) + ax_pthread_check_macro="_THREAD_SAFE" + ;; + + *) + ax_pthread_check_macro="--" ;; esac +if test "x$ax_pthread_check_macro" = "x--"; then : + ax_pthread_check_cond=0 +else + ax_pthread_check_cond="!defined($ax_pthread_check_macro)" +fi + +# Are we compiling with Clang? + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC is Clang" >&5 +$as_echo_n "checking whether $CC is Clang... " >&6; } +if ${ax_cv_PTHREAD_CLANG+:} false; then : + $as_echo_n "(cached) " >&6 +else + ax_cv_PTHREAD_CLANG=no + # Note that Autoconf sets GCC=yes for Clang as well as GCC + if test "x$GCC" = "xyes"; then + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +/* Note: Clang 2.7 lacks __clang_[a-z]+__ */ +# if defined(__clang__) && defined(__llvm__) + AX_PTHREAD_CC_IS_CLANG +# endif + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "AX_PTHREAD_CC_IS_CLANG" >/dev/null 2>&1; then : + ax_cv_PTHREAD_CLANG=yes +fi +rm -f conftest* -if test x"$acx_pthread_ok" = xno; then -for flag in $acx_pthread_flags; do + fi - case $flag in +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_PTHREAD_CLANG" >&5 +$as_echo "$ax_cv_PTHREAD_CLANG" >&6; } +ax_pthread_clang="$ax_cv_PTHREAD_CLANG" + +ax_pthread_clang_warning=no + +# Clang needs special handling, because older versions handle the -pthread +# option in a rather... idiosyncratic way + +if test "x$ax_pthread_clang" = "xyes"; then + + # Clang takes -pthread; it has never supported any other flag + + # (Note 1: This will need to be revisited if a system that Clang + # supports has POSIX threads in a separate library. This tends not + # to be the way of modern systems, but it's conceivable.) + + # (Note 2: On some systems, notably Darwin, -pthread is not needed + # to get POSIX threads support; the API is always present and + # active. We could reasonably leave PTHREAD_CFLAGS empty. But + # -pthread does define _REENTRANT, and while the Darwin headers + # ignore this macro, third-party headers might not.) + + PTHREAD_CFLAGS="-pthread" + PTHREAD_LIBS= + + ax_pthread_ok=yes + + # However, older versions of Clang make a point of warning the user + # that, in an invocation where only linking and no compilation is + # taking place, the -pthread option has no effect ("argument unused + # during compilation"). They expect -pthread to be passed in only + # when source code is being compiled. + # + # Problem is, this is at odds with the way Automake and most other + # C build frameworks function, which is that the same flags used in + # compilation (CFLAGS) are also used in linking. Many systems + # supported by AX_PTHREAD require exactly this for POSIX threads + # support, and in fact it is often not straightforward to specify a + # flag that is used only in the compilation phase and not in + # linking. Such a scenario is extremely rare in practice. + # + # Even though use of the -pthread flag in linking would only print + # a warning, this can be a nuisance for well-run software projects + # that build with -Werror. So if the active version of Clang has + # this misfeature, we search for an option to squash it. + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether Clang needs flag to prevent \"argument unused\" warning when linking with -pthread" >&5 +$as_echo_n "checking whether Clang needs flag to prevent \"argument unused\" warning when linking with -pthread... " >&6; } +if ${ax_cv_PTHREAD_CLANG_NO_WARN_FLAG+:} false; then : + $as_echo_n "(cached) " >&6 +else + ax_cv_PTHREAD_CLANG_NO_WARN_FLAG=unknown + # Create an alternate version of $ac_link that compiles and + # links in two steps (.c -> .o, .o -> exe) instead of one + # (.c -> exe), because the warning occurs only in the second + # step + ax_pthread_save_ac_link="$ac_link" + ax_pthread_sed='s/conftest\.\$ac_ext/conftest.$ac_objext/g' + ax_pthread_link_step=`$as_echo "$ac_link" | sed "$ax_pthread_sed"` + ax_pthread_2step_ac_link="($ac_compile) && (echo ==== >&5) && ($ax_pthread_link_step)" + ax_pthread_save_CFLAGS="$CFLAGS" + for ax_pthread_try in '' -Qunused-arguments -Wno-unused-command-line-argument unknown; do + if test "x$ax_pthread_try" = "xunknown"; then : + break +fi + CFLAGS="-Werror -Wunknown-warning-option $ax_pthread_try -pthread $ax_pthread_save_CFLAGS" + ac_link="$ax_pthread_save_ac_link" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +int main(void){return 0;} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_link="$ax_pthread_2step_ac_link" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +int main(void){return 0;} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + break +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + done + ac_link="$ax_pthread_save_ac_link" + CFLAGS="$ax_pthread_save_CFLAGS" + if test "x$ax_pthread_try" = "x"; then : + ax_pthread_try=no +fi + ax_cv_PTHREAD_CLANG_NO_WARN_FLAG="$ax_pthread_try" + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_PTHREAD_CLANG_NO_WARN_FLAG" >&5 +$as_echo "$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG" >&6; } + + case "$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG" in + no | unknown) ;; + *) PTHREAD_CFLAGS="$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG $PTHREAD_CFLAGS" ;; + esac + +fi # $ax_pthread_clang = yes + +if test "x$ax_pthread_ok" = "xno"; then +for ax_pthread_try_flag in $ax_pthread_flags; do + + case $ax_pthread_try_flag in none) { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether pthreads work without any flags" >&5 $as_echo_n "checking whether pthreads work without any flags... " >&6; } ;; + -mt,pthread) + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether pthreads work with -mt -lpthread" >&5 +$as_echo_n "checking whether pthreads work with -mt -lpthread... " >&6; } + PTHREAD_CFLAGS="-mt" + PTHREAD_LIBS="-lpthread" + ;; + -*) - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether pthreads work with $flag" >&5 -$as_echo_n "checking whether pthreads work with $flag... " >&6; } - PTHREAD_CFLAGS="$flag" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether pthreads work with $ax_pthread_try_flag" >&5 +$as_echo_n "checking whether pthreads work with $ax_pthread_try_flag... " >&6; } + PTHREAD_CFLAGS="$ax_pthread_try_flag" ;; - pthread-config) - # Extract the first word of "pthread-config", so it can be a program name with args. + pthread-config) + # Extract the first word of "pthread-config", so it can be a program name with args. set dummy pthread-config; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_acx_pthread_config+:} false; then : +if ${ac_cv_prog_ax_pthread_config+:} false; then : $as_echo_n "(cached) " >&6 else - if test -n "$acx_pthread_config"; then - ac_cv_prog_acx_pthread_config="$acx_pthread_config" # Let the user override the test. + if test -n "$ax_pthread_config"; then + ac_cv_prog_ax_pthread_config="$ax_pthread_config" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH @@ -8077,7 +8358,7 @@ do test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_acx_pthread_config="yes" + ac_cv_prog_ax_pthread_config="yes" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi @@ -8085,35 +8366,37 @@ done done IFS=$as_save_IFS - test -z "$ac_cv_prog_acx_pthread_config" && ac_cv_prog_acx_pthread_config="no" + test -z "$ac_cv_prog_ax_pthread_config" && ac_cv_prog_ax_pthread_config="no" fi fi -acx_pthread_config=$ac_cv_prog_acx_pthread_config -if test -n "$acx_pthread_config"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $acx_pthread_config" >&5 -$as_echo "$acx_pthread_config" >&6; } +ax_pthread_config=$ac_cv_prog_ax_pthread_config +if test -n "$ax_pthread_config"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_pthread_config" >&5 +$as_echo "$ax_pthread_config" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi - if test x"$acx_pthread_config" = xno; then continue; fi - PTHREAD_CFLAGS="`pthread-config --cflags`" - PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`" - ;; + if test "x$ax_pthread_config" = "xno"; then : + continue +fi + PTHREAD_CFLAGS="`pthread-config --cflags`" + PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`" + ;; *) - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for the pthreads library -l$flag" >&5 -$as_echo_n "checking for the pthreads library -l$flag... " >&6; } - PTHREAD_LIBS="-l$flag" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for the pthreads library -l$ax_pthread_try_flag" >&5 +$as_echo_n "checking for the pthreads library -l$ax_pthread_try_flag... " >&6; } + PTHREAD_LIBS="-l$ax_pthread_try_flag" ;; esac - save_LIBS="$LIBS" - save_CFLAGS="$CFLAGS" - LIBS="$PTHREAD_LIBS $LIBS" + ax_pthread_save_CFLAGS="$CFLAGS" + ax_pthread_save_LIBS="$LIBS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS" + LIBS="$PTHREAD_LIBS $LIBS" # Check for various functions. We must include pthread.h, # since some functions may be macros. (On the Sequent, we @@ -8124,33 +8407,42 @@ $as_echo_n "checking for the pthreads library -l$flag... " >&6; } # pthread_cleanup_push because it is one of the few pthread # functions on Solaris that doesn't have a non-functional libc stub. # We try pthread_create on general principles. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <pthread.h> +# if $ax_pthread_check_cond +# error "$ax_pthread_check_macro must be defined" +# endif + static void routine(void *a) { a = 0; } + static void *start_routine(void *a) { return a; } int main () { -pthread_t th; pthread_join(th, 0); - pthread_attr_init(0); pthread_cleanup_push(0, 0); - pthread_create(0,0,0,0); pthread_cleanup_pop(0); +pthread_t th; pthread_attr_t attr; + pthread_create(&th, 0, start_routine, 0); + pthread_join(th, 0); + pthread_attr_init(&attr); + pthread_cleanup_push(routine, 0); + pthread_cleanup_pop(0) /* ; */ ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : - acx_pthread_ok=yes + ax_pthread_ok=yes fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext - LIBS="$save_LIBS" - CFLAGS="$save_CFLAGS" + CFLAGS="$ax_pthread_save_CFLAGS" + LIBS="$ax_pthread_save_LIBS" - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $acx_pthread_ok" >&5 -$as_echo "$acx_pthread_ok" >&6; } - if test "x$acx_pthread_ok" = xyes; then - break; - fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_pthread_ok" >&5 +$as_echo "$ax_pthread_ok" >&6; } + if test "x$ax_pthread_ok" = "xyes"; then : + break +fi PTHREAD_LIBS="" PTHREAD_CFLAGS="" @@ -8158,63 +8450,127 @@ done fi # Various other checks: -if test "x$acx_pthread_ok" = xyes; then - save_LIBS="$LIBS" - LIBS="$PTHREAD_LIBS $LIBS" - save_CFLAGS="$CFLAGS" +if test "x$ax_pthread_ok" = "xyes"; then + ax_pthread_save_CFLAGS="$CFLAGS" + ax_pthread_save_LIBS="$LIBS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS" + LIBS="$PTHREAD_LIBS $LIBS" # Detect AIX lossage: JOINABLE attribute is called UNDETACHED. - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for joinable pthread attribute" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for joinable pthread attribute" >&5 $as_echo_n "checking for joinable pthread attribute... " >&6; } - attr_name=unknown - for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +if ${ax_cv_PTHREAD_JOINABLE_ATTR+:} false; then : + $as_echo_n "(cached) " >&6 +else + ax_cv_PTHREAD_JOINABLE_ATTR=unknown + for ax_pthread_attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <pthread.h> int main () { -int attr=$attr; return attr; +int attr = $ax_pthread_attr; return attr /* ; */ ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : - attr_name=$attr; break + ax_cv_PTHREAD_JOINABLE_ATTR=$ax_pthread_attr; break fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext - done - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $attr_name" >&5 -$as_echo "$attr_name" >&6; } - if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then + done + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_PTHREAD_JOINABLE_ATTR" >&5 +$as_echo "$ax_cv_PTHREAD_JOINABLE_ATTR" >&6; } + if test "x$ax_cv_PTHREAD_JOINABLE_ATTR" != "xunknown" && \ + test "x$ax_cv_PTHREAD_JOINABLE_ATTR" != "xPTHREAD_CREATE_JOINABLE" && \ + test "x$ax_pthread_joinable_attr_defined" != "xyes"; then : cat >>confdefs.h <<_ACEOF -#define PTHREAD_CREATE_JOINABLE $attr_name +#define PTHREAD_CREATE_JOINABLE $ax_cv_PTHREAD_JOINABLE_ATTR _ACEOF - fi + ax_pthread_joinable_attr_defined=yes - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if more special flags are required for pthreads" >&5 -$as_echo_n "checking if more special flags are required for pthreads... " >&6; } - flag=no - case "${host_cpu}-${host_os}" in - *-aix* | *-freebsd* | *-darwin*) flag="-D_THREAD_SAFE";; - *solaris* | *-osf* | *-hpux*) flag="-D_REENTRANT";; - esac - { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${flag}" >&5 -$as_echo "${flag}" >&6; } - if test "x$flag" != xno; then - PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS" - fi +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether more special flags are required for pthreads" >&5 +$as_echo_n "checking whether more special flags are required for pthreads... " >&6; } +if ${ax_cv_PTHREAD_SPECIAL_FLAGS+:} false; then : + $as_echo_n "(cached) " >&6 +else + ax_cv_PTHREAD_SPECIAL_FLAGS=no + case $host_os in + solaris*) + ax_cv_PTHREAD_SPECIAL_FLAGS="-D_POSIX_PTHREAD_SEMANTICS" + ;; + esac + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_PTHREAD_SPECIAL_FLAGS" >&5 +$as_echo "$ax_cv_PTHREAD_SPECIAL_FLAGS" >&6; } + if test "x$ax_cv_PTHREAD_SPECIAL_FLAGS" != "xno" && \ + test "x$ax_pthread_special_flags_added" != "xyes"; then : + PTHREAD_CFLAGS="$ax_cv_PTHREAD_SPECIAL_FLAGS $PTHREAD_CFLAGS" + ax_pthread_special_flags_added=yes +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for PTHREAD_PRIO_INHERIT" >&5 +$as_echo_n "checking for PTHREAD_PRIO_INHERIT... " >&6; } +if ${ax_cv_PTHREAD_PRIO_INHERIT+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <pthread.h> +int +main () +{ +int i = PTHREAD_PRIO_INHERIT; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ax_cv_PTHREAD_PRIO_INHERIT=yes +else + ax_cv_PTHREAD_PRIO_INHERIT=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_PTHREAD_PRIO_INHERIT" >&5 +$as_echo "$ax_cv_PTHREAD_PRIO_INHERIT" >&6; } + if test "x$ax_cv_PTHREAD_PRIO_INHERIT" = "xyes" && \ + test "x$ax_pthread_prio_inherit_defined" != "xyes"; then : + +$as_echo "#define HAVE_PTHREAD_PRIO_INHERIT 1" >>confdefs.h + + ax_pthread_prio_inherit_defined=yes - LIBS="$save_LIBS" - CFLAGS="$save_CFLAGS" +fi + + CFLAGS="$ax_pthread_save_CFLAGS" + LIBS="$ax_pthread_save_LIBS" - # More AIX lossage: must compile with xlc_r or cc_r - if test x"$GCC" != xyes; then - for ac_prog in xlc_r cc_r + # More AIX lossage: compile with *_r variant + if test "x$GCC" != "xyes"; then + case $host_os in + aix*) + case "x/$CC" in #( + x*/c89|x*/c89_128|x*/c99|x*/c99_128|x*/cc|x*/cc128|x*/xlc|x*/xlc_v6|x*/xlc128|x*/xlc128_v6) : + #handle absolute path differently from PATH based program lookup + case "x$CC" in #( + x/*) : + if as_fn_executable_p ${CC}_r; then : + PTHREAD_CC="${CC}_r" +fi ;; #( + *) : + for ac_prog in ${CC}_r do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 @@ -8255,27 +8611,31 @@ fi test -n "$PTHREAD_CC" && break done -test -n "$PTHREAD_CC" || PTHREAD_CC="${CC}" - - else - PTHREAD_CC=$CC - fi -else - PTHREAD_CC="$CC" +test -n "$PTHREAD_CC" || PTHREAD_CC="$CC" + ;; +esac ;; #( + *) : + ;; +esac + ;; + esac + fi fi +test -n "$PTHREAD_CC" || PTHREAD_CC="$CC" + # Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND: -if test x"$acx_pthread_ok" = xyes; then +if test "x$ax_pthread_ok" = "xyes"; then $as_echo "#define HAVE_PTHREAD 1" >>confdefs.h : else - acx_pthread_ok=no + ax_pthread_ok=no fi ac_ext=c @@ -8804,18 +9164,6 @@ PBX_OPENSSL_EC=0 -OPENSSL_ECDH_AUTO_DESCRIP="OpenSSL Auto ECDH Support" -OPENSSL_ECDH_AUTO_OPTION=crypto -OPENSSL_ECDH_AUTO_DIR=${CRYPTO_DIR} - -PBX_OPENSSL_ECDH_AUTO=0 - - - - - - - DAHDI_DESCRIP="DAHDI" DAHDI_OPTION="dahdi" PBX_DAHDI=0 @@ -17726,6 +18074,74 @@ CFLAGS="$saved_CFLAGS" +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for compiler 'attribute noreturn' support" >&5 +$as_echo_n "checking for compiler 'attribute noreturn' support... " >&6; } +saved_CFLAGS="$CFLAGS" +CFLAGS="$CFLAGS -Wall -Wno-unused -Werror" + + +if test "xnoreturn" = "x" +then +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + void __attribute__((noreturn)) *test(void *muffin, ...) {return (void *) 0;} +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + + +cat >>confdefs.h <<_ACEOF +#define HAVE_ATTRIBUTE_noreturn 1 +_ACEOF + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +else +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + void __attribute__((noreturn)) *test(void *muffin, ...) ; +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + + +cat >>confdefs.h <<_ACEOF +#define HAVE_ATTRIBUTE_noreturn 1 +_ACEOF + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + + +CFLAGS="$saved_CFLAGS" + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -fsanitize=address support" >&5 $as_echo_n "checking for -fsanitize=address support... " >&6; } saved_sanitize_CFLAGS="${CFLAGS}" @@ -17978,19 +18394,13 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -march=native support" >&5 $as_echo_n "checking for -march=native support... " >&6; } if $(${CC} -march=native -S -o /dev/null -xc /dev/null > /dev/null 2>&1); then - if test "${CONFIG_CFLAGS}" = ""; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } - AST_NATIVE_ARCH=1 - else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: user CFLAGS present" >&5 -$as_echo "user CFLAGS present" >&6; } - AST_NATIVE_ARCH= - fi + AST_NATIVE_ARCH=1 else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } - AST_NATIVE_ARCH= + AST_NATIVE_ARCH=0 fi @@ -31561,53 +31971,6 @@ fi if test "$PBX_OPENSSL" = "1"; then - if test "x${PBX_OPENSSL_ECDH_AUTO}" != "x1" -a "${USE_OPENSSL_ECDH_AUTO}" != "no"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for SSL_CTX_set_ecdh_auto declared in openssl/ssl.h" >&5 -$as_echo_n "checking for SSL_CTX_set_ecdh_auto declared in openssl/ssl.h... " >&6; } - saved_cppflags="${CPPFLAGS}" - if test "x${OPENSSL_ECDH_AUTO_DIR}" != "x"; then - OPENSSL_ECDH_AUTO_INCLUDE="-I${OPENSSL_ECDH_AUTO_DIR}/include" - fi - CPPFLAGS="${CPPFLAGS} ${OPENSSL_ECDH_AUTO_INCLUDE}" - - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - #include <openssl/ssl.h> -int -main () -{ -#if !defined(SSL_CTX_set_ecdh_auto) - (void) SSL_CTX_set_ecdh_auto; - #endif - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } - PBX_OPENSSL_ECDH_AUTO=1 - -$as_echo "#define HAVE_OPENSSL_ECDH_AUTO 1" >>confdefs.h - - - -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } - -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - - CPPFLAGS="${saved_cppflags}" - fi - -fi - -if test "$PBX_OPENSSL" = "1"; -then - if test "x${PBX_SSL_OP_NO_TLSV1_1}" != "x1"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for SSL_OP_NO_TLSv1_1 in openssl/ssl.h" >&5 $as_echo_n "checking for SSL_OP_NO_TLSv1_1 in openssl/ssl.h... " >&6; } diff --git a/configure.ac b/configure.ac index 59587c0f4..ed6f8a8d4 100644 --- a/configure.ac +++ b/configure.ac @@ -351,7 +351,7 @@ if test "${MD5}" = "digest" ; then MD5="${MD5} -a md5" fi -ACX_PTHREAD +AX_PTHREAD AC_LANG(C) @@ -414,7 +414,6 @@ AST_EXT_LIB_SETUP([CRYPT], [password and data encryption], [crypt]) AST_EXT_LIB_SETUP([CRYPTO], [OpenSSL Cryptography], [crypto]) AST_EXT_LIB_SETUP_OPTIONAL([OPENSSL_SRTP], [OpenSSL SRTP Extension Support], [CRYPTO], [crypto]) AST_EXT_LIB_SETUP_OPTIONAL([OPENSSL_EC], [OpenSSL Elliptic Curve Support], [CRYPTO], [crypto]) -AST_EXT_LIB_SETUP_OPTIONAL([OPENSSL_ECDH_AUTO], [OpenSSL Auto ECDH Support], [CRYPTO], [crypto]) AST_EXT_LIB_SETUP([DAHDI], [DAHDI], [dahdi]) AST_EXT_LIB_SETUP([FFMPEG], [Ffmpeg and avcodec], [avcodec]) AST_EXT_LIB_SETUP([GSM], [External GSM], [gsm], [, use 'internal' GSM otherwise]) @@ -1080,6 +1079,7 @@ AST_GCC_ATTRIBUTE(warn_unused_result) AST_GCC_ATTRIBUTE(may_alias) AST_GCC_ATTRIBUTE(constructor) AST_GCC_ATTRIBUTE(destructor) +AST_GCC_ATTRIBUTE(noreturn,noreturn) AC_MSG_CHECKING(for -fsanitize=address support) saved_sanitize_CFLAGS="${CFLAGS}" @@ -1220,16 +1220,11 @@ AC_SUBST(AST_SHADOW_WARNINGS) AC_MSG_CHECKING(for -march=native support) if $(${CC} -march=native -S -o /dev/null -xc /dev/null > /dev/null 2>&1); then - if test "${CONFIG_CFLAGS}" = ""; then - AC_MSG_RESULT(yes) - AST_NATIVE_ARCH=1 - else - AC_MSG_RESULT(user CFLAGS present) - AST_NATIVE_ARCH= - fi + AC_MSG_RESULT(yes) + AST_NATIVE_ARCH=1 else AC_MSG_RESULT(no) - AST_NATIVE_ARCH= + AST_NATIVE_ARCH=0 fi AC_SUBST(AST_NATIVE_ARCH) @@ -2416,11 +2411,6 @@ fi if test "$PBX_OPENSSL" = "1"; then - AST_C_DECLARE_CHECK([OPENSSL_ECDH_AUTO], [SSL_CTX_set_ecdh_auto], [openssl/ssl.h]) -fi - -if test "$PBX_OPENSSL" = "1"; -then AST_C_DEFINE_CHECK([SSL_OP_NO_TLSV1_1], [SSL_OP_NO_TLSv1_1], [openssl/ssl.h]) AST_C_DEFINE_CHECK([SSL_OP_NO_TLSV1_2], [SSL_OP_NO_TLSv1_2], [openssl/ssl.h]) fi diff --git a/contrib/ast-db-manage/config/versions/4a6c67fa9b7a_add_fax_detect_timeout_option.py b/contrib/ast-db-manage/config/versions/4a6c67fa9b7a_add_fax_detect_timeout_option.py new file mode 100644 index 000000000..91774c447 --- /dev/null +++ b/contrib/ast-db-manage/config/versions/4a6c67fa9b7a_add_fax_detect_timeout_option.py @@ -0,0 +1,23 @@ +"""add fax_detect_timeout option + +Revision ID: 4a6c67fa9b7a +Revises: 9deac0ae4717 +Create Date: 2016-07-18 18:20:44.249491 + +""" + +# revision identifiers, used by Alembic. +revision = '4a6c67fa9b7a' +down_revision = '9deac0ae4717' + +from alembic import op +import sqlalchemy as sa + + +def upgrade(): + op.add_column('ps_endpoints', sa.Column('fax_detect_timeout', sa.Integer)) + + +def downgrade(): + op.drop_column('ps_endpoints', 'fax_detect_timeout') + diff --git a/funcs/func_curl.c b/funcs/func_curl.c index 6a8c36767..8ec1032a7 100644 --- a/funcs/func_curl.c +++ b/funcs/func_curl.c @@ -856,6 +856,7 @@ static struct ast_custom_function acf_curlopt = { .write = acf_curlopt_write, }; +#ifdef TEST_FRAMEWORK AST_TEST_DEFINE(vulnerable_url) { const char *bad_urls [] = { @@ -903,6 +904,7 @@ AST_TEST_DEFINE(vulnerable_url) return res; } +#endif static int unload_module(void) { diff --git a/include/asterisk/autoconfig.h.in b/include/asterisk/autoconfig.h.in index 380ac2efb..b48257ec0 100644 --- a/include/asterisk/autoconfig.h.in +++ b/include/asterisk/autoconfig.h.in @@ -102,6 +102,9 @@ /* Define to 1 if your GCC C compiler supports the 'may_alias' attribute. */ #undef HAVE_ATTRIBUTE_may_alias +/* Define to 1 if your GCC C compiler supports the 'noreturn' attribute. */ +#undef HAVE_ATTRIBUTE_noreturn + /* Define to 1 if your GCC C compiler supports the 'pure' attribute. */ #undef HAVE_ATTRIBUTE_pure @@ -547,9 +550,6 @@ /* Define to 1 if CRYPTO has the OpenSSL Elliptic Curve Support feature. */ #undef HAVE_OPENSSL_EC -/* Define if your system has SSL_CTX_set_ecdh_auto declared. */ -#undef HAVE_OPENSSL_ECDH_AUTO - /* Define to 1 if CRYPTO has the OpenSSL SRTP Extension Support feature. */ #undef HAVE_OPENSSL_SRTP @@ -707,6 +707,9 @@ */ #undef HAVE_PTHREAD_MUTEX_RECURSIVE_NP +/* Have PTHREAD_PRIO_INHERIT. */ +#undef HAVE_PTHREAD_PRIO_INHERIT + /* Define if your system has the PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP headers. */ #undef HAVE_PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP diff --git a/include/asterisk/compiler.h b/include/asterisk/compiler.h index 77b5de40e..6ceaa5f77 100644 --- a/include/asterisk/compiler.h +++ b/include/asterisk/compiler.h @@ -77,6 +77,12 @@ #define attribute_may_alias #endif +#ifdef HAVE_ATTRIBUTE_noreturn +#define attribute_noreturn __attribute__((noreturn)) +#else +#define attribute_noreturn +#endif + /* Some older version of GNU gcc (3.3.5 on OpenBSD 4.3 for example) dont like 'NULL' as sentinel */ #define SENTINEL ((char *)NULL) diff --git a/include/asterisk/event_defs.h b/include/asterisk/event_defs.h index 80a8d7dda..2d5c75a44 100644 --- a/include/asterisk/event_defs.h +++ b/include/asterisk/event_defs.h @@ -58,8 +58,10 @@ enum ast_event_type { AST_EVENT_ACL_CHANGE = 0x0b, /*! Send out a ping for debugging distributed events */ AST_EVENT_PING = 0x0c, + /*! A cluster discovery message */ + AST_EVENT_CLUSTER_DISCOVERY = 0x0d, /*! Number of event types. This should be the last event type + 1 */ - AST_EVENT_TOTAL = 0x0d, + AST_EVENT_TOTAL = 0x0e, }; /*! \brief Event Information Element types */ @@ -302,8 +304,15 @@ enum ast_event_ie_type { * Payload type: UINT */ AST_EVENT_IE_CACHABLE = 0x003d, + + /*! + * \brief Cluster node ID + * Used by: Corosync + * Payload type: UINT + */ + AST_EVENT_IE_NODE_ID = 0x003e, /*! \brief Must be the last IE value +1 */ - AST_EVENT_IE_TOTAL = 0x003e, + AST_EVENT_IE_TOTAL = 0x003f, }; /*! diff --git a/include/asterisk/format_cache.h b/include/asterisk/format_cache.h index 64e53b9c5..3894ad21b 100644 --- a/include/asterisk/format_cache.h +++ b/include/asterisk/format_cache.h @@ -224,6 +224,14 @@ extern struct ast_format *ast_format_t140_red; extern struct ast_format *ast_format_none; /*! + * \brief Built-in SILK format. + */ +extern struct ast_format *ast_format_silk8; +extern struct ast_format *ast_format_silk12; +extern struct ast_format *ast_format_silk16; +extern struct ast_format *ast_format_silk24; + +/*! * \brief Initialize format cache support within the core. * * \retval 0 success diff --git a/include/asterisk/pbx.h b/include/asterisk/pbx.h index afdcc8da4..d44a245e3 100644 --- a/include/asterisk/pbx.h +++ b/include/asterisk/pbx.h @@ -1227,11 +1227,11 @@ int pbx_checkcondition(const char *condition); const char *ast_get_context_name(struct ast_context *con); const char *ast_get_extension_name(struct ast_exten *exten); struct ast_context *ast_get_extension_context(struct ast_exten *exten); -const char *ast_get_include_name(struct ast_include *include); -const char *ast_get_ignorepat_name(struct ast_ignorepat *ip); -const char *ast_get_switch_name(struct ast_sw *sw); -const char *ast_get_switch_data(struct ast_sw *sw); -int ast_get_switch_eval(struct ast_sw *sw); +const char *ast_get_include_name(const struct ast_include *include); +const char *ast_get_ignorepat_name(const struct ast_ignorepat *ip); +const char *ast_get_switch_name(const struct ast_sw *sw); +const char *ast_get_switch_data(const struct ast_sw *sw); +int ast_get_switch_eval(const struct ast_sw *sw); /*! @} */ @@ -1249,9 +1249,9 @@ void *ast_get_extension_app_data(struct ast_exten *e); /*! @{ */ const char *ast_get_context_registrar(struct ast_context *c); const char *ast_get_extension_registrar(struct ast_exten *e); -const char *ast_get_include_registrar(struct ast_include *i); -const char *ast_get_ignorepat_registrar(struct ast_ignorepat *ip); -const char *ast_get_switch_registrar(struct ast_sw *sw); +const char *ast_get_include_registrar(const struct ast_include *i); +const char *ast_get_ignorepat_registrar(const struct ast_ignorepat *ip); +const char *ast_get_switch_registrar(const struct ast_sw *sw); /*! @} */ /*! @name Walking functions ... */ @@ -1261,11 +1261,22 @@ struct ast_exten *ast_walk_context_extensions(struct ast_context *con, struct ast_exten *priority); struct ast_exten *ast_walk_extension_priorities(struct ast_exten *exten, struct ast_exten *priority); -struct ast_include *ast_walk_context_includes(struct ast_context *con, - struct ast_include *inc); -struct ast_ignorepat *ast_walk_context_ignorepats(struct ast_context *con, - struct ast_ignorepat *ip); -struct ast_sw *ast_walk_context_switches(struct ast_context *con, struct ast_sw *sw); +const struct ast_include *ast_walk_context_includes(const struct ast_context *con, + const struct ast_include *inc); +const struct ast_ignorepat *ast_walk_context_ignorepats(const struct ast_context *con, + const struct ast_ignorepat *ip); +const struct ast_sw *ast_walk_context_switches(const struct ast_context *con, + const struct ast_sw *sw); +/*! @} */ + +/*! @name Iterator functions ... */ +/*! @{ */ +int ast_context_includes_count(const struct ast_context *con); +const struct ast_include *ast_context_includes_get(const struct ast_context *con, int idx); +int ast_context_ignorepats_count(const struct ast_context *con); +const struct ast_ignorepat *ast_context_ignorepats_get(const struct ast_context *con, int idx); +int ast_context_switches_count(const struct ast_context *con); +const struct ast_sw *ast_context_switches_get(const struct ast_context *con, int idx); /*! @} */ /*! diff --git a/include/asterisk/res_fax.h b/include/asterisk/res_fax.h index 2304da734..5119bfa6c 100644 --- a/include/asterisk/res_fax.h +++ b/include/asterisk/res_fax.h @@ -179,11 +179,11 @@ struct ast_fax_session_details { unsigned int t38timeout; /*! the id of the t.38 gateway framehook for this channel */ int gateway_id; - /*! the timeout for this gateway in seconds */ + /*! The timeout for this gateway in ms */ int gateway_timeout; /*! the id of the faxdetect framehook for this channel */ int faxdetect_id; - /*! The timeout for this fax detect in seconds */ + /*! The timeout for this fax detect in ms */ int faxdetect_timeout; /*! flags used for fax detection */ int faxdetect_flags; diff --git a/include/asterisk/res_pjsip.h b/include/asterisk/res_pjsip.h index db5599213..9dd70dbca 100644 --- a/include/asterisk/res_pjsip.h +++ b/include/asterisk/res_pjsip.h @@ -271,7 +271,6 @@ enum ast_sip_contact_status_type { UNKNOWN, CREATED, REMOVED, - UPDATED, }; /*! @@ -296,6 +295,8 @@ struct ast_sip_contact_status { int64_t rtt; /*! Last status for a contact (default - unavailable) */ enum ast_sip_contact_status_type last_status; + /*! TRUE if the contact was refreshed. e.g., re-registered */ + unsigned int refresh:1; }; /*! @@ -752,6 +753,8 @@ struct ast_sip_endpoint { struct ast_acl_list *acl; /* Restrict what IPs are allowed in the Contact header (for registration) */ struct ast_acl_list *contact_acl; + /*! The number of seconds into call to disable fax detection. (0 = disabled) */ + unsigned int faxdetect_timeout; }; /*! diff --git a/include/asterisk/res_pjsip_session.h b/include/asterisk/res_pjsip_session.h index 5ca2c99a5..26dd451a7 100644 --- a/include/asterisk/res_pjsip_session.h +++ b/include/asterisk/res_pjsip_session.h @@ -139,7 +139,7 @@ struct ast_sip_session { struct ast_party_id id; /*! Requested capabilities */ struct ast_format_cap *req_caps; - /*! Optional DSP, used only for inband DTMF detection if configured */ + /*! Optional DSP, used only for inband DTMF/Fax-CNG detection if configured */ struct ast_dsp *dsp; /*! Whether the termination of the session should be deferred */ unsigned int defer_terminate:1; diff --git a/include/asterisk/stasis_system.h b/include/asterisk/stasis_system.h index 8c6e60f46..274c02e49 100644 --- a/include/asterisk/stasis_system.h +++ b/include/asterisk/stasis_system.h @@ -122,6 +122,12 @@ struct stasis_message_type *ast_cc_failure_type(void); struct stasis_message_type *ast_cc_monitorfailed_type(void); /*! + * \brief A \ref stasis_message_type for Cluster discovery + * \since 13.11.0 + */ +struct stasis_message_type *ast_cluster_discovery_type(void); + +/*! * \brief Initialize the stasis system topic and message types * \retval 0 on success * \retval -1 on failure diff --git a/include/asterisk/utils.h b/include/asterisk/utils.h index c7a473732..c311e9cd5 100644 --- a/include/asterisk/utils.h +++ b/include/asterisk/utils.h @@ -843,9 +843,14 @@ struct ast_http_digest { */ int ast_parse_digest(const char *digest, struct ast_http_digest *d, int request, int pedantic); +#ifdef DO_CRASH +#define DO_CRASH_NORETURN attribute_noreturn +#else +#define DO_CRASH_NORETURN +#endif #ifdef AST_DEVMODE -void __ast_assert_failed(int condition, const char *condition_str, const char *file, int line, const char *function); +void DO_CRASH_NORETURN __ast_assert_failed(int condition, const char *condition_str, const char *file, int line, const char *function); #define ast_assert(a) _ast_assert(a, # a, __FILE__, __LINE__, __PRETTY_FUNCTION__) static void force_inline _ast_assert(int condition, const char *condition_str, const char *file, int line, const char *function) { @@ -864,7 +869,7 @@ static void force_inline _ast_assert(int condition, const char *condition_str, c * * \return Nothing */ -void ast_do_crash(void); +void DO_CRASH_NORETURN ast_do_crash(void); #include "asterisk/strings.h" diff --git a/main/cdr.c b/main/cdr.c index 586a10684..e2f9b764c 100644 --- a/main/cdr.c +++ b/main/cdr.c @@ -1409,9 +1409,7 @@ static int base_process_party_a(struct cdr_object *cdr, struct ast_channel_snaps static int base_process_bridge_leave(struct cdr_object *cdr, struct ast_bridge_snapshot *bridge, struct ast_channel_snapshot *channel) { - /* In general, most things shouldn't get a bridge leave */ - ast_assert(0); - return 1; + return 0; } static int base_process_dial_end(struct cdr_object *cdr, struct ast_channel_snapshot *caller, struct ast_channel_snapshot *peer, const char *dial_status) diff --git a/main/channel.c b/main/channel.c index f654e4d25..911c26955 100644 --- a/main/channel.c +++ b/main/channel.c @@ -2692,10 +2692,28 @@ void ast_hangup(struct ast_channel *chan) ast_channel_unref(chan); } +/*! + * \internal + * \brief Set channel answered time if not already set. + * \since 13.11.0 + * + * \param chan Channel to set answered time. + * + * \return Nothing + */ +static void set_channel_answer_time(struct ast_channel *chan) +{ + if (ast_tvzero(ast_channel_answertime(chan))) { + struct timeval answertime; + + answertime = ast_tvnow(); + ast_channel_answertime_set(chan, &answertime); + } +} + int ast_raw_answer(struct ast_channel *chan) { int res = 0; - struct timeval answertime; ast_channel_lock(chan); @@ -2711,8 +2729,11 @@ int ast_raw_answer(struct ast_channel *chan) return -1; } - answertime = ast_tvnow(); - ast_channel_answertime_set(chan, &answertime); + /* + * Mark when incoming channel answered so we can know how + * long the channel has been up. + */ + set_channel_answer_time(chan); ast_channel_unlock(chan); @@ -3911,6 +3932,12 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio) ast_frfree(f); f = &ast_null_frame; } else { + /* + * Mark when outgoing channel answered so we can know how + * long the channel has been up. + */ + set_channel_answer_time(chan); + ast_setstate(chan, AST_STATE_UP); } } else if (f->subclass.integer == AST_CONTROL_READ_ACTION) { diff --git a/main/codec_builtin.c b/main/codec_builtin.c index 913164328..50fbf555c 100644 --- a/main/codec_builtin.c +++ b/main/codec_builtin.c @@ -772,6 +772,65 @@ static struct ast_codec t140 = { .type = AST_MEDIA_TYPE_TEXT, }; +static int silk_samples(struct ast_frame *frame) +{ + /* XXX This is likely not at all what's intended from this callback. However, + * since SILK is variable bit rate, I have no idea how to take a frame of data + * and determine the number of samples present. Instead, we base this on the + * sample rate of the codec and the expected number of samples to receive in 20ms. + * In testing, this has worked just fine. + */ + return ast_format_get_sample_rate(frame->subclass.format) / 50; +} + +static struct ast_codec silk8 = { + .name = "silk", + .description = "SILK Codec (8 KHz)", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 8000, + .minimum_ms = 20, + .maximum_ms = 100, + .default_ms = 20, + .minimum_bytes = 160, + .samples_count = silk_samples +}; + +static struct ast_codec silk12 = { + .name = "silk", + .description = "SILK Codec (12 KHz)", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 12000, + .minimum_ms = 20, + .maximum_ms = 100, + .default_ms = 20, + .minimum_bytes = 240, + .samples_count = silk_samples +}; + +static struct ast_codec silk16 = { + .name = "silk", + .description = "SILK Codec (16 KHz)", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 16000, + .minimum_ms = 20, + .maximum_ms = 100, + .default_ms = 20, + .minimum_bytes = 320, + .samples_count = silk_samples +}; + +static struct ast_codec silk24 = { + .name = "silk", + .description = "SILK Codec (24 KHz)", + .type = AST_MEDIA_TYPE_AUDIO, + .sample_rate = 24000, + .minimum_ms = 20, + .maximum_ms = 100, + .default_ms = 20, + .minimum_bytes = 480, + .samples_count = silk_samples +}; + #define CODEC_REGISTER_AND_CACHE(codec) \ ({ \ int __res_ ## __LINE__ = 0; \ @@ -843,6 +902,10 @@ int ast_codec_builtin_init(void) res |= CODEC_REGISTER_AND_CACHE(t140red); res |= CODEC_REGISTER_AND_CACHE(t140); res |= CODEC_REGISTER_AND_CACHE(none); + res |= CODEC_REGISTER_AND_CACHE_NAMED("silk8", silk8); + res |= CODEC_REGISTER_AND_CACHE_NAMED("silk12", silk12); + res |= CODEC_REGISTER_AND_CACHE_NAMED("silk16", silk16); + res |= CODEC_REGISTER_AND_CACHE_NAMED("silk24", silk24); return res; } diff --git a/main/features.c b/main/features.c index b6e9630b5..4062e96ce 100644 --- a/main/features.c +++ b/main/features.c @@ -64,7 +64,6 @@ ASTERISK_REGISTER_FILE() #include "asterisk/cli.h" #include "asterisk/manager.h" #include "asterisk/utils.h" -#include "asterisk/adsi.h" #include "asterisk/devicestate.h" #include "asterisk/audiohook.h" #include "asterisk/global_datastores.h" diff --git a/main/format_cache.c b/main/format_cache.c index def795c9d..b4d426092 100644 --- a/main/format_cache.c +++ b/main/format_cache.c @@ -232,6 +232,14 @@ struct ast_format *ast_format_t140_red; */ struct ast_format *ast_format_none; +/*! + * \brief Built-in "silk" format + */ +struct ast_format *ast_format_silk8; +struct ast_format *ast_format_silk12; +struct ast_format *ast_format_silk16; +struct ast_format *ast_format_silk24; + /*! \brief Number of buckets to use for the media format cache (should be prime for performance reasons) */ #define CACHE_BUCKETS 53 @@ -331,6 +339,10 @@ static void format_cache_shutdown(void) ao2_replace(ast_format_t140_red, NULL); ao2_replace(ast_format_t140, NULL); ao2_replace(ast_format_none, NULL); + ao2_replace(ast_format_silk8, NULL); + ao2_replace(ast_format_silk12, NULL); + ao2_replace(ast_format_silk16, NULL); + ao2_replace(ast_format_silk24, NULL); } int ast_format_cache_init(void) @@ -426,6 +438,14 @@ static void set_cached_format(const char *name, struct ast_format *format) ao2_replace(ast_format_t140, format); } else if (!strcmp(name, "none")) { ao2_replace(ast_format_none, format); + } else if (!strcmp(name, "silk8")) { + ao2_replace(ast_format_silk8, format); + } else if (!strcmp(name, "silk12")) { + ao2_replace(ast_format_silk12, format); + } else if (!strcmp(name, "silk16")) { + ao2_replace(ast_format_silk16, format); + } else if (!strcmp(name, "silk24")) { + ao2_replace(ast_format_silk24, format); } } diff --git a/main/pbx.c b/main/pbx.c index df9cad326..f9fad0388 100644 --- a/main/pbx.c +++ b/main/pbx.c @@ -255,34 +255,6 @@ struct ast_exten { char stuff[0]; }; -/*! \brief ast_include: include= support in extensions.conf */ -struct ast_include { - const char *name; - const char *rname; /*!< Context to include */ - const char *registrar; /*!< Registrar */ - int hastime; /*!< If time construct exists */ - struct ast_timing timing; /*!< time construct */ - struct ast_include *next; /*!< Link them together */ - char stuff[0]; -}; - -/*! \brief ast_sw: Switch statement in extensions.conf */ -struct ast_sw { - char *name; - const char *registrar; /*!< Registrar */ - char *data; /*!< Data load */ - int eval; - AST_LIST_ENTRY(ast_sw) list; - char stuff[0]; -}; - -/*! \brief ast_ignorepat: Ignore patterns in dial plan */ -struct ast_ignorepat { - const char *registrar; - struct ast_ignorepat *next; - const char pattern[0]; -}; - /*! \brief match_char: forms a syntax tree for quick matching of extension patterns */ struct match_char { @@ -313,12 +285,12 @@ struct ast_context { struct ast_hashtab *root_table; /*!< For exact matches on the extensions in the pattern tree, and for traversals of the pattern_tree */ struct match_char *pattern_tree; /*!< A tree to speed up extension pattern matching */ struct ast_context *next; /*!< Link them together */ - struct ast_include *includes; /*!< Include other contexts */ - struct ast_ignorepat *ignorepats; /*!< Patterns for which to continue playing dialtone */ + struct ast_includes includes; /*!< Include other contexts */ + struct ast_ignorepats ignorepats; /*!< Patterns for which to continue playing dialtone */ + struct ast_sws alts; /*!< Alternative switches */ char *registrar; /*!< Registrar -- make sure you malloc this, as the registrar may have to survive module unloads */ int refcount; /*!< each module that would have created this context should inc/dec this as appropriate */ int autohints; /*!< Whether autohints support is enabled or not */ - AST_LIST_HEAD_NOLOCK(, ast_sw) alts; /*!< Alternative switches */ ast_mutex_t macrolock; /*!< A lock to implement "exclusive" macros - held whilst a call is executing in the macro */ char name[0]; /*!< Name of the context */ }; @@ -1001,14 +973,6 @@ int check_contexts(char *file, int line ) } #endif -static inline int include_valid(struct ast_include *i) -{ - if (!i->hastime) - return 1; - - return ast_check_timing(&(i->timing)); -} - static void pbx_destroy(struct ast_pbx *p) { ast_free(p); @@ -2399,12 +2363,12 @@ struct fake_context /* this struct is purely for matching in the hashtab */ struct ast_hashtab *root_table; struct match_char *pattern_tree; struct ast_context *next; - struct ast_include *includes; - struct ast_ignorepat *ignorepats; + struct ast_includes includes; + struct ast_ignorepats ignorepats; + struct ast_sws alts; const char *registrar; int refcount; int autohints; - AST_LIST_HEAD_NOLOCK(, ast_sw) alts; ast_mutex_t macrolock; char name[256]; }; @@ -2459,11 +2423,10 @@ struct ast_exten *pbx_find_extension(struct ast_channel *chan, int x, res; struct ast_context *tmp = NULL; struct ast_exten *e = NULL, *eroot = NULL; - struct ast_include *i = NULL; - struct ast_sw *sw = NULL; struct ast_exten pattern = {NULL, }; struct scoreboard score = {0, }; struct ast_str *tmpdata = NULL; + int idx; pattern.label = label; pattern.priority = priority; @@ -2683,23 +2646,28 @@ struct ast_exten *pbx_find_extension(struct ast_channel *chan, } /* Check alternative switches */ - AST_LIST_TRAVERSE(&tmp->alts, sw, list) { - struct ast_switch *asw = pbx_findswitch(sw->name); + for (idx = 0; idx < ast_context_switches_count(tmp); idx++) { + const struct ast_sw *sw = ast_context_switches_get(tmp, idx); + struct ast_switch *asw = pbx_findswitch(ast_get_switch_name(sw)); ast_switch_f *aswf = NULL; - char *datap; + const char *datap; if (!asw) { - ast_log(LOG_WARNING, "No such switch '%s'\n", sw->name); + ast_log(LOG_WARNING, "No such switch '%s'\n", ast_get_switch_name(sw)); continue; } /* Substitute variables now */ - if (sw->eval) { + if (ast_get_switch_eval(sw)) { if (!(tmpdata = ast_str_thread_get(&switch_data, 512))) { ast_log(LOG_WARNING, "Can't evaluate switch?!\n"); continue; } - pbx_substitute_variables_helper(chan, sw->data, ast_str_buffer(tmpdata), ast_str_size(tmpdata)); + pbx_substitute_variables_helper(chan, ast_get_switch_data(sw), + ast_str_buffer(tmpdata), ast_str_size(tmpdata)); + datap = ast_str_buffer(tmpdata); + } else { + datap = ast_get_switch_data(sw); } /* equivalent of extension_match_core() at the switch level */ @@ -2709,7 +2677,6 @@ struct ast_exten *pbx_find_extension(struct ast_channel *chan, aswf = asw->matchmore; else /* action == E_MATCH */ aswf = asw->exists; - datap = sw->eval ? ast_str_buffer(tmpdata) : sw->data; if (!aswf) res = 0; else { @@ -2729,9 +2696,11 @@ struct ast_exten *pbx_find_extension(struct ast_channel *chan, } q->incstack[q->stacklen++] = tmp->name; /* Setup the stack */ /* Now try any includes we have in this context */ - for (i = tmp->includes; i; i = i->next) { + for (idx = 0; idx < ast_context_includes_count(tmp); idx++) { + const struct ast_include *i = ast_context_includes_get(tmp, idx); + if (include_valid(i)) { - if ((e = pbx_find_extension(chan, bypass, q, i->rname, exten, priority, label, callerid, action))) { + if ((e = pbx_find_extension(chan, bypass, q, include_rname(i), exten, priority, label, callerid, action))) { #ifdef NEED_DEBUG_HERE ast_log(LOG_NOTICE,"Returning recursive match of %s\n", e->exten); #endif @@ -4786,24 +4755,24 @@ int ast_context_remove_include(const char *context, const char *include, const c */ int ast_context_remove_include2(struct ast_context *con, const char *include, const char *registrar) { - struct ast_include *i, *pi = NULL; int ret = -1; + int idx; ast_wrlock_context(con); /* find our include */ - for (i = con->includes; i; pi = i, i = i->next) { - if (!strcmp(i->name, include) && - (!registrar || !strcmp(i->registrar, registrar))) { + for (idx = 0; idx < ast_context_includes_count(con); idx++) { + struct ast_include *i = AST_VECTOR_GET(&con->includes, idx); + + if (!strcmp(ast_get_include_name(i), include) && + (!registrar || !strcmp(ast_get_include_registrar(i), registrar))) { + /* remove from list */ ast_verb(3, "Removing inclusion of context '%s' in context '%s; registrar=%s'\n", include, ast_get_context_name(con), registrar); - if (pi) - pi->next = i->next; - else - con->includes = i->next; + AST_VECTOR_REMOVE_ORDERED(&con->includes, idx); + /* free include and return */ - ast_destroy_timing(&(i->timing)); - ast_free(i); + include_free(i); ret = 0; break; } @@ -4843,24 +4812,29 @@ int ast_context_remove_switch(const char *context, const char *sw, const char *d */ int ast_context_remove_switch2(struct ast_context *con, const char *sw, const char *data, const char *registrar) { - struct ast_sw *i; + int idx; int ret = -1; ast_wrlock_context(con); /* walk switches */ - AST_LIST_TRAVERSE_SAFE_BEGIN(&con->alts, i, list) { - if (!strcmp(i->name, sw) && !strcmp(i->data, data) && - (!registrar || !strcmp(i->registrar, registrar))) { + for (idx = 0; idx < ast_context_switches_count(con); idx++) { + struct ast_sw *i = AST_VECTOR_GET(&con->alts, idx); + + if (!strcmp(ast_get_switch_name(i), sw) && + !strcmp(ast_get_switch_data(i), data) && + (!registrar || !strcmp(ast_get_switch_registrar(i), registrar))) { + /* found, remove from list */ ast_verb(3, "Removing switch '%s' from context '%s; registrar=%s'\n", sw, ast_get_context_name(con), registrar); - AST_LIST_REMOVE_CURRENT(list); - ast_free(i); /* free switch and return */ + AST_VECTOR_REMOVE_ORDERED(&con->alts, idx); + + /* free switch and return */ + sw_free(i); ret = 0; break; } } - AST_LIST_TRAVERSE_SAFE_END; ast_unlock_context(con); @@ -5400,7 +5374,7 @@ static void print_ext(struct ast_exten *e, char * buf, int buflen) } /* XXX not verified */ -static int show_dialplan_helper(int fd, const char *context, const char *exten, struct dialplan_counters *dpc, struct ast_include *rinclude, int includecount, const char *includes[]) +static int show_dialplan_helper(int fd, const char *context, const char *exten, struct dialplan_counters *dpc, const struct ast_include *rinclude, int includecount, const char *includes[]) { struct ast_context *c = NULL; int res = 0, old_total_exten = dpc->total_exten; @@ -5409,9 +5383,8 @@ static int show_dialplan_helper(int fd, const char *context, const char *exten, /* walk all contexts ... */ while ( (c = ast_walk_contexts(c)) ) { + int idx; struct ast_exten *e; - struct ast_include *i; - struct ast_ignorepat *ip; #ifndef LOW_MEMORY char buf[1024], buf2[1024]; #else @@ -5498,8 +5471,9 @@ static int show_dialplan_helper(int fd, const char *context, const char *exten, } /* walk included and write info ... */ - i = NULL; - while ( (i = ast_walk_context_includes(c, i)) ) { + for (idx = 0; idx < ast_context_includes_count(c); idx++) { + const struct ast_include *i = ast_context_includes_get(c, idx); + snprintf(buf, sizeof(buf), "'%s'", ast_get_include_name(i)); if (exten) { /* Check all includes for the requested extension */ @@ -5528,10 +5502,11 @@ static int show_dialplan_helper(int fd, const char *context, const char *exten, } /* walk ignore patterns and write info ... */ - ip = NULL; - while ( (ip = ast_walk_context_ignorepats(c, ip)) ) { + for (idx = 0; idx < ast_context_ignorepats_count(c); idx++) { + const struct ast_ignorepat *ip = ast_context_ignorepats_get(c, idx); const char *ipname = ast_get_ignorepat_name(ip); char ignorepat[AST_MAX_EXTENSION]; + snprintf(buf, sizeof(buf), "'%s'", ipname); snprintf(ignorepat, sizeof(ignorepat), "_%s.", ipname); if (!exten || ast_extension_match(ignorepat, exten)) { @@ -5540,8 +5515,9 @@ static int show_dialplan_helper(int fd, const char *context, const char *exten, } } if (!rinclude) { - struct ast_sw *sw = NULL; - while ( (sw = ast_walk_context_switches(c, sw)) ) { + for (idx = 0; idx < ast_context_switches_count(c); idx++) { + const struct ast_sw *sw = ast_context_switches_get(c, idx); + snprintf(buf, sizeof(buf), "'%s/%s'", ast_get_switch_name(sw), ast_get_switch_data(sw)); @@ -5751,7 +5727,7 @@ static void manager_dpsendack(struct mansession *s, const struct message *m) static int manager_show_dialplan_helper(struct mansession *s, const struct message *m, const char *actionidtext, const char *context, const char *exten, struct dialplan_counters *dpc, - struct ast_include *rinclude) + const struct ast_include *rinclude) { struct ast_context *c; int res = 0, old_total_exten = dpc->total_exten; @@ -5772,9 +5748,8 @@ static int manager_show_dialplan_helper(struct mansession *s, const struct messa c = NULL; /* walk all contexts ... */ while ( (c = ast_walk_contexts(c)) ) { + int idx; struct ast_exten *e; - struct ast_include *i; - struct ast_ignorepat *ip; if (context && strcmp(ast_get_context_name(c), context) != 0) continue; /* not the name we want */ @@ -5829,8 +5804,9 @@ static int manager_show_dialplan_helper(struct mansession *s, const struct messa } } - i = NULL; /* walk included and write info ... */ - while ( (i = ast_walk_context_includes(c, i)) ) { + for (idx = 0; idx < ast_context_includes_count(c); idx++) { + const struct ast_include *i = ast_context_includes_get(c, idx); + if (exten) { /* Check all includes for the requested extension */ manager_show_dialplan_helper(s, m, actionidtext, ast_get_include_name(i), exten, dpc, i); @@ -5844,8 +5820,8 @@ static int manager_show_dialplan_helper(struct mansession *s, const struct messa } } - ip = NULL; /* walk ignore patterns and write info ... */ - while ( (ip = ast_walk_context_ignorepats(c, ip)) ) { + for (idx = 0; idx < ast_context_ignorepats_count(c); idx++) { + const struct ast_ignorepat *ip = ast_context_ignorepats_get(c, idx); const char *ipname = ast_get_ignorepat_name(ip); char ignorepat[AST_MAX_EXTENSION]; @@ -5859,8 +5835,9 @@ static int manager_show_dialplan_helper(struct mansession *s, const struct messa } } if (!rinclude) { - struct ast_sw *sw = NULL; - while ( (sw = ast_walk_context_switches(c, sw)) ) { + for (idx = 0; idx < ast_context_switches_count(c); idx++) { + const struct ast_sw *sw = ast_context_switches_get(c, idx); + if (!dpc->total_items++) manager_dpsendack(s, m); astman_append(s, "Event: ListDialplan\r\n%s", actionidtext); @@ -6108,8 +6085,9 @@ struct ast_context *ast_context_find_or_create(struct ast_context **extcontexts, tmp->root = NULL; tmp->root_table = NULL; tmp->registrar = ast_strdup(registrar); - tmp->includes = NULL; - tmp->ignorepats = NULL; + AST_VECTOR_INIT(&tmp->includes, 0); + AST_VECTOR_INIT(&tmp->ignorepats, 0); + AST_VECTOR_INIT(&tmp->alts, 0); tmp->refcount = 1; } else { ast_log(LOG_ERROR, "Danger! We failed to allocate a context for %s!\n", name); @@ -6160,30 +6138,37 @@ AST_LIST_HEAD_NOLOCK(store_hints, store_hint); static void context_merge_incls_swits_igps_other_registrars(struct ast_context *new, struct ast_context *old, const char *registrar) { - struct ast_include *i; - struct ast_ignorepat *ip; - struct ast_sw *sw; + int idx; ast_verb(3, "merging incls/swits/igpats from old(%s) to new(%s) context, registrar = %s\n", ast_get_context_name(old), ast_get_context_name(new), registrar); /* copy in the includes, switches, and ignorepats */ /* walk through includes */ - for (i = NULL; (i = ast_walk_context_includes(old, i)) ; ) { - if (strcmp(ast_get_include_registrar(i), registrar) == 0) + for (idx = 0; idx < ast_context_includes_count(old); idx++) { + const struct ast_include *i = ast_context_includes_get(old, idx); + + if (!strcmp(ast_get_include_registrar(i), registrar)) { continue; /* not mine */ + } ast_context_add_include2(new, ast_get_include_name(i), ast_get_include_registrar(i)); } /* walk through switches */ - for (sw = NULL; (sw = ast_walk_context_switches(old, sw)) ; ) { - if (strcmp(ast_get_switch_registrar(sw), registrar) == 0) + for (idx = 0; idx < ast_context_switches_count(old); idx++) { + const struct ast_sw *sw = ast_context_switches_get(old, idx); + + if (!strcmp(ast_get_switch_registrar(sw), registrar)) { continue; /* not mine */ + } ast_context_add_switch2(new, ast_get_switch_name(sw), ast_get_switch_data(sw), ast_get_switch_eval(sw), ast_get_switch_registrar(sw)); } /* walk thru ignorepats ... */ - for (ip = NULL; (ip = ast_walk_context_ignorepats(old, ip)); ) { - if (strcmp(ast_get_ignorepat_registrar(ip), registrar) == 0) + for (idx = 0; idx < ast_context_ignorepats_count(old); idx++) { + const struct ast_ignorepat *ip = ast_context_ignorepats_get(old, idx); + + if (strcmp(ast_get_ignorepat_registrar(ip), registrar) == 0) { continue; /* not mine */ + } ast_context_add_ignorepat2(new, ast_get_ignorepat_name(ip), ast_get_ignorepat_registrar(ip)); } } @@ -6580,54 +6565,32 @@ int ast_context_add_include2(struct ast_context *con, const char *value, const char *registrar) { struct ast_include *new_include; - char *c; - struct ast_include *i, *il = NULL; /* include, include_last */ - int length; - char *p; - - length = sizeof(struct ast_include); - length += 2 * (strlen(value) + 1); + int idx; /* allocate new include structure ... */ - if (!(new_include = ast_calloc(1, length))) + new_include = include_alloc(value, registrar); + if (!new_include) { return -1; - /* Fill in this structure. Use 'p' for assignments, as the fields - * in the structure are 'const char *' - */ - p = new_include->stuff; - new_include->name = p; - strcpy(p, value); - p += strlen(value) + 1; - new_include->rname = p; - strcpy(p, value); - /* Strip off timing info, and process if it is there */ - if ( (c = strchr(p, ',')) ) { - *c++ = '\0'; - new_include->hastime = ast_build_timing(&(new_include->timing), c); - } - new_include->next = NULL; - new_include->registrar = registrar; + } ast_wrlock_context(con); /* ... go to last include and check if context is already included too... */ - for (i = con->includes; i; i = i->next) { - if (!strcasecmp(i->name, new_include->name)) { - ast_destroy_timing(&(new_include->timing)); - ast_free(new_include); + for (idx = 0; idx < ast_context_includes_count(con); idx++) { + const struct ast_include *i = ast_context_includes_get(con, idx); + + if (!strcasecmp(ast_get_include_name(i), ast_get_include_name(new_include))) { + include_free(new_include); ast_unlock_context(con); errno = EEXIST; return -1; } - il = i; } /* ... include new context into context list, unlock, return */ - if (il) - il->next = new_include; - else - con->includes = new_include; - ast_verb(3, "Including context '%s' in context '%s'\n", new_include->name, ast_get_context_name(con)); + AST_VECTOR_APPEND(&con->includes, new_include); + ast_verb(3, "Including context '%s' in context '%s'\n", + ast_get_include_name(new_include), ast_get_context_name(con)); ast_unlock_context(con); @@ -6662,43 +6625,24 @@ int ast_context_add_switch(const char *context, const char *sw, const char *data int ast_context_add_switch2(struct ast_context *con, const char *value, const char *data, int eval, const char *registrar) { + int idx; struct ast_sw *new_sw; - struct ast_sw *i; - int length; - char *p; - - length = sizeof(struct ast_sw); - length += strlen(value) + 1; - if (data) - length += strlen(data); - length++; /* allocate new sw structure ... */ - if (!(new_sw = ast_calloc(1, length))) + if (!(new_sw = sw_alloc(value, data, eval, registrar))) { return -1; - /* ... fill in this structure ... */ - p = new_sw->stuff; - new_sw->name = p; - strcpy(new_sw->name, value); - p += strlen(value) + 1; - new_sw->data = p; - if (data) { - strcpy(new_sw->data, data); - p += strlen(data) + 1; - } else { - strcpy(new_sw->data, ""); - p++; } - new_sw->eval = eval; - new_sw->registrar = registrar; /* ... try to lock this context ... */ ast_wrlock_context(con); /* ... go to last sw and check if context is already swd too... */ - AST_LIST_TRAVERSE(&con->alts, i, list) { - if (!strcasecmp(i->name, new_sw->name) && !strcasecmp(i->data, new_sw->data)) { - ast_free(new_sw); + for (idx = 0; idx < ast_context_switches_count(con); idx++) { + const struct ast_sw *i = ast_context_switches_get(con, idx); + + if (!strcasecmp(ast_get_switch_name(i), ast_get_switch_name(new_sw)) && + !strcasecmp(ast_get_switch_data(i), ast_get_switch_data(new_sw))) { + sw_free(new_sw); ast_unlock_context(con); errno = EEXIST; return -1; @@ -6706,9 +6650,10 @@ int ast_context_add_switch2(struct ast_context *con, const char *value, } /* ... sw new context into context list, unlock, return */ - AST_LIST_INSERT_TAIL(&con->alts, new_sw, list); + AST_VECTOR_APPEND(&con->alts, new_sw); - ast_verb(3, "Including switch '%s/%s' in context '%s'\n", new_sw->name, new_sw->data, ast_get_context_name(con)); + ast_verb(3, "Including switch '%s/%s' in context '%s'\n", + ast_get_switch_name(new_sw), ast_get_switch_data(new_sw), ast_get_context_name(con)); ast_unlock_context(con); @@ -6734,24 +6679,20 @@ int ast_context_remove_ignorepat(const char *context, const char *ignorepat, con int ast_context_remove_ignorepat2(struct ast_context *con, const char *ignorepat, const char *registrar) { - struct ast_ignorepat *ip, *ipl = NULL; + int idx; ast_wrlock_context(con); - for (ip = con->ignorepats; ip; ip = ip->next) { - if (!strcmp(ip->pattern, ignorepat) && - (!registrar || (registrar == ip->registrar))) { - if (ipl) { - ipl->next = ip->next; - ast_free(ip); - } else { - con->ignorepats = ip->next; - ast_free(ip); - } + for (idx = 0; idx < ast_context_ignorepats_count(con); idx++) { + struct ast_ignorepat *ip = AST_VECTOR_GET(&con->ignorepats, idx); + + if (!strcmp(ast_get_ignorepat_name(ip), ignorepat) && + (!registrar || (registrar == ast_get_ignorepat_registrar(ip)))) { + AST_VECTOR_REMOVE_ORDERED(&con->ignorepats, idx); + ignorepat_free(ip); ast_unlock_context(con); return 0; } - ipl = ip; } ast_unlock_context(con); @@ -6778,41 +6719,29 @@ int ast_context_add_ignorepat(const char *context, const char *value, const char int ast_context_add_ignorepat2(struct ast_context *con, const char *value, const char *registrar) { - struct ast_ignorepat *ignorepat, *ignorepatc, *ignorepatl = NULL; - int length; - char *pattern; - length = sizeof(struct ast_ignorepat); - length += strlen(value) + 1; - if (!(ignorepat = ast_calloc(1, length))) + struct ast_ignorepat *ignorepat = ignorepat_alloc(value, registrar); + int idx; + + if (!ignorepat) { return -1; - /* The cast to char * is because we need to write the initial value. - * The field is not supposed to be modified otherwise. Also, gcc 4.2 - * sees the cast as dereferencing a type-punned pointer and warns about - * it. This is the workaround (we're telling gcc, yes, that's really - * what we wanted to do). - */ - pattern = (char *) ignorepat->pattern; - strcpy(pattern, value); - ignorepat->next = NULL; - ignorepat->registrar = registrar; + } + ast_wrlock_context(con); - for (ignorepatc = con->ignorepats; ignorepatc; ignorepatc = ignorepatc->next) { - ignorepatl = ignorepatc; - if (!strcasecmp(ignorepatc->pattern, value)) { + for (idx = 0; idx < ast_context_ignorepats_count(con); idx++) { + const struct ast_ignorepat *i = ast_context_ignorepats_get(con, idx); + + if (!strcasecmp(ast_get_ignorepat_name(i), value)) { /* Already there */ ast_unlock_context(con); - ast_free(ignorepat); + ignorepat_free(ignorepat); errno = EEXIST; return -1; } } - if (ignorepatl) - ignorepatl->next = ignorepat; - else - con->ignorepats = ignorepat; + AST_VECTOR_APPEND(&con->ignorepats, ignorepat); ast_unlock_context(con); - return 0; + return 0; } int ast_ignore_pattern(const char *context, const char *pattern) @@ -6823,10 +6752,12 @@ int ast_ignore_pattern(const char *context, const char *pattern) ast_rdlock_contexts(); con = ast_context_find(context); if (con) { - struct ast_ignorepat *pat; + int idx; - for (pat = con->ignorepats; pat; pat = pat->next) { - if (ast_extension_match(pat->pattern, pattern)) { + for (idx = 0; idx < ast_context_ignorepats_count(con); idx++) { + const struct ast_ignorepat *pat = ast_context_ignorepats_get(con, idx); + + if (ast_extension_match(ast_get_ignorepat_name(pat), pattern)) { ret = 1; break; } @@ -7829,22 +7760,21 @@ int ast_pbx_outgoing_app(const char *type, struct ast_format_cap *cap, const cha static void __ast_internal_context_destroy( struct ast_context *con) { - struct ast_include *tmpi; - struct ast_sw *sw; struct ast_exten *e, *el, *en; - struct ast_ignorepat *ipi; struct ast_context *tmp = con; - for (tmpi = tmp->includes; tmpi; ) { /* Free includes */ - struct ast_include *tmpil = tmpi; - tmpi = tmpi->next; - ast_free(tmpil); - } - for (ipi = tmp->ignorepats; ipi; ) { /* Free ignorepats */ - struct ast_ignorepat *ipl = ipi; - ipi = ipi->next; - ast_free(ipl); - } + /* Free includes */ + AST_VECTOR_CALLBACK_VOID(&tmp->includes, include_free); + AST_VECTOR_FREE(&tmp->includes); + + /* Free ignorepats */ + AST_VECTOR_CALLBACK_VOID(&tmp->ignorepats, ignorepat_free); + AST_VECTOR_FREE(&tmp->ignorepats); + + /* Free switches */ + AST_VECTOR_CALLBACK_VOID(&tmp->alts, sw_free); + AST_VECTOR_FREE(&tmp->alts); + if (tmp->registrar) ast_free(tmp->registrar); @@ -7856,8 +7786,6 @@ static void __ast_internal_context_destroy( struct ast_context *con) if (tmp->pattern_tree) destroy_pattern_tree(tmp->pattern_tree); - while ((sw = AST_LIST_REMOVE_HEAD(&tmp->alts, list))) - ast_free(sw); for (e = tmp->root; e;) { for (en = e->peer; en;) { el = en; @@ -7904,53 +7832,35 @@ void __ast_context_destroy(struct ast_context *list, struct ast_hashtab *context /* then search thru and remove any extens that match registrar. */ struct ast_hashtab_iter *exten_iter; struct ast_hashtab_iter *prio_iter; - struct ast_ignorepat *ip, *ipl = NULL, *ipn = NULL; - struct ast_include *i, *pi = NULL, *ni = NULL; - struct ast_sw *sw = NULL; + int idx; /* remove any ignorepats whose registrar matches */ - for (ip = tmp->ignorepats; ip; ip = ipn) { - ipn = ip->next; - if (!strcmp(ip->registrar, registrar)) { - if (ipl) { - ipl->next = ip->next; - ast_free(ip); - continue; /* don't change ipl */ - } else { - tmp->ignorepats = ip->next; - ast_free(ip); - continue; /* don't change ipl */ - } + for (idx = ast_context_ignorepats_count(tmp) - 1; idx >= 0; idx--) { + struct ast_ignorepat *ip = AST_VECTOR_GET(&tmp->ignorepats, idx); + + if (!strcmp(ast_get_ignorepat_registrar(ip), registrar)) { + AST_VECTOR_REMOVE_ORDERED(&tmp->ignorepats, idx); + ignorepat_free(ip); } - ipl = ip; } /* remove any includes whose registrar matches */ - for (i = tmp->includes; i; i = ni) { - ni = i->next; - if (strcmp(i->registrar, registrar) == 0) { - /* remove from list */ - if (pi) { - pi->next = i->next; - /* free include */ - ast_free(i); - continue; /* don't change pi */ - } else { - tmp->includes = i->next; - /* free include */ - ast_free(i); - continue; /* don't change pi */ - } + for (idx = ast_context_includes_count(tmp) - 1; idx >= 0; idx--) { + struct ast_include *i = AST_VECTOR_GET(&tmp->includes, idx); + + if (!strcmp(ast_get_include_registrar(i), registrar)) { + AST_VECTOR_REMOVE_ORDERED(&tmp->includes, idx); + include_free(i); } - pi = i; } /* remove any switches whose registrar matches */ - AST_LIST_TRAVERSE_SAFE_BEGIN(&tmp->alts, sw, list) { - if (strcmp(sw->registrar,registrar) == 0) { - AST_LIST_REMOVE_CURRENT(list); - ast_free(sw); + for (idx = ast_context_switches_count(tmp) - 1; idx >= 0; idx--) { + struct ast_sw *sw = AST_VECTOR_GET(&tmp->alts, idx); + + if (!strcmp(ast_get_switch_registrar(sw), registrar)) { + AST_VECTOR_REMOVE_ORDERED(&tmp->alts, idx); + sw_free(sw); } } - AST_LIST_TRAVERSE_SAFE_END; if (tmp->root_table) { /* it is entirely possible that the context is EMPTY */ exten_iter = ast_hashtab_start_traversal(tmp->root_table); @@ -8001,7 +7911,7 @@ void __ast_context_destroy(struct ast_context *list, struct ast_hashtab *context /* delete the context if it's registrar matches, is empty, has refcount of 1, */ /* it's not empty, if it has includes, ignorepats, or switches that are registered from another registrar. It's not empty if there are any extensions */ - if (strcmp(tmp->registrar, registrar) == 0 && tmp->refcount < 2 && !tmp->root && !tmp->ignorepats && !tmp->includes && AST_LIST_EMPTY(&tmp->alts)) { + if (strcmp(tmp->registrar, registrar) == 0 && tmp->refcount < 2 && !tmp->root && !ast_context_ignorepats_count(tmp) && !ast_context_includes_count(tmp) && !ast_context_switches_count(tmp)) { ast_debug(1, "delete ctx %s %s\n", tmp->name, tmp->registrar); ast_hashtab_remove_this_object(contexttab, tmp); @@ -8402,16 +8312,6 @@ const char *ast_get_extension_label(struct ast_exten *exten) return exten ? exten->label : NULL; } -const char *ast_get_include_name(struct ast_include *inc) -{ - return inc ? inc->name : NULL; -} - -const char *ast_get_ignorepat_name(struct ast_ignorepat *ip) -{ - return ip ? ip->pattern : NULL; -} - int ast_get_extension_priority(struct ast_exten *exten) { return exten ? exten->priority : -1; @@ -8430,16 +8330,6 @@ const char *ast_get_extension_registrar(struct ast_exten *e) return e ? e->registrar : NULL; } -const char *ast_get_include_registrar(struct ast_include *i) -{ - return i ? i->registrar : NULL; -} - -const char *ast_get_ignorepat_registrar(struct ast_ignorepat *ip) -{ - return ip ? ip->registrar : NULL; -} - int ast_get_extension_matchcid(struct ast_exten *e) { return e ? e->matchcid : 0; @@ -8460,26 +8350,6 @@ void *ast_get_extension_app_data(struct ast_exten *e) return e ? e->data : NULL; } -const char *ast_get_switch_name(struct ast_sw *sw) -{ - return sw ? sw->name : NULL; -} - -const char *ast_get_switch_data(struct ast_sw *sw) -{ - return sw ? sw->data : NULL; -} - -int ast_get_switch_eval(struct ast_sw *sw) -{ - return sw->eval; -} - -const char *ast_get_switch_registrar(struct ast_sw *sw) -{ - return sw ? sw->registrar : NULL; -} - /* * Walking functions ... */ @@ -8497,13 +8367,43 @@ struct ast_exten *ast_walk_context_extensions(struct ast_context *con, return exten->next; } -struct ast_sw *ast_walk_context_switches(struct ast_context *con, - struct ast_sw *sw) +const struct ast_sw *ast_walk_context_switches(const struct ast_context *con, + const struct ast_sw *sw) { - if (!sw) - return con ? AST_LIST_FIRST(&con->alts) : NULL; - else - return AST_LIST_NEXT(sw, list); + if (sw) { + int idx; + int next = 0; + + for (idx = 0; idx < ast_context_switches_count(con); idx++) { + const struct ast_sw *s = ast_context_switches_get(con, idx); + + if (next) { + return s; + } + + if (sw == s) { + next = 1; + } + } + + return NULL; + } + + if (!ast_context_switches_count(con)) { + return NULL; + } + + return ast_context_switches_get(con, 0); +} + +int ast_context_switches_count(const struct ast_context *con) +{ + return AST_VECTOR_SIZE(&con->alts); +} + +const struct ast_sw *ast_context_switches_get(const struct ast_context *con, int idx) +{ + return AST_VECTOR_GET(&con->alts, idx); } struct ast_exten *ast_walk_extension_priorities(struct ast_exten *exten, @@ -8512,36 +8412,103 @@ struct ast_exten *ast_walk_extension_priorities(struct ast_exten *exten, return priority ? priority->peer : exten; } -struct ast_include *ast_walk_context_includes(struct ast_context *con, - struct ast_include *inc) +const struct ast_include *ast_walk_context_includes(const struct ast_context *con, + const struct ast_include *inc) { - if (!inc) - return con ? con->includes : NULL; - else - return inc->next; + if (inc) { + int idx; + int next = 0; + + for (idx = 0; idx < ast_context_includes_count(con); idx++) { + const struct ast_include *include = AST_VECTOR_GET(&con->includes, idx); + + if (next) { + return include; + } + + if (inc == include) { + next = 1; + } + } + + return NULL; + } + + if (!ast_context_includes_count(con)) { + return NULL; + } + + return ast_context_includes_get(con, 0); } -struct ast_ignorepat *ast_walk_context_ignorepats(struct ast_context *con, - struct ast_ignorepat *ip) +int ast_context_includes_count(const struct ast_context *con) { - if (!ip) - return con ? con->ignorepats : NULL; - else - return ip->next; + return AST_VECTOR_SIZE(&con->includes); +} + +const struct ast_include *ast_context_includes_get(const struct ast_context *con, int idx) +{ + return AST_VECTOR_GET(&con->includes, idx); +} + +const struct ast_ignorepat *ast_walk_context_ignorepats(const struct ast_context *con, + const struct ast_ignorepat *ip) +{ + if (!con) { + return NULL; + } + + if (ip) { + int idx; + int next = 0; + + for (idx = 0; idx < ast_context_ignorepats_count(con); idx++) { + const struct ast_ignorepat *i = ast_context_ignorepats_get(con, idx); + + if (next) { + return i; + } + + if (ip == i) { + next = 1; + } + } + + return NULL; + } + + if (!ast_context_ignorepats_count(con)) { + return NULL; + } + + return ast_context_ignorepats_get(con, 0); +} + +int ast_context_ignorepats_count(const struct ast_context *con) +{ + return AST_VECTOR_SIZE(&con->ignorepats); +} + +const struct ast_ignorepat *ast_context_ignorepats_get(const struct ast_context *con, int idx) +{ + return AST_VECTOR_GET(&con->ignorepats, idx); } int ast_context_verify_includes(struct ast_context *con) { - struct ast_include *inc = NULL; + int idx; int res = 0; - while ( (inc = ast_walk_context_includes(con, inc)) ) { - if (ast_context_find(inc->rname)) + for (idx = 0; idx < ast_context_includes_count(con); idx++) { + const struct ast_include *inc = ast_context_includes_get(con, idx); + + if (ast_context_find(include_rname(inc))) { continue; + } res = -1; ast_log(LOG_WARNING, "Context '%s' tries to include nonexistent context '%s'\n", - ast_get_context_name(con), inc->rname); + ast_get_context_name(con), include_rname(inc)); break; } diff --git a/main/pbx_ignorepat.c b/main/pbx_ignorepat.c new file mode 100644 index 000000000..1a2232c57 --- /dev/null +++ b/main/pbx_ignorepat.c @@ -0,0 +1,82 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2016, CFWare, LLC + * + * Corey Farrell <git@cfware.com> + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +/*! \file + * + * \brief Dialplan context ignorepat routines. + * + * \author Corey Farrell <git@cfware.com> + */ + +/*** MODULEINFO + <support_level>core</support_level> + ***/ + +#include "asterisk.h" + +ASTERISK_REGISTER_FILE() + +#include "asterisk/_private.h" +#include "asterisk/pbx.h" +#include "pbx_private.h" + +/*! \brief ast_ignorepat: Ignore patterns in dial plan */ +struct ast_ignorepat { + const char *registrar; + const char pattern[0]; +}; + +const char *ast_get_ignorepat_name(const struct ast_ignorepat *ip) +{ + return ip ? ip->pattern : NULL; +} + +const char *ast_get_ignorepat_registrar(const struct ast_ignorepat *ip) +{ + return ip ? ip->registrar : NULL; +} + +struct ast_ignorepat *ignorepat_alloc(const char *value, const char *registrar) +{ + struct ast_ignorepat *ignorepat; + int length = strlen(value) + 1; + char *pattern; + + /* allocate new include structure ... */ + ignorepat = ast_calloc(1, sizeof(*ignorepat) + length); + if (!ignorepat) { + return NULL; + } + + /* The cast to char * is because we need to write the initial value. + * The field is not supposed to be modified otherwise. Also, gcc 4.2 + * sees the cast as dereferencing a type-punned pointer and warns about + * it. This is the workaround (we're telling gcc, yes, that's really + * what we wanted to do). + */ + pattern = (char *) ignorepat->pattern; + strcpy(pattern, value); + ignorepat->registrar = registrar; + + return ignorepat; +} + +void ignorepat_free(struct ast_ignorepat *ip) +{ + ast_free(ip); +} diff --git a/main/pbx_include.c b/main/pbx_include.c new file mode 100644 index 000000000..46a41fb20 --- /dev/null +++ b/main/pbx_include.c @@ -0,0 +1,112 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2016, CFWare, LLC + * + * Corey Farrell <git@cfware.com> + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +/*! \file + * + * \brief Dialplan context include routines. + * + * \author Corey Farrell <git@cfware.com> + */ + +/*** MODULEINFO + <support_level>core</support_level> + ***/ + +#include "asterisk.h" + +ASTERISK_REGISTER_FILE() + +#include "asterisk/_private.h" +#include "asterisk/pbx.h" +#include "pbx_private.h" + +/*! ast_include: include= support in extensions.conf */ +struct ast_include { + const char *name; + /*! Context to include */ + const char *rname; + /*! Registrar */ + const char *registrar; + /*! If time construct exists */ + int hastime; + /*! time construct */ + struct ast_timing timing; + char stuff[0]; +}; + +const char *ast_get_include_name(const struct ast_include *inc) +{ + return inc ? inc->name : NULL; +} + +const char *include_rname(const struct ast_include *inc) +{ + return inc ? inc->rname : NULL; +} + +const char *ast_get_include_registrar(const struct ast_include *inc) +{ + return inc ? inc->registrar : NULL; +} + +int include_valid(const struct ast_include *inc) +{ + if (!inc->hastime) { + return 1; + } + + return ast_check_timing(&(inc->timing)); +} + +struct ast_include *include_alloc(const char *value, const char *registrar) +{ + struct ast_include *new_include; + char *c; + int valuebufsz = strlen(value) + 1; + char *p; + + /* allocate new include structure ... */ + new_include = ast_calloc(1, sizeof(*new_include) + (valuebufsz * 2)); + if (!new_include) { + return NULL; + } + + /* Fill in this structure. Use 'p' for assignments, as the fields + * in the structure are 'const char *' + */ + p = new_include->stuff; + new_include->name = p; + strcpy(p, value); + p += valuebufsz; + new_include->rname = p; + strcpy(p, value); + /* Strip off timing info, and process if it is there */ + if ((c = strchr(p, ',')) ) { + *c++ = '\0'; + new_include->hastime = ast_build_timing(&(new_include->timing), c); + } + new_include->registrar = registrar; + + return new_include; +} + +void include_free(struct ast_include *inc) +{ + ast_destroy_timing(&(inc->timing)); + ast_free(inc); +} diff --git a/main/pbx_private.h b/main/pbx_private.h index e09194188..da1060e0e 100644 --- a/main/pbx_private.h +++ b/main/pbx_private.h @@ -31,6 +31,30 @@ void set_ext_pri(struct ast_channel *c, const char *exten, int pri); /*! pbx.c function needed by pbx_app.c */ void unreference_cached_app(struct ast_app *app); +/*! pbx_ignorepat.c */ +struct ast_ignorepat; +AST_VECTOR(ast_ignorepats, struct ast_ignorepat *); + +struct ast_ignorepat *ignorepat_alloc(const char *value, const char *registrar); +void ignorepat_free(struct ast_ignorepat *ip); + +/*! pbx_includes.c */ +struct ast_include; +AST_VECTOR(ast_includes, struct ast_include *); + +/*! Allocate and initialize an ast_include. */ +struct ast_include *include_alloc(const char *value, const char *registrar); +/*! Free an ast_include and associated data. */ +void include_free(struct ast_include *inc); +int include_valid(const struct ast_include *inc); +const char *include_rname(const struct ast_include *inc); + +/*! pbx_sw.c */ +struct ast_sw; +AST_VECTOR(ast_sws, struct ast_sw *); +struct ast_sw *sw_alloc(const char *value, const char *data, int eval, const char *registrar); +void sw_free(struct ast_sw *sw); + /*! pbx_builtins.c functions needed by pbx.c */ int indicate_congestion(struct ast_channel *, const char *); int indicate_busy(struct ast_channel *, const char *); diff --git a/main/pbx_sw.c b/main/pbx_sw.c new file mode 100644 index 000000000..0490ac6a2 --- /dev/null +++ b/main/pbx_sw.c @@ -0,0 +1,107 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2016, CFWare, LLC + * + * Corey Farrell <git@cfware.com> + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +/*! \file + * + * \brief Dialplan switch routines. + * + * \author Corey Farrell <git@cfware.com> + */ + +/*** MODULEINFO + <support_level>core</support_level> + ***/ + +#include "asterisk.h" + +ASTERISK_REGISTER_FILE() + +#include "asterisk/_private.h" +#include "asterisk/pbx.h" +#include "pbx_private.h" + +/*! \brief ast_sw: Switch statement in extensions.conf */ +struct ast_sw { + const char *name; + /*! Registrar */ + const char *registrar; + /*! Data load */ + const char *data; + int eval; + AST_LIST_ENTRY(ast_sw) list; + char stuff[0]; +}; + +const char *ast_get_switch_name(const struct ast_sw *sw) +{ + return sw ? sw->name : NULL; +} + +const char *ast_get_switch_data(const struct ast_sw *sw) +{ + return sw ? sw->data : NULL; +} + +int ast_get_switch_eval(const struct ast_sw *sw) +{ + return sw->eval; +} + +const char *ast_get_switch_registrar(const struct ast_sw *sw) +{ + return sw ? sw->registrar : NULL; +} + +struct ast_sw *sw_alloc(const char *value, const char *data, int eval, const char *registrar) +{ + struct ast_sw *new_sw; + int length; + char *p; + + if (!data) { + data = ""; + } + length = sizeof(struct ast_sw); + length += strlen(value) + 1; + length += strlen(data) + 1; + + /* allocate new sw structure ... */ + if (!(new_sw = ast_calloc(1, length))) { + return NULL; + } + + /* ... fill in this structure ... */ + p = new_sw->stuff; + new_sw->name = p; + strcpy(p, value); + + p += strlen(value) + 1; + new_sw->data = p; + strcpy(p, data); + + new_sw->eval = eval; + new_sw->registrar = registrar; + + return new_sw; +} + +void sw_free(struct ast_sw *sw) +{ + ast_free(sw); +} + diff --git a/main/rtp_engine.c b/main/rtp_engine.c index 11e94c699..feadda3d3 100644 --- a/main/rtp_engine.c +++ b/main/rtp_engine.c @@ -2690,6 +2690,11 @@ int ast_rtp_engine_init(void) /* Opus and VP8 */ set_next_mime_type(ast_format_opus, 0, "audio", "opus", 48000); set_next_mime_type(ast_format_vp8, 0, "video", "VP8", 90000); + /* DA SILK */ + set_next_mime_type(ast_format_silk8, 0, "audio", "silk", 8000); + set_next_mime_type(ast_format_silk12, 0, "audio", "silk", 12000); + set_next_mime_type(ast_format_silk16, 0, "audio", "silk", 16000); + set_next_mime_type(ast_format_silk24, 0, "audio", "silk", 24000); /* Define the static rtp payload mappings */ add_static_payload(0, ast_format_ulaw, 0); @@ -2743,6 +2748,11 @@ int ast_rtp_engine_init(void) add_static_payload(100, ast_format_vp8, 0); add_static_payload(107, ast_format_opus, 0); + add_static_payload(108, ast_format_silk8, 0); + add_static_payload(109, ast_format_silk12, 0); + add_static_payload(113, ast_format_silk16, 0); + add_static_payload(114, ast_format_silk24, 0); + return 0; } diff --git a/main/stasis_endpoints.c b/main/stasis_endpoints.c index 2d114210b..c32dbb44f 100644 --- a/main/stasis_endpoints.c +++ b/main/stasis_endpoints.c @@ -253,6 +253,7 @@ static struct ast_json *contactstatus_to_json(struct stasis_message *msg, const struct ast_endpoint_blob *obj = stasis_message_data(msg); struct ast_json *json_endpoint; struct ast_json *json_final; + const char *rtt; const struct timeval *tv = stasis_message_timestamp(msg); json_endpoint = ast_endpoint_snapshot_to_json(obj->snapshot, NULL); @@ -260,15 +261,30 @@ static struct ast_json *contactstatus_to_json(struct stasis_message *msg, const return NULL; } - json_final = ast_json_pack("{s: s, s: o, s: o, s: { s: s, s: s, s: s, s: s } } ", - "type", "ContactStatusChange", - "timestamp", ast_json_timeval(*tv, NULL), - "endpoint", json_endpoint, - "contact_info", - "uri", ast_json_string_get(ast_json_object_get(obj->blob, "uri")), - "contact_status", ast_json_string_get(ast_json_object_get(obj->blob, "contact_status")), - "aor", ast_json_string_get(ast_json_object_get(obj->blob, "aor")), - "roundtrip_usec", ast_json_string_get(ast_json_object_get(obj->blob, "roundtrip_usec"))); + /* The roundtrip time is optional. */ + rtt = ast_json_string_get(ast_json_object_get(obj->blob, "roundtrip_usec")); + if (!ast_strlen_zero(rtt)) { + json_final = ast_json_pack("{s: s, s: o, s: o, s: { s: s, s: s, s: s, s: s } } ", + "type", "ContactStatusChange", + "timestamp", ast_json_timeval(*tv, NULL), + "endpoint", json_endpoint, + "contact_info", + "uri", ast_json_string_get(ast_json_object_get(obj->blob, "uri")), + "contact_status", ast_json_string_get(ast_json_object_get(obj->blob, + "contact_status")), + "aor", ast_json_string_get(ast_json_object_get(obj->blob, "aor")), + "roundtrip_usec", rtt); + } else { + json_final = ast_json_pack("{s: s, s: o, s: o, s: { s: s, s: s, s: s } } ", + "type", "ContactStatusChange", + "timestamp", ast_json_timeval(*tv, NULL), + "endpoint", json_endpoint, + "contact_info", + "uri", ast_json_string_get(ast_json_object_get(obj->blob, "uri")), + "contact_status", ast_json_string_get(ast_json_object_get(obj->blob, + "contact_status")), + "aor", ast_json_string_get(ast_json_object_get(obj->blob, "aor"))); + } if (!json_final) { ast_json_unref(json_endpoint); } diff --git a/main/stasis_system.c b/main/stasis_system.c index 7e449b544..c3a4d8663 100644 --- a/main/stasis_system.c +++ b/main/stasis_system.c @@ -115,6 +115,7 @@ STASIS_MESSAGE_TYPE_DEFN(ast_cc_failure_type, STASIS_MESSAGE_TYPE_DEFN(ast_cc_monitorfailed_type, .to_ami = cc_monitorfailed_to_ami, ); +STASIS_MESSAGE_TYPE_DEFN(ast_cluster_discovery_type); void ast_system_publish_registry(const char *channeltype, const char *username, const char *domain, const char *status, const char *cause) { @@ -362,6 +363,7 @@ static void stasis_system_cleanup(void) STASIS_MESSAGE_TYPE_CLEANUP(ast_cc_recallcomplete_type); STASIS_MESSAGE_TYPE_CLEANUP(ast_cc_failure_type); STASIS_MESSAGE_TYPE_CLEANUP(ast_cc_monitorfailed_type); + STASIS_MESSAGE_TYPE_CLEANUP(ast_cluster_discovery_type); } /*! \brief Initialize the system level items for \ref stasis */ @@ -422,5 +424,9 @@ int ast_stasis_system_init(void) return -1; } + if (STASIS_MESSAGE_TYPE_INIT(ast_cluster_discovery_type) != 0) { + return -1; + } + return 0; } diff --git a/main/threadpool.c b/main/threadpool.c index 9cd33ab1a..6240b7329 100644 --- a/main/threadpool.c +++ b/main/threadpool.c @@ -1384,10 +1384,12 @@ struct ast_taskprocessor *ast_threadpool_serializer_group(const char *name, ao2_ref(ser, -1); return NULL; } - /* ser ref transferred to listener */ tps = ast_taskprocessor_create_with_listener(name, listener); - if (tps && shutdown_group) { + if (!tps) { + /* ser ref transferred to listener but not cleaned without tps */ + ao2_ref(ser, -1); + } else if (shutdown_group) { serializer_shutdown_group_inc(shutdown_group); } diff --git a/main/translate.c b/main/translate.c index 8d37e3724..43e6e29bd 100644 --- a/main/translate.c +++ b/main/translate.c @@ -494,7 +494,7 @@ struct ast_trans_pvt *ast_translator_build_path(struct ast_format *dst, struct a AST_RWLIST_UNLOCK(&translators); return NULL; } - if ((t->dst_codec.sample_rate == ast_format_get_sample_rate(dst)) && (t->dst_codec.type == ast_format_get_type(dst)) && (!strcmp(t->dst_codec.name, ast_format_get_name(dst)))) { + if ((t->dst_codec.sample_rate == ast_format_get_sample_rate(dst)) && (t->dst_codec.type == ast_format_get_type(dst))) { explicit_dst = dst; } if (!(cur = newpvt(t, explicit_dst))) { diff --git a/main/utils.c b/main/utils.c index 09839752b..46edf43ea 100644 --- a/main/utils.c +++ b/main/utils.c @@ -2420,7 +2420,7 @@ char *ast_utils_which(const char *binary, char *fullpath, size_t fullpath_size) return NULL; } -void ast_do_crash(void) +void DO_CRASH_NORETURN ast_do_crash(void) { #if defined(DO_CRASH) abort(); @@ -2433,7 +2433,7 @@ void ast_do_crash(void) } #if defined(AST_DEVMODE) -void __ast_assert_failed(int condition, const char *condition_str, const char *file, int line, const char *function) +void DO_CRASH_NORETURN __ast_assert_failed(int condition, const char *condition_str, const char *file, int line, const char *function) { /* * Attempt to put it into the logger, but hope that at least diff --git a/pbx/pbx_config.c b/pbx/pbx_config.c index eb2a64f70..0da4168f1 100644 --- a/pbx/pbx_config.c +++ b/pbx/pbx_config.c @@ -189,29 +189,49 @@ static char *handle_cli_dialplan_remove_include(struct ast_cli_entry *e, int cmd /*! \brief return true if 'name' is included by context c */ static int lookup_ci(struct ast_context *c, const char *name) { - struct ast_include *i = NULL; + int idx; + int ret = 0; - if (ast_rdlock_context(c)) /* error, skip */ + if (ast_rdlock_context(c)) { + /* error, skip */ return 0; - while ( (i = ast_walk_context_includes(c, i)) ) - if (!strcmp(name, ast_get_include_name(i))) + } + + for (idx = 0; idx < ast_context_includes_count(c); idx++) { + const struct ast_include *i = ast_context_includes_get(c, idx); + + if (!strcmp(name, ast_get_include_name(i))) { + ret = -1; break; + } + } ast_unlock_context(c); - return i ? -1 /* success */ : 0; + + return ret; } /*! \brief return true if 'name' is in the ignorepats for context c */ static int lookup_c_ip(struct ast_context *c, const char *name) { - struct ast_ignorepat *ip = NULL; + int idx; + int ret = 0; - if (ast_rdlock_context(c)) /* error, skip */ + if (ast_rdlock_context(c)) { + /* error, skip */ return 0; - while ( (ip = ast_walk_context_ignorepats(c, ip)) ) - if (!strcmp(name, ast_get_ignorepat_name(ip))) + } + + for (idx = 0; idx < ast_context_ignorepats_count(c); idx++) { + const struct ast_ignorepat *ip = ast_context_ignorepats_get(c, idx); + + if (!strcmp(name, ast_get_ignorepat_name(ip))) { + ret = -1; break; + } + } ast_unlock_context(c); - return ip ? -1 /* success */ : 0; + + return ret; } /*! \brief moves to the n-th word in the string, or empty string if none */ @@ -282,12 +302,13 @@ static char *complete_dialplan_remove_include(struct ast_cli_args *a) } /* walk contexts and their includes, return the n-th match */ while (!res && (c = ast_walk_contexts(c))) { - struct ast_include *i = NULL; + int idx; if (ast_rdlock_context(c)) /* error ? skip this one */ continue; - while ( !res && (i = ast_walk_context_includes(c, i)) ) { + for (idx = 0; idx < ast_context_includes_count(c); idx++) { + const struct ast_include *i = ast_context_includes_get(c, idx); const char *i_name = ast_get_include_name(i); struct ast_context *nc = NULL; int already_served = 0; @@ -906,9 +927,7 @@ static char *handle_cli_dialplan_save(struct ast_cli_entry *e, int cmd, struct a for (c = NULL; (c = ast_walk_contexts(c)); ) { int context_header_written = 0; struct ast_exten *ext, *last_written_e = NULL; - struct ast_include *i; - struct ast_ignorepat *ip; - struct ast_sw *sw; + int idx; /* try to lock context and fireout all info */ if (ast_rdlock_context(c)) { /* lock failure */ @@ -983,17 +1002,22 @@ static char *handle_cli_dialplan_save(struct ast_cli_entry *e, int cmd, struct a fprintf(output, "\n"); /* walk through includes */ - for (i = NULL; (i = ast_walk_context_includes(c, i)) ; ) { + for (idx = 0; idx < ast_context_includes_count(c); idx++) { + const struct ast_include *i = ast_context_includes_get(c, idx); + if (strcmp(ast_get_include_registrar(i), registrar) != 0) continue; /* not mine */ PUT_CTX_HDR; fprintf(output, "include => %s\n", ast_get_include_name(i)); } - if (ast_walk_context_includes(c, NULL)) + if (ast_context_includes_count(c)) { fprintf(output, "\n"); + } /* walk through switches */ - for (sw = NULL; (sw = ast_walk_context_switches(c, sw)) ; ) { + for (idx = 0; idx < ast_context_switches_count(c); idx++) { + const struct ast_sw *sw = ast_context_switches_get(c, idx); + if (strcmp(ast_get_switch_registrar(sw), registrar) != 0) continue; /* not mine */ PUT_CTX_HDR; @@ -1001,11 +1025,14 @@ static char *handle_cli_dialplan_save(struct ast_cli_entry *e, int cmd, struct a ast_get_switch_name(sw), ast_get_switch_data(sw)); } - if (ast_walk_context_switches(c, NULL)) + if (ast_context_switches_count(c)) { fprintf(output, "\n"); + } /* fireout ignorepats ... */ - for (ip = NULL; (ip = ast_walk_context_ignorepats(c, ip)); ) { + for (idx = 0; idx < ast_context_ignorepats_count(c); idx++) { + const struct ast_ignorepat *ip = ast_context_ignorepats_get(c, idx); + if (strcmp(ast_get_ignorepat_registrar(ip), registrar) != 0) continue; /* not mine */ PUT_CTX_HDR; @@ -1472,12 +1499,13 @@ static char *complete_dialplan_remove_ignorepat(struct ast_cli_args *a) } for (c = NULL; !ret && (c = ast_walk_contexts(c));) { - struct ast_ignorepat *ip; + int idx; if (ast_rdlock_context(c)) /* error, skip it */ continue; - - for (ip = NULL; !ret && (ip = ast_walk_context_ignorepats(c, ip));) { + for (idx = 0; idx < ast_context_ignorepats_count(c); idx++) { + const struct ast_ignorepat *ip = ast_context_ignorepats_get(c, idx); + if (partial_match(ast_get_ignorepat_name(ip), a->word, len) && ++which > a->n) { /* n-th match */ struct ast_context *cw = NULL; diff --git a/res/ael/pval.c b/res/ael/pval.c index ce9458c06..485f5ee79 100644 --- a/res/ael/pval.c +++ b/res/ael/pval.c @@ -4410,7 +4410,7 @@ static int context_used(struct ael_extension *exten_list, struct ast_context *co { struct ael_extension *exten; /* Check the simple elements first */ - if (ast_walk_context_extensions(context, NULL) || ast_walk_context_includes(context, NULL) || ast_walk_context_ignorepats(context, NULL) || ast_walk_context_switches(context, NULL)) { + if (ast_walk_context_extensions(context, NULL) || ast_context_includes_count(context) || ast_context_ignorepats_count(context) || ast_context_switches_count(context)) { return 1; } for (exten = exten_list; exten; exten = exten->next_exten) { diff --git a/res/ari/resource_channels.c b/res/ari/resource_channels.c index bce7c7def..35b757267 100644 --- a/res/ari/resource_channels.c +++ b/res/ari/resource_channels.c @@ -1776,6 +1776,9 @@ void ast_ari_channels_create(struct ast_variable *headers, originator = ast_channel_get_by_name(args->originator); if (originator) { request_cap = ao2_bump(ast_channel_nativeformats(originator)); + if (!ast_strlen_zero(args->app)) { + stasis_app_subscribe_channel(args->app, originator); + } } else if (!ast_strlen_zero(args->formats)) { char *format_name; char *formats_copy = ast_strdupa(args->formats); @@ -1816,13 +1819,20 @@ void ast_ari_channels_create(struct ast_variable *headers, chan_data->chan = ast_request(dialtech, request_cap, &assignedids, originator, dialdevice, &cause); ao2_cleanup(request_cap); - ast_channel_cleanup(originator); + if (!chan_data->chan) { ast_ari_response_alloc_failed(response); + ast_channel_cleanup(originator); chan_data_destroy(chan_data); return; } + if (!ast_strlen_zero(args->app)) { + stasis_app_subscribe_channel(args->app, chan_data->chan); + } + + ast_channel_cleanup(originator); + if (save_dialstring(chan_data->chan, stuff)) { ast_ari_response_alloc_failed(response); chan_data_destroy(chan_data); diff --git a/res/res_corosync.c b/res/res_corosync.c index 6642acd2c..675bb3307 100644 --- a/res/res_corosync.c +++ b/res/res_corosync.c @@ -47,11 +47,16 @@ ASTERISK_REGISTER_FILE(); #include "asterisk/app.h" #include "asterisk/stasis.h" #include "asterisk/stasis_message_router.h" +#include "asterisk/stasis_system.h" AST_RWLOCK_DEFINE_STATIC(event_types_lock); static void publish_mwi_to_stasis(struct ast_event *event); static void publish_device_state_to_stasis(struct ast_event *event); +static void publish_cluster_discovery_to_stasis(struct ast_event *event); + +/*! \brief All the nodes that we're aware of */ +static struct ao2_container *nodes; /*! \brief The internal topic used for message forwarding and pings */ static struct stasis_topic *corosync_aggregate_topic; @@ -65,6 +70,78 @@ static struct stasis_topic *corosync_topic(void) return corosync_aggregate_topic; } +struct corosync_node { + /*! The corosync ID */ + int id; + /*! The Asterisk EID */ + struct ast_eid eid; + /*! The IP address of the node */ + struct ast_sockaddr addr; +}; + +static struct corosync_node *corosync_node_alloc(struct ast_event *event) +{ + struct corosync_node *node; + + node = ao2_alloc_options(sizeof(*node), NULL, AO2_ALLOC_OPT_LOCK_NOLOCK); + if (!node) { + return NULL; + } + + memcpy(&node->eid, (struct ast_eid *)ast_event_get_ie_raw(event, AST_EVENT_IE_EID), sizeof(node->eid)); + node->id = ast_event_get_ie_uint(event, AST_EVENT_IE_NODE_ID); + ast_sockaddr_parse(&node->addr, ast_event_get_ie_str(event, AST_EVENT_IE_LOCAL_ADDR), PARSE_PORT_IGNORE); + + return node; +} + +static int corosync_node_hash_fn(const void *obj, const int flags) +{ + const struct corosync_node *node; + const int *id; + + switch (flags & OBJ_SEARCH_MASK) { + case OBJ_SEARCH_KEY: + id = obj; + break; + case OBJ_SEARCH_OBJECT: + node = obj; + id = &node->id; + break; + default: + ast_assert(0); + return 0; + } + return *id; +} + +static int corosync_node_cmp_fn(void *obj, void *arg, int flags) +{ + struct corosync_node *left = obj; + struct corosync_node *right = arg; + const int *id = arg; + int cmp; + + switch (flags & OBJ_SEARCH_MASK) { + case OBJ_SEARCH_OBJECT: + id = &right->id; + /* Fall through */ + case OBJ_SEARCH_KEY: + cmp = (left->id == *id); + break; + case OBJ_SEARCH_PARTIAL_KEY: + cmp = (left->id == right->id); + break; + default: + /* Sort can only work on something with a full or partial key. */ + ast_assert(0); + cmp = 1; + break; + } + return cmp ? CMP_MATCH : 0; +} + + /*! \brief A payload wrapper around a corosync ping event */ struct corosync_ping_payload { /*! The corosync ping event being passed over \ref stasis */ @@ -167,6 +244,12 @@ static struct { .topic_fn = corosync_topic, .message_type_fn = corosync_ping_message_type, .publish_to_stasis = publish_corosync_ping_to_stasis, }, + [AST_EVENT_CLUSTER_DISCOVERY] = { .name = "cluster_discovery", + .publish_default = 1, + .subscribe_default = 1, + .topic_fn = ast_system_topic, + .message_type_fn = ast_cluster_discovery_type, + .publish_to_stasis = publish_cluster_discovery_to_stasis, }, }; static struct { @@ -197,6 +280,97 @@ static corosync_cfg_callbacks_t cfg_callbacks = { .corosync_cfg_shutdown_callback = cfg_shutdown_cb, }; +/*! \brief Publish cluster discovery to \ref stasis */ +static void publish_cluster_discovery_to_stasis_full(struct corosync_node *node, int joined) +{ + struct ast_json *json; + struct ast_json_payload *payload; + struct stasis_message *message; + char eid[18]; + const char *addr; + + ast_eid_to_str(eid, sizeof(eid), &node->eid); + addr = ast_sockaddr_stringify_addr(&node->addr); + + ast_log(AST_LOG_NOTICE, "Node %u (%s) at %s %s the cluster\n", + node->id, + eid, + addr, + joined ? "joined" : "left"); + + json = ast_json_pack("{s: s, s: i, s: s, s: i}", + "address", addr, + "node_id", node->id, + "eid", eid, + "joined", joined); + if (!json) { + return; + } + + payload = ast_json_payload_create(json); + if (!payload) { + ast_json_unref(json); + return; + } + + message = stasis_message_create(ast_cluster_discovery_type(), payload); + if (!message) { + ast_json_unref(json); + ao2_ref(payload, -1); + return; + } + + stasis_publish(ast_system_topic(), message); + ast_json_unref(json); + ao2_ref(payload, -1); + ao2_ref(message, -1); +} + +static void send_cluster_notify(void); + +/*! \brief Publish a received cluster discovery \ref ast_event to \ref stasis */ +static void publish_cluster_discovery_to_stasis(struct ast_event *event) +{ + struct corosync_node *node; + int id = ast_event_get_ie_uint(event, AST_EVENT_IE_NODE_ID); + struct ast_eid *event_eid; + + ast_assert(ast_event_get_type(event) == AST_EVENT_CLUSTER_DISCOVERY); + + event_eid = (struct ast_eid *)ast_event_get_ie_raw(event, AST_EVENT_IE_EID); + if (!ast_eid_cmp(&ast_eid_default, event_eid)) { + /* Don't feed events back in that originated locally. */ + return; + } + + ao2_lock(nodes); + node = ao2_find(nodes, &id, OBJ_SEARCH_KEY | OBJ_NOLOCK); + if (node) { + /* We already know about this node */ + ao2_unlock(nodes); + ao2_ref(node, -1); + return; + } + + node = corosync_node_alloc(event); + if (!node) { + ao2_unlock(nodes); + return; + } + ao2_link_flags(nodes, node, OBJ_NOLOCK); + ao2_unlock(nodes); + + publish_cluster_discovery_to_stasis_full(node, 1); + + ao2_ref(node, -1); + + /* + * When we get news that someone else has joined, we need to let them + * know we exist as well. + */ + send_cluster_notify(); +} + /*! \brief Publish a received MWI \ref ast_event to \ref stasis */ static void publish_mwi_to_stasis(struct ast_event *event) { @@ -228,7 +402,7 @@ static void publish_mwi_to_stasis(struct ast_event *event) if (ast_publish_mwi_state_full(mailbox, context, (int)new_msgs, (int)old_msgs, NULL, event_eid)) { - char eid[16]; + char eid[18]; ast_eid_to_str(eid, sizeof(eid), event_eid); ast_log(LOG_WARNING, "Failed to publish MWI message for %s@%s from %s\n", mailbox, context, eid); @@ -255,7 +429,7 @@ static void publish_device_state_to_stasis(struct ast_event *event) } if (ast_publish_device_state_full(device, state, cachable, event_eid)) { - char eid[16]; + char eid[18]; ast_eid_to_str(eid, sizeof(eid), event_eid); ast_log(LOG_WARNING, "Failed to publish device state message for %s from %s\n", device, eid); @@ -342,10 +516,27 @@ static void cpg_deliver_cb(cpg_handle_t handle, const struct cpg_name *group_nam publish_handler(event); } -static void publish_to_corosync(struct stasis_message *message) +static void publish_event_to_corosync(struct ast_event *event) { cs_error_t cs_err; struct iovec iov; + + iov.iov_base = (void *)event; + iov.iov_len = ast_event_get_size(event); + + ast_debug(5, "Publishing event %s (%u) to corosync\n", + ast_event_get_type_name(event), ast_event_get_type(event)); + + /* The stasis subscription will only exist if we are configured to publish + * these events, so just send away. */ + if ((cs_err = cpg_mcast_joined(cpg_handle, CPG_TYPE_FIFO, &iov, 1)) != CS_OK) { + ast_log(LOG_WARNING, "CPG mcast failed (%u) for event %s (%u)\n", + cs_err, ast_event_get_type_name(event), ast_event_get_type(event)); + } +} + +static void publish_to_corosync(struct stasis_message *message) +{ struct ast_event *event; event = stasis_message_to_event(message); @@ -368,17 +559,7 @@ static void publish_to_corosync(struct stasis_message *message) ast_log(LOG_NOTICE, "Sending event PING from this server with EID: '%s'\n", buf); } - iov.iov_base = (void *)event; - iov.iov_len = ast_event_get_size(event); - - ast_debug(5, "Publishing event %s (%u) to corosync\n", - ast_event_get_type_name(event), ast_event_get_type(event)); - - /* The stasis subscription will only exist if we are configured to publish - * these events, so just send away. */ - if ((cs_err = cpg_mcast_joined(cpg_handle, CPG_TYPE_FIFO, &iov, 1)) != CS_OK) { - ast_log(LOG_WARNING, "CPG mcast failed (%u)\n", cs_err); - } + publish_event_to_corosync(event); } static void stasis_message_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message) @@ -410,9 +591,22 @@ static void cpg_confchg_cb(cpg_handle_t handle, const struct cpg_name *group_nam { unsigned int i; + + for (i = 0; i < left_list_entries; i++) { + const struct cpg_address *cpg_node = &left_list[i]; + struct corosync_node* node; + + node = ao2_find(nodes, &cpg_node->nodeid, OBJ_UNLINK | OBJ_SEARCH_KEY); + if (!node) { + continue; + } + + publish_cluster_discovery_to_stasis_full(node, 0); + ao2_ref(node, -1); + } + /* If any new nodes have joined, dump our cache of events we are publishing * that originated from this server. */ - if (!joined_list_entries) { return; } @@ -442,6 +636,45 @@ static void cpg_confchg_cb(cpg_handle_t handle, const struct cpg_name *group_nam } } +/*! \brief Informs the cluster of our EID and our IP addresses */ +static void send_cluster_notify(void) +{ + struct ast_event *event; + unsigned int node_id; + cs_error_t cs_err; + corosync_cfg_node_address_t corosync_addr; + int num_addrs = 0; + struct sockaddr *sa; + size_t sa_len; + char buf[128]; + int res; + + if ((cs_err = corosync_cfg_local_get(cfg_handle, &node_id)) != CS_OK) { + ast_log(LOG_WARNING, "Failed to extract Corosync node ID for this node. Not informing cluster of existance.\n"); + return; + } + + if (((cs_err = corosync_cfg_get_node_addrs(cfg_handle, node_id, 1, &num_addrs, &corosync_addr)) != CS_OK) || (num_addrs < 1)) { + ast_log(LOG_WARNING, "Failed to get local Corosync address. Not informing cluster of existance.\n"); + return; + } + + sa = (struct sockaddr *)corosync_addr.address; + sa_len = (size_t)corosync_addr.address_length; + if ((res = getnameinfo(sa, sa_len, buf, sizeof(buf), NULL, 0, NI_NUMERICHOST))) { + ast_log(LOG_WARNING, "Failed to determine name of local Corosync address: %s (%d). Not informing cluster of existance.\n", + gai_strerror(res), res); + return; + } + + event = ast_event_new(AST_EVENT_CLUSTER_DISCOVERY, + AST_EVENT_IE_NODE_ID, AST_EVENT_IE_PLTYPE_UINT, node_id, + AST_EVENT_IE_LOCAL_ADDR, AST_EVENT_IE_PLTYPE_STR, buf, + AST_EVENT_IE_END); + publish_event_to_corosync(event); + ast_free(event); +} + static void *dispatch_thread_handler(void *data) { cs_error_t cs_err; @@ -463,6 +696,7 @@ static void *dispatch_thread_handler(void *data) pfd[2].fd = dispatch_thread.alert_pipe[0]; + send_cluster_notify(); while (!dispatch_thread.stop) { int res; @@ -530,6 +764,7 @@ static void *dispatch_thread_handler(void *data) } ast_log(LOG_NOTICE, "Corosync recovery complete.\n"); + send_cluster_notify(); } } @@ -858,6 +1093,9 @@ static void cleanup_module(void) ast_log(LOG_ERROR, "Failed to finalize cfg (%d)\n", (int) cs_err); } cfg_handle = 0; + + ao2_cleanup(nodes); + nodes = NULL; } static int load_module(void) @@ -865,6 +1103,11 @@ static int load_module(void) cs_error_t cs_err; struct cpg_name name; + nodes = ao2_container_alloc(23, corosync_node_hash_fn, corosync_node_cmp_fn); + if (!nodes) { + goto failed; + } + corosync_aggregate_topic = stasis_topic_create("corosync_aggregate_topic"); if (!corosync_aggregate_topic) { ast_log(AST_LOG_ERROR, "Failed to create stasis topic for corosync\n"); diff --git a/res/res_fax.c b/res/res_fax.c index 347168e56..c301aff31 100644 --- a/res/res_fax.c +++ b/res/res_fax.c @@ -468,8 +468,6 @@ struct fax_gateway { struct fax_detect { /*! \brief the start of our timeout counter */ struct timeval timeout_start; - /*! \brief faxdetect timeout */ - int timeout; /*! \brief DSP Processor */ struct ast_dsp *dsp; /*! \brief original audio formats */ @@ -3539,13 +3537,13 @@ static void destroy_faxdetect(void *data) ast_dsp_free(faxdetect->dsp); faxdetect->dsp = NULL; } - ao2_ref(faxdetect->details, -1); + ao2_cleanup(faxdetect->details); ao2_cleanup(faxdetect->orig_format); } /*! \brief Create a new fax detect object. * \param chan the channel attaching to - * \param timeout remove framehook in this time if set + * \param timeout in ms to remove framehook in this time if not zero * \param flags required options * \return NULL or a fax gateway object */ @@ -3652,8 +3650,9 @@ static struct ast_frame *fax_detect_framehook(struct ast_channel *chan, struct a return f; } - if ((!ast_tvzero(faxdetect->timeout_start) && - (ast_tvdiff_ms(ast_tvnow(), faxdetect->timeout_start) > faxdetect->timeout))) { + if (!ast_tvzero(faxdetect->timeout_start) + && ast_tvdiff_ms(ast_tvnow(), faxdetect->timeout_start) > details->faxdetect_timeout) { + ast_debug(1, "FAXOPT(faxdetect) timeout on %s\n", ast_channel_name(chan)); ast_framehook_detach(chan, details->faxdetect_id); details->faxdetect_id = -1; return f; @@ -3701,30 +3700,36 @@ static struct ast_frame *fax_detect_framehook(struct ast_channel *chan, struct a } if (result) { - const char *target_context = S_OR(ast_channel_macrocontext(chan), ast_channel_context(chan)); + const char *target_context; + switch (result) { case 'f': case 't': + target_context = S_OR(ast_channel_macrocontext(chan), ast_channel_context(chan)); + ast_channel_unlock(chan); + ast_frfree(f); + f = &ast_null_frame; if (ast_exists_extension(chan, target_context, "fax", 1, S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) { - ast_channel_lock(chan); ast_verb(2, "Redirecting '%s' to fax extension due to %s detection\n", ast_channel_name(chan), (result == 'f') ? "CNG" : "T38"); pbx_builtin_setvar_helper(chan, "FAXEXTEN", ast_channel_exten(chan)); if (ast_async_goto(chan, target_context, "fax", 1)) { ast_log(LOG_NOTICE, "Failed to async goto '%s' into fax of '%s'\n", ast_channel_name(chan), target_context); } - ast_frfree(f); - f = &ast_null_frame; } else { - ast_channel_lock(chan); ast_log(LOG_NOTICE, "FAX %s detected but no fax extension in context (%s)\n", (result == 'f') ? "CNG" : "T38", target_context); } + ast_channel_lock(chan); + + ast_framehook_detach(chan, details->faxdetect_id); + details->faxdetect_id = -1; + break; + default: + break; } - ast_framehook_detach(chan, details->faxdetect_id); - details->faxdetect_id = -1; } return f; @@ -3732,7 +3737,7 @@ static struct ast_frame *fax_detect_framehook(struct ast_channel *chan, struct a /*! \brief Attach a faxdetect framehook object to a channel. * \param chan the channel to attach to - * \param timeout remove framehook in this time if set + * \param timeout in ms to remove framehook in this time if not zero * \return the faxdetect structure or NULL on error * \param flags required options * \retval -1 error @@ -4480,8 +4485,14 @@ static int acf_faxopt_write(struct ast_channel *chan, const char *cmd, char *dat details->gateway_timeout = 0; if (timeout) { unsigned int gwtimeout; - if (sscanf(timeout, "%u", &gwtimeout) == 1) { - details->gateway_timeout = gwtimeout * 1000; + + if (sscanf(timeout, "%30u", &gwtimeout) == 1) { + if (gwtimeout >= 0) { + details->gateway_timeout = gwtimeout * 1000; + } else { + ast_log(LOG_WARNING, "%s(%s) timeout cannot be negative. Ignoring timeout\n", + cmd, data); + } } else { ast_log(LOG_WARNING, "Unsupported timeout '%s' passed to FAXOPT(%s).\n", timeout, data); } @@ -4516,11 +4527,18 @@ static int acf_faxopt_write(struct ast_channel *chan, const char *cmd, char *dat if (ast_true(val) || !strcasecmp(val, "t38") || !strcasecmp(val, "cng")) { if (details->faxdetect_id < 0) { - if (timeout && (sscanf(timeout, "%u", &fdtimeout) == 1)) { - if (fdtimeout > 0) { - fdtimeout = fdtimeout * 1000; + if (timeout) { + if (sscanf(timeout, "%30u", &fdtimeout) == 1) { + if (fdtimeout >= 0) { + fdtimeout *= 1000; + } else { + ast_log(LOG_WARNING, "%s(%s) timeout cannot be negative. Ignoring timeout\n", + cmd, data); + fdtimeout = 0; + } } else { - ast_log(LOG_WARNING, "Timeout cannot be negative ignoring timeout\n"); + ast_log(LOG_WARNING, "Unsupported timeout '%s' passed to FAXOPT(%s).\n", + timeout, data); } } diff --git a/res/res_format_attr_silk.c b/res/res_format_attr_silk.c index f3f43821c..e69e3f43c 100644 --- a/res/res_format_attr_silk.c +++ b/res/res_format_attr_silk.c @@ -40,7 +40,6 @@ ASTERISK_REGISTER_FILE() * \note The only attribute that affects compatibility here is the sample rate. */ struct silk_attr { - unsigned int samplerate; unsigned int maxbitrate; unsigned int dtx; unsigned int fec; @@ -54,10 +53,15 @@ static void silk_destroy(struct ast_format *format) ast_free(attr); } +static void attr_init(struct silk_attr *attr) +{ + memset(attr, 0, sizeof(*attr)); +} + static int silk_clone(const struct ast_format *src, struct ast_format *dst) { struct silk_attr *original = ast_format_get_attribute_data(src); - struct silk_attr *attr = ast_calloc(1, sizeof(*attr)); + struct silk_attr *attr = ast_malloc(sizeof(*attr)); if (!attr) { return -1; @@ -65,6 +69,8 @@ static int silk_clone(const struct ast_format *src, struct ast_format *dst) if (original) { *attr = *original; + } else { + attr_init(attr); } ast_format_set_attribute_data(dst, attr); @@ -109,17 +115,17 @@ static void silk_generate_sdp_fmtp(const struct ast_format *format, unsigned int ast_str_append(str, 0, "a=fmtp:%u maxaveragebitrate=%u\r\n", payload, attr->maxbitrate); } - ast_str_append(str, 0, "a=fmtp:%u usedtx=%u\r\n", payload, attr->dtx); - ast_str_append(str, 0, "a=fmtp:%u useinbandfec=%u\r\n", payload, attr->fec); + if (attr->dtx) { + ast_str_append(str, 0, "a=fmtp:%u usedtx=%u\r\n", payload, attr->dtx); + } + if (attr->fec) { + ast_str_append(str, 0, "a=fmtp:%u useinbandfec=%u\r\n", payload, attr->fec); + } } static enum ast_format_cmp_res silk_cmp(const struct ast_format *format1, const struct ast_format *format2) { - struct silk_attr *attr1 = ast_format_get_attribute_data(format1); - struct silk_attr *attr2 = ast_format_get_attribute_data(format2); - - if (((!attr1 || !attr1->samplerate) && (!attr2 || !attr2->samplerate)) || - (attr1->samplerate == attr2->samplerate)) { + if (ast_format_get_sample_rate(format1) == ast_format_get_sample_rate(format2)) { return AST_FORMAT_CMP_EQUAL; } @@ -130,13 +136,10 @@ static struct ast_format *silk_getjoint(const struct ast_format *format1, const { struct silk_attr *attr1 = ast_format_get_attribute_data(format1); struct silk_attr *attr2 = ast_format_get_attribute_data(format2); - unsigned int samplerate; struct ast_format *jointformat; struct silk_attr *attr_res; - samplerate = attr1->samplerate & attr2->samplerate; - /* sample rate is the only attribute that has any bearing on if joint capabilities exist or not */ - if (samplerate) { + if (ast_format_get_sample_rate(format1) != ast_format_get_sample_rate(format2)) { return NULL; } @@ -145,22 +148,25 @@ static struct ast_format *silk_getjoint(const struct ast_format *format1, const return NULL; } attr_res = ast_format_get_attribute_data(jointformat); - attr_res->samplerate = samplerate; - /* Take the lowest max bitrate */ - attr_res->maxbitrate = MIN(attr1->maxbitrate, attr2->maxbitrate); + if (!attr1 || !attr2) { + attr_init(attr_res); + } else { + /* Take the lowest max bitrate */ + attr_res->maxbitrate = MIN(attr1->maxbitrate, attr2->maxbitrate); - /* Only do dtx if both sides want it. DTX is a trade off between - * computational complexity and bandwidth. */ - attr_res->dtx = attr1->dtx && attr2->dtx ? 1 : 0; + /* Only do dtx if both sides want it. DTX is a trade off between + * computational complexity and bandwidth. */ + attr_res->dtx = attr1->dtx && attr2->dtx ? 1 : 0; - /* Only do FEC if both sides want it. If a peer specifically requests not - * to receive with FEC, it may be a waste of bandwidth. */ - attr_res->fec = attr1->fec && attr2->fec ? 1 : 0; + /* Only do FEC if both sides want it. If a peer specifically requests not + * to receive with FEC, it may be a waste of bandwidth. */ + attr_res->fec = attr1->fec && attr2->fec ? 1 : 0; - /* Use the maximum packetloss percentage between the two attributes. This affects how - * much redundancy is used in the FEC. */ - attr_res->packetloss_percentage = MAX(attr1->packetloss_percentage, attr2->packetloss_percentage); + /* Use the maximum packetloss percentage between the two attributes. This affects how + * much redundancy is used in the FEC. */ + attr_res->packetloss_percentage = MAX(attr1->packetloss_percentage, attr2->packetloss_percentage); + } return jointformat; } @@ -183,9 +189,7 @@ static struct ast_format *silk_set(const struct ast_format *format, const char * } attr = ast_format_get_attribute_data(cloned); - if (!strcasecmp(name, "sample_rate")) { - attr->samplerate = val; - } else if (!strcasecmp(name, "max_bitrate")) { + if (!strcasecmp(name, "max_bitrate")) { attr->maxbitrate = val; } else if (!strcasecmp(name, "dtx")) { attr->dtx = val; @@ -205,9 +209,7 @@ static const void *silk_get(const struct ast_format *format, const char *name) struct silk_attr *attr = ast_format_get_attribute_data(format); unsigned int *val; - if (!strcasecmp(name, "sample_rate")) { - val = &attr->samplerate; - } else if (!strcasecmp(name, "max_bitrate")) { + if (!strcasecmp(name, "max_bitrate")) { val = &attr->maxbitrate; } else if (!strcasecmp(name, "dtx")) { val = &attr->dtx; diff --git a/res/res_pjsip.c b/res/res_pjsip.c index af2f93749..a1deb9e5f 100644 --- a/res/res_pjsip.c +++ b/res/res_pjsip.c @@ -600,6 +600,14 @@ detected. </para></description> </configOption> + <configOption name="fax_detect_timeout"> + <synopsis>How long into a call before fax_detect is disabled for the call</synopsis> + <description><para> + The option determines how many seconds into a call before the + fax_detect option is disabled for the call. Setting the value + to zero disables the timeout. + </para></description> + </configOption> <configOption name="t38_udptl_nat" default="no"> <synopsis>Whether NAT support is enabled on UDPTL sessions</synopsis> <description><para> @@ -4154,6 +4162,7 @@ long ast_sip_threadpool_queue_size(void) return ast_threadpool_queue_size(sip_threadpool); } +#ifdef TEST_FRAMEWORK AST_TEST_DEFINE(xml_sanitization_end_null) { char sanitized[8]; @@ -4204,6 +4213,7 @@ AST_TEST_DEFINE(xml_sanitization_exceeds_buffer) return AST_TEST_PASS; } +#endif /*! * \internal diff --git a/res/res_pjsip/pjsip_configuration.c b/res/res_pjsip/pjsip_configuration.c index a8b451767..16405ebce 100644 --- a/res/res_pjsip/pjsip_configuration.c +++ b/res/res_pjsip/pjsip_configuration.c @@ -105,6 +105,40 @@ static void endpoint_update_state(struct ast_endpoint *endpoint, enum ast_endpoi ast_devstate_changed(AST_DEVICE_UNKNOWN, AST_DEVSTATE_CACHABLE, "PJSIP/%s", ast_endpoint_get_resource(endpoint)); } +static void endpoint_publish_contact_status(struct ast_endpoint *endpoint, struct ast_sip_contact_status *contact) +{ + struct ast_json *blob; + char rtt[32]; + + snprintf(rtt, sizeof(rtt), "%" PRId64, contact->rtt); + blob = ast_json_pack("{s: s, s: s, s: s, s: s, s: s}", + "contact_status", ast_sip_get_contact_status_label(contact->status), + "aor", contact->aor, + "uri", contact->uri, + "roundtrip_usec", rtt, + "endpoint_name", ast_endpoint_get_resource(endpoint)); + if (blob) { + ast_endpoint_blob_publish(endpoint, ast_endpoint_contact_state_type(), blob); + ast_json_unref(blob); + } +} + +/*! \brief Callback function for publishing the status of an endpoint */ +static int persistent_endpoint_publish_status(void *obj, void *arg, int flags) +{ + struct sip_persistent_endpoint *persistent = obj; + struct ast_endpoint *endpoint = persistent->endpoint; + struct ast_sip_contact_status *status = arg; + + /* If the status' aor isn't one of the endpoint's, we skip */ + if (!strstr(persistent->aors, status->aor)) { + return 0; + } + + endpoint_publish_contact_status(endpoint, status); + return 0; +} + /*! \brief Callback function for changing the state of an endpoint */ static int persistent_endpoint_update_state(void *obj, void *arg, int flags) { @@ -112,37 +146,24 @@ static int persistent_endpoint_update_state(void *obj, void *arg, int flags) struct ast_endpoint *endpoint = persistent->endpoint; struct ast_sip_contact_status *status = arg; struct ao2_container *contacts; - struct ast_json *blob; - struct ao2_iterator i; + struct ao2_iterator iter; struct ast_sip_contact *contact; enum ast_endpoint_state state = AST_ENDPOINT_OFFLINE; - if (status) { - char rtt[32]; - - /* If the status' aor isn't one of the endpoint's, we skip */ - if (!strstr(persistent->aors, status->aor)) { - return 0; - } - - snprintf(rtt, sizeof(rtt), "%" PRId64, status->rtt); - blob = ast_json_pack("{s: s, s: s, s: s, s: s, s: s}", - "contact_status", ast_sip_get_contact_status_label(status->status), - "aor", status->aor, - "uri", status->uri, - "roundtrip_usec", rtt, - "endpoint_name", ast_endpoint_get_resource(endpoint)); - ast_endpoint_blob_publish(endpoint, ast_endpoint_contact_state_type(), blob); - ast_json_unref(blob); + /* If the status' aor isn't one of the endpoint's, we skip */ + if (!strstr(persistent->aors, status->aor)) { + return 0; } + endpoint_publish_contact_status(endpoint, status); + /* Find all the contacts for this endpoint. If ANY are available, * mark the endpoint as ONLINE. */ contacts = ast_sip_location_retrieve_contacts_from_aor_list(persistent->aors); if (contacts) { - i = ao2_iterator_init(contacts, 0); - while (state == AST_ENDPOINT_OFFLINE && (contact = ao2_iterator_next(&i))) { + iter = ao2_iterator_init(contacts, 0); + while (state == AST_ENDPOINT_OFFLINE && (contact = ao2_iterator_next(&iter))) { struct ast_sip_contact_status *contact_status; const char *contact_id = ast_sorcery_object_get_id(contact); @@ -155,11 +176,11 @@ static int persistent_endpoint_update_state(void *obj, void *arg, int flags) ao2_cleanup(contact_status); ao2_ref(contact, -1); } - ao2_iterator_destroy(&i); + ao2_iterator_destroy(&iter); ao2_ref(contacts, -1); } - endpoint_update_state(endpoint,state); + endpoint_update_state(endpoint, state); return 0; } @@ -181,7 +202,7 @@ static void persistent_endpoint_contact_created_observer(const void *object) contact_status->status = CREATED; - ast_verb(2, "Contact %s/%s has been created\n",contact->aor, contact->uri); + ast_verb(2, "Contact %s/%s has been created\n", contact->aor, contact->uri); ao2_callback(persistent_endpoints, OBJ_NODATA, persistent_endpoint_update_state, contact_status); ao2_cleanup(contact_status); @@ -195,7 +216,7 @@ static void persistent_endpoint_contact_deleted_observer(const void *object) contact_status = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), CONTACT_STATUS, ast_sorcery_object_get_id(contact)); if (!contact_status) { - ast_log(LOG_ERROR, "Unable to create ast_sip_contact_status for contact %s/%s\n", + ast_log(LOG_ERROR, "Unable to find ast_sip_contact_status for contact %s/%s\n", contact->aor, contact->uri); return; } @@ -222,13 +243,21 @@ static void persistent_endpoint_contact_status_observer(const void *object) { struct ast_sip_contact_status *contact_status = (struct ast_sip_contact_status *)object; + if (contact_status->refresh) { + /* We are only re-publishing the contact status. */ + ao2_callback(persistent_endpoints, OBJ_NODATA, + persistent_endpoint_publish_status, contact_status); + return; + } + /* If rtt_start is set (this is the outgoing OPTIONS), ignore. */ if (contact_status->rtt_start.tv_sec > 0) { return; } if (contact_status->status != contact_status->last_status) { - ast_verb(3, "Contact %s/%s is now %s. RTT: %.3f msec\n", contact_status->aor, contact_status->uri, + ast_verb(3, "Contact %s/%s is now %s. RTT: %.3f msec\n", + contact_status->aor, contact_status->uri, ast_sip_get_contact_status_label(contact_status->status), contact_status->rtt / 1000.0); @@ -239,19 +268,23 @@ static void persistent_endpoint_contact_status_observer(const void *object) ast_test_suite_event_notify("AOR_CONTACT_UPDATE", "Contact: %s\r\n" - "Status: %s", + "Status: %s", ast_sorcery_object_get_id(contact_status), ast_sip_get_contact_status_label(contact_status->status)); - ao2_callback(persistent_endpoints, OBJ_NODATA, persistent_endpoint_update_state, contact_status); + ao2_callback(persistent_endpoints, OBJ_NODATA, persistent_endpoint_update_state, + contact_status); } else { ast_debug(3, "Contact %s/%s status didn't change: %s, RTT: %.3f msec\n", - contact_status->aor, contact_status->uri, ast_sip_get_contact_status_label(contact_status->status), + contact_status->aor, contact_status->uri, + ast_sip_get_contact_status_label(contact_status->status), contact_status->rtt / 1000.0); } ast_statsd_log_full_va("PJSIP.contacts.%s.rtt", AST_STATSD_TIMER, - contact_status->status != AVAILABLE ? -1 : contact_status->rtt / 1000, 1.0, ast_sorcery_object_get_id(contact_status)); + contact_status->status != AVAILABLE ? -1 : contact_status->rtt / 1000, + 1.0, + ast_sorcery_object_get_id(contact_status)); } /*! \brief Observer for contacts so state can be updated on respective endpoints */ @@ -1816,6 +1849,7 @@ int ast_res_pjsip_initialize_configuration(void) ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "t38_udptl_ec", "none", t38udptl_ec_handler, t38udptl_ec_to_str, NULL, 0, 0); ast_sorcery_object_field_register(sip_sorcery, "endpoint", "t38_udptl_maxdatagram", "0", OPT_UINT_T, 0, FLDSET(struct ast_sip_endpoint, media.t38.maxdatagram)); ast_sorcery_object_field_register(sip_sorcery, "endpoint", "fax_detect", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, faxdetect)); + ast_sorcery_object_field_register(sip_sorcery, "endpoint", "fax_detect_timeout", "0", OPT_UINT_T, 0, FLDSET(struct ast_sip_endpoint, faxdetect_timeout)); ast_sorcery_object_field_register(sip_sorcery, "endpoint", "t38_udptl_nat", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.t38.nat)); ast_sorcery_object_field_register(sip_sorcery, "endpoint", "t38_udptl_ipv6", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.t38.ipv6)); ast_sorcery_object_field_register(sip_sorcery, "endpoint", "tone_zone", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, zone)); diff --git a/res/res_pjsip/pjsip_options.c b/res/res_pjsip/pjsip_options.c index dc3bce06f..5e0fc76cb 100644 --- a/res/res_pjsip/pjsip_options.c +++ b/res/res_pjsip/pjsip_options.c @@ -43,7 +43,6 @@ static const char *status_map [] = { [UNKNOWN] = "Unknown", [CREATED] = "Created", [REMOVED] = "Removed", - [UPDATED] = "Updated", }; static const char *short_status_map [] = { @@ -52,7 +51,6 @@ static const char *short_status_map [] = { [UNKNOWN] = "Unknown", [CREATED] = "Created", [REMOVED] = "Removed", - [UPDATED] = "Updated", }; const char *ast_sip_get_contact_status_label(const enum ast_sip_contact_status_type status) @@ -157,7 +155,7 @@ struct ast_sip_contact_status *ast_res_pjsip_find_or_create_contact_status(const * \brief Update an ast_sip_contact_status's elements. */ static void update_contact_status(const struct ast_sip_contact *contact, - enum ast_sip_contact_status_type value) + enum ast_sip_contact_status_type value, int is_contact_refresh) { RAII_VAR(struct ast_sip_contact_status *, status, NULL, ao2_cleanup); RAII_VAR(struct ast_sip_contact_status *, update, NULL, ao2_cleanup); @@ -169,6 +167,26 @@ static void update_contact_status(const struct ast_sip_contact *contact, return; } + if (is_contact_refresh + && status->status == CREATED) { + /* + * The contact status hasn't been updated since creation + * and we don't want to re-send a created status. + */ + if (contact->qualify_frequency + || status->rtt_start.tv_sec > 0) { + /* Ignore, the status will change soon. */ + return; + } + + /* + * Convert to a regular contact status update + * because the status may never change. + */ + is_contact_refresh = 0; + value = UNKNOWN; + } + update = ast_sorcery_alloc(ast_sip_get_sorcery(), CONTACT_STATUS, ast_sorcery_object_get_id(status)); if (!update) { @@ -178,22 +196,35 @@ static void update_contact_status(const struct ast_sip_contact *contact, } ast_string_field_set(update, uri, contact->uri); - update->last_status = status->status; - update->status = value; - - /* if the contact is available calculate the rtt as - the diff between the last start time and "now" */ - update->rtt = update->status == AVAILABLE && status->rtt_start.tv_sec > 0 ? - ast_tvdiff_us(ast_tvnow(), status->rtt_start) : 0; - update->rtt_start = ast_tv(0, 0); - - ast_test_suite_event_notify("AOR_CONTACT_QUALIFY_RESULT", - "Contact: %s\r\n" - "Status: %s\r\n" - "RTT: %" PRId64, - ast_sorcery_object_get_id(update), - ast_sip_get_contact_status_label(update->status), - update->rtt); + + if (is_contact_refresh) { + /* Copy everything just to set the refresh flag. */ + update->status = status->status; + update->last_status = status->last_status; + update->rtt = status->rtt; + update->rtt_start = status->rtt_start; + update->refresh = 1; + } else { + update->last_status = status->status; + update->status = value; + + /* + * if the contact is available calculate the rtt as + * the diff between the last start time and "now" + */ + update->rtt = update->status == AVAILABLE && status->rtt_start.tv_sec > 0 + ? ast_tvdiff_us(ast_tvnow(), status->rtt_start) + : 0; + update->rtt_start = ast_tv(0, 0); + + ast_test_suite_event_notify("AOR_CONTACT_QUALIFY_RESULT", + "Contact: %s\r\n" + "Status: %s\r\n" + "RTT: %" PRId64, + ast_sorcery_object_get_id(update), + ast_sip_get_contact_status_label(update->status), + update->rtt); + } if (ast_sorcery_update(ast_sip_get_sorcery(), update)) { ast_log(LOG_ERROR, "Unable to update ast_sip_contact_status for contact %s\n", @@ -306,10 +337,10 @@ static void qualify_contact_cb(void *token, pjsip_event *e) /* Fall through */ case PJSIP_EVENT_TRANSPORT_ERROR: case PJSIP_EVENT_TIMER: - update_contact_status(contact, UNAVAILABLE); + update_contact_status(contact, UNAVAILABLE, 0); break; case PJSIP_EVENT_RX_MSG: - update_contact_status(contact, AVAILABLE); + update_contact_status(contact, AVAILABLE, 0); break; } ao2_cleanup(contact); @@ -365,7 +396,7 @@ static int qualify_contact(struct ast_sip_endpoint *endpoint, struct ast_sip_con != PJ_SUCCESS) { ast_log(LOG_ERROR, "Unable to send request to qualify contact %s\n", contact->uri); - update_contact_status(contact, UNAVAILABLE); + update_contact_status(contact, UNAVAILABLE, 0); ao2_ref(contact, -1); return -1; } @@ -525,7 +556,7 @@ static void qualify_and_schedule(struct ast_sip_contact *contact) schedule_qualify(contact, contact->qualify_frequency * 1000); } else { - update_contact_status(contact, UNKNOWN); + update_contact_status(contact, UNKNOWN, 0); } } @@ -544,8 +575,7 @@ static void contact_created(const void *obj) */ static void contact_updated(const void *obj) { - update_contact_status((struct ast_sip_contact *) obj, UPDATED); - qualify_and_schedule((struct ast_sip_contact *) obj); + update_contact_status(obj, AVAILABLE, 1); } /*! @@ -574,8 +604,8 @@ static void contact_deleted(const void *obj) static const struct ast_sorcery_observer contact_observer = { .created = contact_created, + .updated = contact_updated, .deleted = contact_deleted, - .updated = contact_updated }; static pj_bool_t options_start(void) @@ -1051,7 +1081,7 @@ static void qualify_and_schedule_contact(struct ast_sip_contact *contact) if (contact->qualify_frequency) { schedule_qualify(contact, initial_interval); } else { - update_contact_status(contact, UNKNOWN); + update_contact_status(contact, UNKNOWN, 0); } } @@ -1234,7 +1264,7 @@ static void aor_observer_deleted(const void *obj) contacts = ast_sip_location_retrieve_aor_contacts(aor); if (contacts) { - ao2_callback(contacts, OBJ_NODATA, unschedule_contact_cb, NULL); + ao2_callback(contacts, OBJ_NODATA | OBJ_MULTIPLE, unschedule_contact_cb, NULL); ao2_ref(contacts, -1); } } diff --git a/res/res_pjsip_mwi.c b/res/res_pjsip_mwi.c index 9eba335b5..d86c96c74 100644 --- a/res/res_pjsip_mwi.c +++ b/res/res_pjsip_mwi.c @@ -976,38 +976,12 @@ static int create_mwi_subscriptions_for_endpoint(void *obj, void *arg, int flags { RAII_VAR(struct mwi_subscription *, aggregate_sub, NULL, ao2_cleanup); struct ast_sip_endpoint *endpoint = obj; - char *endpoint_aors, *aor_name, *mailboxes, *mailbox; - struct ao2_container *contacts = NULL; + char *mailboxes, *mailbox; if (ast_strlen_zero(endpoint->subscription.mwi.mailboxes)) { return 0; } - endpoint_aors = ast_strdupa(endpoint->aors); - - while ((aor_name = ast_strip(strsep(&endpoint_aors, ",")))) { - RAII_VAR(struct ast_sip_aor *, aor, ast_sip_location_retrieve_aor(aor_name), ao2_cleanup); - - if (!aor) { - continue; - } - - contacts = ast_sip_location_retrieve_aor_contacts(aor); - if (!contacts || (ao2_container_count(contacts) == 0)) { - ao2_cleanup(contacts); - contacts = NULL; - continue; - } - - break; - } - - if (!contacts) { - return 0; - } - - ao2_ref(contacts, -1); - if (endpoint->subscription.mwi.aggregate) { aggregate_sub = mwi_subscription_alloc(endpoint, 0, NULL); if (!aggregate_sub) { diff --git a/res/res_pjsip_pubsub.c b/res/res_pjsip_pubsub.c index 4e4180957..207fae04c 100644 --- a/res/res_pjsip_pubsub.c +++ b/res/res_pjsip_pubsub.c @@ -2965,11 +2965,14 @@ static struct ast_sip_publication *publish_request_initial(struct ast_sip_endpoi resource = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "inbound-publication", resource_name); if (!resource) { + ast_debug(1, "No 'inbound-publication' defined for resource '%s'\n", resource_name); pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 404, NULL, NULL, NULL); return NULL; } if (!ast_strlen_zero(resource->endpoint) && strcmp(resource->endpoint, ast_sorcery_object_get_id(endpoint))) { + ast_debug(1, "Resource %s has a defined endpoint '%s', but does not match endpoint '%s' that received the request\n", + resource_name, resource->endpoint, ast_sorcery_object_get_id(endpoint)); pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 403, NULL, NULL, NULL); return NULL; } @@ -2981,6 +2984,7 @@ static struct ast_sip_publication *publish_request_initial(struct ast_sip_endpoi } if (!event_configuration_name) { + ast_debug(1, "Event '%s' is not configured for '%s'\n", handler->event_name, resource_name); pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 404, NULL, NULL, NULL); return NULL; } diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c index 9f98e34b8..a773c16fc 100644 --- a/res/res_pjsip_session.c +++ b/res/res_pjsip_session.c @@ -792,12 +792,14 @@ static int delay_request(struct ast_sip_session *session, static pjmedia_sdp_session *generate_session_refresh_sdp(struct ast_sip_session *session) { pjsip_inv_session *inv_session = session->inv_session; - const pjmedia_sdp_session *previous_sdp; + const pjmedia_sdp_session *previous_sdp = NULL; - if (pjmedia_sdp_neg_was_answer_remote(inv_session->neg)) { - pjmedia_sdp_neg_get_active_remote(inv_session->neg, &previous_sdp); - } else { - pjmedia_sdp_neg_get_active_local(inv_session->neg, &previous_sdp); + if (inv_session->neg) { + if (pjmedia_sdp_neg_was_answer_remote(inv_session->neg)) { + pjmedia_sdp_neg_get_active_remote(inv_session->neg, &previous_sdp); + } else { + pjmedia_sdp_neg_get_active_local(inv_session->neg, &previous_sdp); + } } return create_local_sdp(inv_session, session, previous_sdp); } @@ -917,7 +919,9 @@ int ast_sip_session_refresh(struct ast_sip_session *session, if (generate_new_sdp) { /* SDP can only be generated if current negotiation has already completed */ - if (pjmedia_sdp_neg_get_state(inv_session->neg) != PJMEDIA_SDP_NEG_STATE_DONE) { + if (inv_session->neg + && pjmedia_sdp_neg_get_state(inv_session->neg) + != PJMEDIA_SDP_NEG_STATE_DONE) { ast_debug(3, "Delay session refresh with new SDP to %s because SDP negotiation is not yet done...\n", ast_sorcery_object_get_id(session->endpoint)); return delay_request(session, on_request_creation, on_sdp_creation, diff --git a/res/res_rtp_asterisk.c b/res/res_rtp_asterisk.c index 79aab1697..6cf69ef0d 100644 --- a/res/res_rtp_asterisk.c +++ b/res/res_rtp_asterisk.c @@ -1340,7 +1340,7 @@ static int ast_rtp_dtls_set_configuration(struct ast_rtp_instance *instance, con { struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); int res; -#ifndef HAVE_OPENSSL_ECDH_AUTO +#ifdef HAVE_OPENSSL_EC EC_KEY *ecdh; #endif @@ -1368,15 +1368,42 @@ static int ast_rtp_dtls_set_configuration(struct ast_rtp_instance *instance, con SSL_CTX_set_read_ahead(rtp->ssl_ctx, 1); -#ifdef HAVE_OPENSSL_ECDH_AUTO - SSL_CTX_set_ecdh_auto(rtp->ssl_ctx, 1); -#else +#ifdef HAVE_OPENSSL_EC + + if (!ast_strlen_zero(dtls_cfg->pvtfile)) { + BIO *bio = BIO_new_file(dtls_cfg->pvtfile, "r"); + if (bio != NULL) { + DH *dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL); + if (dh != NULL) { + if (SSL_CTX_set_tmp_dh(rtp->ssl_ctx, dh)) { + long options = SSL_OP_CIPHER_SERVER_PREFERENCE | + SSL_OP_SINGLE_DH_USE | SSL_OP_SINGLE_ECDH_USE; + options = SSL_CTX_set_options(rtp->ssl_ctx, options); + ast_verb(2, "DTLS DH initialized, PFS enabled\n"); + } + DH_free(dh); + } + BIO_free(bio); + } + } + /* enables AES-128 ciphers, to get AES-256 use NID_secp384r1 */ ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1); - if (ecdh) { - SSL_CTX_set_tmp_ecdh(rtp->ssl_ctx, ecdh); + if (ecdh != NULL) { + if (SSL_CTX_set_tmp_ecdh(rtp->ssl_ctx, ecdh)) { + #ifndef SSL_CTRL_SET_ECDH_AUTO + #define SSL_CTRL_SET_ECDH_AUTO 94 + #endif + /* SSL_CTX_set_ecdh_auto(rtp->ssl_ctx, on); requires OpenSSL 1.0.2 which wraps: */ + if (SSL_CTX_ctrl(rtp->ssl_ctx, SSL_CTRL_SET_ECDH_AUTO, 1, NULL)) { + ast_verb(2, "DTLS ECDH initialized (automatic), faster PFS enabled\n"); + } else { + ast_verb(2, "DTLS ECDH initialized (secp256r1), faster PFS enabled\n"); + } + } EC_KEY_free(ecdh); } -#endif + +#endif /* #ifdef HAVE_OPENSSL_EC */ rtp->dtls_verify = dtls_cfg->verify; @@ -2565,7 +2592,7 @@ static int ast_rtp_new(struct ast_rtp_instance *instance, /* Set default parameters on the newly created RTP structure */ rtp->ssrc = ast_random(); - rtp->seqno = ast_random() & 0xffff; + rtp->seqno = ast_random() & 0x7fff; rtp->strict_rtp_state = (strictrtp ? STRICT_RTP_LEARN : STRICT_RTP_OPEN); if (strictrtp) { rtp_learning_seq_init(&rtp->rtp_source_learn, (uint16_t)rtp->seqno); diff --git a/res/stasis/control.c b/res/stasis/control.c index b255477bf..219a2c6cd 100644 --- a/res/stasis/control.c +++ b/res/stasis/control.c @@ -881,6 +881,9 @@ end: return ret_bridge; } +static int bridge_channel_depart(struct stasis_app_control *control, + struct ast_channel *chan, void *data); + /*! * \brief after bridge callback for the dial bridge * @@ -890,6 +893,15 @@ end: static void dial_bridge_after_cb(struct ast_channel *chan, void *data) { struct stasis_app_control *control = data; + struct ast_bridge_channel *bridge_channel; + + ast_channel_lock(chan); + bridge_channel = ast_channel_get_bridge_channel(chan); + ast_channel_unlock(chan); + + ast_debug(3, "Channel: <%s> Reason: %d\n", ast_channel_name(control->channel), ast_channel_hangupcause(chan)); + + stasis_app_send_command_async(control, bridge_channel_depart, bridge_channel, __ao2_cleanup); control->bridge = NULL; } @@ -898,6 +910,7 @@ static void dial_bridge_after_cb_failed(enum ast_bridge_after_cb_reason reason, { struct stasis_app_control *control = data; + ast_debug(3, "Channel: <%s> Reason: %d\n", ast_channel_name(control->channel), reason); dial_bridge_after_cb(control->channel, data); } @@ -1443,6 +1456,8 @@ static int app_control_dial(struct stasis_app_control *control, return -1; } + ast_channel_publish_dial(NULL, chan, args->dialstring, NULL); + return 0; } diff --git a/utils/conf2ael.c b/utils/conf2ael.c index 76a3ad3f2..3136fe378 100644 --- a/utils/conf2ael.c +++ b/utils/conf2ael.c @@ -664,20 +664,8 @@ struct ast_exten *ast_walk_context_extensions(struct ast_context *con, struct as return NULL; } -struct ast_include *ast_walk_context_includes(struct ast_context *con, struct ast_include *inc); -struct ast_include *ast_walk_context_includes(struct ast_context *con, struct ast_include *inc) -{ - return NULL; -} - -struct ast_ignorepat *ast_walk_context_ignorepats(struct ast_context *con, struct ast_ignorepat *ip); -struct ast_ignorepat *ast_walk_context_ignorepats(struct ast_context *con, struct ast_ignorepat *ip) -{ - return NULL; -} - -struct ast_sw *ast_walk_context_switches(struct ast_context *con, struct ast_sw *sw); -struct ast_sw *ast_walk_context_switches(struct ast_context *con, struct ast_sw *sw) +const struct ast_include *ast_walk_context_includes(const struct ast_context *con, const struct ast_include *inc); +const struct ast_include *ast_walk_context_includes(const struct ast_context *con, const struct ast_include *inc) { return NULL; } diff --git a/utils/extconf.c b/utils/extconf.c index 48053aed6..8588d1a28 100644 --- a/utils/extconf.c +++ b/utils/extconf.c @@ -4381,6 +4381,19 @@ static struct ast_include *ast_walk_context_includes(struct ast_context *con, return inc->next; } +int ast_context_includes_count(struct ast_context *con); +int ast_context_includes_count(struct ast_context *con) +{ + int c = 0; + struct ast_include *inc = NULL; + + while ((inc = ast_walk_context_includes(con, inc))) { + c++; + } + + return c; +} + struct ast_include *localized_walk_context_includes(struct ast_context *con, struct ast_include *inc); struct ast_include *localized_walk_context_includes(struct ast_context *con, @@ -4389,6 +4402,31 @@ struct ast_include *localized_walk_context_includes(struct ast_context *con, return ast_walk_context_includes(con, inc); } +static struct ast_ignorepat *ast_walk_context_ignorepats(struct ast_context *con, + struct ast_ignorepat *ip); + +static struct ast_ignorepat *ast_walk_context_ignorepats(struct ast_context *con, + struct ast_ignorepat *ip) +{ + if (!ip) + return con ? con->ignorepats : NULL; + else + return ip->next; +} + +int ast_context_ignorepats_count(struct ast_context *con); +int ast_context_ignorepats_count(struct ast_context *con) +{ + int c = 0; + struct ast_ignorepat *ip = NULL; + + while ((ip = ast_walk_context_ignorepats(con, ip))) { + c++; + } + + return c; +} + static struct ast_sw *ast_walk_context_switches(struct ast_context *con, struct ast_sw *sw); @@ -4410,6 +4448,19 @@ struct ast_sw *localized_walk_context_switches(struct ast_context *con, return ast_walk_context_switches(con, sw); } +int ast_context_switches_count(struct ast_context *con); +int ast_context_switches_count(struct ast_context *con) +{ + int c = 0; + struct ast_sw *sw = NULL; + + while ((sw = ast_walk_context_switches(con, sw))) { + c++; + } + + return c; +} + static struct ast_context *ast_context_find(const char *name); |