Merge "astobj2: Reduce memory overhead."
authorJenkins2 <jenkins2@gerrit.asterisk.org>
Mon, 1 Oct 2018 14:02:37 +0000 (09:02 -0500)
committerGerrit Code Review <gerrit2@gerrit.digium.api>
Mon, 1 Oct 2018 14:02:37 +0000 (09:02 -0500)
25 files changed:
CHANGES
apps/app_confbridge.c
apps/app_queue.c
apps/confbridge/confbridge_manager.c
apps/confbridge/include/confbridge.h
autoconf/ast_ext_lib.m4
configs/samples/rtp.conf.sample
configure
configure.ac
include/asterisk/astobj2.h
include/asterisk/autoconfig.h.in
include/asterisk/lock.h
main/astobj2.c
main/config.c
main/lock.c
res/ari/resource_bridges.c
res/res_config_odbc.c
res/res_odbc.c
res/res_pjsip/location.c
res/res_resolver_unbound.c
res/res_rtp_asterisk.c
res/res_stasis.c
third-party/jansson/patches/0029-json_pack-Improve-handling-of-formats-with-and.patch [new file with mode: 0644]
third-party/jansson/patches/0030-More-work-on-json_pack-error-reporting.patch [new file with mode: 0644]
utils/extconf.c

diff --git a/CHANGES b/CHANGES
index 26748f7..fef7212 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -9,6 +9,17 @@
 ==============================================================================
 
 ------------------------------------------------------------------------------
+--- Functionality changes from Asterisk 16.0.0 to Asterisk 16.1.0 ------------
+------------------------------------------------------------------------------
+
+res_rtp_asterisk
+------------------
+ * The existing strictrtp option in rtp.conf has a new choice availabe, called
+   'seqno', which behaves the same way as setting strictrtp to 'yes', but will
+   ignore the time interval during learning so that bursts of packets can still
+   trigger learning our source.
+
+------------------------------------------------------------------------------
 --- Functionality changes from Asterisk 15 to Asterisk 16 --------------------
 ------------------------------------------------------------------------------
 
index 1c6b464..a4e5c67 100644 (file)
@@ -576,6 +576,10 @@ static void send_conf_stasis(struct confbridge_conference *conference, struct as
                return;
        }
 
+       if (ast_test_flag(&conference->b_profile, BRIDGE_OPT_ENABLE_EVENTS)) {
+               conf_send_event_to_participants(conference, chan, msg);
+       }
+
        if (channel_topic) {
                stasis_publish(ast_channel_topic(chan), msg);
        } else {
@@ -2311,6 +2315,25 @@ static int join_callback(struct ast_bridge_channel *bridge_channel, void *ignore
        return 0;
 }
 
+struct confbridge_hook_data {
+       struct confbridge_conference *conference;
+       struct confbridge_user *user;
+       enum ast_bridge_hook_type hook_type;
+};
+
+static int send_event_hook_callback(struct ast_bridge_channel *bridge_channel, void *data)
+{
+       struct confbridge_hook_data *hook_data = data;
+
+       if (hook_data->hook_type == AST_BRIDGE_HOOK_TYPE_JOIN) {
+               send_join_event(hook_data->user, hook_data->conference);
+       } else {
+               send_leave_event(hook_data->user, hook_data->conference);
+       }
+
+       return 0;
+}
+
 /*! \brief The ConfBridge application */
 static int confbridge_exec(struct ast_channel *chan, const char *data)
 {
@@ -2328,6 +2351,9 @@ static int confbridge_exec(struct ast_channel *chan, const char *data)
                .tech_args.silence_threshold = DEFAULT_SILENCE_THRESHOLD,
                .tech_args.drop_silence = 0,
        };
+       struct confbridge_hook_data *join_hook_data;
+       struct confbridge_hook_data *leave_hook_data;
+
        AST_DECLARE_APP_ARGS(args,
                AST_APP_ARG(conf_name);
                AST_APP_ARG(b_profile_name);
@@ -2510,8 +2536,39 @@ static int confbridge_exec(struct ast_channel *chan, const char *data)
 
        conf_moh_unsuspend(&user);
 
-       /* Join our conference bridge for real */
-       send_join_event(&user, conference);
+       join_hook_data = ast_malloc(sizeof(*join_hook_data));
+       if (!join_hook_data) {
+               res = -1;
+               goto confbridge_cleanup;
+       }
+       join_hook_data->user = &user;
+       join_hook_data->conference = conference;
+       join_hook_data->hook_type = AST_BRIDGE_HOOK_TYPE_JOIN;
+       res = ast_bridge_join_hook(&user.features, send_event_hook_callback,
+               join_hook_data, ast_free_ptr, 0);
+       if (res) {
+               ast_free(join_hook_data);
+               ast_log(LOG_ERROR, "Couldn't add bridge join hook for channel '%s'\n", ast_channel_name(chan));
+               goto confbridge_cleanup;
+       }
+
+       leave_hook_data = ast_malloc(sizeof(*leave_hook_data));
+       if (!leave_hook_data) {
+               /* join_hook_data is cleaned up by ast_bridge_features_cleanup via the goto */
+               res = -1;
+               goto confbridge_cleanup;
+       }
+       leave_hook_data->user = &user;
+       leave_hook_data->conference = conference;
+       leave_hook_data->hook_type = AST_BRIDGE_HOOK_TYPE_LEAVE;
+       res = ast_bridge_leave_hook(&user.features, send_event_hook_callback,
+               leave_hook_data, ast_free_ptr, 0);
+       if (res) {
+               /* join_hook_data is cleaned up by ast_bridge_features_cleanup via the goto */
+               ast_free(leave_hook_data);
+               ast_log(LOG_ERROR, "Couldn't add bridge leave hook for channel '%s'\n", ast_channel_name(chan));
+               goto confbridge_cleanup;
+       }
 
        if (ast_bridge_join_hook(&user.features, join_callback, NULL, NULL, 0)) {
                async_play_sound_ready(user.chan);
@@ -2533,8 +2590,6 @@ static int confbridge_exec(struct ast_channel *chan, const char *data)
                pbx_builtin_setvar_helper(chan, "CONFBRIDGE_RESULT", "HANGUP");
        }
 
-       send_leave_event(&user, conference);
-
        /* if we're shutting down, don't attempt to do further processing */
        if (ast_shutting_down()) {
                /*
index 7b05133..472feac 100644 (file)
@@ -6987,6 +6987,7 @@ static int try_calling(struct queue_ent *qe, struct ast_flags opts, char **opt_a
 
                                ast_channel_publish_dial(qe->chan, peer, member->interface, ast_hangup_cause_to_dial_status(ast_channel_hangupcause(peer)));
                                ast_autoservice_chan_hangup_peer(qe->chan, peer);
+                               pending_members_remove(member);
                                ao2_ref(member, -1);
                                goto out;
                        } else if (ast_check_hangup(qe->chan)) {
@@ -6997,6 +6998,7 @@ static int try_calling(struct queue_ent *qe, struct ast_flags opts, char **opt_a
                                qe->handled = -1;
                                ast_channel_publish_dial(qe->chan, peer, member->interface, ast_hangup_cause_to_dial_status(ast_channel_hangupcause(peer)));
                                ast_autoservice_chan_hangup_peer(qe->chan, peer);
+                               pending_members_remove(member);
                                ao2_ref(member, -1);
                                return -1;
                        }
@@ -7016,6 +7018,7 @@ static int try_calling(struct queue_ent *qe, struct ast_flags opts, char **opt_a
                        record_abandoned(qe);
                        ast_channel_publish_dial(qe->chan, peer, member->interface, ast_hangup_cause_to_dial_status(ast_channel_hangupcause(peer)));
                        ast_autoservice_chan_hangup_peer(qe->chan, peer);
+                       pending_members_remove(member);
                        ao2_ref(member, -1);
                        return -1;
                }
index 51112ba..a7f2fce 100644 (file)
@@ -395,6 +395,9 @@ static void set_media_labels(struct confbridge_conference *conference,
        struct ast_stream *stream;
        struct ast_channel *chan = dir == LABEL_DIRECTION_SRC ? dest_chan : src_chan;
 
+       if (!chan) {
+               return;
+       }
        topology = ast_channel_get_stream_topology(chan);
        stream = get_stream(topology, AST_MEDIA_TYPE_VIDEO);
        if (stream) {
@@ -458,8 +461,8 @@ static void send_message(const char *msg_name, char *conf_name, struct ast_json
        ast_json_free(json);
 }
 
-static void send_event_to_participants(struct confbridge_conference *conference,
-       struct ast_channel *chan, struct stasis_message * msg)
+void conf_send_event_to_participants(struct confbridge_conference *conference,
+       struct ast_channel *chan, struct stasis_message *msg)
 {
        struct ast_bridge_blob *obj = stasis_message_data(msg);
        struct ast_json *extras = obj->blob;
@@ -597,13 +600,6 @@ static void confbridge_publish_manager_event(
                struct confbridge_conference *conference = conf_find_bridge(conference_name);
 
                channel_text = ast_manager_build_channel_state_string(blob->channel);
-
-               if (conference && ast_test_flag(&conference->b_profile, BRIDGE_OPT_ENABLE_EVENTS)) {
-                       struct ast_channel *chan = ast_channel_get_by_name(blob->channel->name);
-
-                       send_event_to_participants(conference, chan, message);
-                       ast_channel_cleanup(chan);
-               }
                ao2_cleanup(conference);
        }
 
index 51ff9a4..ac403d8 100644 (file)
@@ -701,6 +701,16 @@ int conf_announce_channel_push(struct ast_channel *ast);
  */
 struct confbridge_conference *conf_find_bridge(const char *conference_name);
 
-
+/*!
+ * \brief Send events to bridge participants.
+ * \since 15.7
+ * \since 16.1
+ *
+ * \param conference The conference bridge
+ * \param chan The channel triggering the action
+ * \param msg The stasis message describing the event
+ */
+void conf_send_event_to_participants(struct confbridge_conference *conference,
+       struct ast_channel *chan, struct stasis_message *msg);
 
 #endif
index 8e5b50e..9a91fc3 100644 (file)
@@ -203,3 +203,105 @@ if test "x${PBX_$1}" = "x1"; then
    LIBS="${ast_ext_lib_check_shared_saved_libs}"
 fi
 ])
+
+# Check for existence of a given package ($1), either looking up a function
+# in a library, or, if no function is supplied, only check for the
+# existence of the header files.  Then compile, link and run the supplied
+# code fragment to make the final determination.
+
+# AST_EXT_LIB_EXTRA_CHECK([package], [library], [function], [header],
+#       [extra libs], [extra cflags], [AC_LANG_PROGRAM(extra check code...)],
+#    ["checking for" display string], ["HAVE_package_" extra variable to set])
+AC_DEFUN([AST_EXT_LIB_EXTRA_CHECK],
+[
+if test "x${PBX_$1}" != "x1" -a "${USE_$1}" != "no"; then
+   pbxlibdir=""
+   # if --with-$1=DIR has been specified, use it.
+   if test "x${$1_DIR}" != "x"; then
+      if test -d ${$1_DIR}/lib; then
+         pbxlibdir="-L${$1_DIR}/lib"
+      else
+         pbxlibdir="-L${$1_DIR}"
+      fi
+   fi
+   m4_ifval([$3], [
+      ast_ext_lib_check_save_CFLAGS="${CFLAGS}"
+      CFLAGS="${CFLAGS} $6"
+      AC_CHECK_LIB([$2], [$3], [AST_$1_FOUND=yes], [AST_$1_FOUND=no], [${pbxlibdir} $5])
+      CFLAGS="${ast_ext_lib_check_save_CFLAGS}"
+   ], [
+      # empty lib, assume only headers
+      AST_$1_FOUND=yes
+   ])
+
+   # now check for the header.
+   if test "${AST_$1_FOUND}" = "yes"; then
+      $1_LIB="${pbxlibdir} -l$2 $5"
+      # if --with-$1=DIR has been specified, use it.
+      if test "x${$1_DIR}" != "x"; then
+         $1_INCLUDE="-I${$1_DIR}/include"
+      fi
+      $1_INCLUDE="${$1_INCLUDE} $6"
+      m4_ifval([$4], [
+         # check for the header
+         ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
+         CPPFLAGS="${CPPFLAGS} ${$1_INCLUDE}"
+         AC_CHECK_HEADER([$4], [$1_HEADER_FOUND=1], [$1_HEADER_FOUND=0])
+         CPPFLAGS="${ast_ext_lib_check_saved_CPPFLAGS}"
+      ], [
+         # no header, assume found
+         $1_HEADER_FOUND="1"
+      ])
+   fi
+   # Validate the package with the supplied code.
+   if test "x${$1_HEADER_FOUND}" = "x1" ; then
+      AC_MSG_CHECKING(for $8)
+      ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
+      CPPFLAGS="${CPPFLAGS} ${$1_INCLUDE}"
+      ast_ext_lib_check_saved_LIBS="${LIBS}"
+      LIBS="${$1_LIB}"
+      AC_LINK_IFELSE(
+         [$7],
+         [
+            if test "x${cross_compiling}" = "xyes" ; then
+               $1_VALIDATED="1"
+               AC_MSG_RESULT([yes (guessed for cross-compile)])
+            else
+               ./conftest$EXEEXT
+               if test $? -eq 0 ; then
+                  $1_VALIDATED="1"
+                  AC_MSG_RESULT(yes)
+               else
+                  AC_MSG_RESULT(no)
+               fi
+            fi
+         ],
+         [
+            AC_MSG_RESULT(no)
+         ]
+      )
+      CPPFLAGS="${ast_ext_lib_check_saved_CPPFLAGS}"
+      LIBS="${ast_ext_lib_check_saved_LIBS}"
+   fi
+
+   if test "x${$1_VALIDATED}" = "x1" ; then
+      m4_ifval([$3], [], [
+         # only checking headers -> no library
+         $1_LIB=""
+      ])
+      PBX_$1=1
+      cat >>confdefs.h <<_ACEOF
+[@%:@define] HAVE_$1 1
+_ACEOF
+      m4_ifval([$9], [
+      cat >>confdefs.h <<_ACEOF
+[@%:@define] HAVE_$1_$9 1
+_ACEOF
+            ])
+   else
+      $1_LIB=""
+      $1_INCLUDE=""
+   fi
+fi
+m4_ifval([$9], [AH_TEMPLATE(m4_bpatsubst([[HAVE_$1_$9]], [(.*)]), [Define if $8])])
+])
index de9d590..26a70d2 100644 (file)
@@ -31,6 +31,10 @@ rtpend=20000
 ; seconds after starting learning mode.  Once learning mode completes the
 ; current stream is locked in and cannot change until the next
 ; renegotiation.
+; Valid options are "no" to disable strictrtp, "yes" to enable strictrtp,
+; and "seqno", which does the same thing as strictrtp=yes, but only checks
+; to make sure the sequence number is correct rather than checking the time
+; interval as well.
 ; This option is enabled by default.
 ; strictrtp=yes
 ;
index 70bf5c6..6b71e19 100755 (executable)
--- a/configure
+++ b/configure
 
 
 
-# libunbound v1.5.0 added the ub_ctx_add_ta_autr() API call that we can
-# detect as a useable version so that is going to be the minimum version
-# that we will require.
-# Technically v1.4.21 and later could be used but v1.4.21 has a configure
-# script bug which does not find the ldns library.  The bug is fixed in
-# v1.4.22 but that version is not easily detectable.
-#
+# Check that unbound is installed and the version code fragment compiles
 
 if test "x${PBX_UNBOUND}" != "x1" -a "${USE_UNBOUND}" != "no"; then
    pbxlibdir=""
 
          CPPFLAGS="${ast_ext_lib_check_saved_CPPFLAGS}"
 
-      if test "x${UNBOUND_HEADER_FOUND}" = "x0" ; then
-         UNBOUND_LIB=""
-         UNBOUND_INCLUDE=""
-      else
-
-         PBX_UNBOUND=1
-         cat >>confdefs.h <<_ACEOF
-#define HAVE_UNBOUND 1
-_ACEOF
-
-      fi
    fi
-fi
-
-
-
-    if test "x${PBX_UNBOUND_CONST_PARAMS}" != "x1" -a "${USE_UNBOUND_CONST_PARAMS}" != "no"; then
-        { $as_echo "$as_me:${as_lineno-$LINENO}: checking for UNBOUND_VERSION_MAJOR declared in unbound.h" >&5
-$as_echo_n "checking for UNBOUND_VERSION_MAJOR declared in unbound.h... " >&6; }
-        saved_cppflags="${CPPFLAGS}"
-        if test "x${UNBOUND_CONST_PARAMS_DIR}" != "x"; then
-            UNBOUND_CONST_PARAMS_INCLUDE="-I${UNBOUND_CONST_PARAMS_DIR}/include"
-        fi
-        CPPFLAGS="${CPPFLAGS} ${UNBOUND_CONST_PARAMS_INCLUDE}"
-
-        cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+   # Validate the package with the supplied code.
+   if test "x${UNBOUND_HEADER_FOUND}" = "x1" ; then
+      { $as_echo "$as_me:${as_lineno-$LINENO}: checking for unbound version >= 1.5" >&5
+$as_echo_n "checking for unbound version >= 1.5... " >&6; }
+      ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
+      CPPFLAGS="${CPPFLAGS} ${UNBOUND_INCLUDE}"
+      ast_ext_lib_check_saved_LIBS="${LIBS}"
+      LIBS="${UNBOUND_LIB}"
+      cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
- #include <unbound.h>
+
+      #include <unbound.h>
 int
 main ()
 {
-#if !defined(UNBOUND_VERSION_MAJOR)
-                                    (void) UNBOUND_VERSION_MAJOR;
-                                #endif
+
+            #if (UNBOUND_VERSION_MAJOR < 1 || (UNBOUND_VERSION_MAJOR == 1 && UNBOUND_VERSION_MINOR < 5 ))
+            #error "Unbound version must be >= 1.5"
+            #endif
+
 
   ;
   return 0;
 }
+
 _ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
-     { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+if ac_fn_c_try_link "$LINENO"; then :
+
+            if test "x${cross_compiling}" = "xyes" ; then
+               UNBOUND_VALIDATED="1"
+               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes (guessed for cross-compile)" >&5
+$as_echo "yes (guessed for cross-compile)" >&6; }
+            else
+               ./conftest$EXEEXT
+               if test $? -eq 0 ; then
+                  UNBOUND_VALIDATED="1"
+                  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
 $as_echo "yes" >&6; }
-                PBX_UNBOUND_CONST_PARAMS=1
+               else
+                  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+               fi
+            fi
 
-$as_echo "#define HAVE_UNBOUND_CONST_PARAMS 1" >>confdefs.h
+else
 
+            { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
 
 
-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_exeext conftest.$ac_ext
+      CPPFLAGS="${ast_ext_lib_check_saved_CPPFLAGS}"
+      LIBS="${ast_ext_lib_check_saved_LIBS}"
+   fi
+
+   if test "x${UNBOUND_VALIDATED}" = "x1" ; then
+
+      PBX_UNBOUND=1
+      cat >>confdefs.h <<_ACEOF
+#define HAVE_UNBOUND 1
+_ACEOF
 
+   else
+      UNBOUND_LIB=""
+      UNBOUND_INCLUDE=""
+   fi
 fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
 
-        CPPFLAGS="${saved_cppflags}"
-    fi
 
 
 
index 940bc18..dd0c8ed 100644 (file)
@@ -2261,15 +2261,17 @@ AST_EXT_TOOL_CHECK([NETSNMP], [net-snmp-config], , [--agent-libs],
 
 AST_EXT_LIB_CHECK([NEWT], [newt], [newtBell], [newt.h])
 
-# libunbound v1.5.0 added the ub_ctx_add_ta_autr() API call that we can
-# detect as a useable version so that is going to be the minimum version
-# that we will require.
-# Technically v1.4.21 and later could be used but v1.4.21 has a configure
-# script bug which does not find the ldns library.  The bug is fixed in
-# v1.4.22 but that version is not easily detectable.
-#
-AST_EXT_LIB_CHECK([UNBOUND], [unbound], [ub_ctx_delete], [unbound.h])
-AST_C_DECLARE_CHECK([UNBOUND_CONST_PARAMS], [UNBOUND_VERSION_MAJOR], [unbound.h])
+# Check that unbound is installed and the version code fragment compiles
+AST_EXT_LIB_EXTRA_CHECK([UNBOUND], [unbound], [ub_ctx_delete], [unbound.h],
+   [], [], [
+      AC_LANG_PROGRAM( [#include <unbound.h>],
+         [
+            #if (UNBOUND_VERSION_MAJOR < 1 || (UNBOUND_VERSION_MAJOR == 1 && UNBOUND_VERSION_MINOR < 5 ))
+            #error "Unbound version must be >= 1.5"
+            #endif
+         ]
+      )
+   ], [unbound version >= 1.5])
 
 AST_EXT_LIB_CHECK([UNIXODBC], [odbc], [SQLConnect], [sql.h])
 
index 0e442db..8e3a105 100644 (file)
@@ -752,6 +752,9 @@ int __ao2_trylock(void *a, enum ao2_lock_req lock_how, const char *file, const c
  * lock address, this allows you to correlate against
  * object address, to match objects to reported locks.
  *
+ * \warning AO2 lock objects do not include tracking fields when
+ * DEBUG_THREADS is not enabled.
+ *
  * \since 1.6.1
  */
 void *ao2_object_get_lockaddr(void *obj);
index 59e1e3d..30bb907 100644 (file)
 /* Define to 1 if you have the unbound library. */
 #undef HAVE_UNBOUND
 
-/* Define if your system has UNBOUND_VERSION_MAJOR declared. */
-#undef HAVE_UNBOUND_CONST_PARAMS
-
 /* Define to 1 if you have the <unistd.h> header file. */
 #undef HAVE_UNISTD_H
 
index a46d047..b409a27 100644 (file)
 #define AST_LOCK_TRACK_INIT_VALUE { { NULL }, { 0 }, 0, { NULL }, { 0 }, PTHREAD_MUTEX_INIT_VALUE }
 #endif
 
-#define AST_MUTEX_INIT_VALUE { PTHREAD_MUTEX_INIT_VALUE, NULL, 1 }
-#define AST_MUTEX_INIT_VALUE_NOTRACKING { PTHREAD_MUTEX_INIT_VALUE, NULL, 0 }
+#define AST_MUTEX_INIT_VALUE { PTHREAD_MUTEX_INIT_VALUE, NULL, {1, 0} }
+#define AST_MUTEX_INIT_VALUE_NOTRACKING { PTHREAD_MUTEX_INIT_VALUE, NULL, {0, 0} }
 
-#define AST_RWLOCK_INIT_VALUE { __AST_RWLOCK_INIT_VALUE, NULL, 1 }
-#define AST_RWLOCK_INIT_VALUE_NOTRACKING { __AST_RWLOCK_INIT_VALUE, NULL, 0 }
+#define AST_RWLOCK_INIT_VALUE { __AST_RWLOCK_INIT_VALUE, NULL, {1, 0} }
+#define AST_RWLOCK_INIT_VALUE_NOTRACKING { __AST_RWLOCK_INIT_VALUE, NULL, {0, 0} }
 
 #define AST_MAX_REENTRANCY 10
 
@@ -120,6 +120,13 @@ struct ast_lock_track {
        pthread_mutex_t reentr_mutex;
 };
 
+struct ast_lock_track_flags {
+       /*! non-zero if lock tracking is enabled */
+       unsigned int tracking:1;
+       /*! non-zero if track is setup */
+       volatile unsigned int setup:1;
+};
+
 /*! \brief Structure for mutex and tracking information.
  *
  * We have tracking information in this structure regardless of DEBUG_THREADS being enabled.
@@ -127,9 +134,18 @@ struct ast_lock_track {
  */
 struct ast_mutex_info {
        pthread_mutex_t mutex;
-       /*! Track which thread holds this mutex */
+#if !defined(DEBUG_THREADS) && !defined(DEBUG_THREADS_LOOSE_ABI)
+       /*!
+        * These fields are renamed to ensure they are never used when
+        * DEBUG_THREADS is not defined.
+        */
+       struct ast_lock_track *_track;
+       struct ast_lock_track_flags _flags;
+#elif defined(DEBUG_THREADS)
+       /*! Track which thread holds this mutex. */
        struct ast_lock_track *track;
-       unsigned int tracking:1;
+       struct ast_lock_track_flags flags;
+#endif
 };
 
 /*! \brief Structure for rwlock and tracking information.
@@ -139,9 +155,18 @@ struct ast_mutex_info {
  */
 struct ast_rwlock_info {
        pthread_rwlock_t lock;
+#if !defined(DEBUG_THREADS) && !defined(DEBUG_THREADS_LOOSE_ABI)
+       /*!
+        * These fields are renamed to ensure they are never used when
+        * DEBUG_THREADS is not defined.
+        */
+       struct ast_lock_track *_track;
+       struct ast_lock_track_flags _flags;
+#elif defined(DEBUG_THREADS)
        /*! Track which thread holds this lock */
        struct ast_lock_track *track;
-       unsigned int tracking:1;
+       struct ast_lock_track_flags flags;
+#endif
 };
 
 typedef struct ast_mutex_info ast_mutex_t;
index ea4ad02..23109a6 100644 (file)
        <support_level>core</support_level>
  ***/
 
+/* This reduces the size of lock structures within astobj2 objects when
+ * DEBUG_THREADS is not defined. */
+#define DEBUG_THREADS_LOOSE_ABI
+
 #include "asterisk.h"
 
 #include "asterisk/_private.h"
@@ -1194,8 +1198,11 @@ int astobj2_init(void)
                }
        }
 
+       ast_register_cleanup(astobj2_cleanup);
+
        if (container_init() != 0) {
                fclose(ref_log);
+               ref_log = NULL;
                return -1;
        }
 
@@ -1203,7 +1210,5 @@ int astobj2_init(void)
        ast_cli_register_multiple(cli_astobj2, ARRAY_LEN(cli_astobj2));
 #endif /* defined(AO2_DEBUG) */
 
-       ast_register_cleanup(astobj2_cleanup);
-
        return 0;
 }
index d0447fc..1961b24 100644 (file)
@@ -48,8 +48,6 @@
 #include <math.h>      /* HUGE_VAL */
 #include <regex.h>
 
-#define AST_INCLUDE_GLOB 1
-
 #include "asterisk/config.h"
 #include "asterisk/cli.h"
 #include "asterisk/lock.h"
@@ -2047,10 +2045,8 @@ static struct ast_config *config_text_file_load(const char *database, const char
        /*! Growable string buffer */
        struct ast_str *comment_buffer = NULL;  /*!< this will be a comment collector.*/
        struct ast_str *lline_buffer = NULL;    /*!< A buffer for stuff behind the ; */
-#ifdef AST_INCLUDE_GLOB
        int glob_ret;
        glob_t globbuf;
-#endif
 
        if (cfg) {
                cat = ast_config_get_current_category(cfg);
@@ -2073,7 +2069,7 @@ static struct ast_config *config_text_file_load(const char *database, const char
                        return NULL;
                }
        }
-#ifdef AST_INCLUDE_GLOB
+
        globbuf.gl_offs = 0;    /* initialize it to silence gcc */
        glob_ret = glob(fn, MY_GLOB_FLAGS, NULL, &globbuf);
        if (glob_ret == GLOB_NOSPACE) {
@@ -2101,7 +2097,7 @@ static struct ast_config *config_text_file_load(const char *database, const char
                }
                for (i=0; i<globbuf.gl_pathc; i++) {
                        ast_copy_string(fn, globbuf.gl_pathv[i], sizeof(fn));
-#endif
+
                        /*
                         * The following is not a loop, but just a convenient way to define a block
                         * (using do { } while(0) ), and be able to exit from it with 'continue'
@@ -2160,9 +2156,7 @@ static struct ast_config *config_text_file_load(const char *database, const char
 
                                        if (unchanged) {
                                                AST_LIST_UNLOCK(&cfmtime_head);
-#ifdef AST_INCLUDE_GLOB
                                                globfree(&globbuf);
-#endif
                                                ast_free(comment_buffer);
                                                ast_free(lline_buffer);
                                                return CONFIG_STATUS_FILEUNCHANGED;
@@ -2336,14 +2330,12 @@ static struct ast_config *config_text_file_load(const char *database, const char
                        if (comment) {
                                ast_log(LOG_WARNING,"Unterminated comment detected beginning on line %d\n", nest[comment - 1]);
                        }
-#ifdef AST_INCLUDE_GLOB
                        if (cfg == NULL || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) {
                                break;
                        }
                }
                globfree(&globbuf);
        }
-#endif
 
        ast_free(comment_buffer);
        ast_free(lline_buffer);
index dec814f..5ad9e13 100644 (file)
@@ -72,21 +72,16 @@ static void __dump_backtrace(struct ast_bt *bt, int canlog)
 #ifdef DEBUG_THREADS
 AST_MUTEX_DEFINE_STATIC(reentrancy_lock);
 
-static inline struct ast_lock_track *ast_get_reentrancy(struct ast_lock_track **plt)
+static inline struct ast_lock_track *ast_get_reentrancy(struct ast_lock_track **plt,
+       struct ast_lock_track_flags *flags, int no_setup)
 {
        pthread_mutexattr_t reentr_attr;
        struct ast_lock_track *lt;
 
-       /* It's a bit painful to lock a global mutex for every access to the
-        * reentrancy structure, but it's necessary to ensure that we don't
-        * double-allocate the structure or double-initialize the reentr_mutex.
-        *
-        * If you'd like to replace this with a double-checked lock, be sure to
-        * properly volatile-ize everything to avoid optimizer bugs.
-        *
-        * We also have to use the underlying pthread calls for manipulating
-        * the mutex, because this is called from the Asterisk mutex code.
-        */
+       if (!flags->tracking || flags->setup) {
+               return *plt;
+       }
+
        pthread_mutex_lock(&reentrancy_lock.mutex);
 
        if (*plt) {
@@ -94,6 +89,11 @@ static inline struct ast_lock_track *ast_get_reentrancy(struct ast_lock_track **
                return *plt;
        }
 
+       if (no_setup) {
+               pthread_mutex_unlock(&reentrancy_lock.mutex);
+               return NULL;
+       }
+
        lt = *plt = ast_std_calloc(1, sizeof(*lt));
        if (!lt) {
                fprintf(stderr, "%s: Failed to allocate lock tracking\n", __func__);
@@ -110,6 +110,7 @@ static inline struct ast_lock_track *ast_get_reentrancy(struct ast_lock_track **
        pthread_mutex_init(&lt->reentr_mutex, &reentr_attr);
        pthread_mutexattr_destroy(&reentr_attr);
 
+       flags->setup = 1;
        pthread_mutex_unlock(&reentrancy_lock.mutex);
        return lt;
 }
@@ -148,7 +149,8 @@ int __ast_pthread_mutex_init(int tracking, const char *filename, int lineno, con
 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
 
        t->track = NULL;
-       t->tracking = tracking;
+       t->flags.tracking = tracking;
+       t->flags.setup = 0;
 #endif /* DEBUG_THREADS */
 
        pthread_mutexattr_init(&attr);
@@ -165,8 +167,8 @@ int __ast_pthread_mutex_destroy(const char *filename, int lineno, const char *fu
        int res;
 
 #ifdef DEBUG_THREADS
-       struct ast_lock_track *lt = t->track;
-       int canlog = t->tracking && strcmp(filename, "logger.c");
+       struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 1);
+       int canlog = t->flags.tracking && strcmp(filename, "logger.c");
 
 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
        if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
@@ -243,14 +245,10 @@ int __ast_pthread_mutex_lock(const char *filename, int lineno, const char *func,
        int res;
 
 #ifdef DEBUG_THREADS
-       struct ast_lock_track *lt = NULL;
-       int canlog = t->tracking && strcmp(filename, "logger.c");
+       struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 0);
+       int canlog = t->flags.tracking && strcmp(filename, "logger.c");
        struct ast_bt *bt = NULL;
 
-       if (t->tracking) {
-               lt = ast_get_reentrancy(&t->track);
-       }
-
        if (lt) {
 #ifdef HAVE_BKTR
                struct ast_bt tmp;
@@ -360,14 +358,10 @@ int __ast_pthread_mutex_trylock(const char *filename, int lineno, const char *fu
        int res;
 
 #ifdef DEBUG_THREADS
-       struct ast_lock_track *lt = NULL;
-       int canlog = t->tracking && strcmp(filename, "logger.c");
+       struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 0);
+       int canlog = t->flags.tracking && strcmp(filename, "logger.c");
        struct ast_bt *bt = NULL;
 
-       if (t->tracking) {
-               lt = ast_get_reentrancy(&t->track);
-       }
-
        if (lt) {
 #ifdef HAVE_BKTR
                struct ast_bt tmp;
@@ -420,7 +414,7 @@ int __ast_pthread_mutex_unlock(const char *filename, int lineno, const char *fun
 
 #ifdef DEBUG_THREADS
        struct ast_lock_track *lt = NULL;
-       int canlog = t->tracking && strcmp(filename, "logger.c");
+       int canlog = t->flags.tracking && strcmp(filename, "logger.c");
        struct ast_bt *bt = NULL;
 
 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
@@ -432,10 +426,7 @@ int __ast_pthread_mutex_unlock(const char *filename, int lineno, const char *fun
        }
 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
 
-       if (t->tracking) {
-               lt = ast_get_reentrancy(&t->track);
-       }
-
+       lt = ast_get_reentrancy(&t->track, &t->flags, 0);
        if (lt) {
                ast_reentrancy_lock(lt);
                if (lt->reentrancy && (lt->thread_id[ROFFSET] != pthread_self())) {
@@ -543,7 +534,7 @@ int __ast_cond_wait(const char *filename, int lineno, const char *func,
 #ifdef DEBUG_THREADS
        struct ast_lock_track *lt = NULL;
        struct ast_lock_track lt_orig;
-       int canlog = t->tracking && strcmp(filename, "logger.c");
+       int canlog = t->flags.tracking && strcmp(filename, "logger.c");
 
 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
        if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
@@ -554,10 +545,7 @@ int __ast_cond_wait(const char *filename, int lineno, const char *func,
        }
 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
 
-       if (t->tracking) {
-               lt = ast_get_reentrancy(&t->track);
-       }
-
+       lt = ast_get_reentrancy(&t->track, &t->flags, 0);
        if (lt) {
                ast_reentrancy_lock(lt);
                if (lt->reentrancy && (lt->thread_id[ROFFSET] != pthread_self())) {
@@ -611,7 +599,7 @@ int __ast_cond_timedwait(const char *filename, int lineno, const char *func,
 #ifdef DEBUG_THREADS
        struct ast_lock_track *lt = NULL;
        struct ast_lock_track lt_orig;
-       int canlog = t->tracking && strcmp(filename, "logger.c");
+       int canlog = t->flags.tracking && strcmp(filename, "logger.c");
 
 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
        if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
@@ -622,10 +610,7 @@ int __ast_cond_timedwait(const char *filename, int lineno, const char *func,
        }
 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
 
-       if (t->tracking) {
-               lt = ast_get_reentrancy(&t->track);
-       }
-
+       lt = ast_get_reentrancy(&t->track, &t->flags, 0);
        if (lt) {
                ast_reentrancy_lock(lt);
                if (lt->reentrancy && (lt->thread_id[ROFFSET] != pthread_self())) {
@@ -688,7 +673,8 @@ int __ast_rwlock_init(int tracking, const char *filename, int lineno, const char
 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
 
        t->track = NULL;
-       t->tracking = tracking;
+       t->flags.tracking = tracking;
+       t->flags.setup = 0;
 #endif /* DEBUG_THREADS */
 
        pthread_rwlockattr_init(&attr);
@@ -706,8 +692,8 @@ int __ast_rwlock_destroy(const char *filename, int lineno, const char *func, con
        int res;
 
 #ifdef DEBUG_THREADS
-       struct ast_lock_track *lt = t->track;
-       int canlog = t->tracking && strcmp(filename, "logger.c");
+       struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 1);
+       int canlog = t->flags.tracking && strcmp(filename, "logger.c");
 
 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
        if (t->lock == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
@@ -754,7 +740,7 @@ int __ast_rwlock_unlock(const char *filename, int line, const char *func, ast_rw
 
 #ifdef DEBUG_THREADS
        struct ast_lock_track *lt = NULL;
-       int canlog = t->tracking && strcmp(filename, "logger.c");
+       int canlog = t->flags.tracking && strcmp(filename, "logger.c");
        struct ast_bt *bt = NULL;
        int lock_found = 0;
 
@@ -767,10 +753,7 @@ int __ast_rwlock_unlock(const char *filename, int line, const char *func, ast_rw
        }
 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
 
-       if (t->tracking) {
-               lt = ast_get_reentrancy(&t->track);
-       }
-
+       lt = ast_get_reentrancy(&t->track, &t->flags, 0);
        if (lt) {
                ast_reentrancy_lock(lt);
                if (lt->reentrancy) {
@@ -827,14 +810,10 @@ int __ast_rwlock_rdlock(const char *filename, int line, const char *func, ast_rw
        int res;
 
 #ifdef DEBUG_THREADS
-       struct ast_lock_track *lt = NULL;
-       int canlog = t->tracking && strcmp(filename, "logger.c");
+       struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 0);
+       int canlog = t->flags.tracking && strcmp(filename, "logger.c");
        struct ast_bt *bt = NULL;
 
-       if (t->tracking) {
-               lt = ast_get_reentrancy(&t->track);
-       }
-
        if (lt) {
 #ifdef HAVE_BKTR
                struct ast_bt tmp;
@@ -929,14 +908,10 @@ int __ast_rwlock_wrlock(const char *filename, int line, const char *func, ast_rw
        int res;
 
 #ifdef DEBUG_THREADS
-       struct ast_lock_track *lt = NULL;
-       int canlog = t->tracking && strcmp(filename, "logger.c");
+       struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 0);
+       int canlog = t->flags.tracking && strcmp(filename, "logger.c");
        struct ast_bt *bt = NULL;
 
-       if (t->tracking) {
-               lt = ast_get_reentrancy(&t->track);
-       }
-
        if (lt) {
 #ifdef HAVE_BKTR
                struct ast_bt tmp;
@@ -1031,14 +1006,10 @@ int __ast_rwlock_timedrdlock(const char *filename, int line, const char *func, a
        int res;
 
 #ifdef DEBUG_THREADS
-       struct ast_lock_track *lt = NULL;
-       int canlog = t->tracking && strcmp(filename, "logger.c");
+       struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 0);
+       int canlog = t->flags.tracking && strcmp(filename, "logger.c");
        struct ast_bt *bt = NULL;
 
-       if (t->tracking) {
-               lt = ast_get_reentrancy(&t->track);
-       }
-
        if (lt) {
 #ifdef HAVE_BKTR
                struct ast_bt tmp;
@@ -1117,14 +1088,10 @@ int __ast_rwlock_timedwrlock(const char *filename, int line, const char *func, a
        int res;
 
 #ifdef DEBUG_THREADS
-       struct ast_lock_track *lt = NULL;
-       int canlog = t->tracking && strcmp(filename, "logger.c");
+       struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 0);
+       int canlog = t->flags.tracking && strcmp(filename, "logger.c");
        struct ast_bt *bt = NULL;
 
-       if (t->tracking) {
-               lt = ast_get_reentrancy(&t->track);
-       }
-
        if (lt) {
 #ifdef HAVE_BKTR
                struct ast_bt tmp;
@@ -1202,13 +1169,9 @@ int __ast_rwlock_tryrdlock(const char *filename, int line, const char *func, ast
        int res;
 
 #ifdef DEBUG_THREADS
-       struct ast_lock_track *lt = NULL;
+       struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 0);
        struct ast_bt *bt = NULL;
 
-       if (t->tracking) {
-               lt = ast_get_reentrancy(&t->track);
-       }
-
        if (lt) {
 #ifdef HAVE_BKTR
                struct ast_bt tmp;
@@ -1256,13 +1219,9 @@ int __ast_rwlock_trywrlock(const char *filename, int line, const char *func, ast
        int res;
 
 #ifdef DEBUG_THREADS
-       struct ast_lock_track *lt = NULL;
+       struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 0);
        struct ast_bt *bt = NULL;
 
-       if (t->tracking) {
-               lt = ast_get_reentrancy(&t->track);
-       }
-
        if (lt) {
 #ifdef HAVE_BKTR
                struct ast_bt tmp;
index 9808288..e5fa41c 100644 (file)
@@ -825,6 +825,7 @@ void ast_ari_bridges_start_moh(struct ast_variable *headers,
        }
 
        ast_moh_start(moh_channel, moh_class, NULL);
+       ast_channel_cleanup(moh_channel);
 
        ast_ari_response_no_content(response);
 
index be920d6..6eea305 100644 (file)
@@ -116,6 +116,9 @@ 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)) {
+               if (res == SQL_ERROR) {
+                       ast_odbc_print_errors(SQL_HANDLE_STMT, stmt, "SQL Prepare");
+               }
                ast_log(LOG_WARNING, "SQL Prepare failed! [%s]\n", cps->sql);
                SQLFreeHandle (SQL_HANDLE_STMT, stmt);
                return NULL;
@@ -631,6 +634,9 @@ 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)) {
+               if (res == SQL_ERROR) {
+                       ast_odbc_print_errors(SQL_HANDLE_STMT, stmt, "SQL Prepare");
+               }
                ast_log(LOG_WARNING, "SQL Prepare failed! [%s]\n", ast_str_buffer(sql));
                SQLFreeHandle(SQL_HANDLE_STMT, stmt);
                return NULL;
index b4c1585..1c82e3f 100644 (file)
@@ -431,23 +431,20 @@ struct ast_str *ast_odbc_print_errors(SQLSMALLINT handle_type, SQLHANDLE handle,
 {
        struct ast_str *errors = ast_str_thread_get(&errors_buf, 16);
        SQLINTEGER nativeerror = 0;
-       SQLINTEGER numfields = 0;
        SQLSMALLINT diagbytes = 0;
        SQLSMALLINT i;
        unsigned char state[10];
        unsigned char diagnostic[256];
 
        ast_str_reset(errors);
-       SQLGetDiagField(handle_type, handle, 1, SQL_DIAG_NUMBER, &numfields,
-                       SQL_IS_INTEGER, &diagbytes);
-       for (i = 0; i < numfields; i++) {
-               SQLGetDiagRec(handle_type, handle, i + 1, state, &nativeerror,
-                               diagnostic, sizeof(diagnostic), &diagbytes);
+       i = 0;
+       while (SQLGetDiagRec(handle_type, handle, ++i, state, &nativeerror,
+               diagnostic, sizeof(diagnostic), &diagbytes) == SQL_SUCCESS) {
                ast_str_append(&errors, 0, "%s%s", ast_str_strlen(errors) ? "," : "", state);
                ast_log(LOG_WARNING, "%s returned an error: %s: %s\n", operation, state, diagnostic);
                /* XXX Why is this here? */
                if (i > 10) {
-                       ast_log(LOG_WARNING, "Oh, that was good.  There are really %d diagnostics?\n", (int)numfields);
+                       ast_log(LOG_WARNING, "There are more than 10 diagnostic records! Ignore the rest.\n");
                        break;
                }
        }
index 114a66b..1ddf630 100644 (file)
@@ -990,35 +990,83 @@ static int cli_filter_contacts(void *obj, void *arg, int flags)
        return CMP_MATCH;
 }
 
+static int cli_gather_contact(void *obj, void *arg, int flags)
+{
+       struct ast_sip_contact *contact = obj;
+       RAII_VAR(struct ast_sip_contact_wrapper *, wrapper, NULL, ao2_cleanup);
+
+       if (strcmp(contact->reg_server, ast_config_AST_SYSTEM_NAME ?: "")) {
+               return 0;
+       }
+
+       wrapper = ao2_alloc_options(sizeof(struct ast_sip_contact_wrapper),
+               contact_wrapper_destroy, AO2_ALLOC_OPT_LOCK_NOLOCK);
+       if (!wrapper) {
+               return -1;
+       }
+
+       wrapper->contact_id = ast_malloc(strlen(contact->aor) + strlen(contact->uri) + 2);
+       if (!wrapper->contact_id) {
+               return -1;
+       }
+       sprintf(wrapper->contact_id, "%s/%s", contact->aor, contact->uri);
+
+       wrapper->aor_id = ast_strdup(contact->aor);
+       if (!wrapper->aor_id) {
+               return -1;
+       }
+
+       wrapper->contact = ao2_bump(contact);
+
+       ao2_link(arg, wrapper);
+
+       return 0;
+}
+
 static struct ao2_container *cli_contact_get_container(const char *regex)
 {
-       RAII_VAR(struct ao2_container *, parent_container, NULL, ao2_cleanup);
-       struct ao2_container *child_container;
+       RAII_VAR(struct ao2_container *, aors, NULL, ao2_cleanup);
+       RAII_VAR(struct ao2_container *, contacts, NULL, ao2_cleanup);
+       RAII_VAR(struct ast_variable *, var_aor, NULL, ast_variables_destroy);
+       struct ao2_container *contacts_container;
        regex_t regexbuf;
 
-       parent_container = cli_aor_get_container("");
-       if (!parent_container) {
+       if (!(var_aor = ast_variable_new("contact !=", "", ""))) {
                return NULL;
        }
 
-       child_container = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_NOLOCK, 0,
+       contacts_container = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_NOLOCK, 0,
                cli_contact_sort, cli_contact_compare);
-       if (!child_container) {
+       if (!contacts_container) {
+               return NULL;
+       }
+
+       contacts = ast_sorcery_retrieve_by_regex(ast_sip_get_sorcery(), "contact", regex);
+       if (!contacts) {
+               ao2_ref(contacts_container, -1);
+               return NULL;
+       }
+       ao2_callback(contacts, OBJ_NODATA, cli_gather_contact, contacts_container);
+
+       aors = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(),
+               "aor", AST_RETRIEVE_FLAG_MULTIPLE, var_aor);
+       if (!aors) {
+               ao2_ref(contacts_container, -1);
                return NULL;
        }
 
-       ao2_callback(parent_container, OBJ_NODATA, cli_aor_gather_contacts, child_container);
+       ao2_callback(aors, OBJ_NODATA, cli_aor_gather_contacts, contacts_container);
 
        if (!ast_strlen_zero(regex)) {
                if (regcomp(&regexbuf, regex, REG_EXTENDED | REG_NOSUB)) {
-                       ao2_ref(child_container, -1);
+                       ao2_ref(contacts_container, -1);
                        return NULL;
                }
-               ao2_callback(child_container, OBJ_UNLINK | OBJ_MULTIPLE | OBJ_NODATA, cli_filter_contacts, &regexbuf);
+               ao2_callback(contacts_container, OBJ_UNLINK | OBJ_MULTIPLE | OBJ_NODATA, cli_filter_contacts, &regexbuf);
                regfree(&regexbuf);
        }
 
-       return child_container;
+       return contacts_container;
 }
 
 static void *cli_contact_retrieve_by_id(const char *id)
index 89a934c..7f3836a 100644 (file)
        </configInfo>
  ***/
 
-/*!
- * Unbound versions <= 1.4.20 declare string function parameters as 'char *'
- * but versions >= 1.4.21 declare them as 'const char *'.  Since CentOS6 is still
- * at 1.4.20, we need to cast away the 'const' if we detect the earlier version.
- */
-#ifdef HAVE_UNBOUND_CONST_PARAMS
-#define UNBOUND_CHAR const char
-#else
-#define UNBOUND_CHAR char
-#endif
-
 /*! \brief Structure for an unbound resolver */
 struct unbound_resolver {
        /*! \brief Resolver context itself */
@@ -309,7 +298,7 @@ static int unbound_resolver_resolve(struct ast_dns_query *query)
        data->resolver = ao2_bump(cfg->global->state->resolver);
        ast_dns_resolver_set_data(query, data);
 
-       res = ub_resolve_async(data->resolver->context, (UNBOUND_CHAR *)ast_dns_query_get_name(query),
+       res = ub_resolve_async(data->resolver->context, ast_dns_query_get_name(query),
                ast_dns_query_get_rr_type(query), ast_dns_query_get_rr_class(query),
                ao2_bump(query), unbound_resolver_callback, &data->id);
 
@@ -421,7 +410,7 @@ static int unbound_config_preapply(struct unbound_config *cfg)
        if (!strcmp(cfg->global->hosts, "system")) {
                res = ub_ctx_hosts(cfg->global->state->resolver->context, NULL);
        } else if (!ast_strlen_zero(cfg->global->hosts)) {
-               res = ub_ctx_hosts(cfg->global->state->resolver->context, (UNBOUND_CHAR *)cfg->global->hosts);
+               res = ub_ctx_hosts(cfg->global->state->resolver->context, cfg->global->hosts);
        }
 
        if (res) {
@@ -436,7 +425,7 @@ static int unbound_config_preapply(struct unbound_config *cfg)
 
                it_nameservers = ao2_iterator_init(cfg->global->nameservers, 0);
                while (!res && (nameserver = ao2_iterator_next(&it_nameservers))) {
-                       res = ub_ctx_set_fwd(cfg->global->state->resolver->context, (UNBOUND_CHAR *)nameserver);
+                       res = ub_ctx_set_fwd(cfg->global->state->resolver->context, nameserver);
 
                        if (res) {
                                ast_log(LOG_ERROR, "Failed to add nameserver '%s' to unbound resolver: %s\n",
@@ -453,7 +442,7 @@ static int unbound_config_preapply(struct unbound_config *cfg)
        if (!strcmp(cfg->global->resolv, "system")) {
                res = ub_ctx_resolvconf(cfg->global->state->resolver->context, NULL);
        } else if (!ast_strlen_zero(cfg->global->resolv)) {
-               res = ub_ctx_resolvconf(cfg->global->state->resolver->context, (UNBOUND_CHAR *)cfg->global->resolv);
+               res = ub_ctx_resolvconf(cfg->global->state->resolver->context, cfg->global->resolv);
        }
 
        if (res) {
@@ -463,7 +452,7 @@ static int unbound_config_preapply(struct unbound_config *cfg)
        }
 
        if (!ast_strlen_zero(cfg->global->ta_file)) {
-               res = ub_ctx_add_ta_file(cfg->global->state->resolver->context, (UNBOUND_CHAR *)cfg->global->ta_file);
+               res = ub_ctx_add_ta_file(cfg->global->state->resolver->context, cfg->global->ta_file);
 
                if (res) {
                        ast_log(LOG_ERROR, "Failed to set trusted anchor file to '%s' in unbound resolver: %s\n",
@@ -759,13 +748,13 @@ static enum ast_test_result_state nominal_test(struct ast_test *test, resolve_fn
        static const size_t V4_SIZE = sizeof(struct in_addr);
        static const size_t V6_SIZE = sizeof(struct in6_addr);
 
-       static UNBOUND_CHAR *DOMAIN1 = "goose.feathers";
-       static UNBOUND_CHAR *DOMAIN2 = "duck.feathers";
+       static const char *DOMAIN1 = "goose.feathers";
+       static const char *DOMAIN2 = "duck.feathers";
 
-       static UNBOUND_CHAR *ADDR1 = "127.0.0.2";
-       static UNBOUND_CHAR *ADDR2 = "127.0.0.3";
-       static UNBOUND_CHAR *ADDR3 = "::1";
-       static UNBOUND_CHAR *ADDR4 = "127.0.0.4";
+       static const char *ADDR1 = "127.0.0.2";
+       static const char *ADDR2 = "127.0.0.3";
+       static const char *ADDR3 = "::1";
+       static const char *ADDR4 = "127.0.0.4";
 
        char addr1_buf[V4_SIZE];
        char addr2_buf[V4_SIZE];
@@ -805,7 +794,7 @@ static enum ast_test_result_state nominal_test(struct ast_test *test, resolve_fn
        ub_ctx_zone_add(resolver->context, DOMAIN2, "static");
 
        for (i = 0; i < ARRAY_LEN(records); ++i) {
-               ub_ctx_data_add(resolver->context, (UNBOUND_CHAR *)records[i].as_string);
+               ub_ctx_data_add(resolver->context, records[i].as_string);
        }
 
        for (i = 0; i < ARRAY_LEN(runs); ++i) {
@@ -827,7 +816,7 @@ static enum ast_test_result_state nominal_test(struct ast_test *test, resolve_fn
 
 cleanup:
        for (i = 0; i < ARRAY_LEN(records); ++i) {
-               ub_ctx_data_remove(resolver->context, (UNBOUND_CHAR *)records[i].as_string);
+               ub_ctx_data_remove(resolver->context, records[i].as_string);
        }
        ub_ctx_zone_remove(resolver->context, DOMAIN1);
        ub_ctx_zone_remove(resolver->context, DOMAIN2);
@@ -1031,10 +1020,10 @@ static enum ast_test_result_state off_nominal_test(struct ast_test *test,
 
        static const size_t V4_SIZE = sizeof(struct in_addr);
 
-       static UNBOUND_CHAR *DOMAIN1 = "goose.feathers";
-       static UNBOUND_CHAR *DOMAIN2 = "duck.feathers";
+       static const char *DOMAIN1 = "goose.feathers";
+       static const char *DOMAIN2 = "duck.feathers";
 
-       static UNBOUND_CHAR *ADDR1 = "127.0.0.2";
+       static const char *ADDR1 = "127.0.0.2";
 
        char addr1_buf[V4_SIZE];
 
@@ -1065,7 +1054,7 @@ static enum ast_test_result_state off_nominal_test(struct ast_test *test,
        ub_ctx_zone_add(resolver->context, DOMAIN2, "static");
 
        for (i = 0; i < ARRAY_LEN(records); ++i) {
-               ub_ctx_data_add(resolver->context, (UNBOUND_CHAR *)records[i].as_string);
+               ub_ctx_data_add(resolver->context, records[i].as_string);
        }
 
        for (i = 0; i < ARRAY_LEN(runs); ++i) {
@@ -1253,7 +1242,7 @@ AST_TEST_DEFINE(resolve_naptr)
        ub_ctx_zone_add(resolver->context, DOMAIN1, "static");
 
        for (i = 0; i < ARRAY_LEN(records); ++i) {
-               ub_ctx_data_add(resolver->context, (UNBOUND_CHAR *)records[i].zone_entry);
+               ub_ctx_data_add(resolver->context, records[i].zone_entry);
        }
 
        if (ast_dns_resolve(DOMAIN1, ns_t_naptr, ns_c_in, &result)) {
@@ -1330,8 +1319,8 @@ AST_TEST_DEFINE(resolve_srv)
        RAII_VAR(struct unbound_config *, cfg, NULL, ao2_cleanup);
        RAII_VAR(struct ast_dns_result *, result, NULL, ast_dns_result_free);
        const struct ast_dns_record *record;
-       static UNBOUND_CHAR *DOMAIN1 = "taco.bananas";
-       static UNBOUND_CHAR *DOMAIN1_SRV = "taco.bananas 12345 IN SRV 10 20 5060 sip.taco.bananas";
+       static const char *DOMAIN1 = "taco.bananas";
+       static const char *DOMAIN1_SRV = "taco.bananas 12345 IN SRV 10 20 5060 sip.taco.bananas";
        enum ast_test_result_state res = AST_TEST_PASS;
 
        switch (cmd) {
index 6915186..4b2a138 100644 (file)
@@ -157,6 +157,12 @@ enum strict_rtp_state {
        STRICT_RTP_CLOSED,   /*! Drop all RTP packets not coming from source that was learned */
 };
 
+enum strict_rtp_mode {
+       STRICT_RTP_NO = 0,      /*! Don't adhere to any strict RTP rules */
+       STRICT_RTP_YES,         /*! Strict RTP that restricts packets based on time and sequence number */
+       STRICT_RTP_SEQNO,       /*! Strict RTP that restricts packets based on sequence number */
+};
+
 /*!
  * \brief Strict RTP learning timeout time in milliseconds
  *
@@ -166,7 +172,7 @@ enum strict_rtp_state {
  */
 #define STRICT_RTP_LEARN_TIMEOUT       5000
 
-#define DEFAULT_STRICT_RTP -1  /*!< Enabled */
+#define DEFAULT_STRICT_RTP STRICT_RTP_YES      /*!< Enabled by default */
 #define DEFAULT_ICESUPPORT 1
 
 extern struct ast_srtp_res *res_srtp;
@@ -3154,28 +3160,31 @@ static int rtp_learning_rtp_seq_update(struct rtp_learning_info *info, uint16_t
                info->received = ast_tvnow();
        }
 
-       switch (info->stream_type) {
-       case AST_MEDIA_TYPE_UNKNOWN:
-       case AST_MEDIA_TYPE_AUDIO:
-               /*
-                * Protect against packet floods by checking that we
-                * received the packet sequence in at least the minimum
-                * allowed time.
-                */
-               if (ast_tvzero(info->received)) {
-                       info->received = ast_tvnow();
-               } else if (!info->packets
-                       && ast_tvdiff_ms(ast_tvnow(), info->received) < learning_min_duration) {
-                       /* Packet flood; reset */
-                       info->packets = learning_min_sequential - 1;
-                       info->received = ast_tvnow();
+       /* Only check time if strictrtp is set to yes. Otherwise, we only needed to check seqno */
+       if (strictrtp == STRICT_RTP_YES) {
+               switch (info->stream_type) {
+               case AST_MEDIA_TYPE_UNKNOWN:
+               case AST_MEDIA_TYPE_AUDIO:
+                       /*
+                        * Protect against packet floods by checking that we
+                        * received the packet sequence in at least the minimum
+                        * allowed time.
+                        */
+                       if (ast_tvzero(info->received)) {
+                               info->received = ast_tvnow();
+                       } else if (!info->packets
+                               && ast_tvdiff_ms(ast_tvnow(), info->received) < learning_min_duration) {
+                               /* Packet flood; reset */
+                               info->packets = learning_min_sequential - 1;
+                               info->received = ast_tvnow();
+                       }
+                       break;
+               case AST_MEDIA_TYPE_VIDEO:
+               case AST_MEDIA_TYPE_IMAGE:
+               case AST_MEDIA_TYPE_TEXT:
+               case AST_MEDIA_TYPE_END:
+                       break;
                }
-               break;
-       case AST_MEDIA_TYPE_VIDEO:
-       case AST_MEDIA_TYPE_IMAGE:
-       case AST_MEDIA_TYPE_TEXT:
-       case AST_MEDIA_TYPE_END:
-               break;
        }
 
        info->max_seq = seq;
@@ -6737,6 +6746,8 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc
                        && STRICT_RTP_LEARN_TIMEOUT < ast_tvdiff_ms(ast_tvnow(), rtp->rtp_source_learn.start)) {
                        ast_verb(4, "%p -- Strict RTP learning complete - Locking on source address %s\n",
                                rtp, ast_sockaddr_stringify(&rtp->strict_rtp_address));
+                       ast_test_suite_event_notify("STRICT_RTP_LEARN", "Source: %s",
+                               ast_sockaddr_stringify(&rtp->strict_rtp_address));
                        rtp->strict_rtp_state = STRICT_RTP_CLOSED;
                } else {
                        struct ast_sockaddr target_address;
@@ -6823,6 +6834,16 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc
                }
                ast_debug(1, "%p -- Received RTP packet from %s, dropping due to strict RTP protection.\n",
                        rtp, ast_sockaddr_stringify(&addr));
+#ifdef TEST_FRAMEWORK
+       {
+               static int strict_rtp_test_event = 1;
+               if (strict_rtp_test_event) {
+                       ast_test_suite_event_notify("STRICT_RTP_CLOSED", "Source: %s",
+                               ast_sockaddr_stringify(&addr));
+                       strict_rtp_test_event = 0; /* Only run this event once to prevent possible spam */
+               }
+       }
+#endif
                return &ast_null_frame;
        case STRICT_RTP_OPEN:
                break;
@@ -8111,7 +8132,13 @@ static int rtp_reload(int reload)
                };
        }
        if ((s = ast_variable_retrieve(cfg, "general", "strictrtp"))) {
-               strictrtp = ast_true(s);
+               if (ast_true(s)) {
+                       strictrtp = STRICT_RTP_YES;
+               } else if (!strcasecmp(s, "seqno")) {
+                       strictrtp = STRICT_RTP_SEQNO;
+               } else {
+                       strictrtp = STRICT_RTP_NO;
+               }
        }
        if ((s = ast_variable_retrieve(cfg, "general", "probation"))) {
                if ((sscanf(s, "%d", &learning_min_sequential) != 1) || learning_min_sequential <= 1) {
index 29c0c7c..82d8792 100644 (file)
@@ -472,29 +472,6 @@ static int bridges_channel_sort_fn(const void *obj_left, const void *obj_right,
        return cmp;
 }
 
-/*! Removes the bridge to music on hold channel link */
-static void remove_bridge_moh(char *bridge_id)
-{
-       ao2_find(app_bridges_moh, bridge_id, OBJ_SEARCH_KEY | OBJ_UNLINK | OBJ_NODATA);
-       ast_free(bridge_id);
-}
-
-/*! After bridge failure callback for moh channels */
-static void moh_after_bridge_cb_failed(enum ast_bridge_after_cb_reason reason, void *data)
-{
-       char *bridge_id = data;
-
-       remove_bridge_moh(bridge_id);
-}
-
-/*! After bridge callback for moh channels */
-static void moh_after_bridge_cb(struct ast_channel *chan, void *data)
-{
-       char *bridge_id = data;
-
-       remove_bridge_moh(bridge_id);
-}
-
 /*! Request a bridge MOH channel */
 static struct ast_channel *prepare_bridge_moh_channel(void)
 {
@@ -517,11 +494,34 @@ static struct ast_channel *prepare_bridge_moh_channel(void)
 /*! Provides the moh channel with a thread so it can actually play its music */
 static void *moh_channel_thread(void *data)
 {
-       struct ast_channel *moh_channel = data;
+       struct stasis_app_bridge_channel_wrapper *moh_wrapper = data;
+       struct ast_channel *moh_channel = ast_channel_get_by_name(moh_wrapper->channel_id);
+       struct ast_frame *f;
 
-       while (!ast_safe_sleep(moh_channel, 1000)) {
+       if (!moh_channel) {
+               ao2_unlink(app_bridges_moh, moh_wrapper);
+               ao2_ref(moh_wrapper, -1);
+               return NULL;
        }
 
+       /* Read and discard any frame coming from the stasis bridge. */
+       for (;;) {
+               if (ast_waitfor(moh_channel, -1) < 0) {
+                       /* Error or hungup */
+                       break;
+               }
+
+               f = ast_read(moh_channel);
+               if (!f) {
+                       /* Hungup */
+                       break;
+               }
+               ast_frfree(f);
+       }
+
+       ao2_unlink(app_bridges_moh, moh_wrapper);
+       ao2_ref(moh_wrapper, -1);
+
        ast_moh_stop(moh_channel);
        ast_hangup(moh_channel);
 
@@ -539,15 +539,10 @@ static void *moh_channel_thread(void *data)
  */
 static struct ast_channel *bridge_moh_create(struct ast_bridge *bridge)
 {
-       RAII_VAR(struct stasis_app_bridge_channel_wrapper *, new_wrapper, NULL, ao2_cleanup);
-       RAII_VAR(char *, bridge_id, ast_strdup(bridge->uniqueid), ast_free);
+       struct stasis_app_bridge_channel_wrapper *new_wrapper;
        struct ast_channel *chan;
        pthread_t threadid;
 
-       if (!bridge_id) {
-               return NULL;
-       }
-
        chan = prepare_bridge_moh_channel();
        if (!chan) {
                return NULL;
@@ -558,14 +553,6 @@ static struct ast_channel *bridge_moh_create(struct ast_bridge *bridge)
                return NULL;
        }
 
-       /* The after bridge callback assumes responsibility of the bridge_id. */
-       if (ast_bridge_set_after_callback(chan,
-               moh_after_bridge_cb, moh_after_bridge_cb_failed, bridge_id)) {
-               ast_hangup(chan);
-               return NULL;
-       }
-       bridge_id = NULL;
-
        if (ast_unreal_channel_push_to_bridge(chan, bridge,
                AST_BRIDGE_CHANNEL_FLAG_IMMOVABLE | AST_BRIDGE_CHANNEL_FLAG_LONELY)) {
                ast_hangup(chan);
@@ -579,21 +566,25 @@ static struct ast_channel *bridge_moh_create(struct ast_bridge *bridge)
                return NULL;
        }
 
-       if (ast_string_field_init(new_wrapper, 32)) {
+       if (ast_string_field_init(new_wrapper, AST_UUID_STR_LEN + AST_CHANNEL_NAME)
+               || ast_string_field_set(new_wrapper, bridge_id, bridge->uniqueid)
+               || ast_string_field_set(new_wrapper, channel_id, ast_channel_uniqueid(chan))) {
+               ao2_ref(new_wrapper, -1);
                ast_hangup(chan);
                return NULL;
        }
-       ast_string_field_set(new_wrapper, bridge_id, bridge->uniqueid);
-       ast_string_field_set(new_wrapper, channel_id, ast_channel_uniqueid(chan));
 
        if (!ao2_link_flags(app_bridges_moh, new_wrapper, OBJ_NOLOCK)) {
+               ao2_ref(new_wrapper, -1);
                ast_hangup(chan);
                return NULL;
        }
 
-       if (ast_pthread_create_detached(&threadid, NULL, moh_channel_thread, chan)) {
+       /* Pass the new_wrapper ref to moh_channel_thread() */
+       if (ast_pthread_create_detached(&threadid, NULL, moh_channel_thread, new_wrapper)) {
                ast_log(LOG_ERROR, "Failed to create channel thread. Abandoning MOH channel creation.\n");
                ao2_unlink_flags(app_bridges_moh, new_wrapper, OBJ_NOLOCK);
+               ao2_ref(new_wrapper, -1);
                ast_hangup(chan);
                return NULL;
        }
@@ -2180,8 +2171,8 @@ static int load_module(void)
        app_controls = ao2_container_alloc(CONTROLS_NUM_BUCKETS, control_hash, control_compare);
        app_bridges = ao2_container_alloc(BRIDGES_NUM_BUCKETS, bridges_hash, bridges_compare);
        app_bridges_moh = ao2_container_alloc_hash(
-               AO2_ALLOC_OPT_LOCK_MUTEX, AO2_CONTAINER_ALLOC_OPT_DUPS_REJECT,
-               37, bridges_channel_hash_fn, bridges_channel_sort_fn, NULL);
+               AO2_ALLOC_OPT_LOCK_MUTEX, 0,
+               37, bridges_channel_hash_fn, NULL, NULL);
        app_bridges_playback = ao2_container_alloc_hash(
                AO2_ALLOC_OPT_LOCK_MUTEX, AO2_CONTAINER_ALLOC_OPT_DUPS_REJECT,
                37, bridges_channel_hash_fn, bridges_channel_sort_fn, NULL);
diff --git a/third-party/jansson/patches/0029-json_pack-Improve-handling-of-formats-with-and.patch b/third-party/jansson/patches/0029-json_pack-Improve-handling-of-formats-with-and.patch
new file mode 100644 (file)
index 0000000..fe86db8
--- /dev/null
@@ -0,0 +1,217 @@
+From 5df5fc5b13cac5212482d36e7f3a78951782cfb5 Mon Sep 17 00:00:00 2001
+From: Corey Farrell <git@cfware.com>
+Date: Tue, 25 Sep 2018 14:31:56 -0400
+Subject: [PATCH 29/30] json_pack: Improve handling of formats with '?' and
+ '*'.
+
+Test updates have been removed for easier merging for bundled build.
+
+When NULL is received for an optional argument we should not set an
+error message as this would block later error messages. If NULL is
+received for a non-optional string we should set has_error. Set
+has_error for UTF-8 errors to ensure optional strings with UTF-8
+errors are not replaced with json_null(). Use 'purpose' argument in
+NULL error messages of read_string.
+
+Add error handling and tests for invalid formats where '+', '#', or '%'
+is used on an optional string 's?' or 's*'.
+
+Fix NULL string error messages to use 'purpose'.
+
+Refactor skipping of '*' token, this is now handled by read_string and
+pack_object_inter. This allows invalid format strings such as 's*#' and
+'s*+' to produce error messages.
+
+Fixes #437
+---
+ src/pack_unpack.c           | 74 +++++++++++++++++++++++--------------
+ test/suites/api/test_pack.c | 49 ++++++++++++++++++++++--
+ 2 files changed, 93 insertions(+), 30 deletions(-)
+
+diff --git a/src/pack_unpack.c b/src/pack_unpack.c
+index b842772..fc98df4 100644
+--- a/src/pack_unpack.c
++++ b/src/pack_unpack.c
+@@ -130,7 +130,7 @@ static json_t *pack(scanner_t *s, va_list *ap);
+ /* ours will be set to 1 if jsonp_free() must be called for the result
+    afterwards */
+ static char *read_string(scanner_t *s, va_list *ap,
+-                         const char *purpose, size_t *out_len, int *ours)
++                         const char *purpose, size_t *out_len, int *ours, int optional)
+ {
+     char t;
+     strbuffer_t strbuff;
+@@ -147,7 +147,10 @@ static char *read_string(scanner_t *s, va_list *ap,
+         str = va_arg(*ap, const char *);
+         if(!str) {
+-            set_error(s, "<args>", json_error_null_value, "NULL string argument");
++            if (!optional) {
++                set_error(s, "<args>", json_error_null_value, "NULL %s", purpose);
++                s->has_error = 1;
++            }
+             return NULL;
+         }
+@@ -155,11 +158,17 @@ static char *read_string(scanner_t *s, va_list *ap,
+         if(!utf8_check_string(str, length)) {
+             set_error(s, "<args>", json_error_invalid_utf8, "Invalid UTF-8 %s", purpose);
++            s->has_error = 1;
+             return NULL;
+         }
+         *out_len = length;
+         return (char *)str;
++    } else if (optional) {
++        set_error(s, "<format>", json_error_invalid_format, "Cannot use '%c' on optional strings", t);
++        s->has_error = 1;
++
++        return NULL;
+     }
+     if(strbuffer_init(&strbuff)) {
+@@ -170,7 +179,7 @@ static char *read_string(scanner_t *s, va_list *ap,
+     while(1) {
+         str = va_arg(*ap, const char *);
+         if(!str) {
+-            set_error(s, "<args>", json_error_null_value, "NULL string argument");
++            set_error(s, "<args>", json_error_null_value, "NULL %s", purpose);
+             s->has_error = 1;
+         }
+@@ -226,6 +235,7 @@ static json_t *pack_object(scanner_t *s, va_list *ap)
+         size_t len;
+         int ours;
+         json_t *value;
++        char valueOptional;
+         if(!token(s)) {
+             set_error(s, "<format>", json_error_invalid_format, "Unexpected end of format string");
+@@ -237,20 +247,21 @@ static json_t *pack_object(scanner_t *s, va_list *ap)
+             goto error;
+         }
+-        key = read_string(s, ap, "object key", &len, &ours);
+-        if (!key)
+-            s->has_error = 1;
++        key = read_string(s, ap, "object key", &len, &ours, 0);
+         next_token(s);
++        next_token(s);
++        valueOptional = token(s);
++        prev_token(s);
++
+         value = pack(s, ap);
+         if(!value) {
+             if(ours)
+                 jsonp_free(key);
+-            if(strchr("soO", token(s)) && s->next_token.token == '*') {
+-                next_token(s);
+-            } else {
++            if(valueOptional != '*') {
++                set_error(s, "<args>", json_error_null_value, "NULL object value\n");
+                 s->has_error = 1;
+             }
+@@ -269,8 +280,6 @@ static json_t *pack_object(scanner_t *s, va_list *ap)
+         if(ours)
+             jsonp_free(key);
+-        if(strchr("soO", token(s)) && s->next_token.token == '*')
+-            next_token(s);
+         next_token(s);
+     }
+@@ -289,6 +298,7 @@ static json_t *pack_array(scanner_t *s, va_list *ap)
+     while(token(s) != ']') {
+         json_t *value;
++        char valueOptional;
+         if(!token(s)) {
+             set_error(s, "<format>", json_error_invalid_format, "Unexpected end of format string");
+@@ -296,11 +306,13 @@ static json_t *pack_array(scanner_t *s, va_list *ap)
+             goto error;
+         }
++        next_token(s);
++        valueOptional = token(s);
++        prev_token(s);
++
+         value = pack(s, ap);
+         if(!value) {
+-            if(strchr("soO", token(s)) && s->next_token.token == '*') {
+-                next_token(s);
+-            } else {
++            if(valueOptional != '*') {
+                 s->has_error = 1;
+             }
+@@ -316,8 +328,6 @@ static json_t *pack_array(scanner_t *s, va_list *ap)
+             s->has_error = 1;
+         }
+-        if(strchr("soO", token(s)) && s->next_token.token == '*')
+-            next_token(s);
+         next_token(s);
+     }
+@@ -332,23 +342,33 @@ error:
+ static json_t *pack_string(scanner_t *s, va_list *ap)
+ {
+     char *str;
++    char t;
+     size_t len;
+     int ours;
+-    int nullable;
++    int optional;
+     next_token(s);
+-    nullable = token(s) == '?';
+-    if (!nullable)
++    t = token(s);
++    optional = t == '?' || t == '*';
++    if (!optional)
+         prev_token(s);
+-    str = read_string(s, ap, "string", &len, &ours);
+-    if (!str) {
+-        return nullable ? json_null() : NULL;
+-    } else if (ours) {
+-        return jsonp_stringn_nocheck_own(str, len);
+-    } else {
+-        return json_stringn_nocheck(str, len);
++    str = read_string(s, ap, "string", &len, &ours, optional);
++
++    if (!str)
++        return t == '?' && !s->has_error ? json_null() : NULL;
++
++    if (s->has_error) {
++        if (!ours)
++            jsonp_free(str);
++
++        return NULL;
+     }
++
++    if (ours)
++        return jsonp_stringn_nocheck_own(str, len);
++
++    return json_stringn_nocheck(str, len);
+ }
+ static json_t *pack_object_inter(scanner_t *s, va_list *ap, int need_incref)
+@@ -359,7 +379,7 @@ static json_t *pack_object_inter(scanner_t *s, va_list *ap, int need_incref)
+     next_token(s);
+     ntoken = token(s);
+-    if (ntoken != '?')
++    if (ntoken != '?' && ntoken != '*')
+         prev_token(s);
+     json = va_arg(*ap, json_t *);
+-- 
+2.17.1
+
diff --git a/third-party/jansson/patches/0030-More-work-on-json_pack-error-reporting.patch b/third-party/jansson/patches/0030-More-work-on-json_pack-error-reporting.patch
new file mode 100644 (file)
index 0000000..debb2f5
--- /dev/null
@@ -0,0 +1,100 @@
+From 8d659113d53d7ef60eae6a6e2c5b0ecfc89fc74b Mon Sep 17 00:00:00 2001
+From: Corey Farrell <git@cfware.com>
+Date: Tue, 25 Sep 2018 17:34:25 -0400
+Subject: [PATCH 30/30] More work on json_pack error reporting.
+
+Test updates have been removed for easier merging for bundled build.
+
+* Remove errant line-feed from pack_object error message.
+* Correct error message in pack_object_inter.
+* Create pack_integer / pack_real to get the correct error messages on
+  failure when packing numeric values.
+* Add tests for packing NAN and infinity directly, in an array and as
+  an object value.
+---
+ src/pack_unpack.c           | 46 +++++++++++++++++++++++++++----
+ test/suites/api/test_pack.c | 54 +++++++++++++++++++++++++++++++++++--
+ 2 files changed, 93 insertions(+), 7 deletions(-)
+
+diff --git a/src/pack_unpack.c b/src/pack_unpack.c
+index fc98df4..ec04bc3 100644
+--- a/src/pack_unpack.c
++++ b/src/pack_unpack.c
+@@ -261,7 +261,7 @@ static json_t *pack_object(scanner_t *s, va_list *ap)
+                 jsonp_free(key);
+             if(valueOptional != '*') {
+-                set_error(s, "<args>", json_error_null_value, "NULL object value\n");
++                set_error(s, "<args>", json_error_null_value, "NULL object value");
+                 s->has_error = 1;
+             }
+@@ -396,11 +396,47 @@ static json_t *pack_object_inter(scanner_t *s, va_list *ap, int need_incref)
+             break;
+     }
+-    set_error(s, "<args>", json_error_null_value, "NULL object key");
++    set_error(s, "<args>", json_error_null_value, "NULL object");
+     s->has_error = 1;
+     return NULL;
+ }
++static json_t *pack_integer(scanner_t *s, json_int_t value)
++{
++    json_t *json = json_integer(value);
++
++    if (!json) {
++        set_error(s, "<internal>", json_error_out_of_memory, "Out of memory");
++        s->has_error = 1;
++    }
++
++    return json;
++}
++
++static json_t *pack_real(scanner_t *s, double value)
++{
++    /* Allocate without setting value so we can identify OOM error. */
++    json_t *json = json_real(0.0);
++
++    if (!json) {
++        set_error(s, "<internal>", json_error_out_of_memory, "Out of memory");
++        s->has_error = 1;
++
++        return NULL;
++    }
++
++    if (json_real_set(json, value)) {
++        json_decref(json);
++
++        set_error(s, "<args>", json_error_numeric_overflow, "Invalid floating point value");
++        s->has_error = 1;
++
++        return NULL;
++    }
++
++    return json;
++}
++
+ static json_t *pack(scanner_t *s, va_list *ap)
+ {
+     switch(token(s)) {
+@@ -420,13 +456,13 @@ static json_t *pack(scanner_t *s, va_list *ap)
+             return va_arg(*ap, int) ? json_true() : json_false();
+         case 'i': /* integer from int */
+-            return json_integer(va_arg(*ap, int));
++            return pack_integer(s, va_arg(*ap, int));
+         case 'I': /* integer from json_int_t */
+-            return json_integer(va_arg(*ap, json_int_t));
++            return pack_integer(s, va_arg(*ap, json_int_t));
+         case 'f': /* real */
+-            return json_real(va_arg(*ap, double));
++            return pack_real(s, va_arg(*ap, double));
+         case 'O': /* a json_t object; increments refcount */
+             return pack_object_inter(s, ap, 1);
+-- 
+2.17.1
+
index 708a7ea..2beaef4 100644 (file)
 static void ast_log(int level, const char *file, int line, const char *function, const char *fmt, ...) __attribute__((format(printf, 5, 6)));
 void ast_verbose(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
 
-#define ASINCLUDE_GLOB 1
-#ifdef AST_INCLUDE_GLOB
-
-#if !defined(GLOB_ABORTED)
-#define GLOB_ABORTED GLOB_ABEND
-#endif
-
-# include <glob.h>
-#endif
-
 #define AST_API_MODULE  1 /* gimme the inline defs! */
 struct ast_channel
 {
@@ -3153,29 +3143,6 @@ static struct ast_config *config_text_file_load(const char *database, const char
                CB_INIT();
        }
 
-#ifdef AST_INCLUDE_GLOB
-       {
-               int glob_ret;
-               glob_t globbuf;
-
-               globbuf.gl_offs = 0;    /* initialize it to silence gcc */
-#ifdef SOLARIS
-               glob_ret = glob(fn, GLOB_NOCHECK, NULL, &globbuf);
-#else
-               glob_ret = glob(fn, GLOB_NOMAGIC|GLOB_BRACE, NULL, &globbuf);
-#endif
-               if (glob_ret == GLOB_NOSPACE)
-                       ast_log(LOG_WARNING,
-                               "Glob Expansion of pattern '%s' failed: Not enough memory\n", fn);
-               else if (glob_ret  == GLOB_ABORTED)
-                       ast_log(LOG_WARNING,
-                               "Glob Expansion of pattern '%s' failed: Read error\n", fn);
-               else  {
-                       /* loop over expanded files */
-                       int i;
-                       for (i=0; i<globbuf.gl_pathc; i++) {
-                               ast_copy_string(fn, globbuf.gl_pathv[i], sizeof(fn));
-#endif
        do {
                if (stat(fn, &statbuf))
                        continue;
@@ -3285,14 +3252,6 @@ static struct ast_config *config_text_file_load(const char *database, const char
        if (comment) {
                ast_log(LOG_WARNING,"Unterminated comment detected beginning on line %d\n", nest[comment]);
        }
-#ifdef AST_INCLUDE_GLOB
-                                       if (!cfg)
-                                               break;
-                               }
-                               globfree(&globbuf);
-                       }
-               }
-#endif
        if (cfg && cfg->include_level == 1 && withcomments && comment_buffer) {
                if (comment_buffer) {
                        free(comment_buffer);