Merge "bridge_native_rtp.c: Fail native bridge if no framing match."
authorJoshua Colp <jcolp@digium.com>
Mon, 19 Nov 2018 15:36:17 +0000 (09:36 -0600)
committerGerrit Code Review <gerrit2@gerrit.digium.api>
Mon, 19 Nov 2018 15:36:17 +0000 (09:36 -0600)
65 files changed:
CHANGES
apps/app_queue.c
channels/chan_dahdi.c
channels/chan_iax2.c
channels/chan_mgcp.c
channels/chan_pjsip.c
channels/chan_sip.c
channels/chan_skinny.c
channels/pjsip/dialplan_functions.c
channels/pjsip/include/dialplan_functions.h
channels/sig_pri.c
configure
include/asterisk/backtrace.h
include/asterisk/stasis.h
include/asterisk/stasis_cache_pattern.h
include/asterisk/stasis_message_router.h
main/asterisk.c
main/astmm.c
main/backtrace.c
main/ccss.c
main/devicestate.c
main/dns_naptr.c
main/dns_srv.c
main/endpoints.c
main/logger.c
main/manager.c
main/options.c
main/pbx.c
main/presencestate.c
main/stasis.c
main/stasis_cache.c
main/stasis_cache_pattern.c
main/stasis_message.c
main/stasis_message_router.c
main/taskprocessor.c
main/utils.c
pbx/pbx_config.c
res/parking/parking_applications.c
res/parking/parking_bridge_features.c
res/parking/parking_manager.c
res/res_hep_rtcp.c
res/res_pjsip_caller_id.c
res/res_pjsip_mwi.c
res/res_pjsip_nat.c
res/res_pjsip_outbound_registration.c
res/res_pjsip_publish_asterisk.c
res/res_pjsip_pubsub.c
res/res_pjsip_refer.c
res/res_security_log.c
res/res_stasis_device_state.c
res/res_xmpp.c
tests/CI/gates.jenkinsfile
tests/CI/periodics-daily.jenkinsfile
tests/CI/ref_debug.jenkinsfile
tests/CI/runTestsuite.sh
tests/CI/runUnittests.sh
tests/CI/unittests.jenkinsfile
tests/test_pbx.c
third-party/jansson/patches/0035-Remove-inappropriate-jsonp_free-which-caused-segment.patch [new file with mode: 0644]
third-party/pjproject/Makefile
third-party/pjproject/Makefile.rules
third-party/pjproject/configure.m4
utils/ael_main.c
utils/check_expr.c
utils/conf2ael.c

diff --git a/CHANGES b/CHANGES
index 7fd478b..2c98062 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -23,6 +23,22 @@ chan_sip
 --- Functionality changes from Asterisk 16.0.0 to Asterisk 16.1.0 ------------
 ------------------------------------------------------------------------------
 
+pbx_config
+------------------
+ * pbx_config will now find and process multiple 'globals' sections from
+   extensions.conf.  Variables are processed in the order they are found
+   and duplicate variables overwrite the previous value.
+
+chan_pjsip
+------------------
+ * New dialplan function PJSIP_PARSE_URI added to parse an URI and return
+   a specified part of the URI.
+
+Core
+------------------
+ * ast_bt_get_symbols() now returns a vector of strings instead of an
+   array of strings.  This must be freed with ast_bt_free_symbols.
+
 res_pjsip
 ------------------
  * New options 'trust_connected_line' and 'send_connected_line' have been
index 80c253f..b299889 100644 (file)
@@ -11336,6 +11336,8 @@ static int load_module(void)
        if (!device_state_sub) {
                err = -1;
        }
+       stasis_subscription_accept_message_type(device_state_sub, ast_device_state_message_type());
+       stasis_subscription_set_filter(device_state_sub, STASIS_SUBSCRIPTION_FILTER_SELECTIVE);
 
        manager_topic = ast_manager_get_topic();
        queue_topic = ast_queue_topic_all();
index f4f6514..1eb618b 100644 (file)
@@ -12594,6 +12594,8 @@ static struct dahdi_pvt *mkintf(int channel, const struct dahdi_chan_conf *conf,
                                 * knows that we care about it.  Then, chan_dahdi will get the MWI from the
                                 * event cache instead of checking the mailbox directly. */
                                tmp->mwi_event_sub = stasis_subscribe_pool(mailbox_specific_topic, stasis_subscription_cb_noop, NULL);
+                               stasis_subscription_accept_message_type(tmp->mwi_event_sub, ast_mwi_state_type());
+                               stasis_subscription_set_filter(tmp->mwi_event_sub, STASIS_SUBSCRIPTION_FILTER_SELECTIVE);
                        }
                }
 #ifdef HAVE_DAHDI_LINEREVERSE_VMWI
index 01d42b5..0ca4234 100644 (file)
@@ -1456,6 +1456,8 @@ static void network_change_stasis_subscribe(void)
        if (!network_change_sub) {
                network_change_sub = stasis_subscribe(ast_system_topic(),
                        network_change_stasis_cb, NULL);
+               stasis_subscription_accept_message_type(network_change_sub, ast_network_change_type());
+               stasis_subscription_set_filter(network_change_sub, STASIS_SUBSCRIPTION_FILTER_SELECTIVE);
        }
 }
 
@@ -1469,6 +1471,8 @@ static void acl_change_stasis_subscribe(void)
        if (!acl_change_sub) {
                acl_change_sub = stasis_subscribe(ast_security_topic(),
                        acl_change_stasis_cb, NULL);
+               stasis_subscription_accept_message_type(acl_change_sub, ast_named_acl_change_type());
+               stasis_subscription_set_filter(acl_change_sub, STASIS_SUBSCRIPTION_FILTER_SELECTIVE);
        }
 }
 
@@ -13072,6 +13076,8 @@ static struct iax2_peer *build_peer(const char *name, struct ast_variable *v, st
                         * mailboxes.  However, we just grab the events out of the cache when it
                         * is time to send MWI, since it is only sent with a REGACK. */
                        peer->mwi_event_sub = stasis_subscribe_pool(mailbox_specific_topic, stasis_subscription_cb_noop, NULL);
+                       stasis_subscription_accept_message_type(peer->mwi_event_sub, ast_mwi_state_type());
+                       stasis_subscription_set_filter(peer->mwi_event_sub, STASIS_SUBSCRIPTION_FILTER_SELECTIVE);
                }
        }
 
index 2ac7690..46342ce 100644 (file)
@@ -4242,6 +4242,8 @@ static struct mgcp_gateway *build_gateway(char *cat, struct ast_variable *v)
                                                 * knows that we care about it.  Then, chan_mgcp will get the MWI from the
                                                 * event cache instead of checking the mailbox directly. */
                                                e->mwi_event_sub = stasis_subscribe_pool(mailbox_specific_topic, stasis_subscription_cb_noop, NULL);
+                                               stasis_subscription_accept_message_type(e->mwi_event_sub, ast_mwi_state_type());
+                                               stasis_subscription_set_filter(e->mwi_event_sub, STASIS_SUBSCRIPTION_FILTER_SELECTIVE);
                                        }
                                }
                                snprintf(e->rqnt_ident, sizeof(e->rqnt_ident), "%08lx", (unsigned long)ast_random());
index c28d8ca..9edd989 100644 (file)
@@ -3052,6 +3052,11 @@ static struct ast_custom_function chan_pjsip_dial_contacts_function = {
        .read = pjsip_acf_dial_contacts_read,
 };
 
+static struct ast_custom_function chan_pjsip_parse_uri_function = {
+       .name = "PJSIP_PARSE_URI",
+       .read = pjsip_acf_parse_uri_read,
+};
+
 static struct ast_custom_function media_offer_function = {
        .name = "PJSIP_MEDIA_OFFER",
        .read = pjsip_acf_media_offer_read,
@@ -3101,6 +3106,11 @@ static int load_module(void)
                goto end;
        }
 
+       if (ast_custom_function_register(&chan_pjsip_parse_uri_function)) {
+               ast_log(LOG_ERROR, "Unable to register PJSIP_PARSE_URI dialplan function\n");
+               goto end;
+       }
+
        if (ast_custom_function_register(&media_offer_function)) {
                ast_log(LOG_WARNING, "Unable to register PJSIP_MEDIA_OFFER dialplan function\n");
                goto end;
@@ -3155,6 +3165,7 @@ end:
        ast_custom_function_unregister(&dtmf_mode_function);
        ast_custom_function_unregister(&media_offer_function);
        ast_custom_function_unregister(&chan_pjsip_dial_contacts_function);
+       ast_custom_function_unregister(&chan_pjsip_parse_uri_function);
        ast_custom_function_unregister(&session_refresh_function);
        ast_channel_unregister(&chan_pjsip_tech);
        ast_rtp_glue_unregister(&chan_pjsip_rtp_glue);
@@ -3179,6 +3190,7 @@ static int unload_module(void)
        ast_custom_function_unregister(&dtmf_mode_function);
        ast_custom_function_unregister(&media_offer_function);
        ast_custom_function_unregister(&chan_pjsip_dial_contacts_function);
+       ast_custom_function_unregister(&chan_pjsip_parse_uri_function);
        ast_custom_function_unregister(&session_refresh_function);
 
        ast_channel_unregister(&chan_pjsip_tech);
index 55da37d..cb81901 100644 (file)
@@ -17494,6 +17494,8 @@ static void network_change_stasis_subscribe(void)
        if (!network_change_sub) {
                network_change_sub = stasis_subscribe(ast_system_topic(),
                        network_change_stasis_cb, NULL);
+               stasis_subscription_accept_message_type(network_change_sub, ast_network_change_type());
+               stasis_subscription_set_filter(network_change_sub, STASIS_SUBSCRIPTION_FILTER_SELECTIVE);
        }
 }
 
@@ -17507,6 +17509,8 @@ static void acl_change_stasis_subscribe(void)
        if (!acl_change_sub) {
                acl_change_sub = stasis_subscribe(ast_security_topic(),
                        acl_change_stasis_cb, NULL);
+               stasis_subscription_accept_message_type(acl_change_sub, ast_named_acl_change_type());
+               stasis_subscription_set_filter(acl_change_sub, STASIS_SUBSCRIPTION_FILTER_SELECTIVE);
        }
 
 }
@@ -28385,6 +28389,9 @@ static void add_peer_mwi_subs(struct sip_peer *peer)
                mailbox_specific_topic = ast_mwi_topic(mailbox->id);
                if (mailbox_specific_topic) {
                        mailbox->event_sub = stasis_subscribe_pool(mailbox_specific_topic, mwi_event_cb, peer);
+                       stasis_subscription_accept_message_type(mailbox->event_sub, ast_mwi_state_type());
+                       stasis_subscription_accept_message_type(mailbox->event_sub, stasis_subscription_change_type());
+                       stasis_subscription_set_filter(mailbox->event_sub, STASIS_SUBSCRIPTION_FILTER_SELECTIVE);
                }
        }
 }
index 2b13e5e..910b7b8 100644 (file)
@@ -8334,6 +8334,8 @@ static struct skinny_line *config_line(const char *lname, struct ast_variable *v
                mailbox_specific_topic = ast_mwi_topic(l->mailbox);
                if (mailbox_specific_topic) {
                        l->mwi_event_sub = stasis_subscribe_pool(mailbox_specific_topic, mwi_event_cb, l);
+                       stasis_subscription_accept_message_type(l->mwi_event_sub, ast_mwi_state_type());
+                       stasis_subscription_set_filter(l->mwi_event_sub, STASIS_SUBSCRIPTION_FILTER_SELECTIVE);
                }
        }
 
index d21a80c..70507bb 100644 (file)
                <ref type="function">PJSIP_MEDIA_OFFER</ref>
        </see-also>
 </function>
+<function name="PJSIP_PARSE_URI" language="en_US">
+       <synopsis>
+               Parse an uri and return a type part of the URI.
+       </synopsis>
+       <syntax>
+               <parameter name="uri" required="true">
+                       <para>URI to parse</para>
+               </parameter>
+               <parameter name="type" required="true">
+                       <para>The <literal>type</literal> parameter specifies which URI part to read</para>
+                       <enumlist>
+                               <enum name="display">
+                                       <para>Display name.</para>
+                               </enum>
+                               <enum name="scheme">
+                                       <para>URI scheme.</para>
+                               </enum>
+                               <enum name="user">
+                                       <para>User part.</para>
+                               </enum>
+                               <enum name="passwd">
+                                       <para>Password part.</para>
+                               </enum>
+                               <enum name="host">
+                                       <para>Host part.</para>
+                               </enum>
+                               <enum name="port">
+                                       <para>Port number, or zero.</para>
+                               </enum>
+                               <enum name="user_param">
+                                       <para>User parameter.</para>
+                               </enum>
+                               <enum name="method_param">
+                                       <para>Method parameter.</para>
+                               </enum>
+                               <enum name="transport_param">
+                                       <para>Transport parameter.</para>
+                               </enum>
+                               <enum name="ttl_param">
+                                       <para>TTL param, or -1.</para>
+                               </enum>
+                               <enum name="lr_param">
+                                       <para>Loose routing param, or zero.</para>
+                               </enum>
+                               <enum name="maddr_param">
+                                       <para>Maddr param.</para>
+                               </enum>
+                       </enumlist>
+               </parameter>
+       </syntax>
+       <description>
+               <para>Parse an URI and return a specified part of the URI.</para>
+       </description>
+</function>
 <info name="CHANNEL" language="en_US" tech="PJSIP">
        <enumlist>
                <enum name="rtp">
@@ -1041,6 +1095,127 @@ static struct session_refresh_state *session_refresh_state_get_or_alloc(struct a
        return state;
 }
 
+/*! \brief Struct used to push PJSIP_PARSE_URI function arguments to task processor */
+struct parse_uri_args {
+       const char *uri;
+       const char *type;
+       char *buf;
+       size_t buflen;
+       int ret;
+};
+
+/*! \internal \brief Taskprocessor callback that handles the PJSIP_PARSE_URI on a PJSIP thread */
+static int parse_uri_cb(void *data)
+{
+       struct parse_uri_args *args = data;
+       pj_pool_t *pool;
+       pjsip_name_addr *uri;
+       pjsip_sip_uri *sip_uri;
+       pj_str_t tmp;
+
+       args->ret = 0;
+
+       pool = pjsip_endpt_create_pool(ast_sip_get_pjsip_endpoint(), "ParseUri", 128, 128);
+       if (!pool) {
+               ast_log(LOG_ERROR, "Failed to allocate ParseUri endpoint pool.\n");
+               args->ret = -1;
+               return 0;
+       }
+
+       pj_strdup2_with_null(pool, &tmp, args->uri);
+       uri = (pjsip_name_addr *)pjsip_parse_uri(pool, tmp.ptr, tmp.slen, PJSIP_PARSE_URI_AS_NAMEADDR);
+       if (!uri) {
+               ast_log(LOG_WARNING, "Failed to parse URI '%s'\n", args->uri);
+               pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool);
+               args->ret = -1;
+               return 0;
+       }
+
+       if (!strcmp(args->type, "scheme")) {
+               ast_copy_pj_str(args->buf, pjsip_uri_get_scheme(uri), args->buflen);
+               pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool);
+               return 0;
+       } else if (!strcmp(args->type, "display")) {
+               ast_copy_pj_str(args->buf, &uri->display, args->buflen);
+               pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool);
+               return 0;
+       }
+
+       sip_uri = pjsip_uri_get_uri(uri);
+       if (!sip_uri) {
+               ast_log(LOG_ERROR, "Failed to get an URI object for '%s'\n", args->uri);
+               pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool);
+               args->ret = -1;
+               return 0;
+       }
+
+       if (!strcmp(args->type, "user")) {
+               ast_copy_pj_str(args->buf, &sip_uri->user, args->buflen);
+       } else if (!strcmp(args->type, "passwd")) {
+               ast_copy_pj_str(args->buf, &sip_uri->passwd, args->buflen);
+       } else if (!strcmp(args->type, "host")) {
+               ast_copy_pj_str(args->buf, &sip_uri->host, args->buflen);
+       } else if (!strcmp(args->type, "port")) {
+               snprintf(args->buf, args->buflen, "%d", sip_uri->port);
+       } else if (!strcmp(args->type, "user_param")) {
+               ast_copy_pj_str(args->buf, &sip_uri->user_param, args->buflen);
+       } else if (!strcmp(args->type, "method_param")) {
+               ast_copy_pj_str(args->buf, &sip_uri->method_param, args->buflen);
+       } else if (!strcmp(args->type, "transport_param")) {
+               ast_copy_pj_str(args->buf, &sip_uri->transport_param, args->buflen);
+       } else if (!strcmp(args->type, "ttl_param")) {
+               snprintf(args->buf, args->buflen, "%d", sip_uri->ttl_param);
+       } else if (!strcmp(args->type, "lr_param")) {
+               snprintf(args->buf, args->buflen, "%d", sip_uri->lr_param);
+       } else if (!strcmp(args->type, "maddr_param")) {
+               ast_copy_pj_str(args->buf, &sip_uri->maddr_param, args->buflen);
+       } else {
+               ast_log(AST_LOG_WARNING, "Unknown type part '%s' specified\n", args->type);
+               pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool);
+               args->ret = -1;
+               return 0;
+       }
+
+       pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool);
+
+       return 0;
+}
+
+int pjsip_acf_parse_uri_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
+{
+       struct parse_uri_args func_args = { 0, };
+
+       AST_DECLARE_APP_ARGS(args,
+               AST_APP_ARG(uri_str);
+               AST_APP_ARG(type);
+       );
+
+       AST_STANDARD_APP_ARGS(args, data);
+
+       if (ast_strlen_zero(args.uri_str)) {
+               ast_log(LOG_WARNING, "An URI must be specified when using the '%s' dialplan function\n", cmd);
+               return -1;
+       }
+
+       if (ast_strlen_zero(args.type)) {
+               ast_log(LOG_WARNING, "A type part of the URI must be specified when using the '%s' dialplan function\n", cmd);
+               return -1;
+       }
+
+       memset(buf, 0, buflen);
+
+       func_args.uri = args.uri_str;
+       func_args.type = args.type;
+       func_args.buf = buf;
+       func_args.buflen = buflen;
+       if (ast_sip_push_task_wait_serializer(NULL, parse_uri_cb, &func_args)) {
+               ast_log(LOG_WARNING, "Unable to parse URI: failed to push task\n");
+               return -1;
+       }
+
+       return func_args.ret;
+}
+
 static int media_offer_read_av(struct ast_sip_session *session, char *buf,
                               size_t len, enum ast_media_type media_type)
 {
index 731e91d..a9332a2 100644 (file)
@@ -110,4 +110,17 @@ int pjsip_acf_session_refresh_write(struct ast_channel *chan, const char *cmd, c
  */
 int pjsip_acf_dial_contacts_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len);
 
+/*!
+ * \brief PJSIP_PARSE_URI function read callback
+ * \param chan The channel the function is called on
+ * \param cmd The name of the function
+ * \param data Arguments passed to the function
+ * \param buf Out buffer that should be populated with the data
+ * \param len Size of the buffer
+ *
+ * \retval 0 on success
+ * \retval -1 on failure
+ */
+int pjsip_acf_parse_uri_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len);
+
 #endif /* _PJSIP_DIALPLAN_FUNCTIONS */
\ No newline at end of file
index fbc4e40..ec6d666 100644 (file)
@@ -9130,6 +9130,9 @@ int sig_pri_start_pri(struct sig_pri_span *pri)
                if (!pri->mbox[i].sub) {
                        ast_log(LOG_ERROR, "%s span %d could not subscribe to MWI events for %s(%s).\n",
                                sig_pri_cc_type_name, pri->span, pri->mbox[i].vm_box, mbox_id);
+               } else {
+                       stasis_subscription_accept_message_type(pri->mbox[i].sub, ast_mwi_state_type());
+                       stasis_subscription_set_filter(pri->mbox[i].sub, STASIS_SUBSCRIPTION_FILTER_SELECTIVE);
                }
 #if defined(HAVE_PRI_MWI_V2)
                if (ast_strlen_zero(pri->mbox[i].vm_number)) {
index 47cf7e7..ee3eb4b 100755 (executable)
--- a/configure
+++ b/configure
@@ -9411,7 +9411,7 @@ $as_echo "configuring" >&6; }
        fi
 
        export TAR PATCH SED NM EXTERNALS_CACHE_DIR AST_DOWNLOAD_CACHE DOWNLOAD_TO_STDOUT DOWNLOAD_TIMEOUT DOWNLOAD MD5 CAT CUT GREP
-       export NOISY_BUILD
+       export NOISY_BUILD AST_DEVMODE
        ${GNU_MAKE} --quiet --no-print-directory -C ${PJPROJECT_DIR} \
                PJPROJECT_CONFIGURE_OPTS="$PJPROJECT_CONFIGURE_OPTS" \
                EXTERNALS_CACHE_DIR="${EXTERNALS_CACHE_DIR:-${AST_DOWNLOAD_CACHE}}" \
index 95358bf..fdacf98 100644 (file)
 #define ast_bt_create() __ast_bt_create()
 #define ast_bt_destroy(bt) __ast_bt_destroy((bt))
 #define ast_bt_get_symbols(addresses, num_frames) __ast_bt_get_symbols((addresses), (num_frames))
+#define ast_bt_free_symbols(string_vector) __ast_bt_free_symbols((string_vector))
 #else
 #define ast_bt_get_addresses(bt) 0
 #define ast_bt_create() NULL
 #define ast_bt_destroy(bt) NULL
 #define ast_bt_get_symbols(addresses, num_frames) NULL
+#define ast_bt_free_symbols(string_vector) NULL
 #endif
 
 /* \brief
@@ -86,11 +88,24 @@ void *__ast_bt_destroy(struct ast_bt *bt);
  *
  * \param addresses A list of addresses, such as the ->addresses structure element of struct ast_bt.
  * \param num_frames Number of addresses in the addresses list
+ *
  * \retval NULL Unable to allocate memory
- * \return List of strings. Free the entire list with a single ast_std_free call.
+ * \return Vector of strings. Free with ast_bt_free_symbols
+ *
+ * \note The first frame in the addresses array will usually point to __ast_bt_create
+ * so when printing the symbols you may wish to start at position 1 rather than 0.
+ *
  * \since 1.6.2.16
  */
-char **__ast_bt_get_symbols(void **addresses, size_t num_frames);
+struct ast_vector_string *__ast_bt_get_symbols(void **addresses, size_t num_frames);
+
+/* \brief Free symbols returned from ast_bt_get_symbols
+ *
+ * \param symbols The symbol string vector
+ *
+ * \since 13.24.0
+ */
+void __ast_bt_free_symbols(struct ast_vector_string *symbols);
 
 #endif /* HAVE_BKTR */
 
index 2b56b53..ebd00ee 100644 (file)
@@ -292,6 +292,15 @@ enum stasis_message_type_result {
 };
 
 /*!
+ * \brief Stasis subscription message filters
+ */
+enum stasis_subscription_message_filter {
+       STASIS_SUBSCRIPTION_FILTER_NONE = 0,    /*!< No filter is in place, all messages are raised */
+       STASIS_SUBSCRIPTION_FILTER_FORCED_NONE, /*!< No filter is in place or can be set, all messages are raised */
+       STASIS_SUBSCRIPTION_FILTER_SELECTIVE,   /*!< Only messages of allowed message types are raised */
+};
+
+/*!
  * \brief Create a new message type.
  *
  * \ref stasis_message_type is an AO2 object, so ao2_cleanup() when you're done
@@ -327,6 +336,14 @@ const char *stasis_message_type_name(const struct stasis_message_type *type);
 unsigned int stasis_message_type_hash(const struct stasis_message_type *type);
 
 /*!
+ * \brief Gets the id of a given message type
+ * \param type The type to get the id of.
+ * \return The id
+ * \since 17.0.0
+ */
+int stasis_message_type_id(const struct stasis_message_type *type);
+
+/*!
  * \brief Check whether a message type is declined
  *
  * \param name The name of the message type to check
@@ -495,6 +512,14 @@ struct stasis_topic *stasis_topic_create(const char *name);
 const char *stasis_topic_name(const struct stasis_topic *topic);
 
 /*!
+ * \brief Return the number of subscribers of a topic.
+ * \param topic Topic.
+ * \return Number of subscribers of the topic.
+ * \since 17.0.0
+ */
+size_t stasis_topic_subscribers(const struct stasis_topic *topic);
+
+/*!
  * \brief Publish a message to a topic's subscribers.
  * \param topic Topic.
  * \param message Message to publish.
@@ -559,6 +584,10 @@ void stasis_subscription_cb_noop(void *data, struct stasis_subscription *sub, st
  * \return New \ref stasis_subscription object.
  * \return \c NULL on error.
  * \since 12
+ *
+ * \note This callback will receive a callback with a message indicating it
+ * has been subscribed. This occurs immediately before accepted message
+ * types can be set and the callback must expect to receive it.
  */
 struct stasis_subscription *stasis_subscribe(struct stasis_topic *topic,
        stasis_subscription_cb callback, void *data);
@@ -584,11 +613,69 @@ struct stasis_subscription *stasis_subscribe(struct stasis_topic *topic,
  * \return New \ref stasis_subscription object.
  * \return \c NULL on error.
  * \since 12.8.0
+ *
+ * \note This callback will receive a callback with a message indicating it
+ * has been subscribed. This occurs immediately before accepted message
+ * types can be set and the callback must expect to receive it.
  */
 struct stasis_subscription *stasis_subscribe_pool(struct stasis_topic *topic,
        stasis_subscription_cb callback, void *data);
 
 /*!
+ * \brief Indicate to a subscription that we are interested in a message type.
+ *
+ * This will cause the subscription to allow the given message type to be
+ * raised to our subscription callback. This enables internal filtering in
+ * the stasis message bus to reduce messages.
+ *
+ * \param subscription Subscription to add message type to.
+ * \param type The message type we wish to receive.
+ * \retval 0 on success
+ * \retval -1 failure
+ *
+ * \since 17.0.0
+ *
+ * \note If you are wanting to use stasis_final_message you will need to accept
+ * \ref stasis_subscription_change_type as a message type.
+ *
+ * \note Until the subscription is set to selective filtering it is possible for it
+ * to receive messages of message types that would not normally be accepted.
+ */
+int stasis_subscription_accept_message_type(struct stasis_subscription *subscription,
+       const struct stasis_message_type *type);
+
+/*!
+ * \brief Indicate to a subscription that we are not interested in a message type.
+ *
+ * \param subscription Subscription to remove message type from.
+ * \param type The message type we don't wish to receive.
+ * \retval 0 on success
+ * \retval -1 failure
+ *
+ * \since 17.0.0
+ */
+int stasis_subscription_decline_message_type(struct stasis_subscription *subscription,
+       const struct stasis_message_type *type);
+
+/*!
+ * \brief Set the message type filtering level on a subscription
+ *
+ * This will cause the subscription to filter messages according to the
+ * provided filter level. For example if selective is used then only
+ * messages matching those provided to \ref stasis_subscription_accept_message_type
+ * will be raised to the subscription callback.
+ *
+ * \param subscription Subscription that should receive all messages.
+ * \param filter What filter to use
+ * \retval 0 on success
+ * \retval -1 failure
+ *
+ * \since 17.0.0
+ */
+int stasis_subscription_set_filter(struct stasis_subscription *subscription,
+       enum stasis_subscription_message_filter filter);
+
+/*!
  * \brief Cancel a subscription.
  *
  * Note that in an asynchronous system, there may still be messages queued or
@@ -1037,6 +1124,41 @@ struct stasis_topic *stasis_caching_get_topic(
        struct stasis_caching_topic *caching_topic);
 
 /*!
+ * \brief Indicate to a caching topic that we are interested in a message type.
+ *
+ * This will cause the caching topic to receive messages of the given message
+ * type. This enables internal filtering in the stasis message bus to reduce
+ * messages.
+ *
+ * \param caching_topic The caching topic.
+ * \param type The message type we wish to receive.
+ * \retval 0 on success
+ * \retval -1 failure
+ *
+ * \since 17.0.0
+ */
+int stasis_caching_accept_message_type(struct stasis_caching_topic *caching_topic,
+       struct stasis_message_type *type);
+
+/*!
+ * \brief Set the message type filtering level on a cache
+ *
+ * This will cause the underlying subscription to filter messages according to the
+ * provided filter level. For example if selective is used then only
+ * messages matching those provided to \ref stasis_subscription_accept_message_type
+ * will be raised to the subscription callback.
+ *
+ * \param caching_topic The caching topic.
+ * \param filter What filter to use
+ * \retval 0 on success
+ * \retval -1 failure
+ *
+ * \since 17.0.0
+ */
+int stasis_caching_set_filter(struct stasis_caching_topic *caching_topic,
+       enum stasis_subscription_message_filter filter);
+
+/*!
  * \brief A message which instructs the caching topic to remove an entry from
  * its cache.
  *
index e61d3e9..514d62e 100644 (file)
@@ -169,4 +169,39 @@ struct stasis_topic *stasis_cp_single_topic(struct stasis_cp_single *one);
 struct stasis_topic *stasis_cp_single_topic_cached(
        struct stasis_cp_single *one);
 
+/*!
+ * \brief Indicate to an instance that we are interested in a message type.
+ *
+ * This will cause the caching topic to receive messages of the given message
+ * type. This enables internal filtering in the stasis message bus to reduce
+ * messages.
+ *
+ * \param one One side of the cache pattern.
+ * \param type The message type we wish to receive.
+ * \retval 0 on success
+ * \retval -1 failure
+ *
+ * \since 17.0.0
+ */
+int stasis_cp_single_accept_message_type(struct stasis_cp_single *one,
+       struct stasis_message_type *type);
+
+/*!
+ * \brief Set the message type filtering level on a cache
+ *
+ * This will cause the underlying subscription to filter messages according to the
+ * provided filter level. For example if selective is used then only
+ * messages matching those provided to \ref stasis_subscription_accept_message_type
+ * will be raised to the subscription callback.
+ *
+ * \param one One side of the cache pattern.
+ * \param filter What filter to use
+ * \retval 0 on success
+ * \retval -1 failure
+ *
+ * \since 17.0.0
+ */
+int stasis_cp_single_set_filter(struct stasis_cp_single *one,
+       enum stasis_subscription_message_filter filter);
+
 #endif /* _ASTERISK_STASIS_CACHE_PATTERN_H */
index 50270a7..8dcdfcc 100644 (file)
@@ -233,6 +233,10 @@ void stasis_message_router_remove_cache_update(
  * \retval -1 on failure
  *
  * \since 12
+ *
+ * \note Setting a default callback will automatically cause the underlying
+ * subscription to receive all messages and not be filtered. If filtering is
+ * desired then a specific route for each message type should be provided.
  */
 int stasis_message_router_set_default(struct stasis_message_router *router,
                                      stasis_subscription_cb callback,
index 1d52567..7eb49df 100644 (file)
@@ -392,6 +392,7 @@ static struct {
         unsigned int need_reload:1;
         unsigned int need_quit:1;
         unsigned int need_quit_handler:1;
+        unsigned int need_el_end:1;
 } sig_flags;
 
 #if !defined(LOW_MEMORY)
@@ -1675,9 +1676,15 @@ static struct sigaction urg_handler = {
 static void _hup_handler(int num)
 {
        int save_errno = errno;
-       printf("Received HUP signal -- Reloading configs\n");
-       if (restartnow)
+
+       if (restartnow) {
+               if (el) {
+                       el_end(el);
+               }
                execvp(_argv[0], _argv);
+       }
+
+       printf("Received HUP signal -- Reloading configs\n");
        sig_flags.need_reload = 1;
        if (ast_alertpipe_write(sig_alert_pipe)) {
                fprintf(stderr, "hup_handler: write() failed: %s\n", strerror(errno));
@@ -2018,10 +2025,9 @@ static void really_quit(int num, shutdown_nice_t niceness, int restart)
                        if (el_hist != NULL) {
                                history_end(el_hist);
                        }
-               } else if (mon_sig_flags == pthread_self()) {
-                       if (consolethread != AST_PTHREADT_NULL) {
-                               pthread_kill(consolethread, SIGURG);
-                       }
+               } else if (!restart) {
+                       sig_flags.need_el_end = 1;
+                       pthread_kill(consolethread, SIGURG);
                }
        }
        active_channels = ast_active_channels();
@@ -2638,7 +2644,7 @@ static int ast_el_read_char(EditLine *editline, CHAR_T_LIBEDIT *cp)
                }
                res = ast_poll(fds, max, -1);
                if (res < 0) {
-                       if (sig_flags.need_quit || sig_flags.need_quit_handler) {
+                       if (sig_flags.need_quit || sig_flags.need_quit_handler || sig_flags.need_el_end) {
                                break;
                        }
                        if (errno == EINTR) {
@@ -3166,7 +3172,7 @@ static void ast_remotecontrol(char *data)
                sprintf(tmp, "%s%s", prefix, data);
                if (write(ast_consock, tmp, strlen(tmp) + 1) < 0) {
                        ast_log(LOG_ERROR, "write() failed: %s\n", strerror(errno));
-                       if (sig_flags.need_quit || sig_flags.need_quit_handler) {
+                       if (sig_flags.need_quit || sig_flags.need_quit_handler || sig_flags.need_el_end) {
                                return;
                        }
                }
@@ -3198,7 +3204,7 @@ static void ast_remotecontrol(char *data)
                        char buffer[512] = "", *curline = buffer, *nextline;
                        int not_written = 1;
 
-                       if (sig_flags.need_quit || sig_flags.need_quit_handler) {
+                       if (sig_flags.need_quit || sig_flags.need_quit_handler || sig_flags.need_el_end) {
                                break;
                        }
 
@@ -3258,7 +3264,7 @@ static void ast_remotecontrol(char *data)
        for (;;) {
                ebuf = (char *)el_gets(el, &num);
 
-               if (sig_flags.need_quit || sig_flags.need_quit_handler) {
+               if (sig_flags.need_quit || sig_flags.need_quit_handler || sig_flags.need_el_end) {
                        break;
                }
 
@@ -4201,6 +4207,12 @@ static void asterisk_daemon(int isroot, const char *runuser, const char *rungrou
                el_set(el, EL_GETCFN, ast_el_read_char);
 
                for (;;) {
+                       if (sig_flags.need_el_end) {
+                               el_end(el);
+
+                               return;
+                       }
+
                        if (sig_flags.need_quit || sig_flags.need_quit_handler) {
                                quit_handler(0, SHUTDOWN_FAST, 0);
                                break;
index c845ee7..3a28f5d 100644 (file)
@@ -191,7 +191,7 @@ AST_MUTEX_DEFINE_STATIC_NOTRACKING(reglock);
 static void print_backtrace(struct ast_bt *bt)
 {
        int i = 0;
-       char **strings;
+       struct ast_vector_string *strings;
 
        if (!bt) {
                return;
@@ -199,10 +199,10 @@ static void print_backtrace(struct ast_bt *bt)
 
        if ((strings = ast_bt_get_symbols(bt->addresses, bt->num_frames))) {
                astmm_log("Memory allocation backtrace:\n");
-               for (i = 3; i < bt->num_frames - 2; i++) {
-                       astmm_log("#%d: [%p] %s\n", i - 3, bt->addresses[i], strings[i]);
+               for (i = 3; i < AST_VECTOR_SIZE(strings) - 2; i++) {
+                       astmm_log("#%d: %s\n", i - 3, AST_VECTOR_GET(strings, i));
                }
-               ast_std_free(strings);
+               ast_bt_free_symbols(strings);
        }
 }
 
index 7dfcfc3..16f5a56 100644 (file)
        <support_level>core</support_level>
  ***/
 
-#include "asterisk.h"
+/*
+ * Block automatic include of asterisk/lock.h to allow use of pthread_mutex
+ * functions directly.  We don't need or want the lock.h overhead.
+ */
+#define _ASTERISK_LOCK_H
 
+/*
+ * The astmm ast_ memory management functions can cause ast_bt_get_symbols
+ * to be invoked so we must not use them.
+ */
+#define ASTMM_LIBC ASTMM_IGNORE
+
+#include "asterisk.h"
 #include "asterisk/backtrace.h"
-#include "asterisk/utils.h"
-#include "asterisk/strings.h"
+
+/*
+ * As stated above, the vector macros call the ast_ functions so
+ * we need to remap those back to the libc ones.
+ */
+#undef ast_free
+#undef ast_calloc
+#undef ast_malloc
+#define ast_free(x) free(x)
+#define ast_calloc(n, x) calloc(n, x)
+#define ast_malloc(x) malloc(x)
+
+#include "asterisk/vector.h"
 
 #ifdef HAVE_BKTR
 #include <execinfo.h>
 #include <bfd.h>
 #endif
 
+#include <pthread.h>
+
+/* simple definition of S_OR so we don't have include strings.h */
+#define S_OR(a, b) (a && a[0] != '\0') ? a : b
+
 struct ast_bt *__ast_bt_create(void)
 {
-       struct ast_bt *bt = ast_std_calloc(1, sizeof(*bt));
+       struct ast_bt *bt = calloc(1, sizeof(*bt));
 
        if (!bt) {
                return NULL;
@@ -62,164 +89,217 @@ int __ast_bt_get_addresses(struct ast_bt *bt)
 void *__ast_bt_destroy(struct ast_bt *bt)
 {
        if (bt && bt->alloced) {
-               ast_std_free(bt);
+               free(bt);
        }
        return NULL;
 }
 
-char **__ast_bt_get_symbols(void **addresses, size_t num_frames)
-{
-       char **strings;
-#if defined(BETTER_BACKTRACES)
-       int stackfr;
-       bfd *bfdobj;           /* bfd.h */
+#ifdef BETTER_BACKTRACES
+
+struct bfd_data {
+       struct ast_vector_string *return_strings;
+       bfd_vma pc;            /* bfd.h */
+       asymbol **syms;        /* bfd.h */
        Dl_info dli;           /* dlfcn.h */
-       long allocsize;
-       asymbol **syms = NULL; /* bfd.h */
-       bfd_vma offset;        /* bfd.h */
-       const char *lastslash;
-       asection *section;
+       const char *libname;
+       int dynamic;
+       int has_syms;
+       char *msg;
+       int found;
+};
+
+#define MSG_BUFF_LEN 1024
+
+static void process_section(bfd *bfdobj, asection *section, void *obj)
+{
+       struct bfd_data *data = obj;
        const char *file, *func;
        unsigned int line;
-       char address_str[128];
-       char msg[1024];
-       size_t strings_size;
-       size_t *eachlen;
-#endif
+       bfd_vma offset;
+       bfd_vma vma;
+       bfd_size_type size;
+       bfd_boolean line_found = 0;
+       char *fn;
+       int inlined = 0;
+
+       offset = data->pc - (data->dynamic ? (bfd_vma) data->dli.dli_fbase : 0);
+
+       if (!(bfd_get_section_flags(bfdobj, section) & SEC_ALLOC)) {
+               return;
+       }
 
-#if defined(BETTER_BACKTRACES)
-       strings_size = num_frames * sizeof(*strings);
+       vma = bfd_get_section_vma(bfdobj, section);
+       size = bfd_get_section_size(section);
+
+       if (offset < vma || offset >= vma + size) {
+               /* Not in this section */
+               return;
+       }
+
+       line_found = bfd_find_nearest_line(bfdobj, section, data->syms, offset - vma, &file,
+               &func, &line);
+       if (!line_found) {
+               return;
+       }
+
+       /*
+        * If we find a line, we will want to continue calling bfd_find_inliner_info
+        * to capture any inlined functions that don't have their own stack frames.
+        */
+       do {
+               data->found++;
+               /* file can possibly be null even with a success result from bfd_find_nearest_line */
+               file = file ? file : "";
+               fn = strrchr(file, '/');
+#define FMT_INLINED "[%s] %s %s:%u %s()"
+#define FMT_NOT_INLINED "[%p] %s %s:%u %s()"
+
+               snprintf(data->msg, MSG_BUFF_LEN, inlined ? FMT_INLINED : FMT_NOT_INLINED,
+                       inlined ? "inlined" : (char *)data->pc,
+                       data->libname,
+                       fn ? fn + 1 : file,
+                       line, S_OR(func, "???"));
+
+               if (AST_VECTOR_APPEND(data->return_strings, strdup(data->msg))) {
+                       return;
+               }
+
+               inlined++;
+               /* Let's see if there are any inlined functions */
+       } while (bfd_find_inliner_info(bfdobj, &file, &func, &line));
+}
 
-       eachlen = ast_std_calloc(num_frames, sizeof(*eachlen));
-       strings = ast_std_calloc(num_frames, sizeof(*strings));
-       if (!eachlen || !strings) {
-               ast_std_free(eachlen);
-               ast_std_free(strings);
+struct ast_vector_string *__ast_bt_get_symbols(void **addresses, size_t num_frames)
+{
+       struct ast_vector_string *return_strings;
+       int stackfr;
+       bfd *bfdobj;
+       long allocsize;
+       char msg[MSG_BUFF_LEN];
+       static pthread_mutex_t bfd_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+       return_strings = malloc(sizeof(struct ast_vector_string));
+       if (!return_strings) {
+               return NULL;
+       }
+       if (AST_VECTOR_INIT(return_strings, num_frames)) {
+               free(return_strings);
                return NULL;
        }
 
        for (stackfr = 0; stackfr < num_frames; stackfr++) {
-               int found = 0, symbolcount;
+               int symbolcount;
+               struct bfd_data data = {
+                       .return_strings = return_strings,
+                       .msg = msg,
+                       .pc = (bfd_vma)addresses[stackfr],
+                       .found = 0,
+                       .dynamic = 0,
+               };
 
                msg[0] = '\0';
 
-               if (!dladdr(addresses[stackfr], &dli)) {
+               if (!dladdr((void *)data.pc, &data.dli)) {
                        continue;
                }
+               data.libname = strrchr(data.dli.dli_fname, '/');
+               if (!data.libname) {
+                       data.libname = data.dli.dli_fname;
+               } else {
+                       data.libname++;
+               }
+
+               pthread_mutex_lock(&bfd_mutex);
+               /* Using do while(0) here makes it easier to escape and clean up */
+               do {
+                       bfdobj = bfd_openr(data.dli.dli_fname, NULL);
+                       if (!bfdobj) {
+                               break;
+                       }
+
+                       /* bfd_check_format does more than check.  It HAS to be called */
+                       if (!bfd_check_format(bfdobj, bfd_object)) {
+                               break;
+                       }
 
-               if (strcmp(dli.dli_fname, "asterisk") == 0) {
-                       char asteriskpath[256];
+                       data.has_syms = !!(bfd_get_file_flags(bfdobj) & HAS_SYMS);
+                       data.dynamic = !!(bfd_get_file_flags(bfdobj) & DYNAMIC);
 
-                       if (!(dli.dli_fname = ast_utils_which("asterisk", asteriskpath, sizeof(asteriskpath)))) {
-                               /* This will fail to find symbols */
-                               dli.dli_fname = "asterisk";
+                       if (!data.has_syms) {
+                               break;
                        }
-               }
 
-               lastslash = strrchr(dli.dli_fname, '/');
-               if ((bfdobj = bfd_openr(dli.dli_fname, NULL)) &&
-                       bfd_check_format(bfdobj, bfd_object) &&
-                       (allocsize = bfd_get_symtab_upper_bound(bfdobj)) > 0 &&
-                       (syms = ast_std_malloc(allocsize)) &&
-                       (symbolcount = bfd_canonicalize_symtab(bfdobj, syms))) {
-
-                       if (bfdobj->flags & DYNAMIC) {
-                               offset = addresses[stackfr] - dli.dli_fbase;
-                       } else {
-                               offset = addresses[stackfr] - (void *) 0;
+                       allocsize = data.dynamic ?
+                               bfd_get_dynamic_symtab_upper_bound(bfdobj) : bfd_get_symtab_upper_bound(bfdobj);
+                       if (allocsize < 0) {
+                               break;
                        }
 
-                       for (section = bfdobj->sections; section; section = section->next) {
-                               if (!(bfd_get_section_flags(bfdobj, section) & SEC_ALLOC) ||
-                                       section->vma > offset ||
-                                       section->size + section->vma < offset) {
-                                       continue;
-                               }
-
-                               if (!bfd_find_nearest_line(bfdobj, section, syms, offset - section->vma, &file, &func, &line)) {
-                                       continue;
-                               }
-
-                               /* file can possibly be null even with a success result from bfd_find_nearest_line */
-                               file = file ? file : "";
-
-                               /* Stack trace output */
-                               found++;
-                               if ((lastslash = strrchr(file, '/'))) {
-                                       const char *prevslash;
-
-                                       for (prevslash = lastslash - 1; *prevslash != '/' && prevslash >= file; prevslash--) {
-                                       }
-                                       if (prevslash >= file) {
-                                               lastslash = prevslash;
-                                       }
-                               }
-                               if (dli.dli_saddr == NULL) {
-                                       address_str[0] = '\0';
-                               } else {
-                                       snprintf(address_str, sizeof(address_str), " (%p+%lX)",
-                                               dli.dli_saddr,
-                                               (unsigned long) (addresses[stackfr] - dli.dli_saddr));
-                               }
-                               snprintf(msg, sizeof(msg), "%s:%u %s()%s",
-                                       lastslash ? lastslash + 1 : file, line,
-                                       S_OR(func, "???"),
-                                       address_str);
-
-                               break; /* out of section iteration */
+                       data.syms = malloc(allocsize);
+                       if (!data.syms) {
+                               break;
                        }
-               }
+
+                       symbolcount = data.dynamic ?
+                               bfd_canonicalize_dynamic_symtab(bfdobj, data.syms) : bfd_canonicalize_symtab(bfdobj, data.syms);
+                       if (symbolcount < 0) {
+                               break;
+                       }
+
+                       bfd_map_over_sections(bfdobj, process_section, &data);
+               } while(0);
+
                if (bfdobj) {
                        bfd_close(bfdobj);
-                       ast_std_free(syms);
-                       syms = NULL;
+                       free(data.syms);
+                       data.syms = NULL;
                }
+               pthread_mutex_unlock(&bfd_mutex);
 
                /* Default output, if we cannot find the information within BFD */
-               if (!found) {
-                       if (dli.dli_saddr == NULL) {
-                               address_str[0] = '\0';
-                       } else {
-                               snprintf(address_str, sizeof(address_str), " (%p+%lX)",
-                                       dli.dli_saddr,
-                                       (unsigned long) (addresses[stackfr] - dli.dli_saddr));
-                       }
-                       snprintf(msg, sizeof(msg), "%s %s()%s",
-                               lastslash ? lastslash + 1 : dli.dli_fname,
-                               S_OR(dli.dli_sname, "<unknown>"),
-                               address_str);
+               if (!data.found) {
+                       snprintf(msg, sizeof(msg), "%s %s()",
+                               data.libname,
+                               S_OR(data.dli.dli_sname, "<unknown>"));
+                       AST_VECTOR_APPEND(return_strings, strdup(msg));
                }
+       }
 
-               if (!ast_strlen_zero(msg)) {
-                       char **tmp;
+       return return_strings;
+}
 
-                       eachlen[stackfr] = strlen(msg) + 1;
-                       if (!(tmp = ast_std_realloc(strings, strings_size + eachlen[stackfr]))) {
-                               ast_std_free(strings);
-                               strings = NULL;
-                               break; /* out of stack frame iteration */
-                       }
-                       strings = tmp;
-                       strings[stackfr] = (char *) strings + strings_size;
-                       strcpy(strings[stackfr], msg);/* Safe since we just allocated the room. */
-                       strings_size += eachlen[stackfr];
-               }
+#else
+struct ast_vector_string *__ast_bt_get_symbols(void **addresses, size_t num_frames)
+{
+       char **strings;
+       struct ast_vector_string *return_strings;
+       int i;
+
+       return_strings = malloc(sizeof(struct ast_vector_string));
+       if (!return_strings) {
+               return NULL;
+       }
+       if (AST_VECTOR_INIT(return_strings, num_frames)) {
+               free(return_strings);
+               return NULL;
        }
 
+       strings = backtrace_symbols(addresses, num_frames);
        if (strings) {
-               /* Recalculate the offset pointers because of the reallocs. */
-               strings[0] = (char *) strings + num_frames * sizeof(*strings);
-               for (stackfr = 1; stackfr < num_frames; stackfr++) {
-                       strings[stackfr] = strings[stackfr - 1] + eachlen[stackfr - 1];
+               for (i = 0; i < num_frames; i++) {
+                       AST_VECTOR_APPEND(return_strings, strdup(strings[i]));
                }
+               free(strings);
        }
-       ast_std_free(eachlen);
 
-#else /* !defined(BETTER_BACKTRACES) */
+       return return_strings;
+}
+#endif /* BETTER_BACKTRACES */
 
-       strings = backtrace_symbols(addresses, num_frames);
-#endif /* defined(BETTER_BACKTRACES) */
-       return strings;
+void __ast_bt_free_symbols(struct ast_vector_string *symbols)
+{
+       AST_VECTOR_CALLBACK_VOID(symbols, free);
+       AST_VECTOR_PTR_FREE(symbols);
 }
 
 #endif /* HAVE_BKTR */
index 5758574..52ec586 100644 (file)
@@ -1433,6 +1433,8 @@ static struct generic_monitor_instance_list *create_new_generic_list(struct ast_
                cc_unref(generic_list, "Failed to subscribe to device state");
                return NULL;
        }
+       stasis_subscription_accept_message_type(generic_list->sub, ast_device_state_message_type());
+       stasis_subscription_set_filter(generic_list->sub, STASIS_SUBSCRIPTION_FILTER_SELECTIVE);
        generic_list->current_state = ast_device_state(monitor->interface->device_name);
        ao2_t_link(generic_monitors, generic_list, "linking new generic monitor instance list");
        return generic_list;
@@ -2804,6 +2806,9 @@ static int cc_generic_agent_start_monitoring(struct ast_cc_agent *agent)
        if (!(generic_pvt->sub = stasis_subscribe(device_specific_topic, generic_agent_devstate_cb, agent))) {
                return -1;
        }
+       stasis_subscription_accept_message_type(generic_pvt->sub, ast_device_state_message_type());
+       stasis_subscription_accept_message_type(generic_pvt->sub, stasis_subscription_change_type());
+       stasis_subscription_set_filter(generic_pvt->sub, STASIS_SUBSCRIPTION_FILTER_SELECTIVE);
        cc_ref(agent, "Ref agent for subscription");
        return 0;
 }
index 7dcbe82..b6c740c 100644 (file)
@@ -920,6 +920,8 @@ int devstate_init(void)
        if (!device_state_topic_cached) {
                return -1;
        }
+       stasis_caching_accept_message_type(device_state_topic_cached, ast_device_state_message_type());
+       stasis_caching_set_filter(device_state_topic_cached, STASIS_SUBSCRIPTION_FILTER_SELECTIVE);
 
        devstate_message_sub = stasis_subscribe(ast_device_state_topic_all(),
                devstate_change_cb, NULL);
@@ -927,6 +929,8 @@ int devstate_init(void)
                ast_log(LOG_ERROR, "Failed to create subscription creating uncached device state aggregate events.\n");
                return -1;
        }
+       stasis_subscription_accept_message_type(devstate_message_sub, ast_device_state_message_type());
+       stasis_subscription_set_filter(devstate_message_sub, STASIS_SUBSCRIPTION_FILTER_SELECTIVE);
 
        return 0;
 }
index 5490b55..4d67816 100644 (file)
@@ -393,6 +393,7 @@ struct ast_dns_record *dns_naptr_alloc(struct ast_dns_query *query, const char *
        int replacement_size;
        const char *end_of_record;
        enum flags_result flags_res;
+       size_t naptr_len;
 
        ptr = dns_find_record(data, size, query->result->answer, query->result->answer_size);
        ast_assert(ptr != NULL);
@@ -435,7 +436,14 @@ struct ast_dns_record *dns_naptr_alloc(struct ast_dns_query *query, const char *
                return NULL;
        }
 
-       replacement_size = dn_expand((unsigned char *)query->result->answer, (unsigned char *) end_of_record, (unsigned char *) ptr, replacement, sizeof(replacement) - 1);
+       /*
+        * The return value from dn_expand represents the size of the replacement
+        * in the buffer which MAY be compressed.  Since the expanded replacement
+        * is NULL terminated, you can use strlen() to get the expanded size.
+        */
+       replacement_size = dn_expand((unsigned char *)query->result->answer,
+               (unsigned char *) end_of_record, (unsigned char *) ptr,
+               replacement, sizeof(replacement) - 1);
        if (replacement_size < 0) {
                ast_log(LOG_ERROR, "Failed to expand domain name: %s\n", strerror(errno));
                return NULL;
@@ -475,7 +483,9 @@ struct ast_dns_record *dns_naptr_alloc(struct ast_dns_query *query, const char *
                return NULL;
        }
 
-       naptr = ast_calloc(1, sizeof(*naptr) + size + flags_size + 1 + services_size + 1 + regexp_size + 1 + replacement_size + 1);
+       naptr_len = sizeof(*naptr) + size + flags_size + 1 + services_size + 1
+               + regexp_size + 1 + strlen(replacement) + 1;
+       naptr = ast_calloc(1, naptr_len);
        if (!naptr) {
                return NULL;
        }
index b562e32..e11c84e 100644 (file)
@@ -73,7 +73,13 @@ struct ast_dns_record *dns_srv_alloc(struct ast_dns_query *query, const char *da
                return NULL;
        }
 
-       host_size = dn_expand((unsigned char *)query->result->answer, (unsigned char *) end_of_record, (unsigned char *) ptr, host, sizeof(host) - 1);
+       /*
+        * The return value from dn_expand represents the size of the replacement
+        * in the buffer which MAY be compressed.  Since the expanded replacement
+        * is NULL terminated, you can use strlen() to get the expanded size.
+        */
+       host_size = dn_expand((unsigned char *)query->result->answer,
+               (unsigned char *) end_of_record, (unsigned char *) ptr, host, sizeof(host) - 1);
        if (host_size < 0) {
                ast_log(LOG_ERROR, "Failed to expand domain name: %s\n", strerror(errno));
                return NULL;
@@ -83,7 +89,7 @@ struct ast_dns_record *dns_srv_alloc(struct ast_dns_query *query, const char *da
                return NULL;
        }
 
-       srv = ast_calloc(1, sizeof(*srv) + size + host_size + 1);
+       srv = ast_calloc(1, sizeof(*srv) + size + strlen(host) + 1);
        if (!srv) {
                return NULL;
        }
@@ -94,8 +100,6 @@ struct ast_dns_record *dns_srv_alloc(struct ast_dns_query *query, const char *da
 
        srv->host = srv->data + size;
        strcpy((char *)srv->host, host); /* SAFE */
-       ((char *)srv->host)[host_size] = '\0';
-
        srv->generic.data_ptr = srv->data;
 
        return (struct ast_dns_record *)srv;
index f1608f3..3129fb4 100644 (file)
@@ -202,7 +202,7 @@ static void endpoint_cache_clear(void *data,
        endpoint_publish_snapshot(endpoint);
 }
 
-static void endpoint_default(void *data,
+static void endpoint_subscription_change(void *data,
        struct stasis_subscription *sub,
        struct stasis_message *message)
 {
@@ -263,6 +263,8 @@ static struct ast_endpoint *endpoint_internal_create(const char *tech, const cha
                if (!endpoint->topics) {
                        return NULL;
                }
+               stasis_cp_single_accept_message_type(endpoint->topics, ast_endpoint_snapshot_type());
+               stasis_cp_single_set_filter(endpoint->topics, STASIS_SUBSCRIPTION_FILTER_SELECTIVE);
 
                endpoint->router = stasis_message_router_create_pool(ast_endpoint_topic(endpoint));
                if (!endpoint->router) {
@@ -271,8 +273,9 @@ static struct ast_endpoint *endpoint_internal_create(const char *tech, const cha
                r |= stasis_message_router_add(endpoint->router,
                        stasis_cache_clear_type(), endpoint_cache_clear,
                        endpoint);
-               r |= stasis_message_router_set_default(endpoint->router,
-                       endpoint_default, endpoint);
+               r |= stasis_message_router_add(endpoint->router,
+                       stasis_subscription_change_type(), endpoint_subscription_change,
+                       endpoint);
                if (r) {
                        return NULL;
                }
@@ -288,6 +291,8 @@ static struct ast_endpoint *endpoint_internal_create(const char *tech, const cha
                if (!endpoint->topics) {
                        return NULL;
                }
+               stasis_cp_single_accept_message_type(endpoint->topics, ast_endpoint_snapshot_type());
+               stasis_cp_single_set_filter(endpoint->topics, STASIS_SUBSCRIPTION_FILTER_SELECTIVE);
 
                ao2_link(tech_endpoints, endpoint);
        }
index ff781b1..5a4b3fe 100644 (file)
@@ -385,6 +385,9 @@ static int format_log_default(struct logchannel *chan, struct logmsg *msg, char
        case LOGTYPE_CONSOLE:
                {
                        char linestr[32];
+                       int has_file = !ast_strlen_zero(msg->file);
+                       int has_line = (msg->line > 0);
+                       int has_func = !ast_strlen_zero(msg->function);
 
                        /*
                         * Verbose messages are interpreted by console channels in their own
@@ -394,18 +397,20 @@ static int format_log_default(struct logchannel *chan, struct logmsg *msg, char
                                return logger_add_verbose_magic(msg, buf, size);
                        }
 
-                       /* Turn the numeric line number into a string for colorization */
+                       /* Turn the numerical line number into a string */
                        snprintf(linestr, sizeof(linestr), "%d", msg->line);
-
-                       snprintf(buf, size, "[%s] " COLORIZE_FMT "[%d]%s: " COLORIZE_FMT ":" COLORIZE_FMT " " COLORIZE_FMT ": %s",
-                                msg->date,
-                                COLORIZE(colors[msg->level], 0, msg->level_name),
-                                msg->lwp,
-                                call_identifier_str,
-                                COLORIZE(COLOR_BRWHITE, 0, msg->file),
-                                COLORIZE(COLOR_BRWHITE, 0, linestr),
-                                COLORIZE(COLOR_BRWHITE, 0, msg->function),
-                                msg->message);
+                       /* Build string to print out */
+                       snprintf(buf, size, "[%s] " COLORIZE_FMT "[%d]%s: " COLORIZE_FMT "%s" COLORIZE_FMT " " COLORIZE_FMT "%s %s",
+                               msg->date,
+                               COLORIZE(colors[msg->level], 0, msg->level_name),
+                               msg->lwp,
+                               call_identifier_str,
+                               COLORIZE(COLOR_BRWHITE, 0, has_file ? msg->file : ""),
+                               has_file ? ":" : "",
+                               COLORIZE(COLOR_BRWHITE, 0, has_line ? linestr : ""),
+                               COLORIZE(COLOR_BRWHITE, 0, has_func ? msg->function : ""),
+                               has_func ? ":" : "",
+                               msg->message);
                }
                break;
        }
@@ -2063,7 +2068,7 @@ void ast_log_backtrace(void)
 #ifdef HAVE_BKTR
        struct ast_bt *bt;
        int i = 0;
-       char **strings;
+       struct ast_vector_string *strings;
 
        if (!(bt = ast_bt_create())) {
                ast_log(LOG_WARNING, "Unable to allocate space for backtrace structure\n");
@@ -2071,14 +2076,21 @@ void ast_log_backtrace(void)
        }
 
        if ((strings = ast_bt_get_symbols(bt->addresses, bt->num_frames))) {
-               ast_verbose("Got %d backtrace record%c\n", bt->num_frames, bt->num_frames != 1 ? 's' : ' ');
-               for (i = 3; i < bt->num_frames - 2; i++) {
-                       ast_verbose("#%d: [%p] %s\n", i - 3, bt->addresses[i], strings[i]);
+               int count = AST_VECTOR_SIZE(strings);
+               struct ast_str *buf = ast_str_create(bt->num_frames * 64);
+
+               if (buf) {
+                       ast_str_append(&buf, 0, "Got %d backtrace record%c\n", count - 3, count - 3 != 1 ? 's' : ' ');
+                       for (i = 3; i < AST_VECTOR_SIZE(strings); i++) {
+                               ast_str_append(&buf, 0, "#%2d: %s\n", i - 3, AST_VECTOR_GET(strings, i));
+                       }
+                       ast_log_safe(__LOG_ERROR, NULL, 0, NULL, "%s\n", ast_str_buffer(buf));
+                       ast_free(buf);
                }
 
-               ast_std_free(strings);
+               ast_bt_free_symbols(strings);
        } else {
-               ast_verbose("Could not allocate memory for backtrace\n");
+               ast_log(LOG_ERROR, "Could not allocate memory for backtrace\n");
        }
        ast_bt_destroy(bt);
 #else
index 7accaa1..0da023a 100644 (file)
@@ -1527,6 +1527,8 @@ static void acl_change_stasis_subscribe(void)
        if (!acl_change_sub) {
                acl_change_sub = stasis_subscribe(ast_security_topic(),
                        acl_change_stasis_cb, NULL);
+               stasis_subscription_accept_message_type(acl_change_sub, ast_named_acl_change_type());
+               stasis_subscription_set_filter(acl_change_sub, STASIS_SUBSCRIPTION_FILTER_SELECTIVE);
        }
 }
 
index 4f9b3dc..ea97a6a 100644 (file)
@@ -322,7 +322,9 @@ void load_asterisk_conf(void)
                        ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_QUIET);
                /* Run as console (-c at startup, implies nofork) */
                } else if (!strcasecmp(v->name, "console")) {
-                       ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_CONSOLE);
+                       if (!ast_opt_remote) {
+                               ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_CONSOLE);
+                       }
                /* Run with high priority if the O/S permits (-p at startup) */
                } else if (!strcasecmp(v->name, "highpriority")) {
                        ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_HIGH_PRIORITY);
index f961295..0a23735 100644 (file)
@@ -8416,10 +8416,15 @@ int load_pbx(void)
        if (!(device_state_sub = stasis_subscribe(ast_device_state_topic_all(), device_state_cb, NULL))) {
                return -1;
        }
+       stasis_subscription_accept_message_type(device_state_sub, ast_device_state_message_type());
+       stasis_subscription_accept_message_type(device_state_sub, hint_change_message_type());
+       stasis_subscription_set_filter(device_state_sub, STASIS_SUBSCRIPTION_FILTER_SELECTIVE);
 
        if (!(presence_state_sub = stasis_subscribe(ast_presence_state_topic_all(), presence_state_cb, NULL))) {
                return -1;
        }
+       stasis_subscription_accept_message_type(presence_state_sub, ast_presence_state_message_type());
+       stasis_subscription_set_filter(presence_state_sub, STASIS_SUBSCRIPTION_FILTER_SELECTIVE);
 
        return 0;
 }
index 4121bf5..65b7f69 100644 (file)
@@ -514,6 +514,8 @@ int ast_presence_state_engine_init(void)
        if (!presence_state_topic_cached) {
                return -1;
        }
+       stasis_caching_accept_message_type(presence_state_topic_cached, ast_presence_state_message_type());
+       stasis_caching_set_filter(presence_state_topic_cached, STASIS_SUBSCRIPTION_FILTER_SELECTIVE);
 
        AST_TEST_REGISTER(test_presence_chan);
 
index ed83873..93112d9 100644 (file)
@@ -370,6 +370,11 @@ const char *stasis_topic_name(const struct stasis_topic *topic)
        return topic->name;
 }
 
+size_t stasis_topic_subscribers(const struct stasis_topic *topic)
+{
+       return AST_VECTOR_SIZE(&topic->subscribers);
+}
+
 /*! \internal */
 struct stasis_subscription {
        /*! Unique ID for this subscription */
@@ -391,6 +396,11 @@ struct stasis_subscription {
        /*! Flag set when final message for sub has been processed.
         *  Be sure join_lock is held before reading/setting. */
        int final_message_processed;
+
+       /*! The message types this subscription is accepting */
+       AST_VECTOR(, char) accepted_message_types;
+       /*! The message filter currently in use */
+       enum stasis_subscription_message_filter filter;
 };
 
 static void subscription_dtor(void *obj)
@@ -409,6 +419,8 @@ static void subscription_dtor(void *obj)
        ast_taskprocessor_unreference(sub->mailbox);
        sub->mailbox = NULL;
        ast_cond_destroy(&sub->join_cond);
+
+       AST_VECTOR_FREE(&sub->accepted_message_types);
 }
 
 /*!
@@ -420,19 +432,25 @@ static void subscription_dtor(void *obj)
 static void subscription_invoke(struct stasis_subscription *sub,
                                  struct stasis_message *message)
 {
+       unsigned int final = stasis_subscription_final_message(sub, message);
+       int message_type_id = stasis_message_type_id(stasis_subscription_change_type());
+
        /* Notify that the final message has been received */
-       if (stasis_subscription_final_message(sub, message)) {
+       if (final) {
                ao2_lock(sub);
                sub->final_message_rxed = 1;
                ast_cond_signal(&sub->join_cond);
                ao2_unlock(sub);
        }
 
-       /* Since sub is mostly immutable, no need to lock sub */
-       sub->callback(sub->data, sub, message);
+       if (!final || sub->filter != STASIS_SUBSCRIPTION_FILTER_SELECTIVE ||
+               (message_type_id < AST_VECTOR_SIZE(&sub->accepted_message_types) && AST_VECTOR_GET(&sub->accepted_message_types, message_type_id))) {
+               /* Since sub is mostly immutable, no need to lock sub */
+               sub->callback(sub->data, sub, message);
+       }
 
        /* Notify that the final message has been processed */
-       if (stasis_subscription_final_message(sub, message)) {
+       if (final) {
                ao2_lock(sub);
                sub->final_message_processed = 1;
                ast_cond_signal(&sub->join_cond);
@@ -500,6 +518,8 @@ struct stasis_subscription *internal_stasis_subscribe(
        sub->callback = callback;
        sub->data = data;
        ast_cond_init(&sub->join_cond, NULL);
+       sub->filter = STASIS_SUBSCRIPTION_FILTER_NONE;
+       AST_VECTOR_INIT(&sub->accepted_message_types, 0);
 
        if (topic_add_subscription(topic, sub) != 0) {
                ao2_ref(sub, -1);
@@ -586,6 +606,76 @@ int stasis_subscription_set_congestion_limits(struct stasis_subscription *subscr
        return res;
 }
 
+int stasis_subscription_accept_message_type(struct stasis_subscription *subscription,
+       const struct stasis_message_type *type)
+{
+       if (!subscription) {
+               return -1;
+       }
+
+       ast_assert(type != NULL);
+       ast_assert(stasis_message_type_name(type) != NULL);
+
+       if (!type || !stasis_message_type_name(type)) {
+               /* Filtering is unreliable as this message type is not yet initialized
+                * so force all messages through.
+                */
+               subscription->filter = STASIS_SUBSCRIPTION_FILTER_FORCED_NONE;
+               return 0;
+       }
+
+       ao2_lock(subscription->topic);
+       if (AST_VECTOR_REPLACE(&subscription->accepted_message_types, stasis_message_type_id(type), 1)) {
+               /* We do this for the same reason as above. The subscription can still operate, so allow
+                * it to do so by forcing all messages through.
+                */
+               subscription->filter = STASIS_SUBSCRIPTION_FILTER_FORCED_NONE;
+       }
+       ao2_unlock(subscription->topic);
+
+       return 0;
+}
+
+int stasis_subscription_decline_message_type(struct stasis_subscription *subscription,
+       const struct stasis_message_type *type)
+{
+       if (!subscription) {
+               return -1;
+       }
+
+       ast_assert(type != NULL);
+       ast_assert(stasis_message_type_name(type) != NULL);
+
+       if (!type || !stasis_message_type_name(type)) {
+               return 0;
+       }
+
+       ao2_lock(subscription->topic);
+       if (stasis_message_type_id(type) < AST_VECTOR_SIZE(&subscription->accepted_message_types)) {
+               /* The memory is already allocated so this can't fail */
+               AST_VECTOR_REPLACE(&subscription->accepted_message_types, stasis_message_type_id(type), 0);
+       }
+       ao2_unlock(subscription->topic);
+
+       return 0;
+}
+
+int stasis_subscription_set_filter(struct stasis_subscription *subscription,
+       enum stasis_subscription_message_filter filter)
+{
+       if (!subscription) {
+               return -1;
+       }
+
+       ao2_lock(subscription->topic);
+       if (subscription->filter != STASIS_SUBSCRIPTION_FILTER_FORCED_NONE) {
+               subscription->filter = filter;
+       }
+       ao2_unlock(subscription->topic);
+
+       return 0;
+}
+
 void stasis_subscription_join(struct stasis_subscription *subscription)
 {
        if (subscription) {
@@ -781,6 +871,18 @@ static void dispatch_message(struct stasis_subscription *sub,
        struct stasis_message *message,
        int synchronous)
 {
+       /* Determine if this subscription is interested in this message. Note that final
+        * messages are special and are always invoked on the subscription.
+        */
+       if (sub->filter == STASIS_SUBSCRIPTION_FILTER_SELECTIVE) {
+               int message_type_id = stasis_message_type_id(stasis_message_type(message));
+               if ((message_type_id >= AST_VECTOR_SIZE(&sub->accepted_message_types) ||
+                       !AST_VECTOR_GET(&sub->accepted_message_types, message_type_id)) &&
+                       !stasis_subscription_final_message(sub, message)) {
+                       return;
+               }
+       }
+
        if (!sub->mailbox) {
                /* Dispatch directly */
                subscription_invoke(sub, message);
@@ -840,6 +942,11 @@ static void publish_msg(struct stasis_topic *topic,
        ast_assert(topic != NULL);
        ast_assert(message != NULL);
 
+       /* If there are no subscribers don't bother */
+       if (!stasis_topic_subscribers(topic)) {
+               return;
+       }
+
        /*
         * The topic may be unref'ed by the subscription invocation.
         * Make sure we hold onto a reference while dispatching.
index 3d353b3..bc975fd 100644 (file)
@@ -87,6 +87,35 @@ struct stasis_topic *stasis_caching_get_topic(struct stasis_caching_topic *cachi
        return caching_topic->topic;
 }
 
+int stasis_caching_accept_message_type(struct stasis_caching_topic *caching_topic,
+       struct stasis_message_type *type)
+{
+       int res;
+
+       if (!caching_topic) {
+               return -1;
+       }
+
+       /* We wait to accept the stasis specific message types until now so that by default everything
+        * will flow to us.
+        */
+       res = stasis_subscription_accept_message_type(caching_topic->sub, stasis_cache_clear_type());
+       res |= stasis_subscription_accept_message_type(caching_topic->sub, stasis_subscription_change_type());
+       res |= stasis_subscription_accept_message_type(caching_topic->sub, type);
+
+       return res;
+}
+
+int stasis_caching_set_filter(struct stasis_caching_topic *caching_topic,
+       enum stasis_subscription_message_filter filter)
+{
+       if (!caching_topic) {
+               return -1;
+       }
+       return stasis_subscription_set_filter(caching_topic->sub, filter);
+}
+
+
 struct stasis_caching_topic *stasis_caching_unsubscribe(struct stasis_caching_topic *caching_topic)
 {
        if (!caching_topic) {
@@ -856,11 +885,13 @@ static void caching_topic_exec(void *data, struct stasis_subscription *sub,
                /* Update the cache */
                snapshots = cache_put(caching_topic->cache, msg_type, msg_id, msg_eid, msg_put);
                if (snapshots.old || msg_put) {
-                       update = update_create(snapshots.old, msg_put);
-                       if (update) {
-                               stasis_publish(caching_topic->topic, update);
+                       if (stasis_topic_subscribers(caching_topic->topic)) {
+                               update = update_create(snapshots.old, msg_put);
+                               if (update) {
+                                       stasis_publish(caching_topic->topic, update);
+                                       ao2_ref(update, -1);
+                               }
                        }
-                       ao2_cleanup(update);
                } else {
                        ast_debug(1,
                                "Attempting to remove an item from the %s cache that isn't there: %s %s\n",
@@ -873,11 +904,13 @@ static void caching_topic_exec(void *data, struct stasis_subscription *sub,
                                caching_topic->cache->aggregate_publish_fn(caching_topic->original_topic,
                                        snapshots.aggregate_new);
                        }
-                       update = update_create(snapshots.aggregate_old, snapshots.aggregate_new);
-                       if (update) {
-                               stasis_publish(caching_topic->topic, update);
+                       if (stasis_topic_subscribers(caching_topic->topic)) {
+                               update = update_create(snapshots.aggregate_old, snapshots.aggregate_new);
+                               if (update) {
+                                       stasis_publish(caching_topic->topic, update);
+                                       ao2_ref(update, -1);
+                               }
                        }
-                       ao2_cleanup(update);
                }
 
                ao2_cleanup(snapshots.old);
index f0e34b9..04d8164 100644 (file)
@@ -217,3 +217,21 @@ struct stasis_topic *stasis_cp_single_topic_cached(
        }
        return stasis_caching_get_topic(one->topic_cached);
 }
+
+int stasis_cp_single_accept_message_type(struct stasis_cp_single *one,
+       struct stasis_message_type *type)
+{
+       if (!one) {
+               return -1;
+       }
+       return stasis_caching_accept_message_type(one->topic_cached, type);
+}
+
+int stasis_cp_single_set_filter(struct stasis_cp_single *one,
+       enum stasis_subscription_message_filter filter)
+{
+       if (!one) {
+               return -1;
+       }
+       return stasis_caching_set_filter(one->topic_cached, filter);
+}
index 19f4a92..1fdbe85 100644 (file)
@@ -39,9 +39,11 @@ struct stasis_message_type {
        struct stasis_message_vtable *vtable;
        char *name;
        unsigned int hash;
+       int id;
 };
 
 static struct stasis_message_vtable null_vtable = {};
+static int message_type_id;
 
 static void message_type_dtor(void *obj)
 {
@@ -78,6 +80,7 @@ int stasis_message_type_create(const char *name,
        }
        type->hash = ast_hashtab_hash_string(name);
        type->vtable = vtable;
+       type->id = ast_atomic_fetchadd_int(&message_type_id, +1);
        *result = type;
 
        return STASIS_MESSAGE_TYPE_SUCCESS;
@@ -93,6 +96,11 @@ unsigned int stasis_message_type_hash(const struct stasis_message_type *type)
        return type->hash;
 }
 
+int stasis_message_type_id(const struct stasis_message_type *type)
+{
+       return type->id;
+}
+
 /*! \internal */
 struct stasis_message {
        /*! Time the message was created */
index 41d426b..41ebc7e 100644 (file)
@@ -235,6 +235,9 @@ static struct stasis_message_router *stasis_message_router_create_internal(
                return NULL;
        }
 
+       /* We need to receive subscription change messages so we know when our subscription goes away */
+       stasis_subscription_accept_message_type(router->subscription, stasis_subscription_change_type());
+
        return router;
 }
 
@@ -316,6 +319,14 @@ int stasis_message_router_add(struct stasis_message_router *router,
        }
        ao2_lock(router);
        res = route_table_add(&router->routes, message_type, callback, data);
+       if (!res) {
+               stasis_subscription_accept_message_type(router->subscription, message_type);
+               /* Until a specific message type was added we would already drop the message, so being
+                * selective now doesn't harm us. If we have a default route then we are already forced
+                * to filter nothing and messages will come in regardless.
+                */
+               stasis_subscription_set_filter(router->subscription, STASIS_SUBSCRIPTION_FILTER_SELECTIVE);
+       }
        ao2_unlock(router);
        return res;
 }
@@ -334,6 +345,10 @@ int stasis_message_router_add_cache_update(struct stasis_message_router *router,
        }
        ao2_lock(router);
        res = route_table_add(&router->cache_routes, message_type, callback, data);
+       if (!res) {
+               stasis_subscription_accept_message_type(router->subscription, stasis_cache_update_type());
+               stasis_subscription_set_filter(router->subscription, STASIS_SUBSCRIPTION_FILTER_SELECTIVE);
+       }
        ao2_unlock(router);
        return res;
 }
@@ -378,6 +393,9 @@ int stasis_message_router_set_default(struct stasis_message_router *router,
        router->default_route.callback = callback;
        router->default_route.data = data;
        ao2_unlock(router);
+
+       stasis_subscription_set_filter(router->subscription, STASIS_SUBSCRIPTION_FILTER_FORCED_NONE);
+
        /* While this implementation can never fail, it used to be able to */
        return 0;
 }
index 33acb37..68bd29c 100644 (file)
@@ -67,10 +67,8 @@ struct tps_taskprocessor_stats {
 
 /*! \brief A ast_taskprocessor structure is a singleton by name */
 struct ast_taskprocessor {
-       /*! \brief Friendly name of the taskprocessor */
-       const char *name;
        /*! \brief Taskprocessor statistics */
-       struct tps_taskprocessor_stats *stats;
+       struct tps_taskprocessor_stats stats;
        void *local_data;
        /*! \brief Taskprocessor current queue size */
        long tps_queue_size;
@@ -91,6 +89,8 @@ struct ast_taskprocessor {
        unsigned int high_water_alert:1;
        /*! Indicates if the taskprocessor is currently suspended */
        unsigned int suspended:1;
+       /*! \brief Friendly name of the taskprocessor */
+       char name[0];
 };
 
 /*!
@@ -515,13 +515,8 @@ static char *cli_tps_report(struct ast_cli_entry *e, int cmd, struct ast_cli_arg
        while ((tps = ao2_iterator_next(&iter))) {
                ast_copy_string(name, tps->name, sizeof(name));
                qsize = tps->tps_queue_size;
-               if (tps->stats) {
-                       maxqsize = tps->stats->max_qsize;
-                       processed = tps->stats->_tasks_processed_count;
-               } else {
-                       maxqsize = 0;
-                       processed = 0;
-               }
+               maxqsize = tps->stats.max_qsize;
+               processed = tps->stats._tasks_processed_count;
                ast_cli(a->fd, FMT_FIELDS, name, processed, qsize, maxqsize,
                        tps->tps_queue_low, tps->tps_queue_high);
                ast_taskprocessor_unreference(tps);
@@ -645,10 +640,6 @@ static void tps_taskprocessor_dtor(void *tps)
                tps_alert_add(t, -1);
        }
 
-       ast_free(t->stats);
-       t->stats = NULL;
-       ast_free((char *) t->name);
-       t->name = NULL;
        ao2_cleanup(t->listener);
        t->listener = NULL;
 }
@@ -740,11 +731,22 @@ static void *default_listener_pvt_alloc(void)
        return pvt;
 }
 
+/*!
+ * \internal
+ * \brief Allocate a task processor structure
+ *
+ * \param name Name of the task processor.
+ * \param listener Listener to associate with the task processor.
+ *
+ * \return The newly allocated task processor.
+ *
+ * \pre tps_singletons must be locked by the caller.
+ */
 static struct ast_taskprocessor *__allocate_taskprocessor(const char *name, struct ast_taskprocessor_listener *listener)
 {
        struct ast_taskprocessor *p;
 
-       p = ao2_alloc(sizeof(*p), tps_taskprocessor_dtor);
+       p = ao2_alloc(sizeof(*p) + strlen(name) + 1, tps_taskprocessor_dtor);
        if (!p) {
                ast_log(LOG_WARNING, "failed to create taskprocessor '%s'\n", name);
                return NULL;
@@ -754,12 +756,7 @@ static struct ast_taskprocessor *__allocate_taskprocessor(const char *name, stru
        p->tps_queue_low = (AST_TASKPROCESSOR_HIGH_WATER_LEVEL * 9) / 10;
        p->tps_queue_high = AST_TASKPROCESSOR_HIGH_WATER_LEVEL;
 
-       p->stats = ast_calloc(1, sizeof(*p->stats));
-       p->name = ast_strdup(name);
-       if (!p->stats || !p->name) {
-               ao2_ref(p, -1);
-               return NULL;
-       }
+       strcpy(p->name, name); /*SAFE*/
 
        ao2_ref(listener, +1);
        p->listener = listener;
@@ -769,17 +766,23 @@ static struct ast_taskprocessor *__allocate_taskprocessor(const char *name, stru
        ao2_ref(p, +1);
        listener->tps = p;
 
-       if (!(ao2_link(tps_singletons, p))) {
+       if (!(ao2_link_flags(tps_singletons, p, OBJ_NOLOCK))) {
                ast_log(LOG_ERROR, "Failed to add taskprocessor '%s' to container\n", p->name);
                listener->tps = NULL;
                ao2_ref(p, -2);
                return NULL;
        }
 
-       if (p->listener->callbacks->start(p->listener)) {
+       return p;
+}
+
+static struct ast_taskprocessor *__start_taskprocessor(struct ast_taskprocessor *p)
+{
+       if (p && p->listener->callbacks->start(p->listener)) {
                ast_log(LOG_ERROR, "Unable to start taskprocessor listener for taskprocessor %s\n",
                        p->name);
                ast_taskprocessor_unreference(p);
+
                return NULL;
        }
 
@@ -799,40 +802,51 @@ struct ast_taskprocessor *ast_taskprocessor_get(const char *name, enum ast_tps_o
                ast_log(LOG_ERROR, "requesting a nameless taskprocessor!!!\n");
                return NULL;
        }
-       p = ao2_find(tps_singletons, name, OBJ_KEY);
-       if (p) {
-               return p;
-       }
-       if (create & TPS_REF_IF_EXISTS) {
+       ao2_lock(tps_singletons);
+       p = ao2_find(tps_singletons, name, OBJ_KEY | OBJ_NOLOCK);
+       if (p || (create & TPS_REF_IF_EXISTS)) {
                /* calling function does not want a new taskprocessor to be created if it doesn't already exist */
-               return NULL;
+               ao2_unlock(tps_singletons);
+               return p;
        }
+
        /* Create a new taskprocessor. Start by creating a default listener */
        pvt = default_listener_pvt_alloc();
        if (!pvt) {
+               ao2_unlock(tps_singletons);
                return NULL;
        }
        listener = ast_taskprocessor_listener_alloc(&default_listener_callbacks, pvt);
        if (!listener) {
+               ao2_unlock(tps_singletons);
                default_listener_pvt_destroy(pvt);
                return NULL;
        }
 
        p = __allocate_taskprocessor(name, listener);
-
+       ao2_unlock(tps_singletons);
+       p = __start_taskprocessor(p);
        ao2_ref(listener, -1);
+
        return p;
 }
 
 struct ast_taskprocessor *ast_taskprocessor_create_with_listener(const char *name, struct ast_taskprocessor_listener *listener)
 {
-       struct ast_taskprocessor *p = ao2_find(tps_singletons, name, OBJ_KEY);
+       struct ast_taskprocessor *p;
 
+       ao2_lock(tps_singletons);
+       p = ao2_find(tps_singletons, name, OBJ_KEY | OBJ_NOLOCK);
        if (p) {
+               ao2_unlock(tps_singletons);
                ast_taskprocessor_unreference(p);
                return NULL;
        }
-       return __allocate_taskprocessor(name, listener);
+
+       p = __allocate_taskprocessor(name, listener);
+       ao2_unlock(tps_singletons);
+
+       return __start_taskprocessor(p);
 }
 
 void ast_taskprocessor_set_local(struct ast_taskprocessor *tps,
@@ -985,13 +999,11 @@ int ast_taskprocessor_execute(struct ast_taskprocessor *tps)
        size = ast_taskprocessor_size(tps);
 
        /* Update the stats */
-       if (tps->stats) {
-               ++tps->stats->_tasks_processed_count;
+       ++tps->stats._tasks_processed_count;
 
-               /* Include the task we just executed as part of the queue size. */
-               if (size >= tps->stats->max_qsize) {
-                       tps->stats->max_qsize = size + 1;
-               }
+       /* Include the task we just executed as part of the queue size. */
+       if (size >= tps->stats.max_qsize) {
+               tps->stats.max_qsize = size + 1;
        }
        ao2_unlock(tps);
 
index 75f4360..a062763 100644 (file)
@@ -967,7 +967,7 @@ static const char *locktype2str(enum ast_lock_type type)
 #ifdef HAVE_BKTR
 static void append_backtrace_information(struct ast_str **str, struct ast_bt *bt)
 {
-       char **symbols;
+       struct ast_vector_string *symbols;
        int num_frames;
 
        if (!bt) {
@@ -981,11 +981,11 @@ static void append_backtrace_information(struct ast_str **str, struct ast_bt *bt
        if ((symbols = ast_bt_get_symbols(bt->addresses, num_frames))) {
                int frame_iterator;
 
-               for (frame_iterator = 0; frame_iterator < num_frames; ++frame_iterator) {
-                       ast_str_append(str, 0, "\t%s\n", symbols[frame_iterator]);
+               for (frame_iterator = 1; frame_iterator < AST_VECTOR_SIZE(symbols); ++frame_iterator) {
+                       ast_str_append(str, 0, "\t%s\n", AST_VECTOR_GET(symbols, frame_iterator));
                }
 
-               ast_std_free(symbols);
+               ast_bt_free_symbols(symbols);
        } else {
                ast_str_append(str, 0, "\tCouldn't retrieve backtrace symbols\n");
        }
index 9bb2796..f6af7bf 100644 (file)
@@ -1714,10 +1714,20 @@ static int pbx_load_config(const char *config_file)
 
        ast_copy_string(userscontext, ast_variable_retrieve(cfg, "general", "userscontext") ?: "default", sizeof(userscontext));
 
-       for (v = ast_variable_browse(cfg, "globals"); v; v = v->next) {
-               pbx_substitute_variables_helper(NULL, v->value, realvalue, sizeof(realvalue) - 1);
-               pbx_builtin_setvar_helper(NULL, v->name, realvalue);
+       /* ast_variable_browse does not merge multiple [globals] sections */
+       for (cxt = ast_category_browse(cfg, NULL);
+            cxt;
+            cxt = ast_category_browse(cfg, cxt)) {
+               if (strcasecmp(cxt, "globals")) {
+                       continue;
+               }
+
+               for (v = ast_variable_browse(cfg, cxt); v; v = v->next) {
+                       pbx_substitute_variables_helper(NULL, v->value, realvalue, sizeof(realvalue) - 1);
+                       pbx_builtin_setvar_helper(NULL, v->name, realvalue);
+               }
        }
+
        for (cxt = ast_category_browse(cfg, NULL);
             cxt;
             cxt = ast_category_browse(cfg, cxt)) {
index dd2fb75..f9b3e85 100644 (file)
@@ -868,6 +868,10 @@ static void park_announce_update_cb(void *data, struct stasis_subscription *sub,
                return;
        }
 
+       if (ast_parked_call_type() != stasis_message_type(message)) {
+               return;
+       }
+
        if (payload->event_type != PARKED_CALL) {
                /* We are only concerned with calls parked */
                return;
@@ -954,6 +958,10 @@ static int park_and_announce_app_exec(struct ast_channel *chan, const char *data
                return -1;
        }
 
+       stasis_subscription_accept_message_type(parking_subscription, ast_parked_call_type());
+       stasis_subscription_accept_message_type(parking_subscription, stasis_subscription_change_type());
+       stasis_subscription_set_filter(parking_subscription, STASIS_SUBSCRIPTION_FILTER_SELECTIVE);
+
        /* Now for the fun part... park it! */
        ast_bridge_join(parking_bridge, chan, NULL, &chan_features, NULL, 0);
 
index f73f371..1d3b9e4 100644 (file)
@@ -213,6 +213,9 @@ static int create_parked_subscription_full(struct ast_channel *chan, const char
        if (!(parked_datastore->parked_subscription = stasis_subscribe_pool(ast_parking_topic(), parker_update_cb, subscription_data))) {
                return -1;
        }
+       stasis_subscription_accept_message_type(parked_datastore->parked_subscription, ast_parked_call_type());
+       stasis_subscription_accept_message_type(parked_datastore->parked_subscription, stasis_subscription_change_type());
+       stasis_subscription_set_filter(parked_datastore->parked_subscription, STASIS_SUBSCRIPTION_FILTER_SELECTIVE);
 
        datastore->data = parked_datastore;
 
index 6d0a4c0..83558ba 100644 (file)
@@ -686,6 +686,8 @@ static void parking_manager_enable_stasis(void)
 {
        if (!parking_sub) {
                parking_sub = stasis_subscribe(ast_parking_topic(), parking_event_cb, NULL);
+               stasis_subscription_accept_message_type(parking_sub, ast_parked_call_type());
+               stasis_subscription_set_filter(parking_sub, STASIS_SUBSCRIPTION_FILTER_SELECTIVE);
        }
 }
 
index c3abbc1..f73cd44 100644 (file)
@@ -167,6 +167,9 @@ static int load_module(void)
        if (!stasis_rtp_subscription) {
                return AST_MODULE_LOAD_DECLINE;
        }
+       stasis_subscription_accept_message_type(stasis_rtp_subscription, ast_rtp_rtcp_sent_type());
+       stasis_subscription_accept_message_type(stasis_rtp_subscription, ast_rtp_rtcp_received_type());
+       stasis_subscription_set_filter(stasis_rtp_subscription, STASIS_SUBSCRIPTION_FILTER_SELECTIVE);
 
        return AST_MODULE_LOAD_SUCCESS;
 }
index bc5ad8c..43bf178 100644 (file)
@@ -430,8 +430,7 @@ static pjsip_fromto_hdr *create_new_id_hdr(const pj_str_t *hdr_name, pjsip_fromt
 
        id_hdr = pjsip_from_hdr_create(tdata->pool);
        id_hdr->type = PJSIP_H_OTHER;
-       pj_strdup(tdata->pool, &id_hdr->name, hdr_name);
-       id_hdr->sname = id_hdr->name;
+       id_hdr->sname = id_hdr->name = *hdr_name;
 
        id_name_addr = pjsip_uri_clone(tdata->pool, base->uri);
        id_uri = pjsip_uri_get_uri(id_name_addr->uri);
@@ -779,6 +778,7 @@ static struct ast_sip_session_supplement caller_id_supplement = {
 
 static int load_module(void)
 {
+       ast_module_shutdown_ref(AST_MODULE_SELF);
        ast_sip_session_register_supplement(&caller_id_supplement);
        return AST_MODULE_LOAD_SUCCESS;
 }
index 4cd892c..83bff88 100644 (file)
@@ -269,6 +269,9 @@ static struct mwi_stasis_subscription *mwi_stasis_subscription_alloc(const char
                ao2_ref(mwi_sub, -1);
                mwi_stasis_sub = NULL;
        }
+       stasis_subscription_accept_message_type(mwi_stasis_sub->stasis_sub, ast_mwi_state_type());
+       stasis_subscription_accept_message_type(mwi_stasis_sub->stasis_sub, stasis_subscription_change_type());
+       stasis_subscription_set_filter(mwi_stasis_sub->stasis_sub, STASIS_SUBSCRIPTION_FILTER_SELECTIVE);
        return mwi_stasis_sub;
 }
 
@@ -1364,7 +1367,11 @@ static int load_module(void)
                if (ast_test_flag(&ast_options, AST_OPT_FLAG_FULLY_BOOTED)) {
                        ast_sip_push_task(NULL, send_initial_notify_all, NULL);
                } else {
-                       stasis_subscribe_pool(ast_manager_get_topic(), mwi_startup_event_cb, NULL);
+                       struct stasis_subscription *sub;
+
+                       sub = stasis_subscribe_pool(ast_manager_get_topic(), mwi_startup_event_cb, NULL);
+                       stasis_subscription_accept_message_type(sub, ast_manager_get_generic_type());
+                       stasis_subscription_set_filter(sub, STASIS_SUBSCRIPTION_FILTER_SELECTIVE);
                }
        }
 
index 1d42805..bbf3359 100644 (file)
@@ -45,10 +45,42 @@ static void rewrite_uri(pjsip_rx_data *rdata, pjsip_sip_uri *uri)
        }
 }
 
+/*
+ * Update the Record-Route headers in the request or response and in the dialog
+ * object if exists.
+ *
+ * When NAT is in use, the address of the next hop in the SIP may be incorrect.
+ * To address this  asterisk uses two strategies in parallel:
+ *  1. intercept the messages at the transaction level and rewrite the
+ *     messages before arriving at the dialog layer
+ *  2. after the application processing, update the dialog object with the
+ *     correct information
+ *
+ * The first strategy has a limitation that the SIP message may not have all
+ * the information required to determine if the next hop is in the route set
+ * or in the contact. Causing risk that asterisk will update the Contact on
+ * receipt of an in-dialog message despite there being a route set saved in
+ * the dialog.
+ *
+ * The second strategy has a limitation that not all UAC layers have interfaces
+ * available to invoke this module after dialog creation.  (pjsip_sesion does
+ * but pjsip_pubsub does not), thus this strategy can't update the dialog in
+ * all cases needed.
+ *
+ * The ideal solution would be to implement an "incomming_request" event
+ * in pubsub module that can then pass the dialog object to this module
+ * on SUBSCRIBE, this module then should add itself as a listener to the dialog
+ * for the subsequent requests and responses & then be able to properly update
+ * the dialog object for all required events.
+ */
+
 static int rewrite_route_set(pjsip_rx_data *rdata, pjsip_dialog *dlg)
 {
        pjsip_rr_hdr *rr = NULL;
        pjsip_sip_uri *uri;
+       int res = -1;
+       int ignore_rr = 0;
+       int pubsub = 0;
 
        if (rdata->msg_info.msg->type == PJSIP_RESPONSE_MSG) {
                pjsip_hdr *iter;
@@ -60,21 +92,49 @@ static int rewrite_route_set(pjsip_rx_data *rdata, pjsip_dialog *dlg)
                }
        } else if (pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, &pjsip_register_method)) {
                rr = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_RECORD_ROUTE, NULL);
+       } else {
+               /**
+                * Record-Route header has no meaning in REGISTER requests
+                * and should be ignored
+                */
+               ignore_rr = 1;
+       }
+
+       if (!pjsip_method_cmp(&rdata->msg_info.cseq->method, &pjsip_subscribe_method) ||
+               !pjsip_method_cmp(&rdata->msg_info.cseq->method, &pjsip_notify_method)) {
+               /**
+                * There is currently no good way to get the dlg object for a pubsub dialog
+                * so we will just look at the rr & contact of the current message and
+                * hope for the best
+                */
+               pubsub = 1;
        }
 
        if (rr) {
                uri = pjsip_uri_get_uri(&rr->name_addr);
                rewrite_uri(rdata, uri);
-               if (dlg && !pj_list_empty(&dlg->route_set) && !dlg->route_set_frozen) {
-                       pjsip_routing_hdr *route = dlg->route_set.next;
-                       uri = pjsip_uri_get_uri(&route->name_addr);
-                       rewrite_uri(rdata, uri);
-               }
+               res = 0;
+       }
 
-               return 0;
+       if (dlg && !pj_list_empty(&dlg->route_set) && !dlg->route_set_frozen) {
+               pjsip_routing_hdr *route = dlg->route_set.next;
+               uri = pjsip_uri_get_uri(&route->name_addr);
+               rewrite_uri(rdata, uri);
+               res = 0;
        }
 
-       return -1;
+       if (!dlg && !rr && !ignore_rr  && !pubsub && rdata->msg_info.to->tag.slen){
+               /**
+                * Even if this message doesn't have any route headers
+                * the dialog may, so wait until a later invocation that
+                * has a dialog reference to make sure there isn't a
+                * previously saved routset in the dialog before deciding
+                * the contact needs to be modified
+                */
+               res = 0;
+       }
+
+       return res;
 }
 
 static int rewrite_contact(pjsip_rx_data *rdata, pjsip_dialog *dlg)
index 648deee..33129c8 100644 (file)
@@ -2534,6 +2534,8 @@ static int load_module(void)
 
        network_change_sub = stasis_subscribe(ast_system_topic(),
                network_change_stasis_cb, NULL);
+       stasis_subscription_accept_message_type(network_change_sub, ast_network_change_type());
+       stasis_subscription_set_filter(network_change_sub, STASIS_SUBSCRIPTION_FILTER_SELECTIVE);
 
        return AST_MODULE_LOAD_SUCCESS;
 }
index 220ba0b..692f9a7 100644 (file)
@@ -360,6 +360,9 @@ static int asterisk_start_devicestate_publishing(struct ast_sip_outbound_publish
                ao2_ref(datastore, -1);
                return -1;
        }
+       stasis_subscription_accept_message_type(publisher_state->device_state_subscription, ast_device_state_message_type());
+       stasis_subscription_accept_message_type(publisher_state->device_state_subscription, stasis_subscription_change_type());
+       stasis_subscription_set_filter(publisher_state->device_state_subscription, STASIS_SUBSCRIPTION_FILTER_SELECTIVE);
 
        cached = stasis_cache_dump(ast_device_state_cache(), NULL);
        ao2_callback(cached, OBJ_NODATA, cached_devstate_cb, datastore);
@@ -435,6 +438,9 @@ static int asterisk_start_mwi_publishing(struct ast_sip_outbound_publish *config
                ao2_ref(datastore, -1);
                return -1;
        }
+       stasis_subscription_accept_message_type(publisher_state->mailbox_state_subscription, ast_mwi_state_type());
+       stasis_subscription_accept_message_type(publisher_state->mailbox_state_subscription, stasis_subscription_change_type());
+       stasis_subscription_set_filter(publisher_state->mailbox_state_subscription, STASIS_SUBSCRIPTION_FILTER_SELECTIVE);
 
        cached = stasis_cache_dump(ast_mwi_state_cache(), NULL);
        ao2_callback(cached, OBJ_NODATA, cached_mwistate_cb, datastore);
index b5ee159..9e8a32b 100644 (file)
@@ -5567,7 +5567,11 @@ static int load_module(void)
        if (ast_test_flag(&ast_options, AST_OPT_FLAG_FULLY_BOOTED)) {
                ast_sip_push_task(NULL, subscription_persistence_load, NULL);
        } else {
-               stasis_subscribe_pool(ast_manager_get_topic(), subscription_persistence_event_cb, NULL);
+               struct stasis_subscription *sub;
+
+               sub = stasis_subscribe_pool(ast_manager_get_topic(), subscription_persistence_event_cb, NULL);
+               stasis_subscription_accept_message_type(sub, ast_manager_get_generic_type());
+               stasis_subscription_set_filter(sub, STASIS_SUBSCRIPTION_FILTER_SELECTIVE);
        }
 
        ast_manager_register_xml(AMI_SHOW_SUBSCRIPTIONS_INBOUND, EVENT_FLAG_SYSTEM,
index 1e6ca7f..3dfaabc 100644 (file)
@@ -686,6 +686,10 @@ static void refer_blind_callback(struct ast_channel *chan, struct transfer_chann
                        ast_channel_unlock(chan);
 
                        ao2_cleanup(refer->progress);
+               } else {
+                       stasis_subscription_accept_message_type(refer->progress->bridge_sub, ast_channel_entered_bridge_type());
+                       stasis_subscription_accept_message_type(refer->progress->bridge_sub, stasis_subscription_change_type());
+                       stasis_subscription_set_filter(refer->progress->bridge_sub, STASIS_SUBSCRIPTION_FILTER_SELECTIVE);
                }
        }
 
index 555ba23..95429ca 100644 (file)
@@ -141,6 +141,8 @@ static int load_module(void)
                LOG_SECURITY = -1;
                return AST_MODULE_LOAD_DECLINE;
        }
+       stasis_subscription_accept_message_type(security_stasis_sub, ast_security_event_type());
+       stasis_subscription_set_filter(security_stasis_sub, STASIS_SUBSCRIPTION_FILTER_SELECTIVE);
 
        ast_verb(3, "Security Logging Enabled\n");
 
index be09b15..1c80f9e 100644 (file)
@@ -394,6 +394,9 @@ static int subscribe_device_state(struct stasis_app *app, void *obj)
                ao2_ref(sub, -1);
                return -1;
        }
+       stasis_subscription_accept_message_type(sub->sub, ast_device_state_message_type());
+       stasis_subscription_accept_message_type(sub->sub, stasis_subscription_change_type());
+       stasis_subscription_set_filter(sub->sub, STASIS_SUBSCRIPTION_FILTER_SELECTIVE);
 
        ao2_link_flags(device_state_subscriptions, sub, OBJ_NOLOCK);
        ao2_unlock(device_state_subscriptions);
index 8366a8c..838bed8 100644 (file)
@@ -1599,11 +1599,15 @@ static void xmpp_init_event_distribution(struct ast_xmpp_client *client)
        if (!(client->mwi_sub = stasis_subscribe_pool(ast_mwi_topic_all(), xmpp_pubsub_mwi_cb, client))) {
                return;
        }
+       stasis_subscription_accept_message_type(client->mwi_sub, ast_mwi_state_type());
+       stasis_subscription_set_filter(client->mwi_sub, STASIS_SUBSCRIPTION_FILTER_SELECTIVE);
 
        if (!(client->device_state_sub = stasis_subscribe(ast_device_state_topic_all(), xmpp_pubsub_devstate_cb, client))) {
                client->mwi_sub = stasis_unsubscribe(client->mwi_sub);
                return;
        }
+       stasis_subscription_accept_message_type(client->device_state_sub, ast_device_state_message_type());
+       stasis_subscription_set_filter(client->device_state_sub, STASIS_SUBSCRIPTION_FILTER_SELECTIVE);
 
        cached = stasis_cache_dump(ast_device_state_cache(), NULL);
        ao2_callback(cached, OBJ_NODATA, cached_devstate_cb, client);
index 9835647..1839a8b 100644 (file)
@@ -129,8 +129,9 @@ pipeline {
                                        def r = currentBuild.startTimeInMillis % images.length
                                        def ri = images[(int)r]
                                        def randomImage = env.DOCKER_REGISTRY + "/" + ri
+                                       /* FYI... Jenkins takes care of mouting the workspace for the container */
                                        def dockerOptions = "--privileged --ulimit core=0 --ulimit nofile=10240 " +
-                                               " -v /srv/jenkins:/srv/jenkins:rw -v /srv/cache:/srv/cache:rw " +
+                                               " --mount type=tmpfs,tmpfs-size=1g,dst=/tmp -v /srv/jenkins:/srv/jenkins:rw -v /srv/cache:/srv/cache:rw " +
                                                " --entrypoint=''"
                                        def bt = env.BUILD_TAG.replaceAll(/[^a-zA-Z0-9_.-]/, '-')
                                        def outputdir = "tests/CI/output/Testsuite"
index dcd53cd..ba56665 100644 (file)
@@ -42,7 +42,7 @@ pipeline {
                                        def ri = images[(int)r]
                                        def randomImage = env.DOCKER_REGISTRY + "/" + ri
                                        def dockerOptions = "--privileged --ulimit core=0 --ulimit nofile=10240 " +
-                                               " -v /srv/jenkins:/srv/jenkins:rw -v /srv/cache:/srv/cache:rw " +
+                                               " --mount type=tmpfs,tmpfs-size=1g,dst=/tmp -v /srv/jenkins:/srv/jenkins:rw -v /srv/cache:/srv/cache:rw " +
                                                " --entrypoint=''"
                                        def bt = env.BUILD_TAG.replaceAll(/[^a-zA-Z0-9_.-]/, '-')
                                        def outputdir = "tests/CI/output/Testsuite"
index 7b48585..2c6daf0 100644 (file)
@@ -42,7 +42,7 @@ pipeline {
                                        def ri = images[(int)r]
                                        def randomImage = env.DOCKER_REGISTRY + "/" + ri
                                        def dockerOptions = "--privileged --ulimit core=0 --ulimit nofile=10240 " +
-                                               " -v /srv/jenkins:/srv/jenkins:rw -v /srv/cache:/srv/cache:rw " +
+                                               " --mount type=tmpfs,tmpfs-size=1g,dst=/tmp -v /srv/jenkins:/srv/jenkins:rw -v /srv/cache:/srv/cache:rw " +
                                                " --entrypoint=''"
                                        def bt = env.BUILD_TAG.replaceAll(/[^a-zA-Z0-9_.-]/, '-')
                                        def outputdir = "tests/CI/output/Testsuite"
index 9ee7718..466991a 100755 (executable)
@@ -5,6 +5,11 @@ TEST_TIMEOUT=600
 source $CIDIR/ci.functions
 ASTETCDIR=$DESTDIR/etc/asterisk
 
+if [ x"$WORK_DIR" != x ] ; then
+       export AST_WORK_DIR="$(readlink -f $WORK_DIR)"
+       mkdir -p "$AST_WORK_DIR"
+fi
+
 pushd $TESTSUITE_DIR
 
 ./cleanup-test-remnants.sh
@@ -14,7 +19,7 @@ if [ $REALTIME -eq 1 ] ; then
 fi
 
 export PYTHONPATH=./lib/python/
-echo "Running tests ${TESTSUITE_COMMAND}"
+echo "Running tests ${TESTSUITE_COMMAND} ${AST_WORK_DIR:+with work directory ${AST_WORK_DIR}}"
 ./runtests.py --cleanup --timeout=${TEST_TIMEOUT} ${TESTSUITE_COMMAND} | contrib/scripts/pretty_print --no-color --no-timer --term-width=120 --show-errors || :
 
 if [ $REALTIME -eq 1 ] ; then
index 682c506..e2d7e45 100755 (executable)
@@ -1,5 +1,6 @@
 #!/usr/bin/env bash
 CIDIR=$(dirname $(readlink -fn $0))
+NO_EXPECT=0
 source $CIDIR/ci.functions
 ASTETCDIR=$DESTDIR/etc/asterisk
 
@@ -14,9 +15,54 @@ asterisk_corefile_glob() {
        fi
 }
 
+run_tests_expect() {
+$EXPECT <<-EOF
+       spawn sudo $ASTERISK ${USER_GROUP:+-U ${USER_GROUP%%:*} -G ${USER_GROUP##*:}} -fcng -C $CONFFILE
+       match_max 512
+       set timeout 600
+       expect -notransfer "Asterisk Ready."
+       send "core show settings\r"
+       expect -notransfer "CLI>"
+       send "${UNITTEST_COMMAND:-test execute all}\r"
+       expect -notransfer -ex "Test(s) Executed"
+       expect -notransfer "CLI>"
+       send "test show results failed\r"
+       expect -notransfer "CLI>"
+       send "test generate results xml ${OUTPUTFILE}\r"
+       expect -notransfer "CLI>"
+       send "core stop now\r"
+       expect -notransfer "Executing last minute cleanups"
+       wait
+EOF
+}
+
+run_tests_socket() {
+       sudo $ASTERISK ${USER_GROUP:+-U ${USER_GROUP%%:*} -G ${USER_GROUP##*:}} -gn -C $CONFFILE
+       for n in {1..5} ; do
+               sleep 3
+               $ASTERISK -rx "core waitfullybooted" -C $CONFFILE && break
+       done
+       sleep 1
+       $ASTERISK -rx "core show settings" -C $CONFFILE
+       $ASTERISK -rx "${UNITTEST_COMMAND:-test execute all}" -C $CONFFILE
+       $ASTERISK -rx "test show results failed" -C $CONFFILE
+       $ASTERISK -rx "test generate results xml $OUTPUTFILE" -C $CONFFILE
+       $ASTERISK -rx "core stop now" -C $CONFFILE
+}
+
+# If DESTDIR is used to install and run asterisk from non standard locations,
+# the directory entries in asterisk.conf need to be munged to prepend DESTDIR.
+ALTERED=$(head -10 ../tmp/DESTDIR/etc/asterisk/asterisk.conf | grep -q "DESTDIR" && echo yes)
+if [ x"$ALTERED" = x ] ; then
+       # In the section that starts with [directories and ends with a blank line,
+       # replace "=> " with "=> ${DESTDIR}"
+       sed -i -r -e "/^\[directories/,/^$/ s@=>\s+@=> ${DESTDIR}@" "$ASTETCDIR/asterisk.conf"
+fi
+
 cat <<-EOF > "$ASTETCDIR/logger.conf"
        [logfiles]
        full => notice,warning,error,debug,verbose
+       console => notice,warning,error
 EOF
 
 echo "[default]" > "$ASTETCDIR/extensions.conf"
@@ -58,6 +104,7 @@ ASTERISK="$DESTDIR/usr/sbin/asterisk"
 CONFFILE=$ASTETCDIR/asterisk.conf
 OUTPUTDIR=${OUTPUT_DIR:-tests/CI/output/}
 OUTPUTFILE=${OUTPUT_XML:-${OUTPUTDIR}/unittests-results.xml}
+EXPECT="$(which expect 2>/dev/null || : )"
 
 [ ! -d ${OUTPUTDIR} ] && mkdir -p $OUTPUTDIR
 [ x"$USER_GROUP" != x ] && sudo chown -R $USER_GROUP $OUTPUTDIR
@@ -65,16 +112,14 @@ OUTPUTFILE=${OUTPUT_XML:-${OUTPUTDIR}/unittests-results.xml}
 rm -rf $ASTETCDIR/extensions.{ael,lua} || :
 
 set -x
-sudo $ASTERISK ${USER_GROUP:+-U ${USER_GROUP%%:*} -G ${USER_GROUP##*:}} -gn -C $CONFFILE
-for n in {1..5} ; do
-       sleep 3
-       $ASTERISK -rx "core waitfullybooted" -C $CONFFILE && break
-done
-sleep 1
-$ASTERISK -rx "${UNITTEST_COMMAND:-test execute all}" -C $CONFFILE
-$ASTERISK -rx "test show results failed" -C $CONFFILE
-$ASTERISK -rx "test generate results xml $OUTPUTFILE" -C $CONFFILE
-$ASTERISK -rx "core stop now" -C $CONFFILE
+if [ x"$EXPECT" != x -a $NO_EXPECT -eq 0 ] ; then
+       run_tests_expect
+else
+       run_tests_socket
+fi
+
+# Cleanup "just in case"
+sudo killall -qe -ABRT $ASTERISK 
 
 runner rsync -vaH $DESTDIR/var/log/asterisk/. $OUTPUTDIR
 set +x
@@ -86,6 +131,7 @@ do
        if [ -f $core ]
        then
                echo "*** Found a core file ($core) after running unit tests ***"
+               set -x
                sudo OUTPUTDIR=$OUTPUTDIR $DESTDIR/var/lib/asterisk/scripts/ast_coredumper --no-default-search $core
        fi
 done
index bdd517d..61dac70 100644 (file)
@@ -133,7 +133,7 @@ pipeline {
                                        def randomImage = env.DOCKER_REGISTRY + "/" + ri;
                                        def bt = env.BUILD_TAG.replaceAll(/[^a-zA-Z0-9_.-]/, '-')
                                        def dockerOptions = "--privileged --ulimit core=0 --ulimit nofile=10240 " +
-                                               " -v /srv/jenkins:/srv/jenkins:rw -v /srv/cache:/srv/cache:rw " +
+                                               " --mount type=tmpfs,tmpfs-size=1g,dst=/tmp -v /srv/jenkins:/srv/jenkins:rw -v /srv/cache:/srv/cache:rw " +
                                                " --entrypoint='' --name ${bt}-build"
                                        def outputdir = "tests/CI/output/UnitTests"
 
index 155bec9..d4858e4 100644 (file)
@@ -343,8 +343,50 @@ AST_TEST_DEFINE(segv)
        return AST_TEST_FAIL;
 }
 
+AST_TEST_DEFINE(call_assert)
+{
+       switch (cmd) {
+       case TEST_INIT:
+               info->name = "CALL_ASSERT";
+               info->category = "/DO_NOT_RUN/";
+               info->summary = "Calls ast_asert()!!! (will only be run if explicitly called)";
+               info->description = "Calls ast_asert()!!! (will only be run if explicitly called). "
+                       "This test is mainly used for testing CI and tool failure scenarios.";
+               info->explicit_only = 1;
+               return AST_TEST_NOT_RUN;
+       case TEST_EXECUTE:
+               break;
+       }
+
+       ast_assert(0);
+
+       return AST_TEST_PASS;
+}
+
+AST_TEST_DEFINE(call_backtrace)
+{
+       switch (cmd) {
+       case TEST_INIT:
+               info->name = "CALL_BACKTRACE";
+               info->category = "/DO_NOT_RUN/";
+               info->summary = "Calls ast_log_backtrace()!!! (will only be run if explicitly called)";
+               info->description = "Calls ast_log_backtrace()!!! (will only be run if explicitly called). "
+                       "This test is mainly used for testing CI and tool failure scenarios.";
+               info->explicit_only = 1;
+               return AST_TEST_NOT_RUN;
+       case TEST_EXECUTE:
+               break;
+       }
+
+       ast_log_backtrace();
+
+       return AST_TEST_PASS;
+}
+
 static int unload_module(void)
 {
+       AST_TEST_UNREGISTER(call_backtrace);
+       AST_TEST_UNREGISTER(call_assert);
        AST_TEST_UNREGISTER(segv);
        AST_TEST_UNREGISTER(pattern_match_test);
        return 0;
@@ -354,6 +396,8 @@ static int load_module(void)
 {
        AST_TEST_REGISTER(pattern_match_test);
        AST_TEST_REGISTER(segv);
+       AST_TEST_REGISTER(call_assert);
+       AST_TEST_REGISTER(call_backtrace);
        return AST_MODULE_LOAD_SUCCESS;
 }
 
diff --git a/third-party/jansson/patches/0035-Remove-inappropriate-jsonp_free-which-caused-segment.patch b/third-party/jansson/patches/0035-Remove-inappropriate-jsonp_free-which-caused-segment.patch
new file mode 100644 (file)
index 0000000..258fc67
--- /dev/null
@@ -0,0 +1,58 @@
+From e262ea5fcd789d20d5d20d5d6d9c7ec06e3c00fd Mon Sep 17 00:00:00 2001
+From: Corey Farrell <git@cfware.com>
+Date: Mon, 5 Nov 2018 16:43:10 -0500
+Subject: [PATCH 35/35] Remove inappropriate jsonp_free which caused
+ segmentation fault.
+
+pack_string should never free str on error.  This wouldn't be a problem
+except the check for `ours` was inverted.  Just remove the check for
+ours since the true condition is unreachable.
+
+json_vpack_ex also had an error check for s.has_error.  This can never
+be true unless value is NULL.
+
+Test changes removed for merging into Asterisk bundled copy.
+
+Fixes #444
+---
+ src/pack_unpack.c           |  9 ++-------
+ test/suites/api/test_pack.c | 21 +++++++++++++++++++++
+ 2 files changed, 23 insertions(+), 7 deletions(-)
+
+diff --git a/src/pack_unpack.c b/src/pack_unpack.c
+index ec04bc3..3b99776 100644
+--- a/src/pack_unpack.c
++++ b/src/pack_unpack.c
+@@ -359,9 +359,7 @@ static json_t *pack_string(scanner_t *s, va_list *ap)
+         return t == '?' && !s->has_error ? json_null() : NULL;
+     if (s->has_error) {
+-        if (!ours)
+-            jsonp_free(str);
+-
++        /* It's impossible to reach this point if ours != 0, do not free str. */
+         return NULL;
+     }
+@@ -853,6 +851,7 @@ json_t *json_vpack_ex(json_error_t *error, size_t flags,
+     value = pack(&s, &ap_copy);
+     va_end(ap_copy);
++    /* This will cover all situations where s.has_error is true */
+     if(!value)
+         return NULL;
+@@ -862,10 +861,6 @@ json_t *json_vpack_ex(json_error_t *error, size_t flags,
+         set_error(&s, "<format>", json_error_invalid_format, "Garbage after format string");
+         return NULL;
+     }
+-    if(s.has_error) {
+-        json_decref(value);
+-        return NULL;
+-    }
+     return value;
+ }
+-- 
+2.17.2
+
index c761cb5..97835e4 100644 (file)
@@ -54,14 +54,12 @@ ifeq ($(SPECIAL_TARGETS),)
         include source/build.mak
         CF := $(filter-out -W%,$(CC_CFLAGS))
         CF := $(filter-out -I%,$(CF))
-        ifeq ($(findstring TEST_FRAMEWORK,$(MENUSELECT_CFLAGS)),TEST_FRAMEWORK)
+        ifeq ($(AST_DEVMODE),yes)
             apps := source/pjsip-apps/bin/pjsua-$(TARGET_NAME) source/pjsip-apps/bin/pjsystest-$(TARGET_NAME)
             TARGETS += $(apps)
             ifneq ($(PYTHONDEV_LIB),)
                 TARGETS += source/pjsip-apps/src/python/_pjsua.so
             endif
-        endif
-        ifeq ($(AST_DEVMODE),yes)
             CF += -DPJPROJECT_BUNDLED_ASSERTIONS=yes
         endif
         MALLOC_DEBUG_LIBS = source/pjsip-apps/lib/libasterisk_malloc_debug.a
index 6a48e86..e76a753 100644 (file)
@@ -39,7 +39,7 @@ PJPROJECT_CONFIG_OPTS = $(PJPROJECT_CONFIGURE_OPTS) --prefix=/opt/pjproject \
        --without-external-pa \
        --without-external-srtp
 
-ifeq ($(findstring TEST_FRAMEWORK,$(MENUSELECT_CFLAGS)),)
+ifneq ($(AST_DEVMODE),yes)
     PJPROJECT_CONFIG_OPTS += --disable-resample --disable-g711-codec
 endif
 
index 9e89098..d021152 100644 (file)
@@ -73,7 +73,7 @@ AC_DEFUN([_PJPROJECT_CONFIGURE],
        fi
 
        export TAR PATCH SED NM EXTERNALS_CACHE_DIR AST_DOWNLOAD_CACHE DOWNLOAD_TO_STDOUT DOWNLOAD_TIMEOUT DOWNLOAD MD5 CAT CUT GREP
-       export NOISY_BUILD
+       export NOISY_BUILD AST_DEVMODE
        ${GNU_MAKE} --quiet --no-print-directory -C ${PJPROJECT_DIR} \
                PJPROJECT_CONFIGURE_OPTS="$PJPROJECT_CONFIGURE_OPTS" \
                EXTERNALS_CACHE_DIR="${EXTERNALS_CACHE_DIR:-${AST_DOWNLOAD_CACHE}}" \
index e0e4501..455f5b0 100644 (file)
@@ -617,16 +617,9 @@ int __ast_bt_get_addresses(struct ast_bt *bt)
        return 0;
 }
 
-char **__ast_bt_get_symbols(void **addresses, size_t num_frames)
+struct ast_vector_string *__ast_bt_get_symbols(void **addresses, size_t num_frames)
 {
-       char **foo = calloc(num_frames, sizeof(char *) + 1);
-       if (foo) {
-               int i;
-               for (i = 0; i < num_frames; i++) {
-                       foo[i] = (char *) foo + sizeof(char *) * num_frames;
-               }
-       }
-       return foo;
+       return NULL;
 }
 #endif /* HAVE_BKTR */
 void ast_suspend_lock_info(void *lock_addr)
index d4a4c90..19e5b0d 100644 (file)
@@ -77,17 +77,10 @@ int __ast_bt_get_addresses(struct ast_bt *bt)
        /* Suck it, you stupid utils directory! */
        return 0;
 }
-char **__ast_bt_get_symbols(void **addresses, size_t num_frames);
-char **__ast_bt_get_symbols(void **addresses, size_t num_frames)
+struct ast_vector_string *__ast_bt_get_symbols(void **addresses, size_t num_frames);
+struct ast_vector_string *__ast_bt_get_symbols(void **addresses, size_t num_frames)
 {
-       char **foo = calloc(num_frames, sizeof(char *) + 1);
-       if (foo) {
-               int i;
-               for (i = 0; i < num_frames; i++) {
-                       foo[i] = (char *) foo + sizeof(char *) * num_frames;
-               }
-       }
-       return foo;
+       return NULL;
 }
 #endif /* HAVE_BKTR */
 
index 14b2aa9..0a327ec 100644 (file)
@@ -715,16 +715,9 @@ int __ast_bt_get_addresses(struct ast_bt *bt)
        return 0;
 }
 
-char **__ast_bt_get_symbols(void **addresses, size_t num_frames)
+struct ast_vector_string *__ast_bt_get_symbols(void **addresses, size_t num_frames)
 {
-       char **foo = calloc(num_frames, sizeof(char *) + 1);
-       if (foo) {
-               int i;
-               for (i = 0; i < num_frames; i++) {
-                       foo[i] = (char *) foo + sizeof(char *) * num_frames;
-               }
-       }
-       return foo;
+       return NULL;
 }
 #endif /* HAVE_BKTR */
 void ast_suspend_lock_info(void *lock_addr)