diff options
-rw-r--r-- | CHANGES | 11 | ||||
-rw-r--r-- | configs/samples/pjsip.conf.sample | 1 | ||||
-rw-r--r-- | contrib/ast-db-manage/config/versions/8fce4c573e15_add_pjsip_allow_overlap.py | 31 | ||||
-rw-r--r-- | funcs/func_channel.c | 14 | ||||
-rw-r--r-- | include/asterisk/manager.h | 2 | ||||
-rw-r--r-- | include/asterisk/res_pjsip.h | 2 | ||||
-rw-r--r-- | main/audiohook.c | 2 | ||||
-rw-r--r-- | makeopts.in | 2 | ||||
-rw-r--r-- | res/res_pjsip.c | 6 | ||||
-rw-r--r-- | res/res_pjsip/pjsip_configuration.c | 1 | ||||
-rw-r--r-- | res/res_pjsip_session.c | 24 | ||||
-rw-r--r-- | res/res_xmpp.c | 135 | ||||
-rw-r--r-- | third-party/pjproject/Makefile | 4 |
13 files changed, 166 insertions, 69 deletions
@@ -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 diff --git a/configs/samples/pjsip.conf.sample b/configs/samples/pjsip.conf.sample index 120a7ef1c..bb80768f5 100644 --- a/configs/samples/pjsip.conf.sample +++ b/configs/samples/pjsip.conf.sample @@ -595,6 +595,7 @@ ; "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 index 000000000..24057ecc8 --- /dev/null +++ b/contrib/ast-db-manage/config/versions/8fce4c573e15_add_pjsip_allow_overlap.py @@ -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') diff --git a/funcs/func_channel.c b/funcs/func_channel.c index 27e9f41bf..eb3ceddb4 100644 --- a/funcs/func_channel.c +++ b/funcs/func_channel.c @@ -233,6 +233,10 @@ <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; diff --git a/include/asterisk/manager.h b/include/asterisk/manager.h index 60c51de85..3de7b1d17 100644 --- a/include/asterisk/manager.h +++ b/include/asterisk/manager.h @@ -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 */ diff --git a/include/asterisk/res_pjsip.h b/include/asterisk/res_pjsip.h index c6c308bee..6f44852b1 100644 --- a/include/asterisk/res_pjsip.h +++ b/include/asterisk/res_pjsip.h @@ -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 */ diff --git a/main/audiohook.c b/main/audiohook.c index 836ae0496..986f11f84 100644 --- a/main/audiohook.c +++ b/main/audiohook.c @@ -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); diff --git a/makeopts.in b/makeopts.in index 6a1164c32..5bc5258da 100644 --- a/makeopts.in +++ b/makeopts.in @@ -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@ diff --git a/res/res_pjsip.c b/res/res_pjsip.c index 962c4be4f..e4bcb7038 100644 --- a/res/res_pjsip.c +++ b/res/res_pjsip.c @@ -100,6 +100,9 @@ <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> @@ -2134,6 +2137,9 @@ <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> diff --git a/res/res_pjsip/pjsip_configuration.c b/res/res_pjsip/pjsip_configuration.c index c8ff42708..02562e782 100644 --- a/res/res_pjsip/pjsip_configuration.c +++ b/res/res_pjsip/pjsip_configuration.c @@ -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"); diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c index de073d304..5f42dab9f 100644 --- a/res/res_pjsip_session.c +++ b/res/res_pjsip_session.c @@ -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, diff --git a/res/res_xmpp.c b/res/res_xmpp.c index 1aa865cd6..f4a5d8e05 100644 --- a/res/res_xmpp.c +++ b/res/res_xmpp.c @@ -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); diff --git a/third-party/pjproject/Makefile b/third-party/pjproject/Makefile index 99c22fa8b..e691f2242 100644 --- a/third-party/pjproject/Makefile +++ b/third-party/pjproject/Makefile @@ -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 |