Merge "rtp_engine: allocate RTP dynamic payloads per session"
authorzuul <zuul@gerrit.asterisk.org>
Fri, 24 Mar 2017 21:22:55 +0000 (16:22 -0500)
committerGerrit Code Review <gerrit2@gerrit.digium.api>
Fri, 24 Mar 2017 21:22:55 +0000 (16:22 -0500)
13 files changed:
CHANGES
configs/samples/pjsip.conf.sample
contrib/ast-db-manage/config/versions/8fce4c573e15_add_pjsip_allow_overlap.py [new file with mode: 0644]
funcs/func_channel.c
include/asterisk/manager.h
include/asterisk/res_pjsip.h
main/audiohook.c
makeopts.in
res/res_pjsip.c
res/res_pjsip/pjsip_configuration.c
res/res_pjsip_session.c
res/res_xmpp.c
third-party/pjproject/Makefile

diff --git a/CHANGES b/CHANGES
index 00f318b..5d14c97 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -123,6 +123,13 @@ app_voicemail
  * Added 'fromstring' field to the voicemail boxes. If set, it will override
    the global 'fromstring' field on a per-mailbox basis.
 
+func_channel
+------------------
+ * Added CHANNEL(callid) to retrieve the call log tag associated with the
+   channel.  e.g., [C-00000000]  Dialplan now has access to the call log
+   search key associated with the channel so it can be saved in case there
+   is a problem with the call.
+
 res_pjsip
 ------------------
  * A new transport parameter 'symmetric_transport' has been added.
@@ -139,6 +146,10 @@ res_pjsip
    added to both transport and subscription_persistence, an alembic upgrade
    should be run to bring the database tables up to date.
 
+ * A new option, allow_overlap, has been added to endpoints which allows
+   overlap dialing functionality to be enabled or disabled. The option defaults
+   to enabled.
+
 res_pjsip_transport_websocket
 ------------------
  * Removed non-secure websocket support.  Firefox and Chrome have not allowed
index 120a7ef..bb80768 100644 (file)
                 ; "yes")
 ;aggregate_mwi=yes      ;  (default: "yes")
 ;allow= ; Media Codec s to allow (default: "")
+;allow_overlap=yes ; Enable RFC3578 overlap dialing support. (default: "yes")
 ;aors=  ; AoR s to be used with the endpoint (default: "")
 ;auth=  ; Authentication Object s associated with the endpoint (default: "")
 ;callerid=      ; CallerID information for the endpoint (default: "")
diff --git a/contrib/ast-db-manage/config/versions/8fce4c573e15_add_pjsip_allow_overlap.py b/contrib/ast-db-manage/config/versions/8fce4c573e15_add_pjsip_allow_overlap.py
new file mode 100644 (file)
index 0000000..24057ec
--- /dev/null
@@ -0,0 +1,31 @@
+"""add pjsip allow_overlap
+
+Revision ID: 8fce4c573e15
+Revises: f638dbe2eb23
+Create Date: 2017-03-21 15:14:27.612945
+
+"""
+
+# revision identifiers, used by Alembic.
+revision = '8fce4c573e15'
+down_revision = 'f638dbe2eb23'
+
+from alembic import op
+import sqlalchemy as sa
+from sqlalchemy.dialects.postgresql import ENUM
+
+YESNO_NAME = 'yesno_values'
+YESNO_VALUES = ['yes', 'no']
+
+def upgrade():
+    ############################# Enums ##############################
+
+    # yesno_values have already been created, so use postgres enum object
+    # type to get around "already created" issue - works okay with mysql
+    yesno_values = ENUM(*YESNO_VALUES, name=YESNO_NAME, create_type=False)
+
+    op.add_column('ps_endpoints', sa.Column('allow_overlap', yesno_values))
+
+
+def downgrade():
+    op.drop_column('ps_endpoints', 'allow_overlap')
index 27e9f41..eb3cedd 100644 (file)
                                        <enum name="max_forwards">
                                                <para>R/W The maximum number of forwards allowed.</para>
                                        </enum>
+                                       <enum name="callid">
+                                               <para>R/O Call identifier log tag associated with the channel
+                                               e.g., <literal>[C-00000000]</literal>.</para>
+                                       </enum>
                                </enumlist>
                                <xi:include xpointer="xpointer(/docs/info[@name='CHANNEL'])" />
                        </parameter>
@@ -450,6 +454,16 @@ static int func_channel_read(struct ast_channel *chan, const char *function,
                ast_channel_lock(chan);
                snprintf(buf, len, "%d", ast_max_forwards_get(chan));
                ast_channel_unlock(chan);
+       } else if (!strcasecmp(data, "callid")) {
+               ast_callid callid;
+
+               buf[0] = '\0';
+               ast_channel_lock(chan);
+               callid = ast_channel_callid(chan);
+               if (callid) {
+                       ast_callid_strnprint(buf, len, callid);
+               }
+               ast_channel_unlock(chan);
        } else if (!ast_channel_tech(chan) || !ast_channel_tech(chan)->func_channel_read || ast_channel_tech(chan)->func_channel_read(chan, function, data, buf, len)) {
                ast_log(LOG_WARNING, "Unknown or unavailable item requested: '%s'\n", data);
                ret = -1;
index 60c51de..3de7b1d 100644 (file)
@@ -54,7 +54,7 @@
 - \ref manager.c Main manager code file
  */
 
-#define AMI_VERSION                     "3.1.0"
+#define AMI_VERSION                     "3.2.0"
 #define DEFAULT_MANAGER_PORT 5038      /* Default port for Asterisk management via TCP */
 #define DEFAULT_MANAGER_TLS_PORT 5039  /* Default port for Asterisk management via TCP */
 
index c6c308b..6f44852 100644 (file)
@@ -765,6 +765,8 @@ struct ast_sip_endpoint {
        unsigned int preferred_codec_only;
        /*! Do we allow an asymmetric RTP codec? */
        unsigned int asymmetric_rtp_codec;
+       /*! Do we allow overlap dialling? */
+       unsigned int allow_overlap;
 };
 
 /*! URI parameter for symmetric transport */
index 836ae04..986f11f 100644 (file)
@@ -185,7 +185,7 @@ int ast_audiohook_write_frame(struct ast_audiohook *audiohook, enum ast_audiohoo
        other_factory_samples = ast_slinfactory_available(other_factory);
        other_factory_ms = other_factory_samples / (audiohook->hook_internal_samp_rate / 1000);
 
-       if (ast_test_flag(audiohook, AST_AUDIOHOOK_TRIGGER_SYNC) && other_factory_samples && (our_factory_ms - other_factory_ms > AST_AUDIOHOOK_SYNC_TOLERANCE)) {
+       if (ast_test_flag(audiohook, AST_AUDIOHOOK_TRIGGER_SYNC) && (our_factory_ms - other_factory_ms > AST_AUDIOHOOK_SYNC_TOLERANCE)) {
                ast_debug(1, "Flushing audiohook %p so it remains in sync\n", audiohook);
                ast_slinfactory_flush(factory);
                ast_slinfactory_flush(other_factory);
index 6a1164c..5bc5258 100644 (file)
@@ -28,7 +28,7 @@ WGET=@WGET@
 FETCH=@FETCH@
 DOWNLOAD=@DOWNLOAD@
 DOWNLOAD_TO_STDOUT=@DOWNLOAD_TO_STDOUT@
-DOWNLOAD_MAX_TIMEOUT=@DOWNLOAD_MAX_TIMEOUT@
+DOWNLOAD_TIMEOUT=@DOWNLOAD_TIMEOUT@
 SOUNDS_CACHE_DIR=@SOUNDS_CACHE_DIR@
 EXTERNALS_CACHE_DIR=@EXTERNALS_CACHE_DIR@
 RUBBER=@RUBBER@
index 962c4be..e4bcb70 100644 (file)
                                <configOption name="allow">
                                        <synopsis>Media Codec(s) to allow</synopsis>
                                </configOption>
+                               <configOption name="allow_overlap" default="yes">
+                                       <synopsis>Enable RFC3578 overlap dialing support.</synopsis>
+                               </configOption>
                                <configOption name="aors">
                                        <synopsis>AoR(s) to be used with the endpoint</synopsis>
                                        <description><para>
                                <parameter name="SubscribeContext">
                                        <para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='endpoint']/configOption[@name='subscribe_context']/synopsis/node())"/></para>
                                </parameter>
+                               <parameter name="Allowoverlap">
+                                       <para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='endpoint']/configOption[@name='allow_overlap']/synopsis/node())"/></para>
+                               </parameter>
                        </syntax>
                </managerEventInstance>
        </managerEvent>
index c8ff427..02562e7 100644 (file)
@@ -1938,6 +1938,7 @@ int ast_res_pjsip_initialize_configuration(void)
        ast_sorcery_object_field_register(sip_sorcery, "endpoint", "preferred_codec_only", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, preferred_codec_only));
        ast_sorcery_object_field_register(sip_sorcery, "endpoint", "asymmetric_rtp_codec", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, asymmetric_rtp_codec));
        ast_sorcery_object_field_register(sip_sorcery, "endpoint", "rtcp_mux", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.rtcp_mux));
+       ast_sorcery_object_field_register(sip_sorcery, "endpoint", "allow_overlap", "yes", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, allow_overlap));
 
        if (ast_sip_initialize_sorcery_transport()) {
                ast_log(LOG_ERROR, "Failed to register SIP transport support with sorcery\n");
index de073d3..5f42dab 100644 (file)
@@ -1986,10 +1986,17 @@ static enum sip_get_destination_result get_destination(struct ast_sip_session *s
 
                return SIP_GET_DEST_EXTEN_FOUND;
        }
-       /* XXX In reality, we'll likely have further options so that partial matches
-        * can be indicated here, but for getting something up and running, we're going
-        * to return a "not exists" error here.
+
+       /*
+        * Check for partial match via overlap dialling (if enabled)
         */
+       if (session->endpoint->allow_overlap && (
+               !strncmp(session->exten, pickupexten, strlen(session->exten)) ||
+               ast_canmatch_extension(NULL, session->endpoint->context, session->exten, 1, NULL))) {
+               /* Overlap partial match */
+               return SIP_GET_DEST_EXTEN_PARTIAL;
+       }
+
        return SIP_GET_DEST_EXTEN_NOT_FOUND;
 }
 
@@ -2106,8 +2113,17 @@ static int new_invite(void *data)
                        pjsip_inv_terminate(invite->session->inv_session, 416, PJ_TRUE);
                }
                goto end;
-       case SIP_GET_DEST_EXTEN_NOT_FOUND:
        case SIP_GET_DEST_EXTEN_PARTIAL:
+               ast_debug(1, "Call from '%s' (%s:%s:%d) to extension '%s' - partial match\n", ast_sorcery_object_get_id(invite->session->endpoint),
+                       invite->rdata->tp_info.transport->type_name, invite->rdata->pkt_info.src_name, invite->rdata->pkt_info.src_port, invite->session->exten);
+
+               if (pjsip_inv_initial_answer(invite->session->inv_session, invite->rdata, 484, NULL, NULL, &tdata) == PJ_SUCCESS) {
+                       ast_sip_session_send_response(invite->session, tdata);
+               } else  {
+                       pjsip_inv_terminate(invite->session->inv_session, 484, PJ_TRUE);
+               }
+               goto end;
+       case SIP_GET_DEST_EXTEN_NOT_FOUND:
        default:
                ast_log(LOG_NOTICE, "Call from '%s' (%s:%s:%d) to extension '%s' rejected because extension not found in context '%s'.\n",
                        ast_sorcery_object_get_id(invite->session->endpoint), invite->rdata->tp_info.transport->type_name, invite->rdata->pkt_info.src_name,
index 1aa865c..f4a5d8e 100644 (file)
@@ -1630,6 +1630,35 @@ static int xmpp_resource_immediate(void *obj, void *arg, int flags)
        return CMP_MATCH | CMP_STOP;
 }
 
+#define BUDDY_OFFLINE 6
+#define BUDDY_NOT_IN_ROSTER 7
+
+static int get_buddy_status(struct ast_xmpp_client_config *clientcfg, char *screenname, char *resource)
+{
+       int status = BUDDY_OFFLINE;
+       struct ast_xmpp_resource *res;
+       struct ast_xmpp_buddy *buddy = ao2_find(clientcfg->client->buddies, screenname, OBJ_KEY);
+
+       if (!buddy) {
+               return BUDDY_NOT_IN_ROSTER;
+       }
+
+       res = ao2_callback(
+               buddy->resources,
+               0,
+               ast_strlen_zero(resource) ? xmpp_resource_immediate : xmpp_resource_cmp,
+               resource);
+
+       if (res) {
+               status = res->status;
+       }
+
+       ao2_cleanup(res);
+       ao2_cleanup(buddy);
+
+       return status;
+}
+
 /*
  * \internal
  * \brief Dial plan function status(). puts the status of watched user
@@ -1643,10 +1672,7 @@ static int xmpp_status_exec(struct ast_channel *chan, const char *data)
 {
        RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
        RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
-       struct ast_xmpp_buddy *buddy;
-       struct ast_xmpp_resource *resource;
        char *s = NULL, status[2];
-       int stat = 7;
        static int deprecation_warning = 0;
        AST_DECLARE_APP_ARGS(args,
                             AST_APP_ARG(sender);
@@ -1685,25 +1711,7 @@ static int xmpp_status_exec(struct ast_channel *chan, const char *data)
                return -1;
        }
 
-       if (!(buddy = ao2_find(clientcfg->client->buddies, jid.screenname, OBJ_KEY))) {
-               ast_log(LOG_WARNING, "Could not find buddy in list: '%s'\n", jid.screenname);
-               return -1;
-       }
-
-       if (ast_strlen_zero(jid.resource) || !(resource = ao2_callback(buddy->resources, 0, xmpp_resource_cmp, jid.resource))) {
-               resource = ao2_callback(buddy->resources, OBJ_NODATA, xmpp_resource_immediate, NULL);
-       }
-
-       ao2_ref(buddy, -1);
-
-       if (resource) {
-               stat = resource->status;
-               ao2_ref(resource, -1);
-       } else {
-               ast_log(LOG_NOTICE, "Resource '%s' of buddy '%s' was not found\n", jid.resource, jid.screenname);
-       }
-
-       snprintf(status, sizeof(status), "%d", stat);
+       snprintf(status, sizeof(status), "%d", get_buddy_status(clientcfg, jid.screenname, jid.resource));
        pbx_builtin_setvar_helper(chan, args.variable, status);
 
        return 0;
@@ -1722,9 +1730,6 @@ static int acf_jabberstatus_read(struct ast_channel *chan, const char *name, cha
 {
        RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
        RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
-       struct ast_xmpp_buddy *buddy;
-       struct ast_xmpp_resource *resource;
-       int stat = 7;
        AST_DECLARE_APP_ARGS(args,
                             AST_APP_ARG(sender);
                             AST_APP_ARG(jid);
@@ -1756,25 +1761,7 @@ static int acf_jabberstatus_read(struct ast_channel *chan, const char *name, cha
                return -1;
        }
 
-       if (!(buddy = ao2_find(clientcfg->client->buddies, jid.screenname, OBJ_KEY))) {
-               ast_log(LOG_WARNING, "Could not find buddy in list: '%s'\n", jid.screenname);
-               return -1;
-       }
-
-       if (ast_strlen_zero(jid.resource) || !(resource = ao2_callback(buddy->resources, 0, xmpp_resource_cmp, jid.resource))) {
-               resource = ao2_callback(buddy->resources, OBJ_NODATA, xmpp_resource_immediate, NULL);
-       }
-
-       ao2_ref(buddy, -1);
-
-       if (resource) {
-               stat = resource->status;
-               ao2_ref(resource, -1);
-       } else {
-               ast_log(LOG_NOTICE, "Resource %s of buddy %s was not found.\n", jid.resource, jid.screenname);
-       }
-
-       snprintf(buf, buflen, "%d", stat);
+       snprintf(buf, buflen, "%d", get_buddy_status(clientcfg, jid.screenname, jid.resource));
 
        return 0;
 }
@@ -2562,10 +2549,16 @@ static void xmpp_log_hook(void *data, const char *xmpp, size_t size, int incomin
 static int xmpp_client_send_raw_message(struct ast_xmpp_client *client, const char *message)
 {
        int ret;
-#ifdef HAVE_OPENSSL
-       int len = strlen(message);
 
+       if (client->state == XMPP_STATE_DISCONNECTED) {
+               /* iks_send_raw will crash without a connection */
+               return IKS_NET_NOCONN;
+       }
+
+#ifdef HAVE_OPENSSL
        if (xmpp_is_secure(client)) {
+               int len = strlen(message);
+
                ret = SSL_write(client->ssl_session, message, len);
                if (ret) {
                        /* Log the message here, because iksemel's logHook is
@@ -2629,12 +2622,31 @@ static int xmpp_client_request_tls(struct ast_xmpp_client *client, struct ast_xm
 #endif
 }
 
+#ifdef HAVE_OPENSSL
+static char *openssl_error_string(void)
+{
+       char *buf = NULL, *ret;
+       size_t len;
+       BIO *bio = BIO_new(BIO_s_mem());
+
+       ERR_print_errors(bio);
+       len = BIO_get_mem_data(bio, &buf);
+       ret = ast_calloc(1, len + 1);
+       if (ret) {
+               memcpy(ret, buf, len);
+       }
+       BIO_free(bio);
+       return ret;
+}
+#endif
+
 /*! \brief Internal function called when we receive a response to our TLS initiation request */
 static int xmpp_client_requested_tls(struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, int type, iks *node)
 {
 #ifdef HAVE_OPENSSL
        int sock;
        long ssl_opts;
+       char *err;
 #endif
 
        if (!strcmp(iks_name(node), "success")) {
@@ -2670,7 +2682,7 @@ static int xmpp_client_requested_tls(struct ast_xmpp_client *client, struct ast_
                goto failure;
        }
 
-       if (!SSL_connect(client->ssl_session)) {
+       if (SSL_connect(client->ssl_session) <= 0) {
                goto failure;
        }
 
@@ -2690,7 +2702,10 @@ static int xmpp_client_requested_tls(struct ast_xmpp_client *client, struct ast_
        return 0;
 
 failure:
-       ast_log(LOG_ERROR, "TLS connection for client '%s' cannot be established. OpenSSL initialization failed.\n", client->name);
+       err = openssl_error_string();
+       ast_log(LOG_ERROR, "TLS connection for client '%s' cannot be established. "
+               "OpenSSL initialization failed: %s\n", client->name, err);
+       ast_free(err);
        return -1;
 #endif
 }
@@ -3752,12 +3767,12 @@ static void *xmpp_client_thread(void *data)
 
        do {
                if (client->state == XMPP_STATE_DISCONNECTING) {
-                       ast_debug(1, "JABBER: Disconnecting client '%s'\n", client->name);
+                       ast_debug(1, "[%s] Disconnecting\n", client->name);
                        break;
                }
 
                if (res == IKS_NET_RWERR || client->timeout == 0) {
-                       ast_debug(3, "Connecting client '%s'\n", client->name);
+                       ast_debug(3, "[%s] Connecting\n", client->name);
                        if ((res = xmpp_client_reconnect(client)) != IKS_OK) {
                                sleep(4);
                                res = IKS_NET_RWERR;
@@ -3774,9 +3789,9 @@ static void *xmpp_client_thread(void *data)
                }
 
                if (res == IKS_HOOK) {
-                       ast_debug(2, "JABBER: Got hook event.\n");
+                       ast_debug(2, "[%s] Got hook event\n", client->name);
                } else if (res == IKS_NET_TLSFAIL) {
-                       ast_log(LOG_ERROR, "JABBER:  Failure in TLS.\n");
+                       ast_log(LOG_ERROR, "[%s] TLS failure\n", client->name);
                } else if (!client->timeout && client->state == XMPP_STATE_CONNECTED) {
                        RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
                        RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
@@ -3794,22 +3809,22 @@ static void *xmpp_client_thread(void *data)
                        if (res == IKS_OK) {
                                client->timeout = 50;
                        } else {
-                               ast_log(LOG_WARNING, "JABBER: Network Timeout\n");
+                               ast_log(LOG_WARNING, "[%s] Network timeout\n", client->name);
                        }
                } else if (res == IKS_NET_RWERR) {
-                       ast_log(LOG_WARNING, "JABBER: socket read error\n");
+                       ast_log(LOG_WARNING, "[%s] Socket read error\n", client->name);
                } else if (res == IKS_NET_NOSOCK) {
-                       ast_log(LOG_WARNING, "JABBER: No Socket\n");
+                       ast_log(LOG_WARNING, "[%s] No socket\n", client->name);
                } else if (res == IKS_NET_NOCONN) {
-                       ast_log(LOG_WARNING, "JABBER: No Connection\n");
+                       ast_log(LOG_WARNING, "[%s] No connection\n", client->name);
                } else if (res == IKS_NET_NODNS) {
-                       ast_log(LOG_WARNING, "JABBER: No DNS\n");
+                       ast_log(LOG_WARNING, "[%s] No DNS\n", client->name);
                } else if (res == IKS_NET_NOTSUPP) {
-                       ast_log(LOG_WARNING, "JABBER: Not Supported\n");
+                       ast_log(LOG_WARNING, "[%s] Not supported\n", client->name);
                } else if (res == IKS_NET_DROPPED) {
-                       ast_log(LOG_WARNING, "JABBER: Dropped?\n");
+                       ast_log(LOG_WARNING, "[%s] Dropped?\n", client->name);
                } else if (res == IKS_NET_UNKNOWN) {
-                       ast_debug(5, "JABBER: Unknown\n");
+                       ast_debug(5, "[%s] Unknown\n", client->name);
                }
 
        } while (1);
index 99c22fa..e691f22 100644 (file)
@@ -96,9 +96,9 @@ endef
 
 define download_from_pjproject
        ($(SHELL_ECHO_PREFIX) Downloading $(TARBALL_URL) to $(TARBALL) ;\
-       $(DOWNLOAD_TO_STDOUT) $(call DOWNLOAD_TIMEOUT,5,10) $(TARBALL_URL) > $(TARBALL) &&\
+       $(DOWNLOAD_TO_STDOUT) $(call DOWNLOAD_TIMEOUT,5,60) $(TARBALL_URL) > $(TARBALL) &&\
        $(SHELL_ECHO_PREFIX) Downloading $(PJPROJECT_URL)/MD5SUM to $(PJMD5SUM) &&\
-       $(DOWNLOAD_TO_STDOUT) $(call DOWNLOAD_TIMEOUT,5,10) $(PJPROJECT_URL)/MD5SUM.TXT > $(PJMD5SUM) &&\
+       $(DOWNLOAD_TO_STDOUT) $(call DOWNLOAD_TIMEOUT,5,60) $(PJPROJECT_URL)/MD5SUM.TXT > $(PJMD5SUM) &&\
        $(verify_tarball))
 endef