Merge "cdr_mysql: fix UTC support"
authorJoshua Colp <jcolp@digium.com>
Thu, 22 Sep 2016 11:55:15 +0000 (06:55 -0500)
committerGerrit Code Review <gerrit2@gerrit.digium.api>
Thu, 22 Sep 2016 11:55:15 +0000 (06:55 -0500)
16 files changed:
CHANGES
configs/samples/res_odbc.conf.sample
configure
configure.ac
include/asterisk/autoconfig.h.in
include/asterisk/io.h
main/Makefile
main/asterisk.c
main/io.c
main/loader.c
main/logger.c
main/rtp_engine.c
makeopts.in
res/res_config_odbc.c
res/res_pjsip_multihomed.c
third-party/pjproject/patches/0004-resolver.c-Prevent-SERVFAIL-from-marking-name-server.patch [new file with mode: 0644]

diff --git a/CHANGES b/CHANGES
index 38228e3..da732a7 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -347,6 +347,10 @@ Core
    in the context. If enabled a device state hint will be automatically created
    with the name of the device.
 
+* If Asterisk is built with systemd support, and run under systemd, it will
+  notify systemd of its state using sd_notify. Use 'Type=notify' in
+  asterisk.service.
+
 Functions
 ------------------
  * The func_odbc global option "single_db_connection" default value has been
index a21e96d..42d89ec 100644 (file)
@@ -38,19 +38,6 @@ pre-connect => yes
 ; record.  The default is "select 1".
 ;sanitysql => select 1
 ;
-; On some databases, the connection times out and a reconnection will be
-; necessary.  This setting configures the amount of time a connection
-; may sit idle (in seconds) before a reconnection will be attempted.
-;idlecheck => 3600
-;
-; Should we use a single connection for all queries?  Most databases will
-; allow sharing the connection, though Sybase and MS SQL Server will not.
-;share_connections => yes
-;
-; If we aren't sharing connections, what is the maximum number of connections
-; that we should attempt?
-;limit => 5
-;
 ; The maximum number of connections to have open at any given time.
 ; This defaults to 1 and it is highly recommended to only set this higher
 ; if using a version of UnixODBC greater than 2.3.1.
index 51f0623..a5da739 100755 (executable)
--- a/configure
+++ b/configure
@@ -639,6 +639,11 @@ PBX_SYSLOG_FACILITY_LOG_DAEMON
 PBX_SYSLOG_FACILITY_LOG_CRON
 PBX_SYSLOG_FACILITY_LOG_AUTHPRIV
 PBX_SYSLOG_FACILITY_LOG_AUTH
+SYSTEMD_LIBS
+SYSTEMD_CFLAGS
+SYSTEMD_INCLUDE
+SYSTEMD_LIB
+PBX_SYSTEMD
 PBX_GENERIC_ODBC
 GENERIC_ODBC_INCLUDE
 GENERIC_ODBC_LIB
@@ -1320,6 +1325,7 @@ infodir
 docdir
 oldincludedir
 includedir
+runstatedir
 localstatedir
 sharedstatedir
 sysconfdir
@@ -1460,7 +1466,9 @@ PYTHONDEV_LIBS
 GMIME_CFLAGS
 GMIME_LIBS
 GTK2_CFLAGS
-GTK2_LIBS'
+GTK2_LIBS
+SYSTEMD_CFLAGS
+SYSTEMD_LIBS'
 
 
 # Initialize some variables set by options.
@@ -1499,6 +1507,7 @@ datadir='${datarootdir}'
 sysconfdir='${prefix}/etc'
 sharedstatedir='${prefix}/com'
 localstatedir='${prefix}/var'
+runstatedir='${localstatedir}/run'
 includedir='${prefix}/include'
 oldincludedir='/usr/include'
 docdir='${datarootdir}/doc/${PACKAGE_TARNAME}'
@@ -1751,6 +1760,15 @@ do
   | -silent | --silent | --silen | --sile | --sil)
     silent=yes ;;
 
+  -runstatedir | --runstatedir | --runstatedi | --runstated \
+  | --runstate | --runstat | --runsta | --runst | --runs \
+  | --run | --ru | --r)
+    ac_prev=runstatedir ;;
+  -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \
+  | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \
+  | --run=* | --ru=* | --r=*)
+    runstatedir=$ac_optarg ;;
+
   -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
     ac_prev=sbindir ;;
   -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
@@ -1888,7 +1906,7 @@ fi
 for ac_var in  exec_prefix prefix bindir sbindir libexecdir datarootdir \
                datadir sysconfdir sharedstatedir localstatedir includedir \
                oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
-               libdir localedir mandir
+               libdir localedir mandir runstatedir
 do
   eval ac_val=\$$ac_var
   # Remove trailing slashes.
@@ -2041,6 +2059,7 @@ Fine tuning of the installation directories:
   --sysconfdir=DIR        read-only single-machine data [PREFIX/etc]
   --sharedstatedir=DIR    modifiable architecture-independent data [PREFIX/com]
   --localstatedir=DIR     modifiable single-machine data [PREFIX/var]
+  --runstatedir=DIR       modifiable per-process data [LOCALSTATEDIR/run]
   --libdir=DIR            object code libraries [EPREFIX/lib]
   --includedir=DIR        C header files [PREFIX/include]
   --oldincludedir=DIR     C header files for non-gcc [/usr/include]
@@ -2213,6 +2232,10 @@ Some influential environment variables:
   GMIME_LIBS  linker flags for GMIME, overriding pkg-config
   GTK2_CFLAGS C compiler flags for GTK2, overriding pkg-config
   GTK2_LIBS   linker flags for GTK2, overriding pkg-config
+  SYSTEMD_CFLAGS
+              C compiler flags for SYSTEMD, overriding pkg-config
+  SYSTEMD_LIBS
+              linker flags for SYSTEMD, overriding pkg-config
 
 Use these variables to override the choices made by `configure' or to help
 it to find libraries and programs with nonstandard names/locations.
 
 
 
+
+
+
+
+   if test "x${PBX_SYSTEMD}" != "x1" -a "${USE_SYSTEMD}" != "no"; then
+
+pkg_failed=no
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for SYSTEMD" >&5
+$as_echo_n "checking for SYSTEMD... " >&6; }
+
+if test -n "$SYSTEMD_CFLAGS"; then
+    pkg_cv_SYSTEMD_CFLAGS="$SYSTEMD_CFLAGS"
+ elif test -n "$PKG_CONFIG"; then
+    if test -n "$PKG_CONFIG" && \
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libsystemd\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "libsystemd") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  pkg_cv_SYSTEMD_CFLAGS=`$PKG_CONFIG --cflags "libsystemd" 2>/dev/null`
+                     test "x$?" != "x0" && pkg_failed=yes
+else
+  pkg_failed=yes
+fi
+ else
+    pkg_failed=untried
+fi
+if test -n "$SYSTEMD_LIBS"; then
+    pkg_cv_SYSTEMD_LIBS="$SYSTEMD_LIBS"
+ elif test -n "$PKG_CONFIG"; then
+    if test -n "$PKG_CONFIG" && \
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libsystemd\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "libsystemd") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  pkg_cv_SYSTEMD_LIBS=`$PKG_CONFIG --libs "libsystemd" 2>/dev/null`
+                     test "x$?" != "x0" && pkg_failed=yes
+else
+  pkg_failed=yes
+fi
+ else
+    pkg_failed=untried
+fi
+
+
+
+if test $pkg_failed = yes; then
+       { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+        _pkg_short_errors_supported=yes
+else
+        _pkg_short_errors_supported=no
+fi
+        if test $_pkg_short_errors_supported = yes; then
+               SYSTEMD_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libsystemd" 2>&1`
+        else
+               SYSTEMD_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libsystemd" 2>&1`
+        fi
+       # Put the nasty error message in config.log where it belongs
+       echo "$SYSTEMD_PKG_ERRORS" >&5
+
+
+            PBX_SYSTEMD=0
+
+
+elif test $pkg_failed = untried; then
+       { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+            PBX_SYSTEMD=0
+
+
+else
+       SYSTEMD_CFLAGS=$pkg_cv_SYSTEMD_CFLAGS
+       SYSTEMD_LIBS=$pkg_cv_SYSTEMD_LIBS
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
+            PBX_SYSTEMD=1
+            SYSTEMD_INCLUDE="$SYSTEMD_CFLAGS"
+            SYSTEMD_LIB="$SYSTEMD_LIBS"
+
+$as_echo "#define HAVE_SYSTEMD 1" >>confdefs.h
+
+
+fi
+   fi
+
+
 PBX_SYSLOG=0
 
 if test "${ac_cv_header_syslog_h}" = "yes"; then
index e7fc21c..17b8872 100644 (file)
@@ -2630,6 +2630,11 @@ AC_SUBST([GENERIC_ODBC_LIB])
 AC_SUBST([GENERIC_ODBC_INCLUDE])
 AC_SUBST([PBX_GENERIC_ODBC])
 
+AC_SUBST([PBX_SYSTEMD])
+AC_SUBST([SYSTEMD_LIB])
+AC_SUBST([SYSTEMD_INCLUDE])
+AST_PKG_CONFIG_CHECK([SYSTEMD], [libsystemd])
+
 PBX_SYSLOG=0
 
 if test "${ac_cv_header_syslog_h}" = "yes"; then
index 5e7ea7e..e16b668 100644 (file)
 /* Define to 1 if you have the <syslog.h> header file. */
 #undef HAVE_SYSLOG_H
 
+/* Define if your system has the SYSTEMD libraries. */
+#undef HAVE_SYSTEMD
+
 /* Define to 1 if you have the <sys/dir.h> header file, and it defines `DIR'.
    */
 #undef HAVE_SYS_DIR_H
index 2bddd37..6ee8450 100644 (file)
@@ -139,6 +139,16 @@ int ast_restore_tty(int fd, int oldstatus);
 
 int ast_get_termcols(int fd);
 
+/*!
+ * \brief a wrapper for sd_notify(): notify systemd of any state changes.
+ * \param state a string that states the changes. See sd_notify(3).
+ * The wrapper does nothing if systemd ('s development headers) was not
+ * detected on the system.
+ * \returns >=0 on success, negative value on error.
+ */
+int ast_sd_notify(const char *state);
+
+
 #if defined(__cplusplus) || defined(c_plusplus)
 }
 #endif
index a6c3ab1..d41302a 100644 (file)
@@ -45,6 +45,7 @@ AST_LIBS+=$(UUID_LIB)
 AST_LIBS+=$(CRYPT_LIB)
 AST_LIBS+=$(AST_CLANG_BLOCKS_LIBS)
 AST_LIBS+=$(RT_LIB)
+AST_LIBS+=$(SYSTEMD_LIB)
 
 ifneq ($(findstring $(OSARCH), linux-gnu uclinux linux-uclibc linux-musl kfreebsd-gnu),)
   ifneq ($(findstring LOADABLE_MODULES,$(MENUSELECT_CFLAGS)),)
index 3c2ca25..94481ee 100644 (file)
@@ -591,11 +591,6 @@ void ast_unregister_thread(void *id)
        }
 }
 
-int ast_pbx_uuid_get(char *pbx_uuid, int length)
-{
-       return ast_db_get("pbx", "UUID", pbx_uuid, length);
-}
-
 /*! \brief Give an overview of core settings */
 static char *handle_show_settings(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
@@ -853,7 +848,7 @@ static char *handle_show_sysinfo(struct ast_cli_entry *e, int cmd, struct ast_cl
 #if defined(HAVE_SYSINFO)
        ast_cli(a->fd, "  Buffer RAM:                %" PRIu64 " KiB\n", ((uint64_t) sys_info.bufferram * sys_info.mem_unit) / 1024);
 #endif
-#if defined (HAVE_SYSCTL) || defined(HAVE_SWAPCTL)
+#if defined(HAVE_SWAPCTL) || defined(HAVE_SYSINFO)
        ast_cli(a->fd, "  Total Swap Space:          %d KiB\n", totalswap);
        ast_cli(a->fd, "  Free Swap Space:           %" PRIu64 " KiB\n\n", freeswap);
 #endif
@@ -1040,6 +1035,11 @@ static char *handle_clear_profile(struct ast_cli_entry *e, int cmd, struct ast_c
 
 #endif /* ! LOW_MEMORY */
 
+int ast_pbx_uuid_get(char *pbx_uuid, int length)
+{
+       return ast_db_get("pbx", "UUID", pbx_uuid, length);
+}
+
 static void publish_fully_booted(void)
 {
        RAII_VAR(struct ast_json *, json_object, NULL, ast_json_unref);
@@ -1778,6 +1778,66 @@ static void set_icon(char *text)
                fprintf(stdout, "\033]1;%s\007", text);
 }
 
+/*! \brief Check whether we were set to high(er) priority. */
+static int has_priority(void)
+{
+       /* Neither of these calls should fail with these arguments. */
+#ifdef __linux__
+       /* For SCHED_OTHER, SCHED_BATCH and SCHED_IDLE, this will return
+        * 0. For the realtime priorities SCHED_RR and SCHED_FIFO, it
+        * will return something >= 1. */
+       return sched_getscheduler(0);
+#else
+       /* getpriority() can return a value in -20..19 (or even -INF..20)
+        * where negative numbers are high priority. We don't bother
+        * checking errno. If the query fails and it returns -1, we'll
+        * assume that we're running at high prio; a safe assumption
+        * that will enable the resource starvation monitor (canary)
+        * just in case. */
+       return (getpriority(PRIO_PROCESS, 0) < 0);
+#endif
+}
+
+/*! \brief Set priority on all known threads. */
+static int set_priority_all(int pri)
+{
+#if !defined(__linux__)
+       /* The non-linux version updates the entire process prio. */
+       return ast_set_priority(pri);
+#elif defined(LOW_MEMORY)
+       ast_log(LOG_WARNING, "Unable to enumerate all threads to update priority\n");
+       return ast_set_priority(pri);
+#else
+       struct thread_list_t *cur;
+       struct sched_param sched;
+       char const *policy_str;
+       int policy;
+
+       memset(&sched, 0, sizeof(sched));
+       if (pri) {
+               policy = SCHED_RR;
+               policy_str = "realtime";
+               sched.sched_priority = 10;
+       } else {
+               policy = SCHED_OTHER;
+               policy_str = "regular";
+               sched.sched_priority = 0;
+       }
+       if (sched_setscheduler(getpid(), policy, &sched)) {
+               ast_log(LOG_WARNING, "Unable to set %s thread priority on main thread\n", policy_str);
+               return -1;
+       }
+       ast_verb(1, "Setting %s thread priority on all threads\n", policy_str);
+       AST_RWLIST_RDLOCK(&thread_list);
+       AST_RWLIST_TRAVERSE(&thread_list, cur, list) {
+               /* Don't care about the return value. It should work. */
+               sched_setscheduler(cur->lwp, policy, &sched);
+       }
+       AST_RWLIST_UNLOCK(&thread_list);
+       return 0;
+#endif
+}
+
 /*! \brief We set ourselves to a high priority, that we might pre-empt
  * everything else.  If your PBX has heavy activity on it, this is a
  * good thing.
@@ -1999,6 +2059,9 @@ static void really_quit(int num, shutdown_nice_t niceness, int restart)
                ast_module_shutdown();
        }
 
+       if (!restart) {
+               ast_sd_notify("STOPPING=1");
+       }
        if (ast_opt_console || (ast_opt_remote && !ast_opt_exec)) {
                ast_el_write_default_histfile();
                if (consolethread == AST_PTHREADT_NULL || consolethread == pthread_self()) {
@@ -3744,7 +3807,7 @@ static void *canary_thread(void *unused)
                                "He's kicked the bucket.  He's shuffled off his mortal coil, "
                                "run down the curtain, and joined the bleeding choir invisible!!  "
                                "THIS is an EX-CANARY.  (Reducing priority)\n");
-                       ast_set_priority(0);
+                       set_priority_all(0);
                        pthread_exit(NULL);
                }
 
@@ -3756,8 +3819,11 @@ static void *canary_thread(void *unused)
 /* Used by libc's atexit(3) function */
 static void canary_exit(void)
 {
-       if (canary_pid > 0)
+       if (canary_pid > 0) {
+               int status;
                kill(canary_pid, SIGKILL);
+               waitpid(canary_pid, &status, 0);
+       }
 }
 
 /* Execute CLI commands on startup.  Run by main() thread. */
@@ -4300,8 +4366,16 @@ static void asterisk_daemon(int isroot, const char *runuser, const char *rungrou
        __ast_mm_init_phase_1();
 #endif /* defined(__AST_DEBUG_MALLOC) */
 
+       /* Check whether high prio was succesfully set by us or some
+        * other incantation. */
+       if (has_priority()) {
+               ast_set_flag(&ast_options, AST_OPT_FLAG_HIGH_PRIORITY);
+       } else {
+               ast_clear_flag(&ast_options, AST_OPT_FLAG_HIGH_PRIORITY);
+       }
+
        /* Spawning of astcanary must happen AFTER the call to daemon(3) */
-       if (isroot && ast_opt_high_priority) {
+       if (ast_opt_high_priority) {
                snprintf(canary_filename, sizeof(canary_filename), "%s/alt.asterisk.canary.tweet.tweet.tweet", ast_config_AST_RUN_DIR);
 
                /* Don't let the canary child kill Asterisk, if it dies immediately */
@@ -4408,7 +4482,6 @@ static void asterisk_daemon(int isroot, const char *runuser, const char *rungrou
        check_init(ast_format_cache_init(), "Format Cache");
        check_init(ast_codec_builtin_init(), "Built-in Codecs");
        check_init(aco_init(), "Configuration Option Framework");
-       check_init(init_logger(), "Logger");
        check_init(ast_bucket_init(), "Bucket API");
        check_init(stasis_init(), "Stasis");
        check_init(ast_stasis_system_init(), "Stasis system-level information");
@@ -4438,6 +4511,7 @@ static void asterisk_daemon(int isroot, const char *runuser, const char *rungrou
 
        threadstorage_init();
 
+       check_init(init_logger(), "Logger");
        check_init(ast_rtp_engine_init(), "RTP Engine");
 
        ast_autoservice_init();
@@ -4526,6 +4600,7 @@ static void asterisk_daemon(int isroot, const char *runuser, const char *rungrou
        ast_register_cleanup(main_atexit);
 
        run_startup_commands();
+       ast_sd_notify("READY=1");
 
        ast_verb(0, COLORIZE_FMT "\n", COLORIZE(COLOR_BRGREEN, 0, "Asterisk Ready."));
 
index ff5ca57..3441fba 100644 (file)
--- a/main/io.c
+++ b/main/io.c
@@ -36,6 +36,9 @@ ASTERISK_REGISTER_FILE()
 
 #include "asterisk/io.h"
 #include "asterisk/utils.h"
+#ifdef HAVE_SYSTEMD
+#include <systemd/sd-daemon.h>
+#endif
 
 #ifdef DEBUG_IO
 #define DEBUG DEBUG_M
@@ -384,3 +387,10 @@ int ast_get_termcols(int fd)
        return cols;
 }
 
+int ast_sd_notify(const char *state) {
+#ifdef HAVE_SYSTEMD
+       return sd_notify(0, state);
+#else
+       return 0;
+#endif
+}
index f959221..36a3d5f 100644 (file)
@@ -891,6 +891,7 @@ enum ast_module_reload_result ast_module_reload(const char *name)
                res = AST_MODULE_RELOAD_IN_PROGRESS;
                goto module_reload_exit;
        }
+       ast_sd_notify("RELOAD=1");
        ast_lastreloadtime = ast_tvnow();
 
        if (ast_opt_lock_confdir) {
@@ -904,9 +905,8 @@ enum ast_module_reload_result ast_module_reload(const char *name)
                }
                if (res != AST_LOCK_SUCCESS) {
                        ast_log(AST_LOG_WARNING, "Cannot grab lock on %s\n", ast_config_AST_CONFIG_DIR);
-                       ast_mutex_unlock(&reloadlock);
                        res = AST_MODULE_RELOAD_ERROR;
-                       goto module_reload_exit;
+                       goto module_reload_done;
                }
        }
 
@@ -923,8 +923,7 @@ enum ast_module_reload_result ast_module_reload(const char *name)
                if (ast_opt_lock_confdir) {
                        ast_unlock_path(ast_config_AST_CONFIG_DIR);
                }
-               ast_mutex_unlock(&reloadlock);
-               goto module_reload_exit;
+               goto module_reload_done;
        }
 
        AST_DLLIST_LOCK(&module_list);
@@ -966,7 +965,9 @@ enum ast_module_reload_result ast_module_reload(const char *name)
        if (ast_opt_lock_confdir) {
                ast_unlock_path(ast_config_AST_CONFIG_DIR);
        }
+module_reload_done:
        ast_mutex_unlock(&reloadlock);
+       ast_sd_notify("READY=1");
 
 module_reload_exit:
        publish_reload_message(name, res);
index 9a16dcf..0c839ff 100644 (file)
@@ -479,6 +479,7 @@ static void make_components(struct logchannel *chan)
                 * with calculating the ast_verb_sys_level value.
                 */
                chan->verbosity = -1;
+               logmask |= (1 << __LOG_VERBOSE);
        } else {
                chan->verbosity = verb_level;
        }
@@ -663,7 +664,8 @@ static int init_logger_chain(const char *altconf)
                        return -1;
                }
                chan->type = LOGTYPE_CONSOLE;
-               chan->logmask = __LOG_WARNING | __LOG_NOTICE | __LOG_ERROR;
+               chan->logmask = (1 << __LOG_WARNING) | (1 << __LOG_NOTICE) | (1 << __LOG_ERROR)
+                       | (1 << __LOG_VERBOSE);
                memcpy(&chan->formatter, &logformatter_default, sizeof(chan->formatter));
 
                AST_RWLIST_INSERT_HEAD(&logchannels, chan, list);
@@ -1762,13 +1764,7 @@ void ast_callid_strnprint(char *buffer, size_t buffer_size, ast_callid callid)
 
 ast_callid ast_create_callid(void)
 {
-       ast_callid call;
-
-       call = ast_atomic_fetchadd_int(&next_unique_callid, +1);
-#ifdef TEST_FRAMEWORK
-       ast_debug(3, "CALL_ID [C-%08x] created by thread.\n", call);
-#endif
-       return call;
+       return ast_atomic_fetchadd_int(&next_unique_callid, +1);
 }
 
 ast_callid ast_read_threadstorage_callid(void)
@@ -1778,7 +1774,6 @@ ast_callid ast_read_threadstorage_callid(void)
        callid = ast_threadstorage_get(&unique_callid, sizeof(*callid));
 
        return callid ? *callid : 0;
-
 }
 
 int ast_callid_threadassoc_change(ast_callid callid)
@@ -1786,23 +1781,10 @@ int ast_callid_threadassoc_change(ast_callid callid)
        ast_callid *id = ast_threadstorage_get(&unique_callid, sizeof(*id));
 
        if (!id) {
-               ast_log(LOG_ERROR, "Failed to allocate thread storage.\n");
                return -1;
        }
 
-       if (*id && (*id != callid)) {
-#ifdef TEST_FRAMEWORK
-               ast_debug(3, "CALL_ID [C-%08x] being removed from thread.\n", *id);
-#endif
-               *id = 0;
-       }
-
-       if (!(*id) && callid) {
-               *id = callid;
-#ifdef TEST_FRAMEWORK
-               ast_debug(3, "CALL_ID [C-%08x] bound to thread.\n", callid);
-#endif
-       }
+       *id = callid;
 
        return 0;
 }
@@ -1812,21 +1794,17 @@ int ast_callid_threadassoc_add(ast_callid callid)
        ast_callid *pointing;
 
        pointing = ast_threadstorage_get(&unique_callid, sizeof(*pointing));
-       if (!(pointing)) {
-               ast_log(LOG_ERROR, "Failed to allocate thread storage.\n");
+       if (!pointing) {
                return -1;
        }
 
-       if (!(*pointing)) {
-               *pointing = callid;
-#ifdef TEST_FRAMEWORK
-               ast_debug(3, "CALL_ID [C-%08x] bound to thread.\n", callid);
-#endif
-       } else {
-               ast_log(LOG_WARNING, "Attempted to ast_callid_threadassoc_add on thread already associated with a callid.\n");
+       if (*pointing) {
+               ast_log(LOG_ERROR, "ast_callid_threadassoc_add(C-%08x) on thread "
+                       "already associated with callid [C-%08x].\n", callid, *pointing);
                return 1;
        }
 
+       *pointing = callid;
        return 0;
 }
 
@@ -1835,21 +1813,16 @@ int ast_callid_threadassoc_remove(void)
        ast_callid *pointing;
 
        pointing = ast_threadstorage_get(&unique_callid, sizeof(*pointing));
-       if (!(pointing)) {
-               ast_log(LOG_ERROR, "Failed to allocate thread storage.\n");
+       if (!pointing) {
                return -1;
        }
 
-       if (!(*pointing)) {
-               ast_log(LOG_ERROR, "Tried to clean callid thread storage with no callid in thread storage.\n");
-               return -1;
-       } else {
-#ifdef TEST_FRAMEWORK
-               ast_debug(3, "CALL_ID [C-%08x] being removed from thread.\n", *pointing);
-#endif
+       if (*pointing) {
                *pointing = 0;
                return 0;
        }
+
+       return -1;
 }
 
 int ast_callid_threadstorage_auto(ast_callid *callid)
index 0671374..b91bc41 100644 (file)
@@ -753,18 +753,18 @@ static void rtp_codecs_payloads_copy_rx(struct ast_rtp_codecs *src, struct ast_r
 
 /*!
  * \internal
- * \brief Remove other matching payload mappings.
+ * \brief Determine if a type of payload is already present in mappings.
  * \since 14.0.0
  *
- * \param codecs Codecs that need tx mappings removed.
- * \param instance RTP instance to notify of any payloads removed.
+ * \param codecs Codecs to be checked for mappings.
  * \param to_match Payload type object to compare against.
  *
  * \note It is assumed that codecs is write locked before calling.
  *
- * \return Nothing
+ * \retval 0 not found
+ * \retval 1 found
  */
-static void payload_mapping_tx_remove_other_mappings(struct ast_rtp_codecs *codecs, struct ast_rtp_instance *instance, struct ast_rtp_payload_type *to_match)
+static int payload_mapping_tx_is_present(const struct ast_rtp_codecs *codecs, const struct ast_rtp_payload_type *to_match)
 {
        int idx;
        struct ast_rtp_payload_type *current;
@@ -772,12 +772,18 @@ static void payload_mapping_tx_remove_other_mappings(struct ast_rtp_codecs *code
        for (idx = 0; idx < AST_VECTOR_SIZE(&codecs->payload_mapping_tx); ++idx) {
                current = AST_VECTOR_GET(&codecs->payload_mapping_tx, idx);
 
-               if (!current || current == to_match) {
+               if (!current) {
                        continue;
                }
+               if (current == to_match) {
+                       /* The exact object is already in the mapping. */
+                       return 1;
+               }
                if (current->asterisk_format && to_match->asterisk_format) {
-                       if (ast_format_cmp(current->format, to_match->format) == AST_FORMAT_CMP_NOT_EQUAL) {
+                       if (ast_format_get_codec_id(current->format) != ast_format_get_codec_id(to_match->format)) {
                                continue;
+                       } else if (current->payload == to_match->payload) {
+                               return 0;
                        }
                } else if (!current->asterisk_format && !to_match->asterisk_format) {
                        if (current->rtp_code != to_match->rtp_code) {
@@ -787,13 +793,10 @@ static void payload_mapping_tx_remove_other_mappings(struct ast_rtp_codecs *code
                        continue;
                }
 
-               /* Remove other mapping */
-               AST_VECTOR_REPLACE(&codecs->payload_mapping_tx, idx, NULL);
-               ao2_ref(current, -1);
-               if (instance && instance->engine && instance->engine->payload_set) {
-                       instance->engine->payload_set(instance, idx, 0, NULL, 0);
-               }
+               return 1;
        }
+
+       return 0;
 }
 
 /*!
@@ -833,13 +836,14 @@ static void rtp_codecs_payloads_copy_tx(struct ast_rtp_codecs *src, struct ast_r
                if (instance && instance->engine && instance->engine->payload_set) {
                        instance->engine->payload_set(instance, idx, type->asterisk_format, type->format, type->rtp_code);
                }
-
-               payload_mapping_tx_remove_other_mappings(dest, instance, type);
        }
 }
 
 void ast_rtp_codecs_payloads_copy(struct ast_rtp_codecs *src, struct ast_rtp_codecs *dest, struct ast_rtp_instance *instance)
 {
+       int idx;
+       struct ast_rtp_payload_type *type;
+
        ast_rwlock_wrlock(&dest->codecs_lock);
 
        /* Deadlock avoidance because of held write lock. */
@@ -849,6 +853,17 @@ void ast_rtp_codecs_payloads_copy(struct ast_rtp_codecs *src, struct ast_rtp_cod
                ast_rwlock_wrlock(&dest->codecs_lock);
        }
 
+       /*
+        * This represents a completely new mapping of what the remote party is
+        * expecting for payloads, so we clear out the entire tx payload mapping
+        * vector and replace it.
+        */
+       for (idx = 0; idx < AST_VECTOR_SIZE(&dest->payload_mapping_tx); ++idx) {
+               type = AST_VECTOR_GET(&dest->payload_mapping_tx, idx);
+               ao2_t_cleanup(type, "destroying ast_rtp_codec tx mapping");
+               AST_VECTOR_REPLACE(&dest->payload_mapping_tx, idx, NULL);
+       }
+
        rtp_codecs_payloads_copy_rx(src, dest, instance);
        rtp_codecs_payloads_copy_tx(src, dest, instance);
        dest->framing = src->framing;
@@ -921,18 +936,20 @@ void ast_rtp_codecs_payloads_set_m_type(struct ast_rtp_codecs *codecs, struct as
 
        ast_rwlock_wrlock(&codecs->codecs_lock);
 
-       if (payload < AST_VECTOR_SIZE(&codecs->payload_mapping_tx)) {
-               ao2_t_cleanup(AST_VECTOR_GET(&codecs->payload_mapping_tx, payload),
-                       "cleaning up replaced tx payload type");
-       }
-       AST_VECTOR_REPLACE(&codecs->payload_mapping_tx, payload, new_type);
+       if (!payload_mapping_tx_is_present(codecs, new_type)) {
+               if (payload < AST_VECTOR_SIZE(&codecs->payload_mapping_tx)) {
+                       ao2_t_cleanup(AST_VECTOR_GET(&codecs->payload_mapping_tx, payload),
+                               "cleaning up replaced tx payload type");
+               }
+               AST_VECTOR_REPLACE(&codecs->payload_mapping_tx, payload, new_type);
 
-       if (instance && instance->engine && instance->engine->payload_set) {
-               instance->engine->payload_set(instance, payload, new_type->asterisk_format, new_type->format, new_type->rtp_code);
+               if (instance && instance->engine && instance->engine->payload_set) {
+                       instance->engine->payload_set(instance, payload, new_type->asterisk_format, new_type->format, new_type->rtp_code);
+               }
+       } else {
+               ao2_ref(new_type, -1);
        }
 
-       payload_mapping_tx_remove_other_mappings(codecs, instance, new_type);
-
        ast_rwlock_unlock(&codecs->codecs_lock);
 }
 
@@ -995,17 +1012,20 @@ int ast_rtp_codecs_payloads_set_rtpmap_type_rate(struct ast_rtp_codecs *codecs,
                        new_type->format = ast_format_parse_sdp_fmtp(new_type->format, "");
                }
 
-               if (pt < AST_VECTOR_SIZE(&codecs->payload_mapping_tx)) {
-                       ao2_t_cleanup(AST_VECTOR_GET(&codecs->payload_mapping_tx, pt),
-                               "cleaning up replaced tx payload type");
-               }
-               AST_VECTOR_REPLACE(&codecs->payload_mapping_tx, pt, new_type);
+               if (!payload_mapping_tx_is_present(codecs, new_type)) {
+                       if (pt < AST_VECTOR_SIZE(&codecs->payload_mapping_tx)) {
+                               ao2_t_cleanup(AST_VECTOR_GET(&codecs->payload_mapping_tx, pt),
+                                       "cleaning up replaced tx payload type");
+                       }
+                       AST_VECTOR_REPLACE(&codecs->payload_mapping_tx, pt, new_type);
 
-               if (instance && instance->engine && instance->engine->payload_set) {
-                       instance->engine->payload_set(instance, pt, new_type->asterisk_format, new_type->format, new_type->rtp_code);
+                       if (instance && instance->engine && instance->engine->payload_set) {
+                               instance->engine->payload_set(instance, pt, new_type->asterisk_format, new_type->format, new_type->rtp_code);
+                       }
+               } else {
+                       ao2_ref(new_type, -1);
                }
 
-               payload_mapping_tx_remove_other_mappings(codecs, instance, new_type);
                break;
        }
 
@@ -1088,11 +1108,14 @@ int ast_rtp_codecs_payload_replace_format(struct ast_rtp_codecs *codecs, int pay
        type->primary_mapping = 1;
 
        ast_rwlock_wrlock(&codecs->codecs_lock);
-       if (payload < AST_VECTOR_SIZE(&codecs->payload_mapping_tx)) {
-               ao2_cleanup(AST_VECTOR_GET(&codecs->payload_mapping_tx, payload));
+       if (!payload_mapping_tx_is_present(codecs, type)) {
+               if (payload < AST_VECTOR_SIZE(&codecs->payload_mapping_tx)) {
+                       ao2_cleanup(AST_VECTOR_GET(&codecs->payload_mapping_tx, payload));
+               }
+               AST_VECTOR_REPLACE(&codecs->payload_mapping_tx, payload, type);
+       } else {
+               ao2_ref(type, -1);
        }
-       AST_VECTOR_REPLACE(&codecs->payload_mapping_tx, payload, type);
-       payload_mapping_tx_remove_other_mappings(codecs, NULL, type);
        ast_rwlock_unlock(&codecs->codecs_lock);
 
        return 0;
index 86b7f9d..b2b394b 100644 (file)
@@ -259,6 +259,10 @@ RT_LIB=@RT_LIB@
 SS7_INCLUDE=@SS7_INCLUDE@
 SS7_LIB=@SS7_LIB@
 
+HAVE_SYSTEMD=@PBX_SYSTEMD@
+SYSTEMD_INCLUDE=@SYSTEMD_INCLUDE@
+SYSTEMD_LIB=@SYSTEMD_LIB@
+
 OPENR2_INCLUDE=@OPENR2_INCLUDE@
 OPENR2_LIB=@OPENR2_LIB@
 
index 26aa17b..161dc53 100644 (file)
@@ -47,6 +47,9 @@ ASTERISK_REGISTER_FILE()
 #include "asterisk/utils.h"
 #include "asterisk/stringfields.h"
 
+/*! Initial SQL query buffer size to allocate. */
+#define SQL_BUF_SIZE   1024
+
 AST_THREADSTORAGE(sql_buf);
 AST_THREADSTORAGE(rowdata_buf);
 
@@ -114,7 +117,7 @@ static SQLHSTMT custom_prepare(struct odbc_obj *obj, void *data)
 
        res = SQLPrepare(stmt, (unsigned char *)cps->sql, SQL_NTS);
        if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
-               ast_log(LOG_WARNING, "SQL Prepare failed![%s]\n", cps->sql);
+               ast_log(LOG_WARNING, "SQL Prepare failed! [%s]\n", cps->sql);
                SQLFreeHandle (SQL_HANDLE_STMT, stmt);
                return NULL;
        }
@@ -161,13 +164,13 @@ static SQLHSTMT custom_prepare(struct odbc_obj *obj, void *data)
  *
  * \retval var on success
  * \retval NULL on failure
-*/
+ */
 static struct ast_variable *realtime_odbc(const char *database, const char *table, const struct ast_variable *fields)
 {
        struct odbc_obj *obj;
        SQLHSTMT stmt;
-       char sql[1024];
        char coltitle[256];
+       struct ast_str *sql = ast_str_thread_get(&sql_buf, SQL_BUF_SIZE);
        struct ast_str *rowdata = ast_str_thread_get(&rowdata_buf, 128);
        char *op;
        const struct ast_variable *field = fields;
@@ -183,29 +186,30 @@ static struct ast_variable *realtime_odbc(const char *database, const char *tabl
        SQLSMALLINT decimaldigits;
        SQLSMALLINT nullable;
        SQLLEN indicator;
-       struct custom_prepare_struct cps = { .sql = sql, .fields = fields, };
+       struct custom_prepare_struct cps = { .fields = fields, };
        struct ast_flags connected_flag = { RES_ODBC_CONNECTED };
 
-       if (!table || !field) {
+       if (!table || !field || !sql || !rowdata) {
                return NULL;
        }
 
        obj = ast_odbc_request_obj2(database, connected_flag);
-
        if (!obj) {
                ast_log(LOG_ERROR, "No database handle available with the name of '%s' (check res_odbc.conf)\n", database);
                return NULL;
        }
 
        op = !strchr(field->name, ' ') ? " =" : "";
-       snprintf(sql, sizeof(sql), "SELECT * FROM %s WHERE %s%s ?%s", table, field->name, op,
+       ast_str_set(&sql, 0, "SELECT * FROM %s WHERE %s%s ?%s", table, field->name, op,
                strcasestr(field->name, "LIKE") && !ast_odbc_backslash_is_escape(obj) ? " ESCAPE '\\\\'" : "");
        while ((field = field->next)) {
                op = !strchr(field->name, ' ') ? " =" : "";
-               snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " AND %s%s ?%s", field->name, op,
+               ast_str_append(&sql, 0, " AND %s%s ?%s", field->name, op,
                        strcasestr(field->name, "LIKE") && !ast_odbc_backslash_is_escape(obj) ? " ESCAPE '\\\\'" : "");
        }
 
+       cps.sql = ast_str_buffer(sql);
+
        if (ast_string_field_init(&cps, 256)) {
                ast_odbc_release_obj(obj);
                return NULL;
@@ -220,7 +224,7 @@ static struct ast_variable *realtime_odbc(const char *database, const char *tabl
 
        res = SQLNumResultCols(stmt, &colcount);
        if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
-               ast_log(LOG_WARNING, "SQL Column Count error!\n[%s]\n\n", sql);
+               ast_log(LOG_WARNING, "SQL Column Count error! [%s]\n", ast_str_buffer(sql));
                SQLFreeHandle (SQL_HANDLE_STMT, stmt);
                ast_odbc_release_obj(obj);
                return NULL;
@@ -233,7 +237,7 @@ static struct ast_variable *realtime_odbc(const char *database, const char *tabl
                return NULL;
        }
        if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
-               ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
+               ast_log(LOG_WARNING, "SQL Fetch error! [%s]\n", ast_str_buffer(sql));
                SQLFreeHandle (SQL_HANDLE_STMT, stmt);
                ast_odbc_release_obj(obj);
                return NULL;
@@ -244,7 +248,7 @@ static struct ast_variable *realtime_odbc(const char *database, const char *tabl
                res = SQLDescribeCol(stmt, x + 1, (unsigned char *)coltitle, sizeof(coltitle), &collen, 
                                        &datatype, &colsize, &decimaldigits, &nullable);
                if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
-                       ast_log(LOG_WARNING, "SQL Describe Column error!\n[%s]\n\n", sql);
+                       ast_log(LOG_WARNING, "SQL Describe Column error! [%s]\n", ast_str_buffer(sql));
                        if (var)
                                ast_variables_destroy(var);
                        ast_odbc_release_obj(obj);
@@ -273,7 +277,7 @@ static struct ast_variable *realtime_odbc(const char *database, const char *tabl
                }
 
                if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
-                       ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
+                       ast_log(LOG_WARNING, "SQL Get Data error! [%s]\n", ast_str_buffer(sql));
                        if (var)
                                ast_variables_destroy(var);
                        ast_odbc_release_obj(obj);
@@ -317,13 +321,13 @@ static struct ast_variable *realtime_odbc(const char *database, const char *tabl
  *
  * \retval var on success
  * \retval NULL on failure
-*/
+ */
 static struct ast_config *realtime_multi_odbc(const char *database, const char *table, const struct ast_variable *fields)
 {
        struct odbc_obj *obj;
        SQLHSTMT stmt;
-       char sql[1024];
        char coltitle[256];
+       struct ast_str *sql = ast_str_thread_get(&sql_buf, SQL_BUF_SIZE);
        struct ast_str *rowdata = ast_str_thread_get(&rowdata_buf, 128);
        const char *initfield;
        char *op;
@@ -343,9 +347,9 @@ static struct ast_config *realtime_multi_odbc(const char *database, const char *
        SQLSMALLINT decimaldigits;
        SQLSMALLINT nullable;
        SQLLEN indicator;
-       struct custom_prepare_struct cps = { .sql = sql, .fields = fields, };
+       struct custom_prepare_struct cps = { .fields = fields, };
 
-       if (!table || !field) {
+       if (!table || !field || !sql || !rowdata) {
                return NULL;
        }
 
@@ -360,15 +364,16 @@ static struct ast_config *realtime_multi_odbc(const char *database, const char *
        }
 
        op = !strchr(field->name, ' ') ? " =" : "";
-       snprintf(sql, sizeof(sql), "SELECT * FROM %s WHERE %s%s ?%s", table, field->name, op,
+       ast_str_set(&sql, 0, "SELECT * FROM %s WHERE %s%s ?%s", table, field->name, op,
                strcasestr(field->name, "LIKE") && !ast_odbc_backslash_is_escape(obj) ? " ESCAPE '\\\\'" : "");
        while ((field = field->next)) {
                op = !strchr(field->name, ' ') ? " =" : "";
-               snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " AND %s%s ?%s", field->name, op,
+               ast_str_append(&sql, 0, " AND %s%s ?%s", field->name, op,
                        strcasestr(field->name, "LIKE") && !ast_odbc_backslash_is_escape(obj) ? " ESCAPE '\\\\'" : "");
        }
+       ast_str_append(&sql, 0, " ORDER BY %s", initfield);
 
-       snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " ORDER BY %s", initfield);
+       cps.sql = ast_str_buffer(sql);
 
        if (ast_string_field_init(&cps, 256)) {
                ast_odbc_release_obj(obj);
@@ -384,7 +389,7 @@ static struct ast_config *realtime_multi_odbc(const char *database, const char *
 
        res = SQLNumResultCols(stmt, &colcount);
        if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
-               ast_log(LOG_WARNING, "SQL Column Count error!\n[%s]\n\n", sql);
+               ast_log(LOG_WARNING, "SQL Column Count error! [%s]\n", ast_str_buffer(sql));
                SQLFreeHandle(SQL_HANDLE_STMT, stmt);
                ast_odbc_release_obj(obj);
                return NULL;
@@ -401,7 +406,7 @@ static struct ast_config *realtime_multi_odbc(const char *database, const char *
        while ((res=SQLFetch(stmt)) != SQL_NO_DATA) {
                var = NULL;
                if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
-                       ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
+                       ast_log(LOG_WARNING, "SQL Fetch error! [%s]\n", ast_str_buffer(sql));
                        continue;
                }
                cat = ast_category_new("","",99999);
@@ -415,7 +420,7 @@ static struct ast_config *realtime_multi_odbc(const char *database, const char *
                        res = SQLDescribeCol(stmt, x + 1, (unsigned char *)coltitle, sizeof(coltitle), &collen, 
                                                &datatype, &colsize, &decimaldigits, &nullable);
                        if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
-                               ast_log(LOG_WARNING, "SQL Describe Column error!\n[%s]\n\n", sql);
+                               ast_log(LOG_WARNING, "SQL Describe Column error! [%s]\n", ast_str_buffer(sql));
                                ast_category_destroy(cat);
                                goto next_sql_fetch;
                        }
@@ -440,7 +445,7 @@ static struct ast_config *realtime_multi_odbc(const char *database, const char *
                        }
 
                        if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
-                               ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
+                               ast_log(LOG_WARNING, "SQL Get Data error! [%s]\n", ast_str_buffer(sql));
                                ast_category_destroy(cat);
                                goto next_sql_fetch;
                        }
@@ -482,21 +487,21 @@ next_sql_fetch:;
  *
  * \retval number of rows affected
  * \retval -1 on failure
-*/
+ */
 static int update_odbc(const char *database, const char *table, const char *keyfield, const char *lookup, const struct ast_variable *fields)
 {
        struct odbc_obj *obj;
        SQLHSTMT stmt;
-       char sql[256];
        SQLLEN rowcount=0;
+       struct ast_str *sql = ast_str_thread_get(&sql_buf, SQL_BUF_SIZE);
        const struct ast_variable *field = fields;
        int res, count = 0, paramcount = 0;
-       struct custom_prepare_struct cps = { .sql = sql, .extra = lookup, .fields = fields, };
+       struct custom_prepare_struct cps = { .extra = lookup, .fields = fields, };
        struct odbc_cache_tables *tableptr;
        struct odbc_cache_columns *column = NULL;
        struct ast_flags connected_flag = { RES_ODBC_CONNECTED };
 
-       if (!table || !field || !keyfield) {
+       if (!table || !field || !keyfield || !sql) {
                return -1;
        }
 
@@ -510,19 +515,19 @@ static int update_odbc(const char *database, const char *table, const char *keyf
                ast_log(LOG_WARNING, "Key field '%s' does not exist in table '%s@%s'.  Update will fail\n", keyfield, table, database);
        }
 
-       snprintf(sql, sizeof(sql), "UPDATE %s SET ", table);
+       ast_str_set(&sql, 0, "UPDATE %s SET ", table);
        while (field) {
                if ((tableptr && (column = ast_odbc_find_column(tableptr, field->name))) || count >= 64) {
                        if (paramcount++) {
-                               snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), ", ");
+                               ast_str_append(&sql, 0, ", ");
                        }
                        /* NULL test for non-text columns */
                        if (count < 64 && ast_strlen_zero(field->value) && column->nullable && !is_text(column)) {
-                               snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), "%s=NULL", field->name);
+                               ast_str_append(&sql, 0, "%s=NULL", field->name);
                                cps.skip |= (1LL << count);
                        } else {
                                /* Value is not an empty string, or column is of text type, or we couldn't fit any more into cps.skip (count >= 64 ?!). */
-                               snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), "%s=?", field->name);
+                               ast_str_append(&sql, 0, "%s=?", field->name);
                        }
                } else { /* the column does not exist in the table */
                        cps.skip |= (1LL << count);
@@ -530,9 +535,11 @@ static int update_odbc(const char *database, const char *table, const char *keyf
                ++count;
                field = field->next;
        }
-       snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " WHERE %s=?", keyfield);
+       ast_str_append(&sql, 0, " WHERE %s=?", keyfield);
        ast_odbc_release_table(tableptr);
 
+       cps.sql = ast_str_buffer(sql);
+
        if (ast_string_field_init(&cps, 256)) {
                ast_odbc_release_obj(obj);
                return -1;
@@ -550,7 +557,7 @@ static int update_odbc(const char *database, const char *table, const char *keyf
        ast_odbc_release_obj(obj);
 
        if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
-               ast_log(LOG_WARNING, "SQL Row Count error!\n[%s]\n\n", sql);
+               ast_log(LOG_WARNING, "SQL Row Count error! [%s]\n", ast_str_buffer(sql));
                return -1;
        }
 
@@ -573,17 +580,15 @@ static SQLHSTMT update2_prepare(struct odbc_obj *obj, void *data)
        int res, x = 1, first = 1;
        struct update2_prepare_struct *ups = data;
        const struct ast_variable *field;
-       struct ast_str *sql = ast_str_thread_get(&sql_buf, 16);
+       struct ast_str *sql = ast_str_thread_get(&sql_buf, SQL_BUF_SIZE);
        SQLHSTMT stmt;
-       struct odbc_cache_tables *tableptr = ast_odbc_find_table(ups->database, ups->table);
+       struct odbc_cache_tables *tableptr;
 
        if (!sql) {
-               if (tableptr) {
-                       ast_odbc_release_table(tableptr);
-               }
                return NULL;
        }
 
+       tableptr = ast_odbc_find_table(ups->database, ups->table);
        if (!tableptr) {
                ast_log(LOG_ERROR, "Could not retrieve metadata for table '%s@%s'.  Update will fail!\n", ups->table, ups->database);
                return NULL;
@@ -628,7 +633,7 @@ static SQLHSTMT update2_prepare(struct odbc_obj *obj, void *data)
 
        res = SQLPrepare(stmt, (unsigned char *)ast_str_buffer(sql), SQL_NTS);
        if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
-               ast_log(LOG_WARNING, "SQL Prepare failed![%s]\n", ast_str_buffer(sql));
+               ast_log(LOG_WARNING, "SQL Prepare failed! [%s]\n", ast_str_buffer(sql));
                SQLFreeHandle(SQL_HANDLE_STMT, stmt);
                return NULL;
        }
@@ -674,8 +679,9 @@ static int update2_odbc(const char *database, const char *table, const struct as
 
        if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
                /* Since only a single thread can access this memory, we can retrieve what would otherwise be lost. */
-               sql = ast_str_thread_get(&sql_buf, 16);
-               ast_log(LOG_WARNING, "SQL Row Count error!\n[%s]\n", ast_str_buffer(sql));
+               sql = ast_str_thread_get(&sql_buf, SQL_BUF_SIZE);
+               ast_assert(sql != NULL);
+               ast_log(LOG_WARNING, "SQL Row Count error! [%s]\n", ast_str_buffer(sql));
                return -1;
        }
 
@@ -698,36 +704,47 @@ static int update2_odbc(const char *database, const char *table, const struct as
  *
  * \retval number of rows affected
  * \retval -1 on failure
-*/
+ */
 static int store_odbc(const char *database, const char *table, const struct ast_variable *fields)
 {
        struct odbc_obj *obj;
        SQLHSTMT stmt;
-       char sql[256];
-       char keys[256];
-       char vals[256];
        SQLLEN rowcount=0;
        const struct ast_variable *field = fields;
+       struct ast_str *keys;
+       struct ast_str *vals;
+       struct ast_str *sql = ast_str_thread_get(&sql_buf, SQL_BUF_SIZE);
        int res;
-       struct custom_prepare_struct cps = { .sql = sql, .extra = NULL, .fields = fields, };
+       struct custom_prepare_struct cps = { .fields = fields, };
        struct ast_flags connected_flag = { RES_ODBC_CONNECTED };
 
-       if (!table || !field) {
+       keys = ast_str_create(SQL_BUF_SIZE / 2);
+       vals = ast_str_create(SQL_BUF_SIZE / 4);
+       if (!table || !field || !keys || !vals || !sql) {
+               ast_free(vals);
+               ast_free(keys);
                return -1;
        }
 
        obj = ast_odbc_request_obj2(database, connected_flag);
        if (!obj) {
+               ast_free(vals);
+               ast_free(keys);
                return -1;
        }
 
-       snprintf(keys, sizeof(keys), "%s", field->name);
-       ast_copy_string(vals, "?", sizeof(vals));
+       ast_str_set(&keys, 0, "%s", field->name);
+       ast_str_set(&vals, 0, "?");
        while ((field = field->next)) {
-               snprintf(keys + strlen(keys), sizeof(keys) - strlen(keys), ", %s", field->name);
-               snprintf(vals + strlen(vals), sizeof(vals) - strlen(vals), ", ?");
+               ast_str_append(&keys, 0, ", %s", field->name);
+               ast_str_append(&vals, 0, ", ?");
        }
-       snprintf(sql, sizeof(sql), "INSERT INTO %s (%s) VALUES (%s)", table, keys, vals);
+       ast_str_set(&sql, 0, "INSERT INTO %s (%s) VALUES (%s)",
+               table, ast_str_buffer(keys), ast_str_buffer(vals));
+
+       ast_free(vals);
+       ast_free(keys);
+       cps.sql = ast_str_buffer(sql);
 
        if (ast_string_field_init(&cps, 256)) {
                ast_odbc_release_obj(obj);
@@ -746,7 +763,7 @@ static int store_odbc(const char *database, const char *table, const struct ast_
        ast_odbc_release_obj(obj);
 
        if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
-               ast_log(LOG_WARNING, "SQL Row Count error!\n[%s]\n\n", sql);
+               ast_log(LOG_WARNING, "SQL Row Count error! [%s]\n", ast_str_buffer(sql));
                return -1;
        }
 
@@ -770,19 +787,19 @@ static int store_odbc(const char *database, const char *table, const struct ast_
  *
  * \retval number of rows affected
  * \retval -1 on failure
-*/
+ */
 static int destroy_odbc(const char *database, const char *table, const char *keyfield, const char *lookup, const struct ast_variable *fields)
 {
        struct odbc_obj *obj;
        SQLHSTMT stmt;
-       char sql[256];
        SQLLEN rowcount=0;
+       struct ast_str *sql = ast_str_thread_get(&sql_buf, SQL_BUF_SIZE);
        const struct ast_variable *field;
        int res;
-       struct custom_prepare_struct cps = { .sql = sql, .extra = lookup, .fields = fields, };
+       struct custom_prepare_struct cps = { .extra = lookup, .fields = fields, };
        struct ast_flags connected_flag = { RES_ODBC_CONNECTED };
 
-       if (!table) {
+       if (!table || !sql) {
                return -1;
        }
 
@@ -791,12 +808,13 @@ static int destroy_odbc(const char *database, const char *table, const char *key
                return -1;
        }
 
-       snprintf(sql, sizeof(sql), "DELETE FROM %s WHERE ", table);
-
+       ast_str_set(&sql, 0, "DELETE FROM %s WHERE ", table);
        for (field = fields; field; field = field->next) {
-               snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), "%s=? AND ", field->name);
+               ast_str_append(&sql, 0, "%s=? AND ", field->name);
        }
-       snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), "%s=?", keyfield);
+       ast_str_append(&sql, 0, "%s=?", keyfield);
+
+       cps.sql = ast_str_buffer(sql);
 
        if (ast_string_field_init(&cps, 256)) {
                ast_odbc_release_obj(obj);
@@ -815,7 +833,7 @@ static int destroy_odbc(const char *database, const char *table, const char *key
        ast_odbc_release_obj(obj);
 
        if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
-               ast_log(LOG_WARNING, "SQL Row Count error!\n[%s]\n\n", sql);
+               ast_log(LOG_WARNING, "SQL Row Count error! [%s]\n", ast_str_buffer(sql));
                return -1;
        }
 
@@ -893,9 +911,7 @@ static struct ast_config *config_odbc(const char *database, const char *table, c
        struct ast_category *cur_cat;
        int res = 0;
        struct odbc_obj *obj;
-       char sqlbuf[1024] = "";
-       char *sql = sqlbuf;
-       size_t sqlleft = sizeof(sqlbuf);
+       struct ast_str *sql = ast_str_thread_get(&sql_buf, SQL_BUF_SIZE);
        unsigned int last_cat_metric = 0;
        SQLSMALLINT rowcount = 0;
        SQLHSTMT stmt;
@@ -906,21 +922,21 @@ static struct ast_config *config_odbc(const char *database, const char *table, c
 
        memset(&q, 0, sizeof(q));
 
-       if (!file || !strcmp (file, "res_config_odbc.conf"))
+       if (!file || !strcmp (file, "res_config_odbc.conf") || !sql) {
                return NULL;            /* cant configure myself with myself ! */
+       }
 
        obj = ast_odbc_request_obj2(database, connected_flag);
        if (!obj)
                return NULL;
 
-       q.sql = sqlbuf;
-
-       ast_build_string(&sql, &sqlleft, "SELECT MAX(LENGTH(var_val)) FROM %s WHERE filename='%s'", table, file);
+       ast_str_set(&sql, 0, "SELECT MAX(LENGTH(var_val)) FROM %s WHERE filename='%s'",
+               table, file);
+       q.sql = ast_str_buffer(sql);
 
        stmt = ast_odbc_prepare_and_execute(obj, length_determination_odbc_prepare, &q);
-
        if (!stmt) {
-               ast_log(LOG_WARNING, "SQL select error!\n[%s]\n\n", sql);
+               ast_log(LOG_WARNING, "SQL select error! [%s]\n", ast_str_buffer(sql));
                ast_odbc_release_obj(obj);
                return NULL;
        }
@@ -928,7 +944,7 @@ static struct ast_config *config_odbc(const char *database, const char *table, c
        res = SQLNumResultCols(stmt, &rowcount);
 
        if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
-               ast_log(LOG_WARNING, "SQL NumResultCols error!\n[%s]\n\n", sql);
+               ast_log(LOG_WARNING, "SQL NumResultCols error! [%s]\n", ast_str_buffer(sql));
                SQLFreeHandle(SQL_HANDLE_STMT, stmt);
                ast_odbc_release_obj(obj);
                return NULL;
@@ -950,12 +966,11 @@ static struct ast_config *config_odbc(const char *database, const char *table, c
 
        /* Reset stuff to a fresh state for the actual query which will retrieve all configuration */
        SQLFreeHandle(SQL_HANDLE_STMT, stmt);
-       sql = sqlbuf;
-       sqlleft = sizeof(sqlbuf);
 
-       ast_build_string(&sql, &sqlleft, "SELECT cat_metric, category, var_name, var_val FROM %s ", table);
-       ast_build_string(&sql, &sqlleft, "WHERE filename='%s' AND commented=0 ", file);
-       ast_build_string(&sql, &sqlleft, "ORDER BY cat_metric DESC, var_metric ASC, category, var_name ");
+       ast_str_set(&sql, 0, "SELECT cat_metric, category, var_name, var_val FROM %s ", table);
+       ast_str_append(&sql, 0, "WHERE filename='%s' AND commented=0 ", file);
+       ast_str_append(&sql, 0, "ORDER BY cat_metric DESC, var_metric ASC, category, var_name ");
+       q.sql = ast_str_buffer(sql);
 
        q.var_val_size += 1;
        q.var_val = ast_malloc(q.var_val_size);
@@ -966,9 +981,8 @@ static struct ast_config *config_odbc(const char *database, const char *table, c
        }
 
        stmt = ast_odbc_prepare_and_execute(obj, config_odbc_prepare, &q);
-
        if (!stmt) {
-               ast_log(LOG_WARNING, "SQL select error!\n[%s]\n\n", sql);
+               ast_log(LOG_WARNING, "SQL select error! [%s]\n", ast_str_buffer(sql));
                ast_odbc_release_obj(obj);
                ast_free(q.var_val);
                return NULL;
@@ -977,7 +991,7 @@ static struct ast_config *config_odbc(const char *database, const char *table, c
        res = SQLNumResultCols(stmt, &rowcount);
 
        if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
-               ast_log(LOG_WARNING, "SQL NumResultCols error!\n[%s]\n\n", sql);
+               ast_log(LOG_WARNING, "SQL NumResultCols error! [%s]\n", ast_str_buffer(sql));
                SQLFreeHandle(SQL_HANDLE_STMT, stmt);
                ast_odbc_release_obj(obj);
                ast_free(q.var_val);
index f5deb77..5deeb92 100644 (file)
@@ -109,8 +109,11 @@ static pj_status_t multihomed_on_tx_message(pjsip_tx_data *tdata)
                return PJ_SUCCESS;
        }
 
-       /* The port in the message should always be that of the original transport */
-       prm.ret_port = tdata->tp_info.transport->local_name.port;
+       /* For UDP we can have multiple transports so the port needs to be maintained */
+       if (tdata->tp_info.transport->key.type == PJSIP_TRANSPORT_UDP ||
+               tdata->tp_info.transport->key.type == PJSIP_TRANSPORT_UDP6) {
+               prm.ret_port = tdata->tp_info.transport->local_name.port;
+       }
 
        /* If the IP source differs from the existing transport see if we need to update it */
        if (pj_strcmp(&prm.ret_addr, &tdata->tp_info.transport->local_name.host)) {
diff --git a/third-party/pjproject/patches/0004-resolver.c-Prevent-SERVFAIL-from-marking-name-server.patch b/third-party/pjproject/patches/0004-resolver.c-Prevent-SERVFAIL-from-marking-name-server.patch
new file mode 100644 (file)
index 0000000..55f3d2d
--- /dev/null
@@ -0,0 +1,48 @@
+From a5efddbe9151e9ad99279e59566c86f8bc27d3a9 Mon Sep 17 00:00:00 2001
+From: George Joseph <gjoseph@digium.com>
+Date: Wed, 7 Sep 2016 13:10:57 -0600
+Subject: [PATCH] resolver.c:  Prevent SERVFAIL from marking name server bad
+
+A name server that returns "Server Failure" is indicating only that
+the server couldn't process that particular request.  We should NOT
+assume that the name server is incapable of serving other requests.
+
+Here's the scenario we've been encountering...
+
+* 2 local name servers configured in resolv.conf.
+* An OPTIONS request causes a request for A and AAAA records to go out
+  to both nameservers.
+* The A responses both come back successfully resolved.
+* Because of an issue at some upstream nameserver, the AAAA responses
+  for that particular query come back as "SERVFAIL" from both local
+  name servers.
+* Both local servers are marked as bad and no further queries can be
+  sent until the 60 second ttl expires.  Only previously cached results
+  can be used.
+* In this case, 60 seconds is just enough time for another OPTIONS
+  request to go out to the same host so the cycle repeats.
+
+We could set the bad ttl really low but that also affects REFUSED and
+NOTAUTH which probably DO signal a real server issue.  Besides, even
+a really low bad ttl would be an issue on a pbx.
+---
+ pjlib-util/src/pjlib-util/resolver.c | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+diff --git a/pjlib-util/src/pjlib-util/resolver.c b/pjlib-util/src/pjlib-util/resolver.c
+index d277e4f..540f88f 100644
+--- a/pjlib-util/src/pjlib-util/resolver.c
++++ b/pjlib-util/src/pjlib-util/resolver.c
+@@ -1384,8 +1384,7 @@ static void report_nameserver_status(pj_dns_resolver *resolver,
+       q_id = (pj_uint32_t)-1;
+     }
+-    if (!pkt || rcode == PJ_DNS_RCODE_SERVFAIL ||
+-              rcode == PJ_DNS_RCODE_REFUSED ||
++    if (!pkt || rcode == PJ_DNS_RCODE_REFUSED ||
+               rcode == PJ_DNS_RCODE_NOTAUTH) 
+     {
+       is_good = PJ_FALSE;
+-- 
+2.7.4
+