Merge "tcptls: Use new certificate upon sip reload"
authorJoshua Colp <jcolp@digium.com>
Fri, 2 Dec 2016 13:15:07 +0000 (07:15 -0600)
committerGerrit Code Review <gerrit2@gerrit.digium.api>
Fri, 2 Dec 2016 13:15:08 +0000 (07:15 -0600)
30 files changed:
CHANGES
build_tools/download_externals
channels/chan_pjsip.c
channels/chan_sip.c
codecs/codec_dahdi.c
configs/samples/pjproject.conf.sample
configure
configure.ac
include/asterisk/channel.h
include/asterisk/format.h
include/asterisk/options.h
include/asterisk/utils.h
main/asterisk.c
main/channel.c
main/format.c
main/iostream.c
main/libasteriskpj.c
main/libasteriskssl.c
main/rtp_engine.c
main/tcptls.c
main/utils.c
pbx/pbx_lua.c
res/res_calendar_caldav.c
res/res_format_attr_opus.c
res/res_pjproject.c
res/res_pjsip.c
res/res_pjsip_sdp_rtp.c
res/res_pjsip_t38.c
res/res_rtp_asterisk.c
third-party/pjproject/patches/config_site.h

diff --git a/CHANGES b/CHANGES
index cb3fe95..886cd00 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -63,7 +63,24 @@ RTP
    implementation, please report this and go back to rtp_pt_dynamic = 96.
 
 ------------------------------------------------------------------------------
---- Functionality changes from Asterisk 14.1.0 to Asterisk 14.2.0 ----------
+--- Functionality changes from Asterisk 14.2.0 to Asterisk 14.3.0 ------------
+------------------------------------------------------------------------------
+
+res_pjproject
+------------------
+ * Added new CLI command "pjproject set log level".  The new command allows
+   the maximum PJPROJECT log levels to be adjusted dynamically and
+   independently from the set debug logging level like many other similar
+   module debug logging commands.
+
+ * Added new companion CLI command "pjproject show log level" to allow the
+   user to see the current maximum pjproject logging level.
+
+ * Added new pjproject.conf startup section "log_level' option to set the
+   initial maximum PJPROJECT logging level.
+
+------------------------------------------------------------------------------
+--- Functionality changes from Asterisk 14.1.0 to Asterisk 14.2.0 ------------
 ------------------------------------------------------------------------------
 
 AMI
@@ -143,7 +160,7 @@ res_ari
    ARI event.
 
 ------------------------------------------------------------------------------
---- Functionality changes from Asterisk 14.0.0 to Asterisk 14.1.0 ----------
+--- Functionality changes from Asterisk 14.0.0 to Asterisk 14.1.0 ------------
 ------------------------------------------------------------------------------
 
 Build System
index 2bc357c..d2e2e4f 100755 (executable)
@@ -45,11 +45,11 @@ if [[ -z ${cache_dir} ]] ; then
 fi
 
 version=$(${ASTTOPDIR}/build_tools/make_version ${ASTTOPDIR})
-if [[ ! ${version} =~ ^(GIT-)?([^.-]+)[.-].* ]] ; then
+if [[ ! ${version} =~ ^(GIT-)?(certified/)?([^.-]+)[.-].* ]] ; then
        echo "${module_name}: Couldn't parse version ${version}"
        exit 1
 fi
-major_version=${BASH_REMATCH[2]}
+major_version=${BASH_REMATCH[3]}
 
 if [[ "${major_version}" == "master" ]] ; then
        echo "${module_name}: External module downloading is not available in the 'master' git branch.  Please disable in menuselect and download manually."
index d4a7d61..4aae15c 100644 (file)
@@ -677,7 +677,11 @@ static struct ast_frame *chan_pjsip_cng_tone_detected(struct ast_sip_session *se
        return f;
 }
 
-/*! \brief Function called by core to read any waiting frames */
+/*!
+ * \brief Function called by core to read any waiting frames 
+ *
+ * \note The channel is already locked.
+ */
 static struct ast_frame *chan_pjsip_read(struct ast_channel *ast)
 {
        struct ast_sip_channel_pvt *channel = ast_channel_tech_pvt(ast);
@@ -735,8 +739,7 @@ static struct ast_frame *chan_pjsip_read(struct ast_channel *ast)
                ast_debug(1, "Oooh, got a frame with format of %s on channel '%s' when we're sending '%s', switching to match\n",
                        ast_format_get_name(f->subclass.format), ast_channel_name(ast),
                        ast_format_get_name(ast_channel_rawwriteformat(ast)));
-               ast_channel_set_rawwriteformat(ast, f->subclass.format);
-               ast_set_write_format(ast, ast_channel_writeformat(ast));
+               ast_set_write_format_path(ast, ast_channel_writeformat(ast), f->subclass.format);
 
                if (ast_channel_is_bridged(ast)) {
                        ast_channel_set_unbridged_nolock(ast, 1);
index 870b53e..16d84af 100644 (file)
@@ -2957,6 +2957,7 @@ static void *_sip_tcp_helper_thread(struct ast_tcptls_session_instance *tcptls_s
                if (!(me = sip_threadinfo_create(tcptls_session, ast_iostream_get_ssl(tcptls_session->stream) ? AST_TRANSPORT_TLS : AST_TRANSPORT_TCP))) {
                        goto cleanup;
                }
+               me->threadid = pthread_self();
                ao2_t_ref(me, +1, "Adding threadinfo ref for tcp_helper_thread");
        } else {
                struct sip_threadinfo tmp = {
@@ -2964,8 +2965,13 @@ static void *_sip_tcp_helper_thread(struct ast_tcptls_session_instance *tcptls_s
                };
 
                if ((!(ca = tcptls_session->parent)) ||
-                       (!(me = ao2_t_find(threadt, &tmp, OBJ_POINTER, "ao2_find, getting sip_threadinfo in tcp helper thread"))) ||
-                       (!(tcptls_session = ast_tcptls_client_start(tcptls_session)))) {
+                       (!(me = ao2_t_find(threadt, &tmp, OBJ_POINTER, "ao2_find, getting sip_threadinfo in tcp helper thread")))) {
+                       goto cleanup;
+               }
+
+               me->threadid = pthread_self();
+
+               if (!(tcptls_session = ast_tcptls_client_start(tcptls_session))) {
                        goto cleanup;
                }
        }
@@ -2976,7 +2982,6 @@ static void *_sip_tcp_helper_thread(struct ast_tcptls_session_instance *tcptls_s
                goto cleanup;
        }
 
-       me->threadid = pthread_self();
        ast_debug(2, "Starting thread for %s server\n", ast_iostream_get_ssl(tcptls_session->stream) ? "TLS" : "TCP");
 
        /* set up pollfd to watch for reads on both the socket and the alert_pipe */
index 2d08d36..efb0168 100644 (file)
 #include "asterisk.h"
 #include <stdbool.h>
 
+#include <poll.h>
 #include <fcntl.h>
 #include <netinet/in.h>
 #include <sys/ioctl.h>
 #include <sys/mman.h>
-#include <sys/poll.h>
 #include <dahdi/user.h>
 
 #include "asterisk/lock.h"
index 97af734..82c81a1 100644 (file)
@@ -1,15 +1,36 @@
 ; Common pjproject options
 ;
 
+;[startup]
+;  NOTES: The name of this section in the pjproject.conf configuration file must
+;         remain startup or the configuration will not be applied.
+;
+;log_level=default   ; Initial maximum pjproject logging level to log
+                     ; Valid values are: 0-6, and default
+                     ;
+                     ; Note: This option is needed very early in the startup
+                     ; process so it can only be read from config files because
+                     ; the modules for other methods have not been loaded yet.
+;type=               ; Must be of type startup (default: "")
+
 ;========================LOG_MAPPINGS SECTION OPTIONS===============================
 ;[log_mappings]
 ;  SYNOPSIS: Provides pjproject to Asterisk log level mappings.
 ;  NOTES: The name of this section in the pjproject.conf configuration file must
 ;         remain log_mappings or the configuration will not be applied.
 ;         The defaults mentioned below only apply if this file or the 'log_mappings'
-;         object can'tbe found.  If the object is found, there are no defaults. If
+;         object can't be found.  If the object is found, there are no defaults. If
 ;         you don't specify an entry, nothing will be logged for that level.
 ;
+; These logging level meanings are typically used by pjproject:
+;  - 0: fatal error
+;  - 1: error
+;  - 2: warning
+;  - 3: info
+;  - 4: debug
+;  - 5: trace
+;  - 6: more detailed trace
+;
 ;asterisk_error =    ; A comma separated list of pjproject log levels to map to
                      ; Asterisk errors.
                      ; (default: "0,1")
@@ -24,5 +45,5 @@
                      ; (default: "")
 ;asterisk_debug =    ; A comma separated list of pjproject log levels to map to
                      ; Asterisk debug
-                     ; (default: "3,4,5")
+                     ; (default: "3,4,5,6")
 ;type=               ; Must be of type log_mappings (default: "")
index c7821cc..523f765 100755 (executable)
--- a/configure
+++ b/configure
@@ -4938,7 +4938,7 @@ case "${host_os}" in
      OSARCH=cygwin
      PBX_WINARCH=1
      ;;
-     linux-gnueabi* |  linux-gnuspe)
+     linux-gnu*)
      OSARCH=linux-gnu
      ;;
      linux-musl*)
index 0f9b344..161ccab 100644 (file)
@@ -178,7 +178,7 @@ case "${host_os}" in
      OSARCH=cygwin
      PBX_WINARCH=1
      ;;
-     linux-gnueabi* |  linux-gnuspe)
+     linux-gnu*)
      OSARCH=linux-gnu
      ;;
      linux-musl*)
index 5c73c77..6f22027 100644 (file)
@@ -1993,6 +1993,21 @@ int ast_prod(struct ast_channel *chan);
 int ast_set_read_format_path(struct ast_channel *chan, struct ast_format *raw_format, struct ast_format *core_format);
 
 /*!
+ * \brief Set specific write path on channel.
+ * \since 13.13.0
+ *
+ * \param chan Channel to setup write path.
+ * \param core_format What the core wants to write.
+ * \param raw_format Raw write format.
+ *
+ * \pre chan is locked
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ */
+int ast_set_write_format_path(struct ast_channel *chan, struct ast_format *core_format, struct ast_format *raw_format);
+
+/*!
  * \brief Sets read format on channel chan from capabilities
  * Set read format for channel to whichever component of "format" is best.
  * \param chan channel to change
index a5ca038..b01592d 100644 (file)
@@ -299,6 +299,24 @@ void ast_format_set_attribute_data(struct ast_format *format, void *attribute_da
 const char *ast_format_get_name(const struct ast_format *format);
 
 /*!
+ * \brief Get the channel count on a format
+ *
+ * \param The media format
+ *
+ * \return Currently set channel count
+ */
+unsigned int ast_format_get_channel_count(const struct ast_format *format);
+
+/*!
+ * \brief Set the channel count on a format
+ *
+ * \param format The media format
+ * \param channel_count The number of audio channels used
+ *
+ */
+void ast_format_set_channel_count(struct ast_format *format, unsigned int channel_count);
+
+/*!
  * \brief Get the codec associated with a format
  *
  * \param format The media format
index 345bacf..ff35c16 100644 (file)
@@ -132,6 +132,20 @@ enum ast_option_flags {
 #define ast_opt_generic_plc         ast_test_flag(&ast_options, AST_OPT_FLAG_GENERIC_PLC)
 #define ast_opt_ref_debug           ast_test_flag(&ast_options, AST_OPT_FLAG_REF_DEBUG)
 
+/*! Maximum log level defined by PJPROJECT. */
+#define MAX_PJ_LOG_MAX_LEVEL           6
+/*!
+ * Normal PJPROJECT active log level used by Asterisk.
+ *
+ * These levels are usually mapped to Error and
+ * Warning Asterisk log levels which shouldn't
+ * normally be suppressed.
+ */
+#define DEFAULT_PJ_LOG_MAX_LEVEL       2
+
+/*! Current pjproject logging level */
+extern int ast_option_pjproject_log_level;
+
 extern struct ast_flags ast_options;
 
 extern int option_verbose;
index 2378c69..423d73b 100644 (file)
@@ -1126,4 +1126,13 @@ int ast_file_is_readable(const char *filename);
  */
 int ast_compare_versions(const char *version1, const char *version2);
 
+/*
+ * \brief Test that an OS supports IPv6 Networking.
+ * \since 13.14.0
+ *
+ * \return True (non-zero) if the IPv6 supported.
+ * \return False (zero) if the OS doesn't support IPv6.
+ */
+int ast_check_ipv6(void);
+
 #endif /* _ASTERISK_UTILS_H */
index 4a6567f..338c1f5 100644 (file)
@@ -330,6 +330,7 @@ int ast_verb_sys_level;
 
 int option_verbose;                            /*!< Verbosity level */
 int option_debug;                              /*!< Debug level */
+int ast_option_pjproject_log_level;
 double ast_option_maxload;                     /*!< Max load avg on system */
 int ast_option_maxcalls;                       /*!< Max number of active calls */
 int ast_option_maxfiles;                       /*!< Max number of open file handles (files, sockets) */
@@ -1669,7 +1670,6 @@ static void _urg_handler(int num)
 
 static struct sigaction urg_handler = {
        .sa_handler = _urg_handler,
-       .sa_flags = SA_RESTART,
 };
 
 static void _hup_handler(int num)
@@ -3758,6 +3758,37 @@ static void ast_readconfig(void)
        ast_config_destroy(cfg);
 }
 
+static void read_pjproject_startup_options(void)
+{
+       struct ast_config *cfg;
+       struct ast_variable *v;
+       struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE | CONFIG_FLAG_NOREALTIME };
+
+       ast_option_pjproject_log_level = DEFAULT_PJ_LOG_MAX_LEVEL;
+
+       cfg = ast_config_load2("pjproject.conf", "" /* core, can't reload */, config_flags);
+       if (!cfg
+               || cfg == CONFIG_STATUS_FILEUNCHANGED
+               || cfg == CONFIG_STATUS_FILEINVALID) {
+               /* We'll have to use defaults */
+               return;
+       }
+
+       for (v = ast_variable_browse(cfg, "startup"); v; v = v->next) {
+               if (!strcasecmp(v->name, "log_level")) {
+                       if (sscanf(v->value, "%30d", &ast_option_pjproject_log_level) != 1) {
+                               ast_option_pjproject_log_level = DEFAULT_PJ_LOG_MAX_LEVEL;
+                       } else if (ast_option_pjproject_log_level < 0) {
+                               ast_option_pjproject_log_level = 0;
+                       } else if (MAX_PJ_LOG_MAX_LEVEL < ast_option_pjproject_log_level) {
+                               ast_option_pjproject_log_level = MAX_PJ_LOG_MAX_LEVEL;
+                       }
+               }
+       }
+
+       ast_config_destroy(cfg);
+}
+
 static void *monitor_sig_flags(void *unused)
 {
        for (;;) {
@@ -4514,6 +4545,7 @@ static void asterisk_daemon(int isroot, const char *runuser, const char *rungrou
 
        check_init(ast_timing_init(), "Timing");
        check_init(ast_ssl_init(), "SSL");
+       read_pjproject_startup_options();
        check_init(ast_pj_init(), "Embedded PJProject");
        check_init(app_init(), "App Core");
        check_init(devstate_init(), "Device State Core");
index bd5f351..00cfa31 100644 (file)
@@ -1070,16 +1070,15 @@ void ast_channel_start_defer_frames(struct ast_channel *chan, int defer_hangups)
 
 void ast_channel_stop_defer_frames(struct ast_channel *chan)
 {
+       struct ast_frame *f;
+
        ast_clear_flag(ast_channel_flags(chan), AST_FLAG_DEFER_FRAMES);
 
        /* Move the deferred frames onto the channel read queue, ahead of other queued frames */
-       ast_queue_frame_head(chan, AST_LIST_FIRST(ast_channel_deferred_readq(chan)));
-       /* ast_frfree will mosey down the list and free them all */
-       if (!AST_LIST_EMPTY(ast_channel_deferred_readq(chan))) {
-               ast_frfree(AST_LIST_FIRST(ast_channel_deferred_readq(chan)));
+       while ((f = AST_LIST_REMOVE_HEAD(ast_channel_deferred_readq(chan), frame_list))) {
+               ast_queue_frame_head(chan, f);
+               ast_frfree(f);
        }
-       /* Reset the list to be empty */
-       AST_LIST_HEAD_INIT_NOLOCK(ast_channel_deferred_readq(chan));
 }
 
 static int __ast_queue_frame(struct ast_channel *chan, struct ast_frame *fin, int head, struct ast_frame *after)
@@ -3901,10 +3900,10 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio)
                                                        struct ast_frame *dup;
 
                                                        dup = ast_frdup(f);
-                                                       AST_LIST_INSERT_TAIL(ast_channel_deferred_readq(chan), dup, frame_list);
+                                                       AST_LIST_INSERT_HEAD(ast_channel_deferred_readq(chan), dup, frame_list);
                                                }
                                        } else {
-                                               AST_LIST_INSERT_TAIL(ast_channel_deferred_readq(chan), f, frame_list);
+                                               AST_LIST_INSERT_HEAD(ast_channel_deferred_readq(chan), f, frame_list);
                                                AST_LIST_REMOVE_CURRENT(frame_list);
                                        }
                                }
@@ -5474,6 +5473,42 @@ int ast_set_read_format_path(struct ast_channel *chan, struct ast_format *raw_fo
        return 0;
 }
 
+int ast_set_write_format_path(struct ast_channel *chan, struct ast_format *core_format, struct ast_format *raw_format)
+{
+       struct ast_trans_pvt *trans_old;
+       struct ast_trans_pvt *trans_new;
+
+       if (ast_format_cmp(ast_channel_rawwriteformat(chan), raw_format) == AST_FORMAT_CMP_EQUAL
+               && ast_format_cmp(ast_channel_writeformat(chan), core_format) == AST_FORMAT_CMP_EQUAL) {
+               /* Nothing to setup */
+               return 0;
+       }
+
+       ast_debug(1, "Channel %s setting write format path: %s -> %s\n",
+               ast_channel_name(chan),
+               ast_format_get_name(core_format),
+               ast_format_get_name(raw_format));
+
+       /* Setup new translation path. */
+       if (ast_format_cmp(raw_format, core_format) != AST_FORMAT_CMP_EQUAL) {
+               trans_new = ast_translator_build_path(raw_format, core_format);
+               if (!trans_new) {
+                       return -1;
+               }
+       } else {
+               /* No translation needed. */
+               trans_new = NULL;
+       }
+       trans_old = ast_channel_writetrans(chan);
+       if (trans_old) {
+               ast_translator_free_path(trans_old);
+       }
+       ast_channel_writetrans_set(chan, trans_new);
+       ast_channel_set_rawwriteformat(chan, raw_format);
+       ast_channel_set_writeformat(chan, core_format);
+       return 0;
+}
+
 struct set_format_access {
        const char *direction;
        struct ast_trans_pvt *(*get_trans)(const struct ast_channel *chan);
index b5e5779..5ae5ad9 100644 (file)
@@ -49,6 +49,8 @@ struct ast_format {
        void *attribute_data;
        /*! \brief Pointer to the optional format interface */
        const struct ast_format_interface *interface;
+       /*! \brief The number if audio channels used, if more than one an interleaved format is required */
+       unsigned int channel_count;
 };
 
 /*! \brief Structure used when registering a format interface */
@@ -175,6 +177,16 @@ void ast_format_set_attribute_data(struct ast_format *format, void *attribute_da
        format->attribute_data = attribute_data;
 }
 
+unsigned int ast_format_get_channel_count(const struct ast_format *format)
+{
+       return format->channel_count;
+}
+
+void ast_format_set_channel_count(struct ast_format *format, unsigned int channel_count)
+{
+       format->channel_count = channel_count;
+}
+
 /*! \brief Destructor for media formats */
 static void format_destroy(void *obj)
 {
@@ -199,6 +211,7 @@ struct ast_format *ast_format_create_named(const char *format_name, struct ast_c
        }
        format->name = format_name;
        format->codec = ao2_bump(codec);
+       format->channel_count = 1;
 
        format_interface = ao2_find(interfaces, codec->name, OBJ_SEARCH_KEY);
        if (format_interface) {
index 46abc18..a20a048 100644 (file)
  * at the top of the source tree.
  */
 
+#include "asterisk.h"
+
 #include <fcntl.h>
 #include <stdarg.h>
 
-#include "asterisk.h"
 #include "asterisk/utils.h"
 #include "asterisk/astobj2.h"
 #include "asterisk/iostream.h"
@@ -461,9 +462,19 @@ int ast_iostream_close(struct ast_iostream *stream)
                                        SSL_get_error(stream->ssl, res));
                        }
 
+#if defined(OPENSSL_API_COMPAT) && OPENSSL_API_COMPAT >= 0x10100000L
+                       if (!SSL_is_server(stream->ssl)) {
+#else
                        if (!stream->ssl->server) {
+#endif
                                /* For client threads, ensure that the error stack is cleared */
+#if !defined(OPENSSL_API_COMPAT) || OPENSSL_API_COMPAT < 0x10100000L
+#if OPENSSL_VERSION_NUMBER >= 0x10000000L
+                               ERR_remove_thread_state(NULL);
+#else
                                ERR_remove_state(0);
+#endif /* OPENSSL_VERSION_NUMBER >= 0x10000000L */
+#endif  /* !defined(OPENSSL_API_COMPAT) || OPENSSL_API_COMPAT < 0x10100000L */
                        }
 
                        SSL_free(stream->ssl);
index 22660e6..0f893a2 100644 (file)
@@ -35,6 +35,7 @@
 #include <pjlib.h>
 #endif
 
+#include "asterisk/options.h"
 #include "asterisk/_private.h" /* ast_pj_init() */
 
 /*!
@@ -44,6 +45,7 @@
 int ast_pj_init(void)
 {
 #ifdef HAVE_PJPROJECT_BUNDLED
+       pj_log_set_level(ast_option_pjproject_log_level);
        pj_init();
 #endif
        return 0;
index 16a1aa7..9905b15 100644 (file)
@@ -65,13 +65,14 @@ static void ssl_lock(int mode, int n, const char *file, int line)
                return;
        }
 
-       if (mode & CRYPTO_LOCK) {
+       if (mode & 0x1) {
                ast_mutex_lock(&ssl_locks[n]);
        } else {
                ast_mutex_unlock(&ssl_locks[n]);
        }
 }
 
+#if !defined(OPENSSL_API_COMPAT) || OPENSSL_API_COMPAT < 0x10100000L
 int SSL_library_init(void)
 {
 #if defined(AST_DEVMODE)
@@ -113,6 +114,7 @@ void ERR_free_strings(void)
 {
        /* we can't allow this to be called, ever */
 }
+#endif /* !defined(OPENSSL_API_COMPAT) || OPENSSL_API_COMPAT < 0x10100000L */
 
 #endif /* HAVE_OPENSSL */
 
index 4fc1414..3ef2d87 100644 (file)
@@ -2493,7 +2493,7 @@ static struct ast_manager_event_blob *rtcp_report_to_ami(struct stasis_message *
        if (type == AST_RTP_RTCP_SR) {
                ast_str_append(&packet_string, 0, "SentNTP: %lu.%06lu\r\n",
                        (unsigned long)payload->report->sender_information.ntp_timestamp.tv_sec,
-                       (unsigned long)payload->report->sender_information.ntp_timestamp.tv_usec * 4096);
+                       (unsigned long)payload->report->sender_information.ntp_timestamp.tv_usec);
                ast_str_append(&packet_string, 0, "SentRTP: %u\r\n",
                                payload->report->sender_information.rtp_timestamp);
                ast_str_append(&packet_string, 0, "SentPackets: %u\r\n",
index fce1558..b20e04e 100644 (file)
@@ -312,7 +312,7 @@ static int __ssl_setup(struct ast_tls_config *cfg, int client)
        }
 
        if (client) {
-#ifndef OPENSSL_NO_SSL2
+#if !defined(OPENSSL_NO_SSL2) && (OPENSSL_VERSION_NUMBER < 0x10100000L)
                if (ast_test_flag(&cfg->flags, AST_SSL_SSLV2_CLIENT)) {
                        ast_log(LOG_WARNING, "Usage of SSLv2 is discouraged due to known vulnerabilities. Please use 'tlsv1' or leave the TLS method unspecified!\n");
                        cfg->ssl_ctx = SSL_CTX_new(SSLv2_client_method());
index 2c56af3..2033664 100644 (file)
@@ -2391,6 +2391,18 @@ char *ast_utils_which(const char *binary, char *fullpath, size_t fullpath_size)
        return NULL;
 }
 
+int ast_check_ipv6(void)
+{
+       int udp6_socket = socket(AF_INET6, SOCK_DGRAM, 0);
+
+       if (udp6_socket < 0) {
+               return 0;
+       }
+
+       close(udp6_socket);
+       return 1;
+}
+
 void DO_CRASH_NORETURN ast_do_crash(void)
 {
 #if defined(DO_CRASH)
index 01f468d..0754990 100644 (file)
@@ -60,7 +60,7 @@ static char *registrar = "pbx_lua";
  * applications might return */
 #define LUA_GOTO_DETECTED 5
 
-static char *lua_read_extensions_file(lua_State *L, long *size);
+static char *lua_read_extensions_file(lua_State *L, long *size, int *file_not_openable);
 static int lua_load_extensions(lua_State *L, struct ast_channel *chan);
 static int lua_reload_extensions(lua_State *L);
 static void lua_free_extensions(void);
@@ -1070,12 +1070,13 @@ static int lua_extension_cmp(lua_State *L)
  *
  * \param L the lua_State to use
  * \param size a pointer to store the size of the buffer
+ * \param file_not_openable a pointer to store if config file could be opened
  *
  * \note The caller is expected to free the buffer at some point.
  *
  * \return a pointer to the buffer
  */
-static char *lua_read_extensions_file(lua_State *L, long *size)
+static char *lua_read_extensions_file(lua_State *L, long *size, int *file_not_openable)
 {
        FILE *f;
        int error_func;
@@ -1090,6 +1091,8 @@ static char *lua_read_extensions_file(lua_State *L, long *size)
                lua_pushstring(L, strerror(errno));
                lua_concat(L, 4);
 
+               *file_not_openable = 1;
+
                return NULL;
        }
 
@@ -1199,10 +1202,14 @@ static int lua_reload_extensions(lua_State *L)
 {
        long size = 0;
        char *data = NULL;
+       int file_not_openable = 0;
 
        luaL_openlibs(L);
 
-       if (!(data = lua_read_extensions_file(L, &size))) {
+       if (!(data = lua_read_extensions_file(L, &size, &file_not_openable))) {
+               if (file_not_openable) {
+                       return -1;
+               }
                return 1;
        }
 
@@ -1621,17 +1628,24 @@ static struct ast_switch lua_switch = {
 static int load_or_reload_lua_stuff(void)
 {
        int res = AST_MODULE_LOAD_SUCCESS;
+       int loaded = 0;
 
        lua_State *L = luaL_newstate();
        if (!L) {
                ast_log(LOG_ERROR, "Error allocating lua_State, no memory\n");
-               return AST_MODULE_LOAD_DECLINE;
+               return AST_MODULE_LOAD_FAILURE;
        }
 
-       if (lua_reload_extensions(L)) {
+       loaded = lua_reload_extensions(L);
+       if (loaded) {
                const char *error = lua_tostring(L, -1);
                ast_log(LOG_ERROR, "Error loading extensions.lua: %s\n", error);
-               res = AST_MODULE_LOAD_DECLINE;
+
+               if (loaded < 0) {
+                       res = AST_MODULE_LOAD_DECLINE;
+               } else {
+                       res = AST_MODULE_LOAD_FAILURE;
+               }
        }
 
        if (!res) {
@@ -1664,7 +1678,7 @@ static int load_module(void)
 
        if (ast_register_switch(&lua_switch)) {
                ast_log(LOG_ERROR, "Unable to register LUA PBX switch\n");
-               return AST_MODULE_LOAD_DECLINE;
+               return AST_MODULE_LOAD_FAILURE;
        }
 
        return AST_MODULE_LOAD_SUCCESS;
index 1165037..8a603cf 100644 (file)
@@ -480,7 +480,7 @@ static void handle_start_element(void *data, const xmlChar *fullname, const xmlC
 {
        struct xmlstate *state = data;
 
-       if (!xmlStrcasecmp(fullname, BAD_CAST "C:calendar-data")) {
+       if (!xmlStrcasecmp(fullname, BAD_CAST "C:calendar-data") || !xmlStrcasecmp(fullname, BAD_CAST "caldav:calendar-data")) {
                state->in_caldata = 1;
                ast_str_reset(state->cdata);
        }
@@ -494,7 +494,7 @@ static void handle_end_element(void *data, const xmlChar *name)
        icalcomponent *iter;
        icalcomponent *comp;
 
-       if (xmlStrcasecmp(name, BAD_CAST "C:calendar-data")) {
+       if (xmlStrcasecmp(name, BAD_CAST "C:calendar-data") && xmlStrcasecmp(name, BAD_CAST "caldav:calendar-data")) {
                return;
        }
 
index 81a07a1..45aa5e5 100644 (file)
@@ -94,6 +94,7 @@ static int opus_clone(const struct ast_format *src, struct ast_format *dst)
        ao2_bump(attr->data);
 
        ast_format_set_attribute_data(dst, attr);
+       ast_format_set_channel_count(dst, ast_format_get_channel_count(src));
 
        return 0;
 }
@@ -145,6 +146,9 @@ static struct ast_format *opus_parse_sdp_fmtp(const struct ast_format *format, c
        sdp_fmtp_get(attributes, CODEC_OPUS_ATTR_PTIME, &attr->ptime);
        sdp_fmtp_get(attributes, CODEC_OPUS_ATTR_MAX_AVERAGE_BITRATE, &attr->maxbitrate);
        sdp_fmtp_get(attributes, CODEC_OPUS_ATTR_STEREO, &attr->stereo);
+       if (attr->stereo) {
+               ast_format_set_channel_count(cloned, 2);
+       }
        sdp_fmtp_get(attributes, CODEC_OPUS_ATTR_SPROP_STEREO, &attr->spropstereo);
        sdp_fmtp_get(attributes, CODEC_OPUS_ATTR_CBR, &attr->cbr);
        sdp_fmtp_get(attributes, CODEC_OPUS_ATTR_FEC, &attr->fec);
@@ -238,6 +242,10 @@ static struct ast_format *opus_getjoint(const struct ast_format *format1, const
        if (!jointformat) {
                return NULL;
        }
+
+       if (ast_format_get_channel_count(format1) == 2 || ast_format_get_channel_count(format2) == 2) {
+               ast_format_set_channel_count(jointformat, 2);
+       }
        attr_res = ast_format_get_attribute_data(jointformat);
 
        attr_res->dtx = attr1->dtx || attr2->dtx ? 1 : 0;
index 66c95f2..476defb 100644 (file)
        <configInfo name="res_pjproject" language="en_US">
                <synopsis>pjproject common configuration</synopsis>
                <configFile name="pjproject.conf">
+                       <configObject name="startup">
+                               <synopsis>Asterisk startup time options for PJPROJECT</synopsis>
+                               <description>
+                                       <note><para>The id of this object, as well as its type, must be
+                                       'startup' or it won't be found.</para></note>
+                               </description>
+                               <configOption name="type">
+                                       <synopsis>Must be of type 'startup'.</synopsis>
+                               </configOption>
+                               <configOption name="log_level" default="2">
+                                       <synopsis>Initial maximum pjproject logging level to log.</synopsis>
+                                       <description>
+                                               <para>Valid values are: 0-6, and default</para>
+                                       <note><para>
+                                               This option is needed very early in the startup process
+                                               so it can only be read from config files because the
+                                               modules for other methods have not been loaded yet.
+                                       </para></note>
+                                       </description>
+                               </configOption>
+                       </configObject>
                        <configObject name="log_mappings">
                                <synopsis>PJPROJECT to Asterisk Log Level Mapping</synopsis>
                                <description><para>Warnings and errors in the pjproject libraries are generally handled
@@ -64,7 +85,7 @@
                                <configOption name="asterisk_notice" default="">
                                        <synopsis>A comma separated list of pjproject log levels to map to Asterisk LOG_NOTICE.</synopsis>
                                </configOption>
-                               <configOption name="asterisk_debug" default="3,4,5">
+                               <configOption name="asterisk_debug" default="3,4,5,6">
                                        <synopsis>A comma separated list of pjproject log levels to map to Asterisk LOG_DEBUG.</synopsis>
                                </configOption>
                                <configOption name="asterisk_verbose" default="">
 #include <pjsip.h>
 #include <pj/log.h>
 
+#include "asterisk/options.h"
 #include "asterisk/logger.h"
 #include "asterisk/module.h"
 #include "asterisk/cli.h"
@@ -144,9 +166,11 @@ static struct log_mappings *get_log_mappings(void)
 
 static int get_log_level(int pj_level)
 {
-       RAII_VAR(struct log_mappings *, mappings, get_log_mappings(), ao2_cleanup);
+       int mapped_level;
        unsigned char l;
+       struct log_mappings *mappings;
 
+       mappings = get_log_mappings();
        if (!mappings) {
                return __LOG_ERROR;
        }
@@ -154,18 +178,21 @@ static int get_log_level(int pj_level)
        l = '0' + fmin(pj_level, 9);
 
        if (strchr(mappings->asterisk_error, l)) {
-               return __LOG_ERROR;
+               mapped_level = __LOG_ERROR;
        } else if (strchr(mappings->asterisk_warning, l)) {
-               return __LOG_WARNING;
+               mapped_level = __LOG_WARNING;
        } else if (strchr(mappings->asterisk_notice, l)) {
-               return __LOG_NOTICE;
+               mapped_level = __LOG_NOTICE;
        } else if (strchr(mappings->asterisk_verbose, l)) {
-               return __LOG_VERBOSE;
+               mapped_level = __LOG_VERBOSE;
        } else if (strchr(mappings->asterisk_debug, l)) {
-               return __LOG_DEBUG;
+               mapped_level = __LOG_DEBUG;
+       } else {
+               mapped_level = __LOG_SUPPRESS;
        }
 
-       return __LOG_SUPPRESS;
+       ao2_ref(mappings, -1);
+       return mapped_level;
 }
 
 static void log_forwarder(int level, const char *data, int len)
@@ -192,13 +219,6 @@ static void log_forwarder(int level, const char *data, int len)
                return;
        }
 
-       if (ast_level == __LOG_DEBUG) {
-               /* Obey the debug level for res_pjproject */
-               if (!DEBUG_ATLEAST(level)) {
-                       return;
-               }
-       }
-
        /* PJPROJECT uses indention to indicate function call depth. We'll prepend
         * log statements with a tab so they'll have a better shot at lining
         * up */
@@ -349,9 +369,95 @@ static char *handle_pjproject_show_log_mappings(struct ast_cli_entry *e, int cmd
        return CLI_SUCCESS;
 }
 
+struct max_pjproject_log_level_check {
+       /*!
+        * Compile time sanity check to determine if
+        * MAX_PJ_LOG_MAX_LEVEL matches CLI syntax.
+        */
+       char check[1 / (6 == MAX_PJ_LOG_MAX_LEVEL)];
+};
+
+static char *handle_pjproject_set_log_level(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+       int level_new;
+       int level_old;
+
+       switch (cmd) {
+       case CLI_INIT:
+               e->command = "pjproject set log level {default|0|1|2|3|4|5|6}";
+               e->usage =
+                       "Usage: pjproject set log level {default|<level>}\n"
+                       "\n"
+                       "       Set the maximum active pjproject logging level.\n"
+                       "       See pjproject.conf.sample for additional information\n"
+                       "       about the various levels pjproject uses.\n";
+               return NULL;
+       case CLI_GENERATE:
+               return NULL;
+       }
+
+       if (a->argc != 5) {
+               return CLI_SHOWUSAGE;
+       }
+
+       if (!strcasecmp(a->argv[4], "default")) {
+               level_new = DEFAULT_PJ_LOG_MAX_LEVEL;
+       } else {
+               if (sscanf(a->argv[4], "%30d", &level_new) != 1
+                       || level_new < 0 || MAX_PJ_LOG_MAX_LEVEL < level_new) {
+                       return CLI_SHOWUSAGE;
+               }
+       }
+
+       /* Update pjproject logging level */
+       level_old = ast_option_pjproject_log_level;
+       if (level_old == level_new) {
+               ast_cli(a->fd, "pjproject log level is still %d.\n", level_old);
+       } else {
+               ast_cli(a->fd, "pjproject log level was %d and is now %d.\n",
+                       level_old, level_new);
+               pj_log_set_level(level_new);
+       }
+       ast_option_pjproject_log_level = pj_log_get_level();
+       if (ast_option_pjproject_log_level != level_new) {
+               ast_log(LOG_WARNING, "Asterisk built with pjproject PJ_LOG_MAX_LEVEL set too low.\n");
+       }
+
+       return CLI_SUCCESS;
+}
+
+static char *handle_pjproject_show_log_level(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+       switch (cmd) {
+       case CLI_INIT:
+               e->command = "pjproject show log level";
+               e->usage =
+                       "Usage: pjproject show log level\n"
+                       "\n"
+                       "       Show the current maximum active pjproject logging level.\n"
+                       "       See pjproject.conf.sample for additional information\n"
+                       "       about the various levels pjproject uses.\n";
+               return NULL;
+       case CLI_GENERATE:
+               return NULL;
+       }
+
+       if (a->argc != 4) {
+               return CLI_SHOWUSAGE;
+       }
+
+       ast_cli(a->fd, "pjproject log level is %d.%s\n",
+               ast_option_pjproject_log_level,
+               ast_option_pjproject_log_level == DEFAULT_PJ_LOG_MAX_LEVEL ? " (default)" : "");
+
+       return CLI_SUCCESS;
+}
+
 static struct ast_cli_entry pjproject_cli[] = {
+       AST_CLI_DEFINE(handle_pjproject_set_log_level, "Set the maximum active pjproject logging level"),
        AST_CLI_DEFINE(handle_pjproject_show_buildopts, "Show the compiled config of the pjproject in use"),
        AST_CLI_DEFINE(handle_pjproject_show_log_mappings, "Show pjproject to Asterisk log mappings"),
+       AST_CLI_DEFINE(handle_pjproject_show_log_level, "Show the maximum active pjproject logging level"),
 };
 
 static int load_module(void)
@@ -385,10 +491,11 @@ static int load_module(void)
        }
        ast_string_field_set(default_log_mappings, asterisk_error, "0,1");
        ast_string_field_set(default_log_mappings, asterisk_warning, "2");
-       ast_string_field_set(default_log_mappings, asterisk_debug, "3,4,5");
+       ast_string_field_set(default_log_mappings, asterisk_debug, "3,4,5,6");
 
        ast_sorcery_load(pjproject_sorcery);
 
+       pj_log_set_level(ast_option_pjproject_log_level);
        pj_init();
 
        decor_orig = pj_log_get_decor();
@@ -403,9 +510,15 @@ static int load_module(void)
         */
        pj_log_set_log_func(capture_buildopts_cb);
        pj_log_set_decor(0);
+       pj_log_set_level(MAX_PJ_LOG_MAX_LEVEL);/* Set level to guarantee the dump output. */
        pj_dump_config();
+       pj_log_set_level(ast_option_pjproject_log_level);
        pj_log_set_decor(PJ_LOG_HAS_SENDER | PJ_LOG_HAS_INDENT);
        pj_log_set_log_func(log_forwarder);
+       if (!AST_VECTOR_SIZE(&buildopts)
+               || ast_option_pjproject_log_level != pj_log_get_level()) {
+               ast_log(LOG_WARNING, "Asterisk built or linked with pjproject PJ_LOG_MAX_LEVEL set too low.\n");
+       }
 
        ast_cli_register_multiple(pjproject_cli, ARRAY_LEN(pjproject_cli));
 
index 98530cb..8c2d371 100644 (file)
                                                On outbound requests, force the user portion of the Contact header to this value.
                                        </para></description>
                                </configOption>
-                                <configOption name="asymmetric_rtp_codec" default="no">
-                                        <synopsis>Allow the sending and receiving RTP codec to differ</synopsis>
-                                        <description><para>
-                                                When set to "yes" the codec in use for sending will be allowed to differ from
-                                                that of the received one. PJSIP will not automatically switch the sending one
-                                                to the receiving one.
-                                        </para></description>
-                                </configOption>
+                               <configOption name="asymmetric_rtp_codec" default="no">
+                                       <synopsis>Allow the sending and receiving RTP codec to differ</synopsis>
+                                       <description><para>
+                                               When set to "yes" the codec in use for sending will be allowed to differ from
+                                               that of the received one. PJSIP will not automatically switch the sending one
+                                               to the receiving one.
+                                       </para></description>
+                               </configOption>
                        </configObject>
                        <configObject name="auth">
                                <synopsis>Authentication type</synopsis>
index 7fd4f9a..4d6a1a1 100644 (file)
@@ -38,6 +38,7 @@
 #include <pjmedia.h>
 #include <pjlib.h>
 
+#include "asterisk/utils.h"
 #include "asterisk/module.h"
 #include "asterisk/format.h"
 #include "asterisk/format_cap.h"
@@ -1514,7 +1515,11 @@ static int load_module(void)
 {
        CHECK_PJSIP_SESSION_MODULE_LOADED();
 
-       ast_sockaddr_parse(&address_rtp, "::", 0);
+       if (ast_check_ipv6()) {
+               ast_sockaddr_parse(&address_rtp, "::", 0);
+       } else {
+               ast_sockaddr_parse(&address_rtp, "0.0.0.0", 0);
+       }
 
        if (!(sched = ast_sched_context_create())) {
                ast_log(LOG_ERROR, "Unable to create scheduler context.\n");
index adc99c3..79dc9c3 100644 (file)
@@ -37,6 +37,7 @@
 #include <pjmedia.h>
 #include <pjlib.h>
 
+#include "asterisk/utils.h"
 #include "asterisk/module.h"
 #include "asterisk/udptl.h"
 #include "asterisk/netsock2.h"
@@ -916,7 +917,11 @@ static int load_module(void)
 {
        CHECK_PJSIP_SESSION_MODULE_LOADED();
 
-       ast_sockaddr_parse(&address, "::", 0);
+       if (ast_check_ipv6()) {
+               ast_sockaddr_parse(&address, "::", 0);
+       } else {
+               ast_sockaddr_parse(&address, "0.0.0.0", 0);
+       }
 
        if (ast_sip_session_register_supplement(&t38_supplement)) {
                ast_log(LOG_ERROR, "Unable to register T.38 session supplement\n");
index a882033..58c217e 100644 (file)
@@ -52,6 +52,7 @@
 #include <ifaddrs.h>
 #endif
 
+#include "asterisk/options.h"
 #include "asterisk/stun.h"
 #include "asterisk/pbx.h"
 #include "asterisk/frame.h"
@@ -3084,7 +3085,26 @@ static void timeval2ntp(struct timeval tv, unsigned int *msw, unsigned int *lsw)
        unsigned int sec, usec, frac;
        sec = tv.tv_sec + 2208988800u; /* Sec between 1900 and 1970 */
        usec = tv.tv_usec;
-       frac = (usec << 12) + (usec << 8) - ((usec * 3650) >> 6);
+       /*
+        * Convert usec to 0.32 bit fixed point without overflow.
+        *
+        * = usec * 2^32 / 10^6
+        * = usec * 2^32 / (2^6 * 5^6)
+        * = usec * 2^26 / 5^6
+        *
+        * The usec value needs 20 bits to represent 999999 usec.  So
+        * splitting the 2^26 to get the most precision using 32 bit
+        * values gives:
+        *
+        * = ((usec * 2^12) / 5^6) * 2^14
+        *
+        * Splitting the division into two stages preserves all the
+        * available significant bits of usec over doing the division
+        * all at once.
+        *
+        * = ((((usec * 2^12) / 5^3) * 2^7) / 5^3) * 2^7
+        */
+       frac = ((((usec << 12) / 125) << 7) / 125) << 7;
        *msw = sec;
        *lsw = frac;
 }
@@ -3092,7 +3112,8 @@ static void timeval2ntp(struct timeval tv, unsigned int *msw, unsigned int *lsw)
 static void ntp2timeval(unsigned int msw, unsigned int lsw, struct timeval *tv)
 {
        tv->tv_sec = msw - 2208988800u;
-       tv->tv_usec = ((lsw << 6) / 3650) - (lsw >> 12) - (lsw >> 8);
+       /* Reverse the sequence in timeval2ntp() */
+       tv->tv_usec = ((((lsw >> 7) * 125) >> 7) * 125) >> 12;
 }
 
 static void calculate_lost_packet_statistics(struct ast_rtp *rtp,
@@ -3277,9 +3298,9 @@ static int ast_rtcp_write_report(struct ast_rtp_instance *instance, int sr)
                                ast_sockaddr_stringify(&remote_address), ice ? " (via ICE)" : "");
                ast_verbose("  Our SSRC: %u\n", rtcp_report->ssrc);
                if (sr) {
-                       ast_verbose("  Sent(NTP): %u.%010u\n",
+                       ast_verbose("  Sent(NTP): %u.%06u\n",
                                (unsigned int)rtcp_report->sender_information.ntp_timestamp.tv_sec,
-                               (unsigned int)rtcp_report->sender_information.ntp_timestamp.tv_usec * 4096);
+                               (unsigned int)rtcp_report->sender_information.ntp_timestamp.tv_usec);
                        ast_verbose("  Sent(RTP): %u\n", rtcp_report->sender_information.rtp_timestamp);
                        ast_verbose("  Sent packets: %u\n", rtcp_report->sender_information.packet_count);
                        ast_verbose("  Sent octets: %u\n", rtcp_report->sender_information.octet_count);
@@ -4016,9 +4037,22 @@ static int update_rtt_stats(struct ast_rtp *rtp, unsigned int lsr, unsigned int
        lsr_a = ((msw & 0x0000ffff) << 16) | ((lsw & 0xffff0000) >> 16);
        rtt = lsr_a - lsr - dlsr;
        rtt_msw = (rtt & 0xffff0000) >> 16;
-       rtt_lsw = (rtt & 0x0000ffff) << 16;
+       rtt_lsw = (rtt & 0x0000ffff);
        rtt_tv.tv_sec = rtt_msw;
-       rtt_tv.tv_usec = ((rtt_lsw << 6) / 3650) - (rtt_lsw >> 12) - (rtt_lsw >> 8);
+       /*
+        * Convert 16.16 fixed point rtt_lsw to usec without
+        * overflow.
+        *
+        * = rtt_lsw * 10^6 / 2^16
+        * = rtt_lsw * (2^6 * 5^6) / 2^16
+        * = rtt_lsw * 5^6 / 2^10
+        *
+        * The rtt_lsw value is in 16.16 fixed point format and 5^6
+        * requires 14 bits to represent.  We have enough space to
+        * directly do the conversion because there is no integer
+        * component in rtt_lsw.
+        */
+       rtt_tv.tv_usec = (rtt_lsw * 15625) >> 10;
        rtp->rtcp->rtt = (double)rtt_tv.tv_sec + ((double)rtt_tv.tv_usec / 1000000);
        if (lsr_a - dlsr < lsr) {
                return 1;
@@ -4214,9 +4248,9 @@ static struct ast_frame *ast_rtcp_read(struct ast_rtp_instance *instance)
                                        &rtcp_report->sender_information.ntp_timestamp);
                        rtcp_report->sender_information.rtp_timestamp = ntohl(rtcpheader[i + 2]);
                        if (rtcp_debug_test_addr(&addr)) {
-                               ast_verbose("NTP timestamp: %u.%010u\n",
+                               ast_verbose("NTP timestamp: %u.%06u\n",
                                                (unsigned int)rtcp_report->sender_information.ntp_timestamp.tv_sec,
-                                               (unsigned int)rtcp_report->sender_information.ntp_timestamp.tv_usec * 4096);
+                                               (unsigned int)rtcp_report->sender_information.ntp_timestamp.tv_usec);
                                ast_verbose("RTP timestamp: %u\n", rtcp_report->sender_information.rtp_timestamp);
                                ast_verbose("SPC: %u\tSOC: %u\n",
                                                rtcp_report->sender_information.packet_count,
@@ -5632,6 +5666,7 @@ static int load_module(void)
 #ifdef HAVE_PJPROJECT
        pj_lock_t *lock;
 
+       pj_log_set_level(ast_option_pjproject_log_level);
        if (pj_init() != PJ_SUCCESS) {
                return AST_MODULE_LOAD_DECLINE;
        }
index 1a48695..66e8e84 100644 (file)
@@ -34,7 +34,7 @@
 
 #define PJ_SCANNER_USE_BITWISE 0
 #define PJ_OS_HAS_CHECK_STACK  0
-#define PJ_LOG_MAX_LEVEL               3
+#define PJ_LOG_MAX_LEVEL               6
 #define PJ_ENABLE_EXTRA_CHECK  1
 #define PJSIP_MAX_TSX_COUNT            ((64*1024)-1)
 #define PJSIP_MAX_DIALOG_COUNT ((64*1024)-1)