Merge "chan_sip: Enable Session-Timers for SIP over TCP (and TLS)."
[asterisk/asterisk.git] / channels / chan_sip.c
index 9098c14..5f422d7 100644 (file)
@@ -284,6 +284,7 @@ ASTERISK_REGISTER_FILE()
 #include "asterisk/features_config.h"
 #include "asterisk/http_websocket.h"
 #include "asterisk/format_cache.h"
+#include "asterisk/linkedlists.h"      /* for AST_LIST_NEXT */
 
 /*** DOCUMENTATION
        <application name="SIPDtmfMode" language="en_US">
@@ -8600,29 +8601,31 @@ static struct ast_frame *sip_read(struct ast_channel *ast)
        if (faxdetected && ast_test_flag(&p->flags[1], SIP_PAGE2_FAX_DETECT_CNG)) {
                if (strcmp(ast_channel_exten(ast), "fax")) {
                        const char *target_context = S_OR(ast_channel_macrocontext(ast), ast_channel_context(ast));
-                       /* We need to unlock 'ast' here because
+                       /*
+                        * We need to unlock 'ast' here because
                         * ast_exists_extension has the potential to start and
                         * stop an autoservice on the channel. Such action is
                         * prone to deadlock if the channel is locked.
+                        *
+                        * ast_async_goto() has its own restriction on not holding
+                        * the channel lock.
                         */
                        sip_pvt_unlock(p);
                        ast_channel_unlock(ast);
+                       ast_frfree(fr);
+                       fr = &ast_null_frame;
                        if (ast_exists_extension(ast, target_context, "fax", 1,
                                S_COR(ast_channel_caller(ast)->id.number.valid, ast_channel_caller(ast)->id.number.str, NULL))) {
-                               ast_channel_lock(ast);
-                               sip_pvt_lock(p);
                                ast_verb(2, "Redirecting '%s' to fax extension due to CNG detection\n", ast_channel_name(ast));
                                pbx_builtin_setvar_helper(ast, "FAXEXTEN", ast_channel_exten(ast));
                                if (ast_async_goto(ast, target_context, "fax", 1)) {
                                        ast_log(LOG_NOTICE, "Failed to async goto '%s' into fax of '%s'\n", ast_channel_name(ast), target_context);
                                }
-                               ast_frfree(fr);
-                               fr = &ast_null_frame;
                        } else {
-                               ast_channel_lock(ast);
-                               sip_pvt_lock(p);
                                ast_log(LOG_NOTICE, "FAX CNG detected but no fax extension\n");
                        }
+                       ast_channel_lock(ast);
+                       sip_pvt_lock(p);
                }
        }
 
@@ -13211,21 +13214,34 @@ static void get_our_media_address(struct sip_pvt *p, int needvideo, int needtext
 
 static char *crypto_get_attrib(struct ast_sdp_srtp *srtp, int dtls_enabled, int default_taglen_32)
 {
+       struct ast_sdp_srtp *tmp = srtp;
        char *a_crypto;
-       const char *orig_crypto;
 
-       if (!srtp || dtls_enabled) {
+       if (!tmp || dtls_enabled) {
                return NULL;
        }
 
-       orig_crypto = ast_sdp_srtp_get_attrib(srtp, dtls_enabled, default_taglen_32);
-       if (ast_strlen_zero(orig_crypto)) {
+       a_crypto = ast_strdup("");
+       if (!a_crypto) {
                return NULL;
        }
 
-       if (ast_asprintf(&a_crypto, "a=crypto:%s\r\n", orig_crypto) == -1) {
-               return NULL;
-       }
+       do {
+               char *copy = a_crypto;
+               const char *orig_crypto = ast_sdp_srtp_get_attrib(tmp, dtls_enabled, default_taglen_32);
+
+               if (ast_strlen_zero(orig_crypto)) {
+                       ast_free(copy);
+                       return NULL;
+               }
+               if (ast_asprintf(&a_crypto, "%sa=crypto:%s\r\n", copy, orig_crypto) == -1) {
+                       ast_free(copy);
+                       return NULL;
+               }
+
+               ast_free(copy);
+       } while ((tmp = AST_LIST_NEXT(tmp, sdp_srtp_list)));
+
        return a_crypto;
 }
 
@@ -21312,15 +21328,13 @@ static char *sip_unregister(struct ast_cli_entry *e, int cmd, struct ast_cli_arg
 }
 
 /*! \brief Callback for show_chanstats */
-static int show_chanstats_cb(void *__cur, void *__arg, int flags)
+static int show_chanstats_cb(struct sip_pvt *cur, struct __show_chan_arg *arg)
 {
 #define FORMAT2 "%-15.15s  %-11.11s  %-8.8s %-10.10s  %-10.10s (     %%) %-6.6s %-10.10s  %-10.10s (     %%) %-6.6s\n"
 #define FORMAT  "%-15.15s  %-11.11s  %-8.8s %-10.10u%-1.1s %-10.10u (%5.2f%%) %-6.4lf %-10.10u%-1.1s %-10.10u (%5.2f%%) %-6.4lf\n"
-       struct sip_pvt *cur = __cur;
        struct ast_rtp_instance_stats stats;
        char durbuf[10];
        struct ast_channel *c;
-       struct __show_chan_arg *arg = __arg;
        int fd = arg->fd;
 
        sip_pvt_lock(cur);
@@ -21380,6 +21394,8 @@ static int show_chanstats_cb(void *__cur, void *__arg, int flags)
 static char *sip_show_channelstats(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
        struct __show_chan_arg arg = { .fd = a->fd, .numchans = 0 };
+       struct sip_pvt *cur;
+       struct ao2_iterator i;
 
        switch (cmd) {
        case CLI_INIT:
@@ -21397,8 +21413,14 @@ static char *sip_show_channelstats(struct ast_cli_entry *e, int cmd, struct ast_
                return CLI_SHOWUSAGE;
 
        ast_cli(a->fd, FORMAT2, "Peer", "Call ID", "Duration", "Recv: Pack", "Lost", "Jitter", "Send: Pack", "Lost", "Jitter");
+
        /* iterate on the container and invoke the callback on each item */
-       ao2_t_callback(dialogs, OBJ_NODATA, show_chanstats_cb, &arg, "callback to sip show chanstats");
+       i = ao2_iterator_init(dialogs, 0);
+       for (; (cur = ao2_iterator_next(&i)); ao2_ref(cur, -1)) {
+               show_chanstats_cb(cur, &arg);
+       }
+       ao2_iterator_destroy(&i);
+
        ast_cli(a->fd, "%d active SIP channel%s\n", arg.numchans, (arg.numchans != 1) ? "s" : "");
        return CLI_SUCCESS;
 }
@@ -21718,10 +21740,8 @@ static const struct cfsubscription_types *find_subscription_type(enum subscripti
 #define FORMAT  "%-15.15s  %-15.15s  %-15.15s  %-15.15s  %-3.3s %-3.3s  %-15.15s %-10.10s %-10.10s\n"
 
 /*! \brief callback for show channel|subscription */
-static int show_channels_cb(void *__cur, void *__arg, int flags)
+static int show_channels_cb(struct sip_pvt *cur, struct __show_chan_arg *arg)
 {
-       struct sip_pvt *cur = __cur;
-       struct __show_chan_arg *arg = __arg;
        const struct ast_sockaddr *dst;
 
        sip_pvt_lock(cur);
@@ -21773,7 +21793,8 @@ static int show_channels_cb(void *__cur, void *__arg, int flags)
 static char *sip_show_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
        struct __show_chan_arg arg = { .fd = a->fd, .numchans = 0 };
-
+       struct sip_pvt *cur;
+       struct ao2_iterator i;
 
        if (cmd == CLI_INIT) {
                e->command = "sip show {channels|subscriptions}";
@@ -21795,7 +21816,11 @@ static char *sip_show_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_
                ast_cli(arg.fd, FORMAT3, "Peer", "User", "Call ID", "Extension", "Last state", "Type", "Mailbox", "Expiry");
 
        /* iterate on the container and invoke the callback on each item */
-       ao2_t_callback(dialogs, OBJ_NODATA, show_channels_cb, &arg, "callback to show channels");
+       i = ao2_iterator_init(dialogs, 0);
+       for (; (cur = ao2_iterator_next(&i)); ao2_ref(cur, -1)) {
+               show_channels_cb(cur, &arg);
+       }
+       ao2_iterator_destroy(&i);
 
        /* print summary information */
        ast_cli(arg.fd, "%d active SIP %s%s\n", arg.numchans,