diff options
45 files changed, 1753 insertions, 550 deletions
@@ -9,6 +9,10 @@ ============================================================================== ------------------------------------------------------------------------------ +--- Functionality changes from Asterisk 14 to Asterisk 15 -------------------- +------------------------------------------------------------------------------ + +------------------------------------------------------------------------------ --- Functionality changes from Asterisk 13 to Asterisk 14 -------------------- ------------------------------------------------------------------------------ @@ -372,8 +376,18 @@ cdr_csv --- Functionality changes from Asterisk 13.10.0 to Asterisk 13.11.0 ---------- ------------------------------------------------------------------------------ +chan_dahdi +------------------ + * Added "faxdetect_timeout" option. + The option determines how many seconds into a call before faxdetect + is disabled for the call. Setting the value to zero disables the timeout. + res_pjsip ------------------ + * Added "fax_detect_timeout" to endpoint. + The option determines how many seconds into a call before fax_detect + is disabled for the call. Setting the value to zero disables the timeout. + * Added "subscribe_context" to endpoint. If specified, incoming SUBSCRIBE requests will be searched for the matching extension in the indicated context. If no "subscribe_context" is specified, @@ -491,7 +491,7 @@ doc/core-en_US.xml: makeopts .lastclean $(XML_core_en_US) @printf "Building Documentation For: " @echo "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" > $@ @echo "<!DOCTYPE docs SYSTEM \"appdocsxml.dtd\">" >> $@ - @echo "<?xml-stylesheet type=\"text/xsl\" href=\"appdocsxml.xslt\"?>" > $@ + @echo "<?xml-stylesheet type=\"text/xsl\" href=\"appdocsxml.xslt\"?>" >> $@ @echo "<docs xmlns:xi=\"http://www.w3.org/2001/XInclude\">" >> $@ @for x in $(MOD_SUBDIRS); do \ printf "$$x " ; \ @@ -515,7 +515,7 @@ else @printf "Building Documentation For: " @echo "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" > $@ @echo "<!DOCTYPE docs SYSTEM \"appdocsxml.dtd\">" >> $@ - @echo "<?xml-stylesheet type=\"text/xsl\" href=\"appdocsxml.xslt\"?>" > $@ + @echo "<?xml-stylesheet type=\"text/xsl\" href=\"appdocsxml.xslt\"?>" >> $@ @echo "<docs xmlns:xi=\"http://www.w3.org/2001/XInclude\">" >> $@ @for x in $(MOD_SUBDIRS); do \ printf "$$x " ; \ @@ -824,7 +824,7 @@ install-logrotate: rm -f contrib/scripts/asterisk.logrotate.tmp config: - if [ -f /etc/redhat-release -o -f /etc/fedora-release ]; then \ + @if [ -f /etc/redhat-release -o -f /etc/fedora-release ]; then \ ./build_tools/install_subst contrib/init.d/rc.redhat.asterisk "$(DESTDIR)/etc/rc.d/init.d/asterisk"; \ if [ ! -f "$(DESTDIR)/etc/sysconfig/asterisk" ] ; then \ $(INSTALL) -m 644 contrib/init.d/etc_default_asterisk "$(DESTDIR)/etc/sysconfig/asterisk" ; \ diff --git a/UPGRADE-14.txt b/UPGRADE-14.txt new file mode 100644 index 000000000..f8fa7906b --- /dev/null +++ b/UPGRADE-14.txt @@ -0,0 +1,91 @@ +=========================================================== +=== +=== Information for upgrading between Asterisk versions +=== +=== These files document all the changes that MUST be taken +=== into account when upgrading between the Asterisk +=== versions listed below. These changes may require that +=== you modify your configuration files, dialplan or (in +=== some cases) source code if you have your own Asterisk +=== modules or patches. These files also include advance +=== notice of any functionality that has been marked as +=== 'deprecated' and may be removed in a future release, +=== along with the suggested replacement functionality. +=== +=== UPGRADE-1.2.txt -- Upgrade info for 1.0 to 1.2 +=== UPGRADE-1.4.txt -- Upgrade info for 1.2 to 1.4 +=== UPGRADE-1.6.txt -- Upgrade info for 1.4 to 1.6 +=== UPGRADE-1.8.txt -- Upgrade info for 1.6 to 1.8 +=== UPGRADE-10.txt -- Upgrade info for 1.8 to 10 +=== UPGRADE-11.txt -- Upgrade info for 10 to 11 +=== UPGRADE-12.txt -- Upgrade info for 11 to 12 +=== UPGRADE-13.txt -- Upgrade info for 12 to 13 +=========================================================== + +ARI: + - The policy for when to send "Dial" events has changed. Previously, "Dial" + events were sent on the calling channel's topic. However, starting in Asterisk + 14, if there is no calling channel on which to send the event, the event is + instead sent on the called channel's topic. Note that for the ARI channels + resource's dial operation, this means that the "Dial" events will always be + sent on the called channel's topic. + +Channel Drivers: + +chan_dahdi: + - For users using the FXO port (FXS signaling) distinctive ring detection + feature, you will need to adjust the dringX count values. The count + values now only record ring end events instead of any DAHDI event. A + ring-ring-ring pattern would exceed the pattern limits and stop + Caller-ID detection. + +chan_sip: + - The SIP dial string has been extended past the [!dnid] option by another + exclamation mark: [!dnid[!fromuri]. An exclamation mark in the To-URI + will now mean changes to the From-URI. + +Core: + - The REF_DEBUG compiler flag is now used to enable refdebug by default. + The setting can be overridden in asterisk.conf by setting refdebug in + the options category. No recompile is required to enable/disable it. + + - Modified processing of command-line options to first parse only what + is necessary to read asterisk.conf. Once asterisk.conf is fully loaded, + the remaining options are processed. The -X option now applies to + asterisk.conf only. To enable #exec for other config files you must + set execincludes=yes in asterisk.conf. Any other option set on the + command-line will now override the equivalent setting from asterisk.conf. + +AMI: + - The 'ModuleCheck' Action's Version key will no longer show the module + version. The value will always be blank. + +CLI: + - The 'core show file version' command has been removed. When Asterisk + moved to Git, the source control version support was removed. As a + result, the CLi command was no longer useful and was removed as well. + +Logging: + - The first callid created is now 1 instead of 0. The value 0 + is now reserved to represent a lack of callid. + +AMI: + - The Command action now sends the output from the CLI command as a series + of Output headers for each line instead of as a block of text with the + --END COMMAND-- delimiter to match the output from other actions. + + Commands that fail to execute (no such command, invalid syntax etc.) now + return an Error response instead of Success. + +app_amd: + - The 'maximum_number_of_words' configuration option and parameter to the AMD + application previously did not match the documented functionality + variable + name. In Asterisk 13, a value of '3' would mean that if '3' words were detected, + the result would be detection as a 'MACHINE'. As of this version, the value + reflects the maximum words that if EXCEEDED (rather than reached), would + result in detection as a machine. This means that you should update this + value to be one higher than your previos value, if your previous value + was working well for you. + +=========================================================== +=========================================================== diff --git a/UPGRADE.txt b/UPGRADE.txt index f8fa7906b..ad03edf84 100644 --- a/UPGRADE.txt +++ b/UPGRADE.txt @@ -20,72 +20,5 @@ === UPGRADE-11.txt -- Upgrade info for 10 to 11 === UPGRADE-12.txt -- Upgrade info for 11 to 12 === UPGRADE-13.txt -- Upgrade info for 12 to 13 -=========================================================== - -ARI: - - The policy for when to send "Dial" events has changed. Previously, "Dial" - events were sent on the calling channel's topic. However, starting in Asterisk - 14, if there is no calling channel on which to send the event, the event is - instead sent on the called channel's topic. Note that for the ARI channels - resource's dial operation, this means that the "Dial" events will always be - sent on the called channel's topic. - -Channel Drivers: - -chan_dahdi: - - For users using the FXO port (FXS signaling) distinctive ring detection - feature, you will need to adjust the dringX count values. The count - values now only record ring end events instead of any DAHDI event. A - ring-ring-ring pattern would exceed the pattern limits and stop - Caller-ID detection. - -chan_sip: - - The SIP dial string has been extended past the [!dnid] option by another - exclamation mark: [!dnid[!fromuri]. An exclamation mark in the To-URI - will now mean changes to the From-URI. - -Core: - - The REF_DEBUG compiler flag is now used to enable refdebug by default. - The setting can be overridden in asterisk.conf by setting refdebug in - the options category. No recompile is required to enable/disable it. - - - Modified processing of command-line options to first parse only what - is necessary to read asterisk.conf. Once asterisk.conf is fully loaded, - the remaining options are processed. The -X option now applies to - asterisk.conf only. To enable #exec for other config files you must - set execincludes=yes in asterisk.conf. Any other option set on the - command-line will now override the equivalent setting from asterisk.conf. - -AMI: - - The 'ModuleCheck' Action's Version key will no longer show the module - version. The value will always be blank. - -CLI: - - The 'core show file version' command has been removed. When Asterisk - moved to Git, the source control version support was removed. As a - result, the CLi command was no longer useful and was removed as well. - -Logging: - - The first callid created is now 1 instead of 0. The value 0 - is now reserved to represent a lack of callid. - -AMI: - - The Command action now sends the output from the CLI command as a series - of Output headers for each line instead of as a block of text with the - --END COMMAND-- delimiter to match the output from other actions. - - Commands that fail to execute (no such command, invalid syntax etc.) now - return an Error response instead of Success. - -app_amd: - - The 'maximum_number_of_words' configuration option and parameter to the AMD - application previously did not match the documented functionality + variable - name. In Asterisk 13, a value of '3' would mean that if '3' words were detected, - the result would be detection as a 'MACHINE'. As of this version, the value - reflects the maximum words that if EXCEEDED (rather than reached), would - result in detection as a machine. This means that you should update this - value to be one higher than your previos value, if your previous value - was working well for you. - -=========================================================== +=== UPGRADE-14.txt -- Upgrade info for 13 to 14 =========================================================== diff --git a/apps/app_voicemail.c b/apps/app_voicemail.c index 6607f529e..894038bdb 100644 --- a/apps/app_voicemail.c +++ b/apps/app_voicemail.c @@ -12307,6 +12307,7 @@ static int append_mailbox(const char *context, const char *box, const char *data return 0; } +#ifdef TEST_FRAMEWORK AST_TEST_DEFINE(test_voicemail_vmuser) { int res = 0; @@ -12494,6 +12495,7 @@ AST_TEST_DEFINE(test_voicemail_vmuser) free_user(vmu); return res ? AST_TEST_FAIL : AST_TEST_PASS; } +#endif static int vm_box_exists(struct ast_channel *chan, const char *data) { diff --git a/channels/chan_dahdi.c b/channels/chan_dahdi.c index e4b7c0ee8..7a3c31fd5 100644 --- a/channels/chan_dahdi.c +++ b/channels/chan_dahdi.c @@ -1693,26 +1693,28 @@ static void my_handle_dtmf(void *pvt, struct ast_channel *ast, enum analog_sub a 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 ast_exists_extension has the + /* + * We need to unlock 'ast' here because ast_exists_extension has the * potential to start autoservice on the channel. Such action is prone - * to deadlock. + * to deadlock if the channel is locked. + * + * ast_async_goto() has its own restriction on not holding the + * channel lock. */ ast_mutex_unlock(&p->lock); ast_channel_unlock(ast); 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); - ast_mutex_lock(&p->lock); ast_verb(3, "Redirecting %s to fax extension\n", ast_channel_name(ast)); /* Save the DID/DNIS when we transfer the fax call to a "fax" extension */ pbx_builtin_setvar_helper(ast, "FAXEXTEN", ast_channel_exten(ast)); if (ast_async_goto(ast, target_context, "fax", 1)) ast_log(LOG_WARNING, "Failed to async goto '%s' into fax of '%s'\n", ast_channel_name(ast), target_context); } else { - ast_channel_lock(ast); - ast_mutex_lock(&p->lock); ast_log(LOG_NOTICE, "Fax detected, but no fax extension\n"); } + ast_channel_lock(ast); + ast_mutex_lock(&p->lock); } else { ast_debug(1, "Already in a fax extension, not redirecting\n"); } @@ -2345,7 +2347,6 @@ static void my_pri_ss7_open_media(void *p) if (pvt->dsp_features && pvt->dsp) { ast_dsp_set_features(pvt->dsp, pvt->dsp_features); - pvt->dsp_features = 0; } } #endif /* defined(HAVE_PRI) || defined(HAVE_SS7) */ @@ -7200,26 +7201,28 @@ static void dahdi_handle_dtmf(struct ast_channel *ast, int idx, struct ast_frame 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 ast_exists_extension has the + /* + * We need to unlock 'ast' here because ast_exists_extension has the * potential to start autoservice on the channel. Such action is prone - * to deadlock. + * to deadlock if the channel is locked. + * + * ast_async_goto() has its own restriction on not holding the + * channel lock. */ ast_mutex_unlock(&p->lock); ast_channel_unlock(ast); 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); - ast_mutex_lock(&p->lock); ast_verb(3, "Redirecting %s to fax extension\n", ast_channel_name(ast)); /* Save the DID/DNIS when we transfer the fax call to a "fax" extension */ pbx_builtin_setvar_helper(ast, "FAXEXTEN", ast_channel_exten(ast)); if (ast_async_goto(ast, target_context, "fax", 1)) ast_log(LOG_WARNING, "Failed to async goto '%s' into fax of '%s'\n", ast_channel_name(ast), target_context); } else { - ast_channel_lock(ast); - ast_mutex_lock(&p->lock); ast_log(LOG_NOTICE, "Fax detected, but no fax extension\n"); } + ast_channel_lock(ast); + ast_mutex_lock(&p->lock); } else { ast_debug(1, "Already in a fax extension, not redirecting\n"); } @@ -8640,6 +8643,15 @@ static struct ast_frame *dahdi_read(struct ast_channel *ast) /* Perform busy detection etc on the dahdi line */ int mute; + if ((p->dsp_features & DSP_FEATURE_FAX_DETECT) + && p->faxdetect_timeout + && p->faxdetect_timeout <= ast_channel_get_up_time(ast)) { + p->dsp_features &= ~DSP_FEATURE_FAX_DETECT; + ast_dsp_set_features(p->dsp, p->dsp_features); + ast_debug(1, "Channel driver fax CNG detection timeout on %s\n", + ast_channel_name(ast)); + } + f = ast_dsp_process(ast, p->dsp, &p->subs[idx].f); /* Check if DSP code thinks we should be muting this frame and mute the conference if so */ @@ -12539,6 +12551,7 @@ static struct dahdi_pvt *mkintf(int channel, const struct dahdi_chan_conf *conf, tmp->callprogress = conf->chan.callprogress; tmp->waitfordialtone = conf->chan.waitfordialtone; tmp->dialtone_detect = conf->chan.dialtone_detect; + tmp->faxdetect_timeout = conf->chan.faxdetect_timeout; tmp->cancallforward = conf->chan.cancallforward; tmp->dtmfrelax = conf->chan.dtmfrelax; tmp->callwaiting = tmp->permcallwaiting; @@ -17790,6 +17803,10 @@ static int process_dahdi(struct dahdi_chan_conf *confp, const char *cat, struct confp->chan.callprogress |= CALLPROGRESS_FAX_OUTGOING; } else if (!strcasecmp(v->value, "both") || ast_true(v->value)) confp->chan.callprogress |= CALLPROGRESS_FAX_INCOMING | CALLPROGRESS_FAX_OUTGOING; + } else if (!strcasecmp(v->name, "faxdetect_timeout")) { + if (sscanf(v->value, "%30u", &confp->chan.faxdetect_timeout) != 1) { + confp->chan.faxdetect_timeout = 0; + } } else if (!strcasecmp(v->name, "echocancel")) { process_echocancel(confp, v->value, v->lineno); } else if (!strcasecmp(v->name, "echotraining")) { diff --git a/channels/chan_dahdi.h b/channels/chan_dahdi.h index 4bb5d19a2..ab5c1eba9 100644 --- a/channels/chan_dahdi.h +++ b/channels/chan_dahdi.h @@ -612,6 +612,11 @@ struct dahdi_pvt { */ int dialtone_detect; int dialtone_scanning_time_elapsed; /*!< Amount of audio scanned for dialtone, in frames */ + /*! + * \brief The number of seconds into call to disable fax detection. (0 = disabled) + * \note Set from the "faxdetect_timeout" value read in from chan_dahdi.conf + */ + unsigned int faxdetect_timeout; struct timeval waitingfordt; /*!< Time we started waiting for dialtone */ struct timeval flashtime; /*!< Last flash-hook time */ /*! \brief Opaque DSP configuration structure. */ diff --git a/channels/chan_pjsip.c b/channels/chan_pjsip.c index 5ad117404..2e87393a6 100644 --- a/channels/chan_pjsip.c +++ b/channels/chan_pjsip.c @@ -612,10 +612,12 @@ static struct ast_frame *chan_pjsip_cng_tone_detected(struct ast_sip_session *se { const char *target_context; int exists; + int dsp_features; - /* If we only needed this DSP for fax detection purposes we can just drop it now */ - if (session->endpoint->dtmf == AST_SIP_DTMF_INBAND || session->endpoint->dtmf == AST_SIP_DTMF_AUTO) { - ast_dsp_set_features(session->dsp, DSP_FEATURE_DIGIT_DETECT); + dsp_features = ast_dsp_get_features(session->dsp); + dsp_features &= ~DSP_FEATURE_FAX_DETECT; + if (dsp_features) { + ast_dsp_set_features(session->dsp, dsp_features); } else { ast_dsp_free(session->dsp); session->dsp = NULL; @@ -628,16 +630,19 @@ static struct ast_frame *chan_pjsip_cng_tone_detected(struct ast_sip_session *se target_context = S_OR(ast_channel_macrocontext(session->channel), ast_channel_context(session->channel)); - /* We need to unlock the channel here because ast_exists_extension has the + /* + * We need to unlock the channel 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. */ ast_channel_unlock(session->channel); + ast_frfree(f); + f = &ast_null_frame; exists = ast_exists_extension(session->channel, target_context, "fax", 1, S_COR(ast_channel_caller(session->channel)->id.number.valid, ast_channel_caller(session->channel)->id.number.str, NULL)); - ast_channel_lock(session->channel); - if (exists) { ast_verb(2, "Redirecting '%s' to fax extension due to CNG detection\n", ast_channel_name(session->channel)); @@ -646,12 +651,11 @@ static struct ast_frame *chan_pjsip_cng_tone_detected(struct ast_sip_session *se ast_log(LOG_ERROR, "Failed to async goto '%s' into fax extension in '%s'\n", ast_channel_name(session->channel), target_context); } - ast_frfree(f); - f = &ast_null_frame; } else { ast_log(LOG_NOTICE, "FAX CNG detected on '%s' but no fax extension in '%s'\n", ast_channel_name(session->channel), target_context); } + ast_channel_lock(session->channel); return f; } @@ -660,6 +664,7 @@ static struct ast_frame *chan_pjsip_cng_tone_detected(struct ast_sip_session *se static struct ast_frame *chan_pjsip_read(struct ast_channel *ast) { struct ast_sip_channel_pvt *channel = ast_channel_tech_pvt(ast); + struct ast_sip_session *session; struct chan_pjsip_pvt *pvt = channel->pvt; struct ast_frame *f; struct ast_sip_session_media *media = NULL; @@ -697,22 +702,42 @@ static struct ast_frame *chan_pjsip_read(struct ast_channel *ast) return f; } - if (ast_format_cap_iscompatible_format(channel->session->endpoint->media.codecs, f->subclass.format) == AST_FORMAT_CMP_NOT_EQUAL) { + session = channel->session; + + if (ast_format_cap_iscompatible_format(session->endpoint->media.codecs, f->subclass.format) == AST_FORMAT_CMP_NOT_EQUAL) { ast_debug(1, "Oooh, got a frame with format of %s on channel '%s' when endpoint '%s' is not configured for it\n", ast_format_get_name(f->subclass.format), ast_channel_name(ast), - ast_sorcery_object_get_id(channel->session->endpoint)); + ast_sorcery_object_get_id(session->endpoint)); ast_frfree(f); return &ast_null_frame; } - if (channel->session->dsp) { - f = ast_dsp_process(ast, channel->session->dsp, f); + if (session->dsp) { + int dsp_features; + dsp_features = ast_dsp_get_features(session->dsp); + if ((dsp_features & DSP_FEATURE_FAX_DETECT) + && session->endpoint->faxdetect_timeout + && session->endpoint->faxdetect_timeout <= ast_channel_get_up_time(ast)) { + dsp_features &= ~DSP_FEATURE_FAX_DETECT; + if (dsp_features) { + ast_dsp_set_features(session->dsp, dsp_features); + } else { + ast_dsp_free(session->dsp); + session->dsp = NULL; + } + ast_debug(3, "Channel driver fax CNG detection timeout on %s\n", + ast_channel_name(ast)); + } + } + if (session->dsp) { + f = ast_dsp_process(ast, session->dsp, f); if (f && (f->frametype == AST_FRAME_DTMF)) { if (f->subclass.integer == 'f') { - ast_debug(3, "Fax CNG detected on %s\n", ast_channel_name(ast)); - f = chan_pjsip_cng_tone_detected(channel->session, f); + ast_debug(3, "Channel driver fax CNG detected on %s\n", + ast_channel_name(ast)); + f = chan_pjsip_cng_tone_detected(session, f); } else { ast_debug(3, "* Detected inband DTMF '%c' on '%s'\n", f->subclass.integer, ast_channel_name(ast)); diff --git a/channels/chan_sip.c b/channels/chan_sip.c index 9098c14e5..5f422d72a 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -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, diff --git a/channels/sip/config_parser.c b/channels/sip/config_parser.c index 56d04b260..036f7f7d2 100644 --- a/channels/sip/config_parser.c +++ b/channels/sip/config_parser.c @@ -274,6 +274,7 @@ int sip_parse_register_line(struct sip_registry *reg, int default_expiry, const return 0; } +#ifdef TEST_FRAMEWORK AST_TEST_DEFINE(sip_parse_register_line_test) { int res = AST_TEST_PASS; @@ -643,6 +644,7 @@ alloc_fail: ast_test_status_update(test, "Out of memory. \n"); return res; } +#endif int sip_parse_host(char *line, int lineno, char **hostname, int *portnum, enum ast_transport *transport) { @@ -708,6 +710,7 @@ int sip_parse_host(char *line, int lineno, char **hostname, int *portnum, enum a return 0; } +#ifdef TEST_FRAMEWORK AST_TEST_DEFINE(sip_parse_host_line_test) { int res = AST_TEST_PASS; @@ -787,6 +790,7 @@ AST_TEST_DEFINE(sip_parse_host_line_test) return res; } +#endif /*! \brief Parse the comma-separated nat= option values */ void sip_parse_nat_option(const char *value, struct ast_flags *mask, struct ast_flags *flags) @@ -834,6 +838,7 @@ void sip_parse_nat_option(const char *value, struct ast_flags *mask, struct ast_ } } +#ifdef TEST_FRAMEWORK #define TEST_FORCE_RPORT 1 << 0 #define TEST_COMEDIA 1 << 1 #define TEST_AUTO_FORCE_RPORT 1 << 2 @@ -904,6 +909,8 @@ AST_TEST_DEFINE(sip_parse_nat_test) return res; } +#endif + /*! \brief SIP test registration */ void sip_config_parser_register_tests(void) { diff --git a/channels/sip/reqresp_parser.c b/channels/sip/reqresp_parser.c index 298b8cb95..358d6e568 100644 --- a/channels/sip/reqresp_parser.c +++ b/channels/sip/reqresp_parser.c @@ -258,7 +258,7 @@ int parse_uri_full(char *uri, const char *scheme, char **user, char **pass, return error; } - +#ifdef TEST_FRAMEWORK AST_TEST_DEFINE(sip_parse_uri_full_test) { int res = AST_TEST_PASS; @@ -514,7 +514,7 @@ AST_TEST_DEFINE(sip_parse_uri_full_test) return res; } - +#endif int parse_uri(char *uri, const char *scheme, char **user, char **pass, char **hostport, char **transport) { @@ -530,6 +530,7 @@ int parse_uri(char *uri, const char *scheme, char **user, char **pass, return ret; } +#ifdef TEST_FRAMEWORK AST_TEST_DEFINE(sip_parse_uri_test) { int res = AST_TEST_PASS; @@ -687,6 +688,7 @@ AST_TEST_DEFINE(sip_parse_uri_test) return res; } +#endif /*! \brief Get caller id name from SIP headers, copy into output buffer * @@ -817,6 +819,7 @@ const char *get_calleridname(const char *input, char *output, size_t outputsize) return input; } +#ifdef TEST_FRAMEWORK AST_TEST_DEFINE(get_calleridname_test) { int res = AST_TEST_PASS; @@ -899,6 +902,7 @@ AST_TEST_DEFINE(get_calleridname_test) return res; } +#endif int get_name_and_number(const char *hdr, char **name, char **number) { @@ -940,6 +944,7 @@ int get_name_and_number(const char *hdr, char **name, char **number) return 0; } +#ifdef TEST_FRAMEWORK AST_TEST_DEFINE(get_name_and_number_test) { int res = AST_TEST_PASS; @@ -1044,6 +1049,7 @@ AST_TEST_DEFINE(get_name_and_number_test) return res; } +#endif int get_in_brackets_const(const char *src,const char **start,int *length) { @@ -1176,6 +1182,7 @@ char *get_in_brackets(char *tmp) return out; } +#ifdef TEST_FRAMEWORK AST_TEST_DEFINE(get_in_brackets_test) { int res = AST_TEST_PASS; @@ -1252,7 +1259,7 @@ AST_TEST_DEFINE(get_in_brackets_test) return res; } - +#endif int parse_name_andor_addr(char *uri, const char *scheme, char **name, char **user, char **pass, char **hostport, @@ -1298,6 +1305,7 @@ int parse_name_andor_addr(char *uri, const char *scheme, char **name, return parse_uri_full(uri, scheme, user, pass, hostport, params, headers, residue2); } +#ifdef TEST_FRAMEWORK AST_TEST_DEFINE(parse_name_andor_addr_test) { int res = AST_TEST_PASS; @@ -1427,6 +1435,7 @@ AST_TEST_DEFINE(parse_name_andor_addr_test) return res; } +#endif int get_comma(char *in, char **out) { @@ -1523,6 +1532,7 @@ int parse_contact_header(char *contactheader, struct contactliststruct *contactl return last; } +#ifdef TEST_FRAMEWORK AST_TEST_DEFINE(parse_contact_header_test) { int res = AST_TEST_PASS; @@ -1668,6 +1678,7 @@ AST_TEST_DEFINE(parse_contact_header_test) return res; } +#endif /*! * \brief Parse supported header in incoming packet @@ -1755,6 +1766,7 @@ unsigned int parse_sip_options(const char *options, char *unsupported, size_t un return profile; } +#ifdef TEST_FRAMEWORK AST_TEST_DEFINE(sip_parse_options_test) { int res = AST_TEST_PASS; @@ -1892,6 +1904,7 @@ AST_TEST_DEFINE(sip_parse_options_test) return res; } +#endif /*! \brief helper routine for sip_uri_cmp to compare URI parameters * @@ -2246,6 +2259,7 @@ int sip_uri_cmp(const char *input1, const char *input2) #define URI_CMP_MATCH 0 #define URI_CMP_NOMATCH 1 +#ifdef TEST_FRAMEWORK AST_TEST_DEFINE(sip_uri_cmp_test) { static const struct { @@ -2362,6 +2376,7 @@ AST_TEST_DEFINE(sip_uri_cmp_test) return test_res; } +#endif void free_via(struct sip_via *v) { @@ -2448,6 +2463,7 @@ struct sip_via *parse_via(const char *header) return v; } +#ifdef TEST_FRAMEWORK AST_TEST_DEFINE(parse_via_test) { int res = AST_TEST_PASS; @@ -2625,6 +2641,7 @@ AST_TEST_DEFINE(parse_via_test) } return res; } +#endif void sip_request_parser_register_tests(void) { diff --git a/configs/samples/chan_dahdi.conf.sample b/configs/samples/chan_dahdi.conf.sample index e0c69ebef..a0c729c11 100644 --- a/configs/samples/chan_dahdi.conf.sample +++ b/configs/samples/chan_dahdi.conf.sample @@ -1119,6 +1119,15 @@ pickupgroup=1 ;faxdetect=outgoing ;faxdetect=no ; +; When 'faxdetect' is enabled, one could use 'faxdetect_timeout' to disable fax +; detection after the specified number of seconds into a call. Be aware that +; outgoing analog channels may consider the channel is answered immediately +; when dialing completes. Analog does not have a reliable method of detecting +; when the far end answers. Zero disables the timeout. +; Default is 0 to disable the timeout. +; +;faxdetect_timeout=30 +; ; When 'faxdetect' is used, one could use 'faxbuffers' to configure the DAHDI ; transmit buffer policy. The default is *OFF*. When this configuration ; option is used, the faxbuffer policy will be used for the life of the call diff --git a/configs/samples/pjsip.conf.sample b/configs/samples/pjsip.conf.sample index 9069a669f..99bdfb99d 100644 --- a/configs/samples/pjsip.conf.sample +++ b/configs/samples/pjsip.conf.sample @@ -672,7 +672,7 @@ ; usage of media encryption for this endpoint (default: ; "no") ;media_encryption_optimistic=no ; Use encryption if possible but don't fail the call - ; if not possible. + ; if not possible. ;g726_non_standard=no ; When set to "yes" and an endpoint negotiates g.726 ; audio then g.726 for AAL2 packing order is used contrary ; to what is recommended in RFC3551. Note, 'g726aal2' also @@ -693,6 +693,10 @@ ;t38_udptl_maxdatagram=0 ; T 38 UDPTL maximum datagram size (default: ; "0") ;fax_detect=no ; Whether CNG tone detection is enabled (default: "no") +;fax_detect_timeout=30 ; How many seconds into a call before fax_detect is + ; disabled for the call. + ; Zero disables the timeout. + ; (default: "0") ;t38_udptl_nat=no ; Whether NAT support is enabled on UDPTL sessions ; (default: "no") ;t38_udptl_ipv6=no ; Whether IPv6 is used for UDPTL Sessions (default: @@ -748,7 +752,7 @@ ;srtp_tag_32=no ; Determines whether 32 byte tags should be used instead of 80 ; byte tags (default: "no") ;set_var= ; Variable set on a channel involving the endpoint. For multiple - ; channel variables specify multiple 'set_var'(s) + ; channel variables specify multiple 'set_var'(s) ;rtp_keepalive= ; Interval, in seconds, between comfort noise RTP packets if ; RTP is not flowing. This setting is useful for ensuring that ; holes in NATs and firewalls are kept open throughout a call. @@ -790,7 +794,7 @@ ; (default: "") ;ca_list_path= ; Path to directory containing certificates to read TLS ONLY. ; PJProject version 2.4 or higher is required for this option to - ; be used. + ; be used. ; (default: "") ;cert_file= ; Certificate file for endpoint TLS ONLY ; Will read .crt or .pem file but only uses cert, @@ -882,8 +886,8 @@ ;disable_tcp_switch=yes ; Disable automatic switching from UDP to TCP transports ; if outgoing request is too large. ; See RFC 3261 section 18.1.1. - ; Disabling this option has been known to cause interoperability - ; issues, so disable at your own risk. + ; Disabling this option has been known to cause interoperability + ; issues, so disable at your own risk. ; (default: "yes") ;type= ; Must be of type system (default: "") @@ -913,10 +917,10 @@ ;contact_expiration_check_interval=30 ; The interval (in seconds) to check for expired contacts. ;disable_multi_domain=no - ; Disable Multi Domain support. - ; If disabled it can improve realtime performace by reducing - ; number of database requsts - ; (default: "no") + ; Disable Multi Domain support. + ; If disabled it can improve realtime performace by reducing + ; number of database requsts + ; (default: "no") ;endpoint_identifier_order=ip,username,anonymous ; The order by which endpoint identifiers are given priority. ; Currently, "ip", "username", "auth_username" and "anonymous" are valid @@ -778,6 +778,18 @@ PBX_SRTP_SHUTDOWN SRTP_SHUTDOWN_DIR SRTP_SHUTDOWN_INCLUDE SRTP_SHUTDOWN_LIB +PBX_SRTP_GCM +SRTP_GCM_DIR +SRTP_GCM_INCLUDE +SRTP_GCM_LIB +PBX_SRTP_192 +SRTP_192_DIR +SRTP_192_INCLUDE +SRTP_192_LIB +PBX_SRTP_256 +SRTP_256_DIR +SRTP_256_INCLUDE +SRTP_256_LIB PBX_SRTP SRTP_DIR SRTP_INCLUDE @@ -11743,6 +11755,42 @@ fi +SRTP_256_DESCRIP="SRTP Library AES-256 (ICM)" +SRTP_256_OPTION=srtp +SRTP_256_DIR=${SRTP_DIR} + +PBX_SRTP_256=0 + + + + + + + +SRTP_192_DESCRIP="SRTP Library AES-192 (ICM)" +SRTP_192_OPTION=srtp +SRTP_192_DIR=${SRTP_DIR} + +PBX_SRTP_192=0 + + + + + + + +SRTP_GCM_DESCRIP="SRTP Library AES-128 (GCM) and AES-256 (GCM)" +SRTP_GCM_OPTION=srtp +SRTP_GCM_DIR=${SRTP_DIR} + +PBX_SRTP_GCM=0 + + + + + + + SRTP_SHUTDOWN_DESCRIP="SRTP Library Shutdown Function" SRTP_SHUTDOWN_OPTION=srtp SRTP_SHUTDOWN_DIR=${SRTP_DIR} @@ -18026,6 +18074,74 @@ CFLAGS="$saved_CFLAGS" +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for compiler 'attribute noreturn' support" >&5 +$as_echo_n "checking for compiler 'attribute noreturn' support... " >&6; } +saved_CFLAGS="$CFLAGS" +CFLAGS="$CFLAGS -Wall -Wno-unused -Werror" + + +if test "xnoreturn" = "x" +then +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + void __attribute__((noreturn)) *test(void *muffin, ...) {return (void *) 0;} +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + + +cat >>confdefs.h <<_ACEOF +#define HAVE_ATTRIBUTE_noreturn 1 +_ACEOF + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +else +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + void __attribute__((noreturn)) *test(void *muffin, ...) ; +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + + +cat >>confdefs.h <<_ACEOF +#define HAVE_ATTRIBUTE_noreturn 1 +_ACEOF + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + + +CFLAGS="$saved_CFLAGS" + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -fsanitize=address support" >&5 $as_echo_n "checking for -fsanitize=address support... " >&6; } saved_sanitize_CFLAGS="${CFLAGS}" @@ -32115,6 +32231,322 @@ rm -f core conftest.err conftest.$ac_objext \ CFLAGS="${saved_cflags}" fi +if test "$PBX_SRTP" = "1"; +then + +if test "x${PBX_SRTP_256}" != "x1" -a "${USE_SRTP_256}" != "no"; then + pbxlibdir="" + # if --with-SRTP_256=DIR has been specified, use it. + if test "x${SRTP_256_DIR}" != "x"; then + if test -d ${SRTP_256_DIR}/lib; then + pbxlibdir="-L${SRTP_256_DIR}/lib" + else + pbxlibdir="-L${SRTP_256_DIR}" + fi + fi + pbxfuncname="crypto_policy_set_aes_cm_256_hmac_sha1_80" + if test "x${pbxfuncname}" = "x" ; then # empty lib, assume only headers + AST_SRTP_256_FOUND=yes + else + ast_ext_lib_check_save_CFLAGS="${CFLAGS}" + CFLAGS="${CFLAGS} " + as_ac_Lib=`$as_echo "ac_cv_lib_srtp_${pbxfuncname}" | $as_tr_sh` +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lsrtp" >&5 +$as_echo_n "checking for ${pbxfuncname} in -lsrtp... " >&6; } +if eval \${$as_ac_Lib+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lsrtp ${pbxlibdir} $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char ${pbxfuncname} (); +int +main () +{ +return ${pbxfuncname} (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + eval "$as_ac_Lib=yes" +else + eval "$as_ac_Lib=no" +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +eval ac_res=\$$as_ac_Lib + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then : + AST_SRTP_256_FOUND=yes +else + AST_SRTP_256_FOUND=no +fi + + CFLAGS="${ast_ext_lib_check_save_CFLAGS}" + fi + + # now check for the header. + if test "${AST_SRTP_256_FOUND}" = "yes"; then + SRTP_256_LIB="${pbxlibdir} -lsrtp " + # if --with-SRTP_256=DIR has been specified, use it. + if test "x${SRTP_256_DIR}" != "x"; then + SRTP_256_INCLUDE="-I${SRTP_256_DIR}/include" + fi + SRTP_256_INCLUDE="${SRTP_256_INCLUDE} " + if test "x" = "x" ; then # no header, assume found + SRTP_256_HEADER_FOUND="1" + else # check for the header + ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}" + CPPFLAGS="${CPPFLAGS} ${SRTP_256_INCLUDE}" + ac_fn_c_check_header_mongrel "$LINENO" "" "ac_cv_header_" "$ac_includes_default" +if test "x$ac_cv_header_" = xyes; then : + SRTP_256_HEADER_FOUND=1 +else + SRTP_256_HEADER_FOUND=0 +fi + + + CPPFLAGS="${ast_ext_lib_check_saved_CPPFLAGS}" + fi + if test "x${SRTP_256_HEADER_FOUND}" = "x0" ; then + SRTP_256_LIB="" + SRTP_256_INCLUDE="" + else + if test "x${pbxfuncname}" = "x" ; then # only checking headers -> no library + SRTP_256_LIB="" + fi + PBX_SRTP_256=1 + cat >>confdefs.h <<_ACEOF +#define HAVE_SRTP_256 1 +_ACEOF + + fi + fi +fi + + + +if test "x${PBX_SRTP_192}" != "x1" -a "${USE_SRTP_192}" != "no"; then + pbxlibdir="" + # if --with-SRTP_192=DIR has been specified, use it. + if test "x${SRTP_192_DIR}" != "x"; then + if test -d ${SRTP_192_DIR}/lib; then + pbxlibdir="-L${SRTP_192_DIR}/lib" + else + pbxlibdir="-L${SRTP_192_DIR}" + fi + fi + pbxfuncname="crypto_policy_set_aes_cm_192_hmac_sha1_80" + if test "x${pbxfuncname}" = "x" ; then # empty lib, assume only headers + AST_SRTP_192_FOUND=yes + else + ast_ext_lib_check_save_CFLAGS="${CFLAGS}" + CFLAGS="${CFLAGS} " + as_ac_Lib=`$as_echo "ac_cv_lib_srtp_${pbxfuncname}" | $as_tr_sh` +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lsrtp" >&5 +$as_echo_n "checking for ${pbxfuncname} in -lsrtp... " >&6; } +if eval \${$as_ac_Lib+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lsrtp ${pbxlibdir} $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char ${pbxfuncname} (); +int +main () +{ +return ${pbxfuncname} (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + eval "$as_ac_Lib=yes" +else + eval "$as_ac_Lib=no" +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +eval ac_res=\$$as_ac_Lib + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then : + AST_SRTP_192_FOUND=yes +else + AST_SRTP_192_FOUND=no +fi + + CFLAGS="${ast_ext_lib_check_save_CFLAGS}" + fi + + # now check for the header. + if test "${AST_SRTP_192_FOUND}" = "yes"; then + SRTP_192_LIB="${pbxlibdir} -lsrtp " + # if --with-SRTP_192=DIR has been specified, use it. + if test "x${SRTP_192_DIR}" != "x"; then + SRTP_192_INCLUDE="-I${SRTP_192_DIR}/include" + fi + SRTP_192_INCLUDE="${SRTP_192_INCLUDE} " + if test "x" = "x" ; then # no header, assume found + SRTP_192_HEADER_FOUND="1" + else # check for the header + ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}" + CPPFLAGS="${CPPFLAGS} ${SRTP_192_INCLUDE}" + ac_fn_c_check_header_mongrel "$LINENO" "" "ac_cv_header_" "$ac_includes_default" +if test "x$ac_cv_header_" = xyes; then : + SRTP_192_HEADER_FOUND=1 +else + SRTP_192_HEADER_FOUND=0 +fi + + + CPPFLAGS="${ast_ext_lib_check_saved_CPPFLAGS}" + fi + if test "x${SRTP_192_HEADER_FOUND}" = "x0" ; then + SRTP_192_LIB="" + SRTP_192_INCLUDE="" + else + if test "x${pbxfuncname}" = "x" ; then # only checking headers -> no library + SRTP_192_LIB="" + fi + PBX_SRTP_192=1 + cat >>confdefs.h <<_ACEOF +#define HAVE_SRTP_192 1 +_ACEOF + + fi + fi +fi + + + +if test "x${PBX_SRTP_GCM}" != "x1" -a "${USE_SRTP_GCM}" != "no"; then + pbxlibdir="" + # if --with-SRTP_GCM=DIR has been specified, use it. + if test "x${SRTP_GCM_DIR}" != "x"; then + if test -d ${SRTP_GCM_DIR}/lib; then + pbxlibdir="-L${SRTP_GCM_DIR}/lib" + else + pbxlibdir="-L${SRTP_GCM_DIR}" + fi + fi + pbxfuncname="aes_gcm_128_openssl" + if test "x${pbxfuncname}" = "x" ; then # empty lib, assume only headers + AST_SRTP_GCM_FOUND=yes + else + ast_ext_lib_check_save_CFLAGS="${CFLAGS}" + CFLAGS="${CFLAGS} " + as_ac_Lib=`$as_echo "ac_cv_lib_srtp_${pbxfuncname}" | $as_tr_sh` +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lsrtp" >&5 +$as_echo_n "checking for ${pbxfuncname} in -lsrtp... " >&6; } +if eval \${$as_ac_Lib+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lsrtp ${pbxlibdir} $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char ${pbxfuncname} (); +int +main () +{ +return ${pbxfuncname} (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + eval "$as_ac_Lib=yes" +else + eval "$as_ac_Lib=no" +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +eval ac_res=\$$as_ac_Lib + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then : + AST_SRTP_GCM_FOUND=yes +else + AST_SRTP_GCM_FOUND=no +fi + + CFLAGS="${ast_ext_lib_check_save_CFLAGS}" + fi + + # now check for the header. + if test "${AST_SRTP_GCM_FOUND}" = "yes"; then + SRTP_GCM_LIB="${pbxlibdir} -lsrtp " + # if --with-SRTP_GCM=DIR has been specified, use it. + if test "x${SRTP_GCM_DIR}" != "x"; then + SRTP_GCM_INCLUDE="-I${SRTP_GCM_DIR}/include" + fi + SRTP_GCM_INCLUDE="${SRTP_GCM_INCLUDE} " + if test "x" = "x" ; then # no header, assume found + SRTP_GCM_HEADER_FOUND="1" + else # check for the header + ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}" + CPPFLAGS="${CPPFLAGS} ${SRTP_GCM_INCLUDE}" + ac_fn_c_check_header_mongrel "$LINENO" "" "ac_cv_header_" "$ac_includes_default" +if test "x$ac_cv_header_" = xyes; then : + SRTP_GCM_HEADER_FOUND=1 +else + SRTP_GCM_HEADER_FOUND=0 +fi + + + CPPFLAGS="${ast_ext_lib_check_saved_CPPFLAGS}" + fi + if test "x${SRTP_GCM_HEADER_FOUND}" = "x0" ; then + SRTP_GCM_LIB="" + SRTP_GCM_INCLUDE="" + else + if test "x${pbxfuncname}" = "x" ; then # only checking headers -> no library + SRTP_GCM_LIB="" + fi + PBX_SRTP_GCM=1 + cat >>confdefs.h <<_ACEOF +#define HAVE_SRTP_GCM 1 +_ACEOF + + fi + fi +fi + + +fi + if test "x${PBX_SRTP_SHUTDOWN}" != "x1" -a "${USE_SRTP_SHUTDOWN}" != "no"; then pbxlibdir="" diff --git a/configure.ac b/configure.ac index dedfd8a2e..ed6f8a8d4 100644 --- a/configure.ac +++ b/configure.ac @@ -529,6 +529,9 @@ AST_EXT_LIB_SETUP_DEPENDENT([SPEEX_PREPROCESS], [speex_preprocess_ctl], [], [spe AST_EXT_LIB_SETUP([SQLITE], [SQLite], [sqlite]) AST_EXT_LIB_SETUP([SQLITE3], [SQLite], [sqlite3]) AST_EXT_LIB_SETUP([SRTP], [Secure RTP], [srtp]) +AST_EXT_LIB_SETUP_OPTIONAL([SRTP_256], [SRTP Library AES-256 (ICM)], [SRTP], [srtp]) +AST_EXT_LIB_SETUP_OPTIONAL([SRTP_192], [SRTP Library AES-192 (ICM)], [SRTP], [srtp]) +AST_EXT_LIB_SETUP_OPTIONAL([SRTP_GCM], [SRTP Library AES-128 (GCM) and AES-256 (GCM)], [SRTP], [srtp]) AST_EXT_LIB_SETUP_OPTIONAL([SRTP_SHUTDOWN], [SRTP Library Shutdown Function], [SRTP], [srtp]) AST_EXT_LIB_SETUP([OPENSSL], [OpenSSL Secure Sockets Layer], [ssl]) AST_EXT_LIB_SETUP_OPTIONAL([RT], [Realtime functions], [rt]) @@ -1076,6 +1079,7 @@ AST_GCC_ATTRIBUTE(warn_unused_result) AST_GCC_ATTRIBUTE(may_alias) AST_GCC_ATTRIBUTE(constructor) AST_GCC_ATTRIBUTE(destructor) +AST_GCC_ATTRIBUTE(noreturn,noreturn) AC_MSG_CHECKING(for -fsanitize=address support) saved_sanitize_CFLAGS="${CFLAGS}" @@ -2450,6 +2454,13 @@ then CFLAGS="${saved_cflags}" fi +if test "$PBX_SRTP" = "1"; +then + AST_EXT_LIB_CHECK([SRTP_256], [srtp], [crypto_policy_set_aes_cm_256_hmac_sha1_80]) + AST_EXT_LIB_CHECK([SRTP_192], [srtp], [crypto_policy_set_aes_cm_192_hmac_sha1_80]) + AST_EXT_LIB_CHECK([SRTP_GCM], [srtp], [aes_gcm_128_openssl]) +fi + AST_EXT_LIB_CHECK([SRTP_SHUTDOWN], [srtp], [srtp_shutdown], [srtp/srtp.h]) for ver in 2.0 2.2 2.4 2.6; do diff --git a/contrib/ast-db-manage/config/versions/4a6c67fa9b7a_add_fax_detect_timeout_option.py b/contrib/ast-db-manage/config/versions/4a6c67fa9b7a_add_fax_detect_timeout_option.py new file mode 100644 index 000000000..91774c447 --- /dev/null +++ b/contrib/ast-db-manage/config/versions/4a6c67fa9b7a_add_fax_detect_timeout_option.py @@ -0,0 +1,23 @@ +"""add fax_detect_timeout option + +Revision ID: 4a6c67fa9b7a +Revises: 9deac0ae4717 +Create Date: 2016-07-18 18:20:44.249491 + +""" + +# revision identifiers, used by Alembic. +revision = '4a6c67fa9b7a' +down_revision = '9deac0ae4717' + +from alembic import op +import sqlalchemy as sa + + +def upgrade(): + op.add_column('ps_endpoints', sa.Column('fax_detect_timeout', sa.Integer)) + + +def downgrade(): + op.drop_column('ps_endpoints', 'fax_detect_timeout') + diff --git a/funcs/func_curl.c b/funcs/func_curl.c index 6a8c36767..8ec1032a7 100644 --- a/funcs/func_curl.c +++ b/funcs/func_curl.c @@ -856,6 +856,7 @@ static struct ast_custom_function acf_curlopt = { .write = acf_curlopt_write, }; +#ifdef TEST_FRAMEWORK AST_TEST_DEFINE(vulnerable_url) { const char *bad_urls [] = { @@ -903,6 +904,7 @@ AST_TEST_DEFINE(vulnerable_url) return res; } +#endif static int unload_module(void) { diff --git a/include/asterisk/autoconfig.h.in b/include/asterisk/autoconfig.h.in index 51f0f1462..b48257ec0 100644 --- a/include/asterisk/autoconfig.h.in +++ b/include/asterisk/autoconfig.h.in @@ -102,6 +102,9 @@ /* Define to 1 if your GCC C compiler supports the 'may_alias' attribute. */ #undef HAVE_ATTRIBUTE_may_alias +/* Define to 1 if your GCC C compiler supports the 'noreturn' attribute. */ +#undef HAVE_ATTRIBUTE_noreturn + /* Define to 1 if your GCC C compiler supports the 'pure' attribute. */ #undef HAVE_ATTRIBUTE_pure @@ -838,6 +841,16 @@ /* Define to 1 if you have the Secure RTP library. */ #undef HAVE_SRTP +/* Define to 1 if SRTP has the SRTP Library AES-192 (ICM) feature. */ +#undef HAVE_SRTP_192 + +/* Define to 1 if SRTP has the SRTP Library AES-256 (ICM) feature. */ +#undef HAVE_SRTP_256 + +/* Define to 1 if SRTP has the SRTP Library AES-128 (GCM) and AES-256 (GCM) + feature. */ +#undef HAVE_SRTP_GCM + /* Define to 1 if SRTP has the SRTP Library Shutdown Function feature. */ #undef HAVE_SRTP_SHUTDOWN diff --git a/include/asterisk/compiler.h b/include/asterisk/compiler.h index 77b5de40e..6ceaa5f77 100644 --- a/include/asterisk/compiler.h +++ b/include/asterisk/compiler.h @@ -77,6 +77,12 @@ #define attribute_may_alias #endif +#ifdef HAVE_ATTRIBUTE_noreturn +#define attribute_noreturn __attribute__((noreturn)) +#else +#define attribute_noreturn +#endif + /* Some older version of GNU gcc (3.3.5 on OpenBSD 4.3 for example) dont like 'NULL' as sentinel */ #define SENTINEL ((char *)NULL) diff --git a/include/asterisk/pbx.h b/include/asterisk/pbx.h index 378bb556d..d44a245e3 100644 --- a/include/asterisk/pbx.h +++ b/include/asterisk/pbx.h @@ -1228,10 +1228,10 @@ const char *ast_get_context_name(struct ast_context *con); const char *ast_get_extension_name(struct ast_exten *exten); struct ast_context *ast_get_extension_context(struct ast_exten *exten); const char *ast_get_include_name(const struct ast_include *include); -const char *ast_get_ignorepat_name(struct ast_ignorepat *ip); -const char *ast_get_switch_name(struct ast_sw *sw); -const char *ast_get_switch_data(struct ast_sw *sw); -int ast_get_switch_eval(struct ast_sw *sw); +const char *ast_get_ignorepat_name(const struct ast_ignorepat *ip); +const char *ast_get_switch_name(const struct ast_sw *sw); +const char *ast_get_switch_data(const struct ast_sw *sw); +int ast_get_switch_eval(const struct ast_sw *sw); /*! @} */ @@ -1250,8 +1250,8 @@ void *ast_get_extension_app_data(struct ast_exten *e); const char *ast_get_context_registrar(struct ast_context *c); const char *ast_get_extension_registrar(struct ast_exten *e); const char *ast_get_include_registrar(const struct ast_include *i); -const char *ast_get_ignorepat_registrar(struct ast_ignorepat *ip); -const char *ast_get_switch_registrar(struct ast_sw *sw); +const char *ast_get_ignorepat_registrar(const struct ast_ignorepat *ip); +const char *ast_get_switch_registrar(const struct ast_sw *sw); /*! @} */ /*! @name Walking functions ... */ @@ -1263,15 +1263,20 @@ struct ast_exten *ast_walk_extension_priorities(struct ast_exten *exten, struct ast_exten *priority); const struct ast_include *ast_walk_context_includes(const struct ast_context *con, const struct ast_include *inc); -struct ast_ignorepat *ast_walk_context_ignorepats(struct ast_context *con, - struct ast_ignorepat *ip); -struct ast_sw *ast_walk_context_switches(struct ast_context *con, struct ast_sw *sw); +const struct ast_ignorepat *ast_walk_context_ignorepats(const struct ast_context *con, + const struct ast_ignorepat *ip); +const struct ast_sw *ast_walk_context_switches(const struct ast_context *con, + const struct ast_sw *sw); /*! @} */ /*! @name Iterator functions ... */ /*! @{ */ int ast_context_includes_count(const struct ast_context *con); const struct ast_include *ast_context_includes_get(const struct ast_context *con, int idx); +int ast_context_ignorepats_count(const struct ast_context *con); +const struct ast_ignorepat *ast_context_ignorepats_get(const struct ast_context *con, int idx); +int ast_context_switches_count(const struct ast_context *con); +const struct ast_sw *ast_context_switches_get(const struct ast_context *con, int idx); /*! @} */ /*! diff --git a/include/asterisk/res_fax.h b/include/asterisk/res_fax.h index 2304da734..5119bfa6c 100644 --- a/include/asterisk/res_fax.h +++ b/include/asterisk/res_fax.h @@ -179,11 +179,11 @@ struct ast_fax_session_details { unsigned int t38timeout; /*! the id of the t.38 gateway framehook for this channel */ int gateway_id; - /*! the timeout for this gateway in seconds */ + /*! The timeout for this gateway in ms */ int gateway_timeout; /*! the id of the faxdetect framehook for this channel */ int faxdetect_id; - /*! The timeout for this fax detect in seconds */ + /*! The timeout for this fax detect in ms */ int faxdetect_timeout; /*! flags used for fax detection */ int faxdetect_flags; diff --git a/include/asterisk/res_pjsip.h b/include/asterisk/res_pjsip.h index 6f5928365..9bb2a82c5 100644 --- a/include/asterisk/res_pjsip.h +++ b/include/asterisk/res_pjsip.h @@ -749,10 +749,12 @@ struct ast_sip_endpoint { unsigned int usereqphone; /*! Whether to pass through hold and unhold using re-invites with recvonly and sendrecv */ unsigned int moh_passthrough; - /* Access control list */ + /*! Access control list */ struct ast_acl_list *acl; - /* Restrict what IPs are allowed in the Contact header (for registration) */ + /*! Restrict what IPs are allowed in the Contact header (for registration) */ struct ast_acl_list *contact_acl; + /*! The number of seconds into call to disable fax detection. (0 = disabled) */ + unsigned int faxdetect_timeout; }; /*! diff --git a/include/asterisk/res_pjsip_session.h b/include/asterisk/res_pjsip_session.h index 5ca2c99a5..26dd451a7 100644 --- a/include/asterisk/res_pjsip_session.h +++ b/include/asterisk/res_pjsip_session.h @@ -139,7 +139,7 @@ struct ast_sip_session { struct ast_party_id id; /*! Requested capabilities */ struct ast_format_cap *req_caps; - /*! Optional DSP, used only for inband DTMF detection if configured */ + /*! Optional DSP, used only for inband DTMF/Fax-CNG detection if configured */ struct ast_dsp *dsp; /*! Whether the termination of the session should be deferred */ unsigned int defer_terminate:1; diff --git a/include/asterisk/res_srtp.h b/include/asterisk/res_srtp.h index c7fdc40b7..741d4f9ac 100644 --- a/include/asterisk/res_srtp.h +++ b/include/asterisk/res_srtp.h @@ -21,6 +21,8 @@ #ifndef _ASTERISK_RES_SRTP_H #define _ASTERISK_RES_SRTP_H +#include "asterisk.h" /* for size_t */ + struct ast_srtp; struct ast_srtp_policy; struct ast_rtp_instance; @@ -52,9 +54,17 @@ struct ast_srtp_res { /* Crypto suites */ enum ast_srtp_suite { + /* https://www.iana.org/assignments/srtp-protection/srtp-protection.xhtml */ AST_AES_CM_128_HMAC_SHA1_80 = 1, - AST_AES_CM_128_HMAC_SHA1_32 = 2, - AST_F8_128_HMAC_SHA1_80 = 3 + AST_AES_CM_128_HMAC_SHA1_32, + AST_AES_CM_256_HMAC_SHA1_80, + AST_AES_CM_256_HMAC_SHA1_32, + AST_AES_GCM_128 = 7, + AST_AES_GCM_256, + AST_AES_GCM_128_8, + AST_AES_GCM_256_8, + AST_AES_CM_192_HMAC_SHA1_80, + AST_AES_CM_192_HMAC_SHA1_32, }; struct ast_srtp_policy_res { diff --git a/include/asterisk/sdp_srtp.h b/include/asterisk/sdp_srtp.h index 772c3c38d..5d8f0e7d1 100644 --- a/include/asterisk/sdp_srtp.h +++ b/include/asterisk/sdp_srtp.h @@ -20,8 +20,7 @@ * * \brief SRTP and SDP Security descriptions * - * Specified in RFC 4568 - * Specified in RFC 3711 + * Specified in RFC 3711, 6188, 7714, and 4568 * * \author Mikael Magnusson <mikma@users.sourceforge.net> */ @@ -29,7 +28,8 @@ #ifndef _SDP_SRTP_H #define _SDP_SRTP_H -#include <asterisk/rtp_engine.h> +#include "asterisk/linkedlists.h" /* for AST_LIST_ENTRY */ +#include "asterisk/rtp_engine.h" /* for ast_rtp_instance */ struct ast_sdp_crypto; @@ -37,12 +37,18 @@ struct ast_sdp_crypto; struct ast_sdp_srtp { unsigned int flags; struct ast_sdp_crypto *crypto; + AST_LIST_ENTRY(ast_sdp_srtp) sdp_srtp_list; }; /* SRTP flags */ -#define AST_SRTP_CRYPTO_OFFER_OK (1 << 1) -#define AST_SRTP_CRYPTO_TAG_32 (1 << 2) -#define AST_SRTP_CRYPTO_TAG_80 (1 << 3) +#define AST_SRTP_CRYPTO_OFFER_OK (1 << 1) +#define AST_SRTP_CRYPTO_TAG_32 (1 << 2) +#define AST_SRTP_CRYPTO_TAG_80 (1 << 3) +#define AST_SRTP_CRYPTO_TAG_16 (1 << 4) +#define AST_SRTP_CRYPTO_TAG_8 (1 << 5) +#define AST_SRTP_CRYPTO_AES_192 (1 << 6) +#define AST_SRTP_CRYPTO_AES_256 (1 << 7) +#define AST_SRTP_CRYPTO_OLD_NAME (1 << 8) /*! * \brief allocate a ast_sdp_srtp structure diff --git a/include/asterisk/utils.h b/include/asterisk/utils.h index c7a473732..c311e9cd5 100644 --- a/include/asterisk/utils.h +++ b/include/asterisk/utils.h @@ -843,9 +843,14 @@ struct ast_http_digest { */ int ast_parse_digest(const char *digest, struct ast_http_digest *d, int request, int pedantic); +#ifdef DO_CRASH +#define DO_CRASH_NORETURN attribute_noreturn +#else +#define DO_CRASH_NORETURN +#endif #ifdef AST_DEVMODE -void __ast_assert_failed(int condition, const char *condition_str, const char *file, int line, const char *function); +void DO_CRASH_NORETURN __ast_assert_failed(int condition, const char *condition_str, const char *file, int line, const char *function); #define ast_assert(a) _ast_assert(a, # a, __FILE__, __LINE__, __PRETTY_FUNCTION__) static void force_inline _ast_assert(int condition, const char *condition_str, const char *file, int line, const char *function) { @@ -864,7 +869,7 @@ static void force_inline _ast_assert(int condition, const char *condition_str, c * * \return Nothing */ -void ast_do_crash(void); +void DO_CRASH_NORETURN ast_do_crash(void); #include "asterisk/strings.h" diff --git a/main/channel.c b/main/channel.c index f654e4d25..911c26955 100644 --- a/main/channel.c +++ b/main/channel.c @@ -2692,10 +2692,28 @@ void ast_hangup(struct ast_channel *chan) ast_channel_unref(chan); } +/*! + * \internal + * \brief Set channel answered time if not already set. + * \since 13.11.0 + * + * \param chan Channel to set answered time. + * + * \return Nothing + */ +static void set_channel_answer_time(struct ast_channel *chan) +{ + if (ast_tvzero(ast_channel_answertime(chan))) { + struct timeval answertime; + + answertime = ast_tvnow(); + ast_channel_answertime_set(chan, &answertime); + } +} + int ast_raw_answer(struct ast_channel *chan) { int res = 0; - struct timeval answertime; ast_channel_lock(chan); @@ -2711,8 +2729,11 @@ int ast_raw_answer(struct ast_channel *chan) return -1; } - answertime = ast_tvnow(); - ast_channel_answertime_set(chan, &answertime); + /* + * Mark when incoming channel answered so we can know how + * long the channel has been up. + */ + set_channel_answer_time(chan); ast_channel_unlock(chan); @@ -3911,6 +3932,12 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio) ast_frfree(f); f = &ast_null_frame; } else { + /* + * Mark when outgoing channel answered so we can know how + * long the channel has been up. + */ + set_channel_answer_time(chan); + ast_setstate(chan, AST_STATE_UP); } } else if (f->subclass.integer == AST_CONTROL_READ_ACTION) { diff --git a/main/pbx.c b/main/pbx.c index f6768bb54..f9fad0388 100644 --- a/main/pbx.c +++ b/main/pbx.c @@ -255,23 +255,6 @@ struct ast_exten { char stuff[0]; }; -/*! \brief ast_sw: Switch statement in extensions.conf */ -struct ast_sw { - char *name; - const char *registrar; /*!< Registrar */ - char *data; /*!< Data load */ - int eval; - AST_LIST_ENTRY(ast_sw) list; - char stuff[0]; -}; - -/*! \brief ast_ignorepat: Ignore patterns in dial plan */ -struct ast_ignorepat { - const char *registrar; - struct ast_ignorepat *next; - const char pattern[0]; -}; - /*! \brief match_char: forms a syntax tree for quick matching of extension patterns */ struct match_char { @@ -303,11 +286,11 @@ struct ast_context { struct match_char *pattern_tree; /*!< A tree to speed up extension pattern matching */ struct ast_context *next; /*!< Link them together */ struct ast_includes includes; /*!< Include other contexts */ - struct ast_ignorepat *ignorepats; /*!< Patterns for which to continue playing dialtone */ + struct ast_ignorepats ignorepats; /*!< Patterns for which to continue playing dialtone */ + struct ast_sws alts; /*!< Alternative switches */ char *registrar; /*!< Registrar -- make sure you malloc this, as the registrar may have to survive module unloads */ int refcount; /*!< each module that would have created this context should inc/dec this as appropriate */ int autohints; /*!< Whether autohints support is enabled or not */ - AST_LIST_HEAD_NOLOCK(, ast_sw) alts; /*!< Alternative switches */ ast_mutex_t macrolock; /*!< A lock to implement "exclusive" macros - held whilst a call is executing in the macro */ char name[0]; /*!< Name of the context */ }; @@ -2381,11 +2364,11 @@ struct fake_context /* this struct is purely for matching in the hashtab */ struct match_char *pattern_tree; struct ast_context *next; struct ast_includes includes; - struct ast_ignorepat *ignorepats; + struct ast_ignorepats ignorepats; + struct ast_sws alts; const char *registrar; int refcount; int autohints; - AST_LIST_HEAD_NOLOCK(, ast_sw) alts; ast_mutex_t macrolock; char name[256]; }; @@ -2440,7 +2423,6 @@ struct ast_exten *pbx_find_extension(struct ast_channel *chan, int x, res; struct ast_context *tmp = NULL; struct ast_exten *e = NULL, *eroot = NULL; - struct ast_sw *sw = NULL; struct ast_exten pattern = {NULL, }; struct scoreboard score = {0, }; struct ast_str *tmpdata = NULL; @@ -2664,23 +2646,28 @@ struct ast_exten *pbx_find_extension(struct ast_channel *chan, } /* Check alternative switches */ - AST_LIST_TRAVERSE(&tmp->alts, sw, list) { - struct ast_switch *asw = pbx_findswitch(sw->name); + for (idx = 0; idx < ast_context_switches_count(tmp); idx++) { + const struct ast_sw *sw = ast_context_switches_get(tmp, idx); + struct ast_switch *asw = pbx_findswitch(ast_get_switch_name(sw)); ast_switch_f *aswf = NULL; - char *datap; + const char *datap; if (!asw) { - ast_log(LOG_WARNING, "No such switch '%s'\n", sw->name); + ast_log(LOG_WARNING, "No such switch '%s'\n", ast_get_switch_name(sw)); continue; } /* Substitute variables now */ - if (sw->eval) { + if (ast_get_switch_eval(sw)) { if (!(tmpdata = ast_str_thread_get(&switch_data, 512))) { ast_log(LOG_WARNING, "Can't evaluate switch?!\n"); continue; } - pbx_substitute_variables_helper(chan, sw->data, ast_str_buffer(tmpdata), ast_str_size(tmpdata)); + pbx_substitute_variables_helper(chan, ast_get_switch_data(sw), + ast_str_buffer(tmpdata), ast_str_size(tmpdata)); + datap = ast_str_buffer(tmpdata); + } else { + datap = ast_get_switch_data(sw); } /* equivalent of extension_match_core() at the switch level */ @@ -2690,7 +2677,6 @@ struct ast_exten *pbx_find_extension(struct ast_channel *chan, aswf = asw->matchmore; else /* action == E_MATCH */ aswf = asw->exists; - datap = sw->eval ? ast_str_buffer(tmpdata) : sw->data; if (!aswf) res = 0; else { @@ -4826,24 +4812,29 @@ int ast_context_remove_switch(const char *context, const char *sw, const char *d */ int ast_context_remove_switch2(struct ast_context *con, const char *sw, const char *data, const char *registrar) { - struct ast_sw *i; + int idx; int ret = -1; ast_wrlock_context(con); /* walk switches */ - AST_LIST_TRAVERSE_SAFE_BEGIN(&con->alts, i, list) { - if (!strcmp(i->name, sw) && !strcmp(i->data, data) && - (!registrar || !strcmp(i->registrar, registrar))) { + for (idx = 0; idx < ast_context_switches_count(con); idx++) { + struct ast_sw *i = AST_VECTOR_GET(&con->alts, idx); + + if (!strcmp(ast_get_switch_name(i), sw) && + !strcmp(ast_get_switch_data(i), data) && + (!registrar || !strcmp(ast_get_switch_registrar(i), registrar))) { + /* found, remove from list */ ast_verb(3, "Removing switch '%s' from context '%s; registrar=%s'\n", sw, ast_get_context_name(con), registrar); - AST_LIST_REMOVE_CURRENT(list); - ast_free(i); /* free switch and return */ + AST_VECTOR_REMOVE_ORDERED(&con->alts, idx); + + /* free switch and return */ + sw_free(i); ret = 0; break; } } - AST_LIST_TRAVERSE_SAFE_END; ast_unlock_context(con); @@ -5394,7 +5385,6 @@ static int show_dialplan_helper(int fd, const char *context, const char *exten, while ( (c = ast_walk_contexts(c)) ) { int idx; struct ast_exten *e; - struct ast_ignorepat *ip; #ifndef LOW_MEMORY char buf[1024], buf2[1024]; #else @@ -5512,10 +5502,11 @@ static int show_dialplan_helper(int fd, const char *context, const char *exten, } /* walk ignore patterns and write info ... */ - ip = NULL; - while ( (ip = ast_walk_context_ignorepats(c, ip)) ) { + for (idx = 0; idx < ast_context_ignorepats_count(c); idx++) { + const struct ast_ignorepat *ip = ast_context_ignorepats_get(c, idx); const char *ipname = ast_get_ignorepat_name(ip); char ignorepat[AST_MAX_EXTENSION]; + snprintf(buf, sizeof(buf), "'%s'", ipname); snprintf(ignorepat, sizeof(ignorepat), "_%s.", ipname); if (!exten || ast_extension_match(ignorepat, exten)) { @@ -5524,8 +5515,9 @@ static int show_dialplan_helper(int fd, const char *context, const char *exten, } } if (!rinclude) { - struct ast_sw *sw = NULL; - while ( (sw = ast_walk_context_switches(c, sw)) ) { + for (idx = 0; idx < ast_context_switches_count(c); idx++) { + const struct ast_sw *sw = ast_context_switches_get(c, idx); + snprintf(buf, sizeof(buf), "'%s/%s'", ast_get_switch_name(sw), ast_get_switch_data(sw)); @@ -5758,7 +5750,6 @@ static int manager_show_dialplan_helper(struct mansession *s, const struct messa while ( (c = ast_walk_contexts(c)) ) { int idx; struct ast_exten *e; - struct ast_ignorepat *ip; if (context && strcmp(ast_get_context_name(c), context) != 0) continue; /* not the name we want */ @@ -5829,8 +5820,8 @@ static int manager_show_dialplan_helper(struct mansession *s, const struct messa } } - ip = NULL; /* walk ignore patterns and write info ... */ - while ( (ip = ast_walk_context_ignorepats(c, ip)) ) { + for (idx = 0; idx < ast_context_ignorepats_count(c); idx++) { + const struct ast_ignorepat *ip = ast_context_ignorepats_get(c, idx); const char *ipname = ast_get_ignorepat_name(ip); char ignorepat[AST_MAX_EXTENSION]; @@ -5844,8 +5835,9 @@ static int manager_show_dialplan_helper(struct mansession *s, const struct messa } } if (!rinclude) { - struct ast_sw *sw = NULL; - while ( (sw = ast_walk_context_switches(c, sw)) ) { + for (idx = 0; idx < ast_context_switches_count(c); idx++) { + const struct ast_sw *sw = ast_context_switches_get(c, idx); + if (!dpc->total_items++) manager_dpsendack(s, m); astman_append(s, "Event: ListDialplan\r\n%s", actionidtext); @@ -6094,7 +6086,8 @@ struct ast_context *ast_context_find_or_create(struct ast_context **extcontexts, tmp->root_table = NULL; tmp->registrar = ast_strdup(registrar); AST_VECTOR_INIT(&tmp->includes, 0); - tmp->ignorepats = NULL; + AST_VECTOR_INIT(&tmp->ignorepats, 0); + AST_VECTOR_INIT(&tmp->alts, 0); tmp->refcount = 1; } else { ast_log(LOG_ERROR, "Danger! We failed to allocate a context for %s!\n", name); @@ -6146,8 +6139,6 @@ AST_LIST_HEAD_NOLOCK(store_hints, store_hint); static void context_merge_incls_swits_igps_other_registrars(struct ast_context *new, struct ast_context *old, const char *registrar) { int idx; - struct ast_ignorepat *ip; - struct ast_sw *sw; ast_verb(3, "merging incls/swits/igpats from old(%s) to new(%s) context, registrar = %s\n", ast_get_context_name(old), ast_get_context_name(new), registrar); /* copy in the includes, switches, and ignorepats */ @@ -6162,16 +6153,22 @@ static void context_merge_incls_swits_igps_other_registrars(struct ast_context * } /* walk through switches */ - for (sw = NULL; (sw = ast_walk_context_switches(old, sw)) ; ) { - if (strcmp(ast_get_switch_registrar(sw), registrar) == 0) + for (idx = 0; idx < ast_context_switches_count(old); idx++) { + const struct ast_sw *sw = ast_context_switches_get(old, idx); + + if (!strcmp(ast_get_switch_registrar(sw), registrar)) { continue; /* not mine */ + } ast_context_add_switch2(new, ast_get_switch_name(sw), ast_get_switch_data(sw), ast_get_switch_eval(sw), ast_get_switch_registrar(sw)); } /* walk thru ignorepats ... */ - for (ip = NULL; (ip = ast_walk_context_ignorepats(old, ip)); ) { - if (strcmp(ast_get_ignorepat_registrar(ip), registrar) == 0) + for (idx = 0; idx < ast_context_ignorepats_count(old); idx++) { + const struct ast_ignorepat *ip = ast_context_ignorepats_get(old, idx); + + if (strcmp(ast_get_ignorepat_registrar(ip), registrar) == 0) { continue; /* not mine */ + } ast_context_add_ignorepat2(new, ast_get_ignorepat_name(ip), ast_get_ignorepat_registrar(ip)); } } @@ -6628,43 +6625,24 @@ int ast_context_add_switch(const char *context, const char *sw, const char *data int ast_context_add_switch2(struct ast_context *con, const char *value, const char *data, int eval, const char *registrar) { + int idx; struct ast_sw *new_sw; - struct ast_sw *i; - int length; - char *p; - - length = sizeof(struct ast_sw); - length += strlen(value) + 1; - if (data) - length += strlen(data); - length++; /* allocate new sw structure ... */ - if (!(new_sw = ast_calloc(1, length))) + if (!(new_sw = sw_alloc(value, data, eval, registrar))) { return -1; - /* ... fill in this structure ... */ - p = new_sw->stuff; - new_sw->name = p; - strcpy(new_sw->name, value); - p += strlen(value) + 1; - new_sw->data = p; - if (data) { - strcpy(new_sw->data, data); - p += strlen(data) + 1; - } else { - strcpy(new_sw->data, ""); - p++; } - new_sw->eval = eval; - new_sw->registrar = registrar; /* ... try to lock this context ... */ ast_wrlock_context(con); /* ... go to last sw and check if context is already swd too... */ - AST_LIST_TRAVERSE(&con->alts, i, list) { - if (!strcasecmp(i->name, new_sw->name) && !strcasecmp(i->data, new_sw->data)) { - ast_free(new_sw); + for (idx = 0; idx < ast_context_switches_count(con); idx++) { + const struct ast_sw *i = ast_context_switches_get(con, idx); + + if (!strcasecmp(ast_get_switch_name(i), ast_get_switch_name(new_sw)) && + !strcasecmp(ast_get_switch_data(i), ast_get_switch_data(new_sw))) { + sw_free(new_sw); ast_unlock_context(con); errno = EEXIST; return -1; @@ -6672,9 +6650,10 @@ int ast_context_add_switch2(struct ast_context *con, const char *value, } /* ... sw new context into context list, unlock, return */ - AST_LIST_INSERT_TAIL(&con->alts, new_sw, list); + AST_VECTOR_APPEND(&con->alts, new_sw); - ast_verb(3, "Including switch '%s/%s' in context '%s'\n", new_sw->name, new_sw->data, ast_get_context_name(con)); + ast_verb(3, "Including switch '%s/%s' in context '%s'\n", + ast_get_switch_name(new_sw), ast_get_switch_data(new_sw), ast_get_context_name(con)); ast_unlock_context(con); @@ -6700,24 +6679,20 @@ int ast_context_remove_ignorepat(const char *context, const char *ignorepat, con int ast_context_remove_ignorepat2(struct ast_context *con, const char *ignorepat, const char *registrar) { - struct ast_ignorepat *ip, *ipl = NULL; + int idx; ast_wrlock_context(con); - for (ip = con->ignorepats; ip; ip = ip->next) { - if (!strcmp(ip->pattern, ignorepat) && - (!registrar || (registrar == ip->registrar))) { - if (ipl) { - ipl->next = ip->next; - ast_free(ip); - } else { - con->ignorepats = ip->next; - ast_free(ip); - } + for (idx = 0; idx < ast_context_ignorepats_count(con); idx++) { + struct ast_ignorepat *ip = AST_VECTOR_GET(&con->ignorepats, idx); + + if (!strcmp(ast_get_ignorepat_name(ip), ignorepat) && + (!registrar || (registrar == ast_get_ignorepat_registrar(ip)))) { + AST_VECTOR_REMOVE_ORDERED(&con->ignorepats, idx); + ignorepat_free(ip); ast_unlock_context(con); return 0; } - ipl = ip; } ast_unlock_context(con); @@ -6744,41 +6719,29 @@ int ast_context_add_ignorepat(const char *context, const char *value, const char int ast_context_add_ignorepat2(struct ast_context *con, const char *value, const char *registrar) { - struct ast_ignorepat *ignorepat, *ignorepatc, *ignorepatl = NULL; - int length; - char *pattern; - length = sizeof(struct ast_ignorepat); - length += strlen(value) + 1; - if (!(ignorepat = ast_calloc(1, length))) + struct ast_ignorepat *ignorepat = ignorepat_alloc(value, registrar); + int idx; + + if (!ignorepat) { return -1; - /* The cast to char * is because we need to write the initial value. - * The field is not supposed to be modified otherwise. Also, gcc 4.2 - * sees the cast as dereferencing a type-punned pointer and warns about - * it. This is the workaround (we're telling gcc, yes, that's really - * what we wanted to do). - */ - pattern = (char *) ignorepat->pattern; - strcpy(pattern, value); - ignorepat->next = NULL; - ignorepat->registrar = registrar; + } + ast_wrlock_context(con); - for (ignorepatc = con->ignorepats; ignorepatc; ignorepatc = ignorepatc->next) { - ignorepatl = ignorepatc; - if (!strcasecmp(ignorepatc->pattern, value)) { + for (idx = 0; idx < ast_context_ignorepats_count(con); idx++) { + const struct ast_ignorepat *i = ast_context_ignorepats_get(con, idx); + + if (!strcasecmp(ast_get_ignorepat_name(i), value)) { /* Already there */ ast_unlock_context(con); - ast_free(ignorepat); + ignorepat_free(ignorepat); errno = EEXIST; return -1; } } - if (ignorepatl) - ignorepatl->next = ignorepat; - else - con->ignorepats = ignorepat; + AST_VECTOR_APPEND(&con->ignorepats, ignorepat); ast_unlock_context(con); - return 0; + return 0; } int ast_ignore_pattern(const char *context, const char *pattern) @@ -6789,10 +6752,12 @@ int ast_ignore_pattern(const char *context, const char *pattern) ast_rdlock_contexts(); con = ast_context_find(context); if (con) { - struct ast_ignorepat *pat; + int idx; - for (pat = con->ignorepats; pat; pat = pat->next) { - if (ast_extension_match(pat->pattern, pattern)) { + for (idx = 0; idx < ast_context_ignorepats_count(con); idx++) { + const struct ast_ignorepat *pat = ast_context_ignorepats_get(con, idx); + + if (ast_extension_match(ast_get_ignorepat_name(pat), pattern)) { ret = 1; break; } @@ -7795,20 +7760,21 @@ int ast_pbx_outgoing_app(const char *type, struct ast_format_cap *cap, const cha static void __ast_internal_context_destroy( struct ast_context *con) { - struct ast_sw *sw; struct ast_exten *e, *el, *en; - struct ast_ignorepat *ipi; struct ast_context *tmp = con; /* Free includes */ AST_VECTOR_CALLBACK_VOID(&tmp->includes, include_free); AST_VECTOR_FREE(&tmp->includes); - for (ipi = tmp->ignorepats; ipi; ) { /* Free ignorepats */ - struct ast_ignorepat *ipl = ipi; - ipi = ipi->next; - ast_free(ipl); - } + /* Free ignorepats */ + AST_VECTOR_CALLBACK_VOID(&tmp->ignorepats, ignorepat_free); + AST_VECTOR_FREE(&tmp->ignorepats); + + /* Free switches */ + AST_VECTOR_CALLBACK_VOID(&tmp->alts, sw_free); + AST_VECTOR_FREE(&tmp->alts); + if (tmp->registrar) ast_free(tmp->registrar); @@ -7820,8 +7786,6 @@ static void __ast_internal_context_destroy( struct ast_context *con) if (tmp->pattern_tree) destroy_pattern_tree(tmp->pattern_tree); - while ((sw = AST_LIST_REMOVE_HEAD(&tmp->alts, list))) - ast_free(sw); for (e = tmp->root; e;) { for (en = e->peer; en;) { el = en; @@ -7868,25 +7832,16 @@ void __ast_context_destroy(struct ast_context *list, struct ast_hashtab *context /* then search thru and remove any extens that match registrar. */ struct ast_hashtab_iter *exten_iter; struct ast_hashtab_iter *prio_iter; - struct ast_ignorepat *ip, *ipl = NULL, *ipn = NULL; - struct ast_sw *sw = NULL; int idx; /* remove any ignorepats whose registrar matches */ - for (ip = tmp->ignorepats; ip; ip = ipn) { - ipn = ip->next; - if (!strcmp(ip->registrar, registrar)) { - if (ipl) { - ipl->next = ip->next; - ast_free(ip); - continue; /* don't change ipl */ - } else { - tmp->ignorepats = ip->next; - ast_free(ip); - continue; /* don't change ipl */ - } + for (idx = ast_context_ignorepats_count(tmp) - 1; idx >= 0; idx--) { + struct ast_ignorepat *ip = AST_VECTOR_GET(&tmp->ignorepats, idx); + + if (!strcmp(ast_get_ignorepat_registrar(ip), registrar)) { + AST_VECTOR_REMOVE_ORDERED(&tmp->ignorepats, idx); + ignorepat_free(ip); } - ipl = ip; } /* remove any includes whose registrar matches */ for (idx = ast_context_includes_count(tmp) - 1; idx >= 0; idx--) { @@ -7898,13 +7853,14 @@ void __ast_context_destroy(struct ast_context *list, struct ast_hashtab *context } } /* remove any switches whose registrar matches */ - AST_LIST_TRAVERSE_SAFE_BEGIN(&tmp->alts, sw, list) { - if (strcmp(sw->registrar,registrar) == 0) { - AST_LIST_REMOVE_CURRENT(list); - ast_free(sw); + for (idx = ast_context_switches_count(tmp) - 1; idx >= 0; idx--) { + struct ast_sw *sw = AST_VECTOR_GET(&tmp->alts, idx); + + if (!strcmp(ast_get_switch_registrar(sw), registrar)) { + AST_VECTOR_REMOVE_ORDERED(&tmp->alts, idx); + sw_free(sw); } } - AST_LIST_TRAVERSE_SAFE_END; if (tmp->root_table) { /* it is entirely possible that the context is EMPTY */ exten_iter = ast_hashtab_start_traversal(tmp->root_table); @@ -7955,7 +7911,7 @@ void __ast_context_destroy(struct ast_context *list, struct ast_hashtab *context /* delete the context if it's registrar matches, is empty, has refcount of 1, */ /* it's not empty, if it has includes, ignorepats, or switches that are registered from another registrar. It's not empty if there are any extensions */ - if (strcmp(tmp->registrar, registrar) == 0 && tmp->refcount < 2 && !tmp->root && !tmp->ignorepats && !ast_context_includes_count(tmp) && AST_LIST_EMPTY(&tmp->alts)) { + if (strcmp(tmp->registrar, registrar) == 0 && tmp->refcount < 2 && !tmp->root && !ast_context_ignorepats_count(tmp) && !ast_context_includes_count(tmp) && !ast_context_switches_count(tmp)) { ast_debug(1, "delete ctx %s %s\n", tmp->name, tmp->registrar); ast_hashtab_remove_this_object(contexttab, tmp); @@ -8356,11 +8312,6 @@ const char *ast_get_extension_label(struct ast_exten *exten) return exten ? exten->label : NULL; } -const char *ast_get_ignorepat_name(struct ast_ignorepat *ip) -{ - return ip ? ip->pattern : NULL; -} - int ast_get_extension_priority(struct ast_exten *exten) { return exten ? exten->priority : -1; @@ -8379,11 +8330,6 @@ const char *ast_get_extension_registrar(struct ast_exten *e) return e ? e->registrar : NULL; } -const char *ast_get_ignorepat_registrar(struct ast_ignorepat *ip) -{ - return ip ? ip->registrar : NULL; -} - int ast_get_extension_matchcid(struct ast_exten *e) { return e ? e->matchcid : 0; @@ -8404,26 +8350,6 @@ void *ast_get_extension_app_data(struct ast_exten *e) return e ? e->data : NULL; } -const char *ast_get_switch_name(struct ast_sw *sw) -{ - return sw ? sw->name : NULL; -} - -const char *ast_get_switch_data(struct ast_sw *sw) -{ - return sw ? sw->data : NULL; -} - -int ast_get_switch_eval(struct ast_sw *sw) -{ - return sw->eval; -} - -const char *ast_get_switch_registrar(struct ast_sw *sw) -{ - return sw ? sw->registrar : NULL; -} - /* * Walking functions ... */ @@ -8441,13 +8367,43 @@ struct ast_exten *ast_walk_context_extensions(struct ast_context *con, return exten->next; } -struct ast_sw *ast_walk_context_switches(struct ast_context *con, - struct ast_sw *sw) +const struct ast_sw *ast_walk_context_switches(const struct ast_context *con, + const struct ast_sw *sw) { - if (!sw) - return con ? AST_LIST_FIRST(&con->alts) : NULL; - else - return AST_LIST_NEXT(sw, list); + if (sw) { + int idx; + int next = 0; + + for (idx = 0; idx < ast_context_switches_count(con); idx++) { + const struct ast_sw *s = ast_context_switches_get(con, idx); + + if (next) { + return s; + } + + if (sw == s) { + next = 1; + } + } + + return NULL; + } + + if (!ast_context_switches_count(con)) { + return NULL; + } + + return ast_context_switches_get(con, 0); +} + +int ast_context_switches_count(const struct ast_context *con) +{ + return AST_VECTOR_SIZE(&con->alts); +} + +const struct ast_sw *ast_context_switches_get(const struct ast_context *con, int idx) +{ + return AST_VECTOR_GET(&con->alts, idx); } struct ast_exten *ast_walk_extension_priorities(struct ast_exten *exten, @@ -8495,13 +8451,47 @@ const struct ast_include *ast_context_includes_get(const struct ast_context *con return AST_VECTOR_GET(&con->includes, idx); } -struct ast_ignorepat *ast_walk_context_ignorepats(struct ast_context *con, - struct ast_ignorepat *ip) +const struct ast_ignorepat *ast_walk_context_ignorepats(const struct ast_context *con, + const struct ast_ignorepat *ip) { - if (!ip) - return con ? con->ignorepats : NULL; - else - return ip->next; + if (!con) { + return NULL; + } + + if (ip) { + int idx; + int next = 0; + + for (idx = 0; idx < ast_context_ignorepats_count(con); idx++) { + const struct ast_ignorepat *i = ast_context_ignorepats_get(con, idx); + + if (next) { + return i; + } + + if (ip == i) { + next = 1; + } + } + + return NULL; + } + + if (!ast_context_ignorepats_count(con)) { + return NULL; + } + + return ast_context_ignorepats_get(con, 0); +} + +int ast_context_ignorepats_count(const struct ast_context *con) +{ + return AST_VECTOR_SIZE(&con->ignorepats); +} + +const struct ast_ignorepat *ast_context_ignorepats_get(const struct ast_context *con, int idx) +{ + return AST_VECTOR_GET(&con->ignorepats, idx); } int ast_context_verify_includes(struct ast_context *con) diff --git a/main/pbx_ignorepat.c b/main/pbx_ignorepat.c new file mode 100644 index 000000000..1a2232c57 --- /dev/null +++ b/main/pbx_ignorepat.c @@ -0,0 +1,82 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2016, CFWare, LLC + * + * Corey Farrell <git@cfware.com> + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +/*! \file + * + * \brief Dialplan context ignorepat routines. + * + * \author Corey Farrell <git@cfware.com> + */ + +/*** MODULEINFO + <support_level>core</support_level> + ***/ + +#include "asterisk.h" + +ASTERISK_REGISTER_FILE() + +#include "asterisk/_private.h" +#include "asterisk/pbx.h" +#include "pbx_private.h" + +/*! \brief ast_ignorepat: Ignore patterns in dial plan */ +struct ast_ignorepat { + const char *registrar; + const char pattern[0]; +}; + +const char *ast_get_ignorepat_name(const struct ast_ignorepat *ip) +{ + return ip ? ip->pattern : NULL; +} + +const char *ast_get_ignorepat_registrar(const struct ast_ignorepat *ip) +{ + return ip ? ip->registrar : NULL; +} + +struct ast_ignorepat *ignorepat_alloc(const char *value, const char *registrar) +{ + struct ast_ignorepat *ignorepat; + int length = strlen(value) + 1; + char *pattern; + + /* allocate new include structure ... */ + ignorepat = ast_calloc(1, sizeof(*ignorepat) + length); + if (!ignorepat) { + return NULL; + } + + /* The cast to char * is because we need to write the initial value. + * The field is not supposed to be modified otherwise. Also, gcc 4.2 + * sees the cast as dereferencing a type-punned pointer and warns about + * it. This is the workaround (we're telling gcc, yes, that's really + * what we wanted to do). + */ + pattern = (char *) ignorepat->pattern; + strcpy(pattern, value); + ignorepat->registrar = registrar; + + return ignorepat; +} + +void ignorepat_free(struct ast_ignorepat *ip) +{ + ast_free(ip); +} diff --git a/main/pbx_private.h b/main/pbx_private.h index 22d454ad0..da1060e0e 100644 --- a/main/pbx_private.h +++ b/main/pbx_private.h @@ -31,6 +31,13 @@ void set_ext_pri(struct ast_channel *c, const char *exten, int pri); /*! pbx.c function needed by pbx_app.c */ void unreference_cached_app(struct ast_app *app); +/*! pbx_ignorepat.c */ +struct ast_ignorepat; +AST_VECTOR(ast_ignorepats, struct ast_ignorepat *); + +struct ast_ignorepat *ignorepat_alloc(const char *value, const char *registrar); +void ignorepat_free(struct ast_ignorepat *ip); + /*! pbx_includes.c */ struct ast_include; AST_VECTOR(ast_includes, struct ast_include *); @@ -42,6 +49,12 @@ void include_free(struct ast_include *inc); int include_valid(const struct ast_include *inc); const char *include_rname(const struct ast_include *inc); +/*! pbx_sw.c */ +struct ast_sw; +AST_VECTOR(ast_sws, struct ast_sw *); +struct ast_sw *sw_alloc(const char *value, const char *data, int eval, const char *registrar); +void sw_free(struct ast_sw *sw); + /*! pbx_builtins.c functions needed by pbx.c */ int indicate_congestion(struct ast_channel *, const char *); int indicate_busy(struct ast_channel *, const char *); diff --git a/main/pbx_sw.c b/main/pbx_sw.c new file mode 100644 index 000000000..0490ac6a2 --- /dev/null +++ b/main/pbx_sw.c @@ -0,0 +1,107 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2016, CFWare, LLC + * + * Corey Farrell <git@cfware.com> + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +/*! \file + * + * \brief Dialplan switch routines. + * + * \author Corey Farrell <git@cfware.com> + */ + +/*** MODULEINFO + <support_level>core</support_level> + ***/ + +#include "asterisk.h" + +ASTERISK_REGISTER_FILE() + +#include "asterisk/_private.h" +#include "asterisk/pbx.h" +#include "pbx_private.h" + +/*! \brief ast_sw: Switch statement in extensions.conf */ +struct ast_sw { + const char *name; + /*! Registrar */ + const char *registrar; + /*! Data load */ + const char *data; + int eval; + AST_LIST_ENTRY(ast_sw) list; + char stuff[0]; +}; + +const char *ast_get_switch_name(const struct ast_sw *sw) +{ + return sw ? sw->name : NULL; +} + +const char *ast_get_switch_data(const struct ast_sw *sw) +{ + return sw ? sw->data : NULL; +} + +int ast_get_switch_eval(const struct ast_sw *sw) +{ + return sw->eval; +} + +const char *ast_get_switch_registrar(const struct ast_sw *sw) +{ + return sw ? sw->registrar : NULL; +} + +struct ast_sw *sw_alloc(const char *value, const char *data, int eval, const char *registrar) +{ + struct ast_sw *new_sw; + int length; + char *p; + + if (!data) { + data = ""; + } + length = sizeof(struct ast_sw); + length += strlen(value) + 1; + length += strlen(data) + 1; + + /* allocate new sw structure ... */ + if (!(new_sw = ast_calloc(1, length))) { + return NULL; + } + + /* ... fill in this structure ... */ + p = new_sw->stuff; + new_sw->name = p; + strcpy(p, value); + + p += strlen(value) + 1; + new_sw->data = p; + strcpy(p, data); + + new_sw->eval = eval; + new_sw->registrar = registrar; + + return new_sw; +} + +void sw_free(struct ast_sw *sw) +{ + ast_free(sw); +} + diff --git a/main/sdp_srtp.c b/main/sdp_srtp.c index c92387bc2..a55aedf82 100644 --- a/main/sdp_srtp.c +++ b/main/sdp_srtp.c @@ -20,8 +20,7 @@ * * \brief SRTP and SDP Security descriptions * - * Specified in RFC 3711 - * Specified in RFC 4568 + * Specified in RFC 3711, 6188, 7714, and 4568 * * \author Mikael Magnusson <mikma@users.sourceforge.net> */ @@ -34,15 +33,15 @@ ASTERISK_REGISTER_FILE() -#include <math.h> -#include "asterisk/options.h" -#include "asterisk/utils.h" -#include "asterisk/sdp_srtp.h" +#include <math.h> /* for pow */ +#include <srtp/srtp.h> /* for SRTP_MAX_KEY_LEN, etc */ -#define SRTP_MASTER_LEN 30 -#define SRTP_MASTERKEY_LEN 16 -#define SRTP_MASTERSALT_LEN ((SRTP_MASTER_LEN) - (SRTP_MASTERKEY_LEN)) -#define SRTP_MASTER_LEN64 (((SRTP_MASTER_LEN) * 8 + 5) / 6 + 1) +#include "asterisk/linkedlists.h" /* for AST_LIST_NEXT, etc */ +#include "asterisk/logger.h" /* for ast_log, LOG_ERROR, etc */ +#include "asterisk/rtp_engine.h" /* for ast_rtp_engine_dtls, etc */ +#include "asterisk/sdp_srtp.h" /* for ast_sdp_srtp, etc */ +#include "asterisk/strings.h" /* for ast_strlen_zero */ +#include "asterisk/utils.h" /* for ast_set_flag, ast_test_flag, etc */ extern struct ast_srtp_res *res_srtp; extern struct ast_srtp_policy_res *res_srtp_policy; @@ -59,22 +58,31 @@ struct ast_sdp_srtp *ast_sdp_srtp_alloc(void) void ast_sdp_srtp_destroy(struct ast_sdp_srtp *srtp) { - if (srtp->crypto) { - ast_sdp_crypto_destroy(srtp->crypto); + struct ast_sdp_srtp *next; + + for (next = AST_LIST_NEXT(srtp, sdp_srtp_list); + srtp; + srtp = next, next = srtp ? AST_LIST_NEXT(srtp, sdp_srtp_list) : NULL) { + if (srtp->crypto) { + ast_sdp_crypto_destroy(srtp->crypto); + } + srtp->crypto = NULL; + ast_free(srtp); } - srtp->crypto = NULL; - ast_free(srtp); } struct ast_sdp_crypto { char *a_crypto; - unsigned char local_key[SRTP_MASTER_LEN]; + unsigned char local_key[SRTP_MAX_KEY_LEN]; int tag; - char local_key64[SRTP_MASTER_LEN64]; - unsigned char remote_key[SRTP_MASTER_LEN]; + char local_key64[((SRTP_MAX_KEY_LEN) * 8 + 5) / 6 + 1]; + unsigned char remote_key[SRTP_MAX_KEY_LEN]; + int key_len; }; -static int set_crypto_policy(struct ast_srtp_policy *policy, int suite_val, const unsigned char *master_key, unsigned long ssrc, int inbound); +static struct ast_sdp_crypto *sdp_crypto_alloc(const int key_len); +static struct ast_sdp_crypto *crypto_init_keys(struct ast_sdp_crypto *p, const int key_len); +static int set_crypto_policy(struct ast_srtp_policy *policy, int suite_val, const unsigned char *master_key, int key_len, unsigned long ssrc, int inbound); void ast_sdp_crypto_destroy(struct ast_sdp_crypto *crypto) { @@ -83,57 +91,67 @@ void ast_sdp_crypto_destroy(struct ast_sdp_crypto *crypto) ast_free(crypto); } -struct ast_sdp_crypto *ast_sdp_crypto_alloc(void) +static struct ast_sdp_crypto *crypto_init_keys(struct ast_sdp_crypto *p, const int key_len) { - struct ast_sdp_crypto *p; - int key_len; - unsigned char remote_key[SRTP_MASTER_LEN]; + unsigned char remote_key[key_len]; - if (!ast_rtp_engine_srtp_is_registered()) { + if (res_srtp->get_random(p->local_key, key_len) < 0) { return NULL; } - if (!(p = ast_calloc(1, sizeof(*p)))) { + ast_base64encode(p->local_key64, p->local_key, key_len, sizeof(p->local_key64)); + + p->key_len = ast_base64decode(remote_key, p->local_key64, sizeof(remote_key)); + + if (p->key_len != key_len) { + ast_log(LOG_ERROR, "base64 encode/decode bad len %d != %d\n", p->key_len, key_len); return NULL; } - p->tag = 1; - if (res_srtp->get_random(p->local_key, sizeof(p->local_key)) < 0) { - ast_sdp_crypto_destroy(p); + if (memcmp(remote_key, p->local_key, p->key_len)) { + ast_log(LOG_ERROR, "base64 encode/decode bad key\n"); return NULL; } - ast_base64encode(p->local_key64, p->local_key, SRTP_MASTER_LEN, sizeof(p->local_key64)); + ast_debug(1 , "local_key64 %s len %zu\n", p->local_key64, strlen(p->local_key64)); - key_len = ast_base64decode(remote_key, p->local_key64, sizeof(remote_key)); + return p; +} - if (key_len != SRTP_MASTER_LEN) { - ast_log(LOG_ERROR, "base64 encode/decode bad len %d != %d\n", key_len, SRTP_MASTER_LEN); - ast_sdp_crypto_destroy(p); +static struct ast_sdp_crypto *sdp_crypto_alloc(const int key_len) +{ + struct ast_sdp_crypto *p, *result; + + if (!ast_rtp_engine_srtp_is_registered()) { return NULL; } - if (memcmp(remote_key, p->local_key, SRTP_MASTER_LEN)) { - ast_log(LOG_ERROR, "base64 encode/decode bad key\n"); - ast_sdp_crypto_destroy(p); + if (!(p = ast_calloc(1, sizeof(*p)))) { return NULL; } + p->tag = 1; - ast_debug(1 , "local_key64 %s len %zu\n", p->local_key64, strlen(p->local_key64)); + /* default is a key which uses AST_AES_CM_128_HMAC_SHA1_xx */ + result = crypto_init_keys(p, key_len); + if (!result) { + ast_sdp_crypto_destroy(p); + } - return p; + return result; } -static int set_crypto_policy(struct ast_srtp_policy *policy, int suite_val, const unsigned char *master_key, unsigned long ssrc, int inbound) +struct ast_sdp_crypto *ast_sdp_crypto_alloc(void) { - const unsigned char *master_salt = NULL; + return sdp_crypto_alloc(SRTP_MASTER_KEY_LEN); +} +static int set_crypto_policy(struct ast_srtp_policy *policy, int suite_val, const unsigned char *master_key, int key_len, unsigned long ssrc, int inbound) +{ if (!ast_rtp_engine_srtp_is_registered()) { return -1; } - master_salt = master_key + SRTP_MASTERKEY_LEN; - if (res_srtp_policy->set_master_key(policy, master_key, SRTP_MASTERKEY_LEN, master_salt, SRTP_MASTERSALT_LEN) < 0) { + if (res_srtp_policy->set_master_key(policy, master_key, key_len, NULL, 0) < 0) { return -1; } @@ -147,7 +165,7 @@ static int set_crypto_policy(struct ast_srtp_policy *policy, int suite_val, cons return 0; } -static int crypto_activate(struct ast_sdp_crypto *p, int suite_val, unsigned char *remote_key, struct ast_rtp_instance *rtp) +static int crypto_activate(struct ast_sdp_crypto *p, int suite_val, unsigned char *remote_key, int key_len, struct ast_rtp_instance *rtp) { struct ast_srtp_policy *local_policy = NULL; struct ast_srtp_policy *remote_policy = NULL; @@ -174,11 +192,11 @@ static int crypto_activate(struct ast_sdp_crypto *p, int suite_val, unsigned cha goto err; } - if (set_crypto_policy(local_policy, suite_val, p->local_key, stats.local_ssrc, 0) < 0) { + if (set_crypto_policy(local_policy, suite_val, p->local_key, key_len, stats.local_ssrc, 0) < 0) { goto err; } - if (set_crypto_policy(remote_policy, suite_val, remote_key, 0, 1) < 0) { + if (set_crypto_policy(remote_policy, suite_val, remote_key, key_len, 0, 1) < 0) { goto err; } @@ -215,12 +233,15 @@ int ast_sdp_crypto_process(struct ast_rtp_instance *rtp, struct ast_sdp_srtp *sr char *lifetime = NULL; /* Key lifetime (# of RTP packets) */ char *mki = NULL; /* Master Key Index */ int found = 0; - int key_len = 0; + int key_len_from_sdp; + int key_len_expected; + int tag_from_sdp; int suite_val = 0; - unsigned char remote_key[SRTP_MASTER_LEN]; - int taglen = 0; + unsigned char remote_key[SRTP_MAX_KEY_LEN]; + int taglen; double sdes_lifetime; - struct ast_sdp_crypto *crypto = srtp->crypto; + struct ast_sdp_crypto *crypto; + struct ast_sdp_srtp *tmp; if (!ast_rtp_engine_srtp_is_registered()) { return -1; @@ -239,7 +260,7 @@ int ast_sdp_crypto_process(struct ast_rtp_instance *rtp, struct ast_sdp_srtp *sr } /* RFC4568 9.1 - tag is 1-9 digits, greater than zero */ - if (sscanf(tag, "%30d", &crypto->tag) != 1 || crypto->tag <= 0 || crypto->tag > 999999999) { + if (sscanf(tag, "%30d", &tag_from_sdp) != 1 || tag_from_sdp <= 0 || tag_from_sdp > 999999999) { ast_log(LOG_WARNING, "Unacceptable a=crypto tag: %s\n", tag); return -1; } @@ -249,16 +270,107 @@ int ast_sdp_crypto_process(struct ast_rtp_instance *rtp, struct ast_sdp_srtp *sr return -1; } + /* On egress, Asterisk sent several crypto lines in the SIP/SDP offer + The remote party might have choosen another line than the first */ + for (tmp = srtp; tmp && tmp->crypto && tmp->crypto->tag != tag_from_sdp;) { + tmp = AST_LIST_NEXT(tmp, sdp_srtp_list); + } + if (tmp) { /* tag matched an already created crypto line */ + unsigned int flags = tmp->flags; + + /* Make that crypto line the head of the list, not by changing the + list structure but by exchanging the content of the list members */ + crypto = tmp->crypto; + tmp->crypto = srtp->crypto; + tmp->flags = srtp->flags; + srtp->crypto = crypto; + srtp->flags = flags; + } else { + crypto = srtp->crypto; + crypto->tag = tag_from_sdp; + } + if (!strcmp(suite, "AES_CM_128_HMAC_SHA1_80")) { suite_val = AST_AES_CM_128_HMAC_SHA1_80; ast_set_flag(srtp, AST_SRTP_CRYPTO_TAG_80); - taglen = 80; + key_len_expected = 30; } else if (!strcmp(suite, "AES_CM_128_HMAC_SHA1_32")) { suite_val = AST_AES_CM_128_HMAC_SHA1_32; ast_set_flag(srtp, AST_SRTP_CRYPTO_TAG_32); - taglen = 32; + key_len_expected = 30; +#ifdef HAVE_SRTP_192 + } else if (!strcmp(suite, "AES_192_CM_HMAC_SHA1_80")) { + suite_val = AST_AES_CM_192_HMAC_SHA1_80; + ast_set_flag(srtp, AST_SRTP_CRYPTO_TAG_80); + ast_set_flag(srtp, AST_SRTP_CRYPTO_AES_192); + key_len_expected = 38; + } else if (!strcmp(suite, "AES_192_CM_HMAC_SHA1_32")) { + suite_val = AST_AES_CM_192_HMAC_SHA1_32; + ast_set_flag(srtp, AST_SRTP_CRYPTO_TAG_32); + ast_set_flag(srtp, AST_SRTP_CRYPTO_AES_192); + key_len_expected = 38; + /* RFC used a different name while in draft, some still use that */ + } else if (!strcmp(suite, "AES_CM_192_HMAC_SHA1_80")) { + suite_val = AST_AES_CM_192_HMAC_SHA1_80; + ast_set_flag(srtp, AST_SRTP_CRYPTO_TAG_80); + ast_set_flag(srtp, AST_SRTP_CRYPTO_AES_192); + ast_set_flag(srtp, AST_SRTP_CRYPTO_OLD_NAME); + key_len_expected = 38; + } else if (!strcmp(suite, "AES_CM_192_HMAC_SHA1_32")) { + suite_val = AST_AES_CM_192_HMAC_SHA1_32; + ast_set_flag(srtp, AST_SRTP_CRYPTO_TAG_32); + ast_set_flag(srtp, AST_SRTP_CRYPTO_AES_192); + ast_set_flag(srtp, AST_SRTP_CRYPTO_OLD_NAME); + key_len_expected = 38; +#endif +#ifdef HAVE_SRTP_256 + } else if (!strcmp(suite, "AES_256_CM_HMAC_SHA1_80")) { + suite_val = AST_AES_CM_256_HMAC_SHA1_80; + ast_set_flag(srtp, AST_SRTP_CRYPTO_TAG_80); + ast_set_flag(srtp, AST_SRTP_CRYPTO_AES_256); + key_len_expected = 46; + } else if (!strcmp(suite, "AES_256_CM_HMAC_SHA1_32")) { + suite_val = AST_AES_CM_256_HMAC_SHA1_32; + ast_set_flag(srtp, AST_SRTP_CRYPTO_TAG_32); + ast_set_flag(srtp, AST_SRTP_CRYPTO_AES_256); + key_len_expected = 46; + /* RFC used a different name while in draft, some still use that */ + } else if (!strcmp(suite, "AES_CM_256_HMAC_SHA1_80")) { + suite_val = AST_AES_CM_256_HMAC_SHA1_80; + ast_set_flag(srtp, AST_SRTP_CRYPTO_TAG_80); + ast_set_flag(srtp, AST_SRTP_CRYPTO_AES_256); + ast_set_flag(srtp, AST_SRTP_CRYPTO_OLD_NAME); + key_len_expected = 46; + } else if (!strcmp(suite, "AES_CM_256_HMAC_SHA1_32")) { + suite_val = AST_AES_CM_256_HMAC_SHA1_32; + ast_set_flag(srtp, AST_SRTP_CRYPTO_TAG_32); + ast_set_flag(srtp, AST_SRTP_CRYPTO_AES_256); + ast_set_flag(srtp, AST_SRTP_CRYPTO_OLD_NAME); + key_len_expected = 46; +#endif +#ifdef HAVE_SRTP_GCM + } else if (!strcmp(suite, "AEAD_AES_128_GCM")) { + suite_val = AST_AES_GCM_128; + ast_set_flag(srtp, AST_SRTP_CRYPTO_TAG_16); + key_len_expected = AES_128_GCM_KEYSIZE_WSALT; + } else if (!strcmp(suite, "AEAD_AES_256_GCM")) { + suite_val = AST_AES_GCM_256; + ast_set_flag(srtp, AST_SRTP_CRYPTO_TAG_16); + ast_set_flag(srtp, AST_SRTP_CRYPTO_AES_256); + key_len_expected = AES_256_GCM_KEYSIZE_WSALT; + /* RFC contained a (too) short auth tag for RTP media, some still use that */ + } else if (!strcmp(suite, "AEAD_AES_128_GCM_8")) { + suite_val = AST_AES_GCM_128_8; + ast_set_flag(srtp, AST_SRTP_CRYPTO_TAG_8); + key_len_expected = AES_128_GCM_KEYSIZE_WSALT; + } else if (!strcmp(suite, "AEAD_AES_256_GCM_8")) { + suite_val = AST_AES_GCM_256_8; + ast_set_flag(srtp, AST_SRTP_CRYPTO_TAG_8); + ast_set_flag(srtp, AST_SRTP_CRYPTO_AES_256); + key_len_expected = AES_256_GCM_KEYSIZE_WSALT; +#endif } else { - ast_log(LOG_WARNING, "Unsupported crypto suite: %s\n", suite); + ast_verb(1, "Unsupported crypto suite: %s\n", suite); return -1; } @@ -341,23 +453,55 @@ int ast_sdp_crypto_process(struct ast_rtp_instance *rtp, struct ast_sdp_srtp *sr return -1; } - key_len = ast_base64decode(remote_key, key_salt, sizeof(remote_key)); - if (key_len != SRTP_MASTER_LEN) { - ast_log(LOG_WARNING, "SRTP descriptions key length '%d' != master length '%d'\n", - key_len, SRTP_MASTER_LEN); + key_len_from_sdp = ast_base64decode(remote_key, key_salt, sizeof(remote_key)); + if (key_len_from_sdp != key_len_expected) { + ast_log(LOG_WARNING, "SRTP descriptions key length is '%d', not '%d'\n", + key_len_from_sdp, key_len_expected); return -1; } - if (!memcmp(crypto->remote_key, remote_key, sizeof(crypto->remote_key))) { + /* on default, the key is 30 (AES-128); throw that away (only) when the suite changed actually */ + /* ingress: optional, but saves one expensive call to get_random(.) */ + /* egress: required, because the local key was communicated before the remote key is processed */ + if (crypto->key_len != key_len_from_sdp) { + if (!crypto_init_keys(crypto, key_len_from_sdp)) { + return -1; + } + } else if (!memcmp(crypto->remote_key, remote_key, key_len_from_sdp)) { ast_debug(1, "SRTP remote key unchanged; maintaining current policy\n"); ast_set_flag(srtp, AST_SRTP_CRYPTO_OFFER_OK); return 0; } - memcpy(crypto->remote_key, remote_key, sizeof(crypto->remote_key)); - if (crypto_activate(crypto, suite_val, remote_key, rtp) < 0) { + if (key_len_from_sdp > sizeof(crypto->remote_key)) { + ast_log(LOG_ERROR, + "SRTP key buffer is %zu although it must be at least %d bytes\n", + sizeof(crypto->remote_key), key_len_from_sdp); return -1; } + memcpy(crypto->remote_key, remote_key, key_len_from_sdp); + + if (crypto_activate(crypto, suite_val, remote_key, key_len_from_sdp, rtp) < 0) { + return -1; + } + + if (ast_test_flag(srtp, AST_SRTP_CRYPTO_TAG_32)) { + taglen = 32; + } else if (ast_test_flag(srtp, AST_SRTP_CRYPTO_TAG_16)) { + taglen = 16; + } else if (ast_test_flag(srtp, AST_SRTP_CRYPTO_TAG_8)) { + taglen = 8; + } else { + taglen = 80; + } + if (ast_test_flag(srtp, AST_SRTP_CRYPTO_AES_256)) { + taglen |= 0x0200; + } else if (ast_test_flag(srtp, AST_SRTP_CRYPTO_AES_192)) { + taglen |= 0x0100; + } + if (ast_test_flag(srtp, AST_SRTP_CRYPTO_OLD_NAME)) { + taglen |= 0x0080; + } /* Finally, rebuild the crypto line */ if (ast_sdp_crypto_build_offer(crypto, taglen)) { @@ -375,10 +519,30 @@ int ast_sdp_crypto_build_offer(struct ast_sdp_crypto *p, int taglen) ast_free(p->a_crypto); } - if (ast_asprintf(&p->a_crypto, "%d AES_CM_128_HMAC_SHA1_%i inline:%s", - p->tag, taglen, p->local_key64) == -1) { - ast_log(LOG_ERROR, "Could not allocate memory for crypto line\n"); - return -1; + if ((taglen & 0x007f) == 8) { + if (ast_asprintf(&p->a_crypto, "%d AEAD_AES_%d_GCM_%d inline:%s", + p->tag, 128 + ((taglen & 0x0300) >> 2), taglen & 0x007f, p->local_key64) == -1) { + ast_log(LOG_ERROR, "Could not allocate memory for crypto line\n"); + return -1; + } + } else if ((taglen & 0x007f) == 16) { + if (ast_asprintf(&p->a_crypto, "%d AEAD_AES_%d_GCM inline:%s", + p->tag, 128 + ((taglen & 0x0300) >> 2), p->local_key64) == -1) { + ast_log(LOG_ERROR, "Could not allocate memory for crypto line\n"); + return -1; + } + } else if ((taglen & 0x0300) && !(taglen & 0x0080)) { + if (ast_asprintf(&p->a_crypto, "%d AES_%d_CM_HMAC_SHA1_%d inline:%s", + p->tag, 128 + ((taglen & 0x0300) >> 2), taglen & 0x007f, p->local_key64) == -1) { + ast_log(LOG_ERROR, "Could not allocate memory for crypto line\n"); + return -1; + } + } else { + if (ast_asprintf(&p->a_crypto, "%d AES_CM_%d_HMAC_SHA1_%d inline:%s", + p->tag, 128 + ((taglen & 0x0300) >> 2), taglen & 0x007f, p->local_key64) == -1) { + ast_log(LOG_ERROR, "Could not allocate memory for crypto line\n"); + return -1; + } } ast_debug(1, "Crypto line: a=crypto:%s\n", p->a_crypto); @@ -388,7 +552,7 @@ int ast_sdp_crypto_build_offer(struct ast_sdp_crypto *p, int taglen) const char *ast_sdp_srtp_get_attrib(struct ast_sdp_srtp *srtp, int dtls_enabled, int default_taglen_32) { - int taglen = default_taglen_32 ? 32 : 80; + int taglen; if (!srtp) { return NULL; @@ -396,7 +560,72 @@ const char *ast_sdp_srtp_get_attrib(struct ast_sdp_srtp *srtp, int dtls_enabled, /* Set encryption properties */ if (!srtp->crypto) { - srtp->crypto = ast_sdp_crypto_alloc(); + + if (AST_LIST_NEXT(srtp, sdp_srtp_list)) { + srtp->crypto = ast_sdp_crypto_alloc(); + ast_log(LOG_ERROR, "SRTP SDP list was not empty\n"); + } else { + const int len = default_taglen_32 ? AST_SRTP_CRYPTO_TAG_32 : AST_SRTP_CRYPTO_TAG_80; + const int attr[][3] = { + /* This array creates the following list: + * a=crypto:1 AES_CM_128_HMAC_SHA1_ ... + * a=crypto:2 AEAD_AES_128_GCM ... + * a=crypto:3 AES_256_CM_HMAC_SHA1_ ... + * a=crypto:4 AEAD_AES_256_GCM ... + * a=crypto:5 AES_192_CM_HMAC_SHA1_ ... + * something like 'AEAD_AES_192_GCM' is not specified by the RFCs + * + * If you want to prefer another crypto suite or you want to + * exclude a suite, change this array and recompile Asterisk. + * This list cannot be changed from rtp.conf because you should + * know what you are doing. Especially AES-192 and AES-GCM are + * broken in many VoIP clients, see + * https://github.com/cisco/libsrtp/pull/170 + * https://github.com/cisco/libsrtp/pull/184 + * Furthermore, AES-GCM uses a shorter crypto-suite string which + * causes Nokia phones based on Symbian/S60 to reject the whole + * INVITE with status 500, even if a matching suite was offered. + * AES-256 might just waste your processor cycles, especially if + * your TLS transport is not secured with equivalent grade, see + * https://security.stackexchange.com/q/61361 + * Therefore, AES-128 was preferred here. + * + * If you want to enable one of those defines, please, go for + * CFLAGS='-DENABLE_SRTP_AES_GCM' ./configure && sudo make install + */ + { len, 0, 30 }, +#if defined(HAVE_SRTP_GCM) && defined(ENABLE_SRTP_AES_GCM) + { AST_SRTP_CRYPTO_TAG_16, 0, AES_128_GCM_KEYSIZE_WSALT }, +#endif +#if defined(HAVE_SRTP_256) && defined(ENABLE_SRTP_AES_256) + { len, AST_SRTP_CRYPTO_AES_256, 46 }, +#endif +#if defined(HAVE_SRTP_GCM) && defined(ENABLE_SRTP_AES_GCM) && defined(ENABLE_SRTP_AES_256) + { AST_SRTP_CRYPTO_TAG_16, AST_SRTP_CRYPTO_AES_256, AES_256_GCM_KEYSIZE_WSALT }, +#endif +#if defined(HAVE_SRTP_192) && defined(ENABLE_SRTP_AES_192) + { len, AST_SRTP_CRYPTO_AES_192, 38 }, +#endif + }; + struct ast_sdp_srtp *tmp = srtp; + int i; + + for (i = 0; i < ARRAY_LEN(attr); i++) { + if (attr[i][0]) { + ast_set_flag(tmp, attr[i][0]); + } + if (attr[i][1]) { + ast_set_flag(tmp, attr[i][1]); + } + tmp->crypto = sdp_crypto_alloc(attr[i][2]); /* key_len */ + tmp->crypto->tag = (i + 1); /* tag starts at 1 */ + + if (i < ARRAY_LEN(attr) - 1) { + AST_LIST_NEXT(tmp, sdp_srtp_list) = ast_sdp_srtp_alloc(); + tmp = AST_LIST_NEXT(tmp, sdp_srtp_list); + } + } + } } if (dtls_enabled) { @@ -409,6 +638,20 @@ const char *ast_sdp_srtp_get_attrib(struct ast_sdp_srtp *srtp, int dtls_enabled, taglen = 80; } else if (ast_test_flag(srtp, AST_SRTP_CRYPTO_TAG_32)) { taglen = 32; + } else if (ast_test_flag(srtp, AST_SRTP_CRYPTO_TAG_16)) { + taglen = 16; + } else if (ast_test_flag(srtp, AST_SRTP_CRYPTO_TAG_8)) { + taglen = 8; + } else { + taglen = default_taglen_32 ? 32 : 80; + } + if (ast_test_flag(srtp, AST_SRTP_CRYPTO_AES_256)) { + taglen |= 0x0200; + } else if (ast_test_flag(srtp, AST_SRTP_CRYPTO_AES_192)) { + taglen |= 0x0100; + } + if (ast_test_flag(srtp, AST_SRTP_CRYPTO_OLD_NAME)) { + taglen |= 0x0080; } if (srtp->crypto && (ast_sdp_crypto_build_offer(srtp->crypto, taglen) >= 0)) { diff --git a/main/utils.c b/main/utils.c index 09839752b..46edf43ea 100644 --- a/main/utils.c +++ b/main/utils.c @@ -2420,7 +2420,7 @@ char *ast_utils_which(const char *binary, char *fullpath, size_t fullpath_size) return NULL; } -void ast_do_crash(void) +void DO_CRASH_NORETURN ast_do_crash(void) { #if defined(DO_CRASH) abort(); @@ -2433,7 +2433,7 @@ void ast_do_crash(void) } #if defined(AST_DEVMODE) -void __ast_assert_failed(int condition, const char *condition_str, const char *file, int line, const char *function) +void DO_CRASH_NORETURN __ast_assert_failed(int condition, const char *condition_str, const char *file, int line, const char *function) { /* * Attempt to put it into the logger, but hope that at least diff --git a/pbx/pbx_config.c b/pbx/pbx_config.c index 478c0a321..0da4168f1 100644 --- a/pbx/pbx_config.c +++ b/pbx/pbx_config.c @@ -213,15 +213,25 @@ static int lookup_ci(struct ast_context *c, const char *name) /*! \brief return true if 'name' is in the ignorepats for context c */ static int lookup_c_ip(struct ast_context *c, const char *name) { - struct ast_ignorepat *ip = NULL; + int idx; + int ret = 0; - if (ast_rdlock_context(c)) /* error, skip */ + if (ast_rdlock_context(c)) { + /* error, skip */ return 0; - while ( (ip = ast_walk_context_ignorepats(c, ip)) ) - if (!strcmp(name, ast_get_ignorepat_name(ip))) + } + + for (idx = 0; idx < ast_context_ignorepats_count(c); idx++) { + const struct ast_ignorepat *ip = ast_context_ignorepats_get(c, idx); + + if (!strcmp(name, ast_get_ignorepat_name(ip))) { + ret = -1; break; + } + } ast_unlock_context(c); - return ip ? -1 /* success */ : 0; + + return ret; } /*! \brief moves to the n-th word in the string, or empty string if none */ @@ -918,8 +928,6 @@ static char *handle_cli_dialplan_save(struct ast_cli_entry *e, int cmd, struct a int context_header_written = 0; struct ast_exten *ext, *last_written_e = NULL; int idx; - struct ast_ignorepat *ip; - struct ast_sw *sw; /* try to lock context and fireout all info */ if (ast_rdlock_context(c)) { /* lock failure */ @@ -1007,7 +1015,9 @@ static char *handle_cli_dialplan_save(struct ast_cli_entry *e, int cmd, struct a } /* walk through switches */ - for (sw = NULL; (sw = ast_walk_context_switches(c, sw)) ; ) { + for (idx = 0; idx < ast_context_switches_count(c); idx++) { + const struct ast_sw *sw = ast_context_switches_get(c, idx); + if (strcmp(ast_get_switch_registrar(sw), registrar) != 0) continue; /* not mine */ PUT_CTX_HDR; @@ -1015,11 +1025,14 @@ static char *handle_cli_dialplan_save(struct ast_cli_entry *e, int cmd, struct a ast_get_switch_name(sw), ast_get_switch_data(sw)); } - if (ast_walk_context_switches(c, NULL)) + if (ast_context_switches_count(c)) { fprintf(output, "\n"); + } /* fireout ignorepats ... */ - for (ip = NULL; (ip = ast_walk_context_ignorepats(c, ip)); ) { + for (idx = 0; idx < ast_context_ignorepats_count(c); idx++) { + const struct ast_ignorepat *ip = ast_context_ignorepats_get(c, idx); + if (strcmp(ast_get_ignorepat_registrar(ip), registrar) != 0) continue; /* not mine */ PUT_CTX_HDR; @@ -1486,12 +1499,13 @@ static char *complete_dialplan_remove_ignorepat(struct ast_cli_args *a) } for (c = NULL; !ret && (c = ast_walk_contexts(c));) { - struct ast_ignorepat *ip; + int idx; if (ast_rdlock_context(c)) /* error, skip it */ continue; - - for (ip = NULL; !ret && (ip = ast_walk_context_ignorepats(c, ip));) { + for (idx = 0; idx < ast_context_ignorepats_count(c); idx++) { + const struct ast_ignorepat *ip = ast_context_ignorepats_get(c, idx); + if (partial_match(ast_get_ignorepat_name(ip), a->word, len) && ++which > a->n) { /* n-th match */ struct ast_context *cw = NULL; diff --git a/res/ael/pval.c b/res/ael/pval.c index 8b6760f99..485f5ee79 100644 --- a/res/ael/pval.c +++ b/res/ael/pval.c @@ -4410,7 +4410,7 @@ static int context_used(struct ael_extension *exten_list, struct ast_context *co { struct ael_extension *exten; /* Check the simple elements first */ - if (ast_walk_context_extensions(context, NULL) || ast_context_includes_count(context) || ast_walk_context_ignorepats(context, NULL) || ast_walk_context_switches(context, NULL)) { + if (ast_walk_context_extensions(context, NULL) || ast_context_includes_count(context) || ast_context_ignorepats_count(context) || ast_context_switches_count(context)) { return 1; } for (exten = exten_list; exten; exten = exten->next_exten) { diff --git a/res/res_fax.c b/res/res_fax.c index 347168e56..c301aff31 100644 --- a/res/res_fax.c +++ b/res/res_fax.c @@ -468,8 +468,6 @@ struct fax_gateway { struct fax_detect { /*! \brief the start of our timeout counter */ struct timeval timeout_start; - /*! \brief faxdetect timeout */ - int timeout; /*! \brief DSP Processor */ struct ast_dsp *dsp; /*! \brief original audio formats */ @@ -3539,13 +3537,13 @@ static void destroy_faxdetect(void *data) ast_dsp_free(faxdetect->dsp); faxdetect->dsp = NULL; } - ao2_ref(faxdetect->details, -1); + ao2_cleanup(faxdetect->details); ao2_cleanup(faxdetect->orig_format); } /*! \brief Create a new fax detect object. * \param chan the channel attaching to - * \param timeout remove framehook in this time if set + * \param timeout in ms to remove framehook in this time if not zero * \param flags required options * \return NULL or a fax gateway object */ @@ -3652,8 +3650,9 @@ static struct ast_frame *fax_detect_framehook(struct ast_channel *chan, struct a return f; } - if ((!ast_tvzero(faxdetect->timeout_start) && - (ast_tvdiff_ms(ast_tvnow(), faxdetect->timeout_start) > faxdetect->timeout))) { + if (!ast_tvzero(faxdetect->timeout_start) + && ast_tvdiff_ms(ast_tvnow(), faxdetect->timeout_start) > details->faxdetect_timeout) { + ast_debug(1, "FAXOPT(faxdetect) timeout on %s\n", ast_channel_name(chan)); ast_framehook_detach(chan, details->faxdetect_id); details->faxdetect_id = -1; return f; @@ -3701,30 +3700,36 @@ static struct ast_frame *fax_detect_framehook(struct ast_channel *chan, struct a } if (result) { - const char *target_context = S_OR(ast_channel_macrocontext(chan), ast_channel_context(chan)); + const char *target_context; + switch (result) { case 'f': case 't': + target_context = S_OR(ast_channel_macrocontext(chan), ast_channel_context(chan)); + ast_channel_unlock(chan); + ast_frfree(f); + f = &ast_null_frame; if (ast_exists_extension(chan, target_context, "fax", 1, S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) { - ast_channel_lock(chan); ast_verb(2, "Redirecting '%s' to fax extension due to %s detection\n", ast_channel_name(chan), (result == 'f') ? "CNG" : "T38"); pbx_builtin_setvar_helper(chan, "FAXEXTEN", ast_channel_exten(chan)); if (ast_async_goto(chan, target_context, "fax", 1)) { ast_log(LOG_NOTICE, "Failed to async goto '%s' into fax of '%s'\n", ast_channel_name(chan), target_context); } - ast_frfree(f); - f = &ast_null_frame; } else { - ast_channel_lock(chan); ast_log(LOG_NOTICE, "FAX %s detected but no fax extension in context (%s)\n", (result == 'f') ? "CNG" : "T38", target_context); } + ast_channel_lock(chan); + + ast_framehook_detach(chan, details->faxdetect_id); + details->faxdetect_id = -1; + break; + default: + break; } - ast_framehook_detach(chan, details->faxdetect_id); - details->faxdetect_id = -1; } return f; @@ -3732,7 +3737,7 @@ static struct ast_frame *fax_detect_framehook(struct ast_channel *chan, struct a /*! \brief Attach a faxdetect framehook object to a channel. * \param chan the channel to attach to - * \param timeout remove framehook in this time if set + * \param timeout in ms to remove framehook in this time if not zero * \return the faxdetect structure or NULL on error * \param flags required options * \retval -1 error @@ -4480,8 +4485,14 @@ static int acf_faxopt_write(struct ast_channel *chan, const char *cmd, char *dat details->gateway_timeout = 0; if (timeout) { unsigned int gwtimeout; - if (sscanf(timeout, "%u", &gwtimeout) == 1) { - details->gateway_timeout = gwtimeout * 1000; + + if (sscanf(timeout, "%30u", &gwtimeout) == 1) { + if (gwtimeout >= 0) { + details->gateway_timeout = gwtimeout * 1000; + } else { + ast_log(LOG_WARNING, "%s(%s) timeout cannot be negative. Ignoring timeout\n", + cmd, data); + } } else { ast_log(LOG_WARNING, "Unsupported timeout '%s' passed to FAXOPT(%s).\n", timeout, data); } @@ -4516,11 +4527,18 @@ static int acf_faxopt_write(struct ast_channel *chan, const char *cmd, char *dat if (ast_true(val) || !strcasecmp(val, "t38") || !strcasecmp(val, "cng")) { if (details->faxdetect_id < 0) { - if (timeout && (sscanf(timeout, "%u", &fdtimeout) == 1)) { - if (fdtimeout > 0) { - fdtimeout = fdtimeout * 1000; + if (timeout) { + if (sscanf(timeout, "%30u", &fdtimeout) == 1) { + if (fdtimeout >= 0) { + fdtimeout *= 1000; + } else { + ast_log(LOG_WARNING, "%s(%s) timeout cannot be negative. Ignoring timeout\n", + cmd, data); + fdtimeout = 0; + } } else { - ast_log(LOG_WARNING, "Timeout cannot be negative ignoring timeout\n"); + ast_log(LOG_WARNING, "Unsupported timeout '%s' passed to FAXOPT(%s).\n", + timeout, data); } } diff --git a/res/res_pjsip.c b/res/res_pjsip.c index af2f93749..f56790df7 100644 --- a/res/res_pjsip.c +++ b/res/res_pjsip.c @@ -217,10 +217,9 @@ <enum name="info"> <para>DTMF is sent as SIP INFO packets.</para> </enum> - <enum name="auto"> - <para>DTMF is sent as RFC 4733 if the other side supports it or as INBAND if not.</para> - </enum> - + <enum name="auto"> + <para>DTMF is sent as RFC 4733 if the other side supports it or as INBAND if not.</para> + </enum> </enumlist> </description> </configOption> @@ -510,15 +509,15 @@ <configOption name="g726_non_standard" default="no"> <synopsis>Force g.726 to use AAL2 packing order when negotiating g.726 audio</synopsis> <description><para> - When set to "yes" and an endpoint negotiates g.726 audio then use g.726 for AAL2 - packing order instead of what is recommended by RFC3551. Since this essentially - replaces the underlying 'g726' codec with 'g726aal2' then 'g726aal2' needs to be - specified in the endpoint's allowed codec list. + When set to "yes" and an endpoint negotiates g.726 audio then use g.726 for AAL2 + packing order instead of what is recommended by RFC3551. Since this essentially + replaces the underlying 'g726' codec with 'g726aal2' then 'g726aal2' needs to be + specified in the endpoint's allowed codec list. </para></description> </configOption> <configOption name="inband_progress" default="no"> <synopsis>Determines whether chan_pjsip will indicate ringing using inband - progress.</synopsis> + progress.</synopsis> <description><para> If set to <literal>yes</literal>, chan_pjsip will send a 183 Session Progress when told to indicate ringing and will immediately start sending ringing @@ -600,6 +599,14 @@ detected. </para></description> </configOption> + <configOption name="fax_detect_timeout"> + <synopsis>How long into a call before fax_detect is disabled for the call</synopsis> + <description><para> + The option determines how many seconds into a call before the + fax_detect option is disabled for the call. Setting the value + to zero disables the timeout. + </para></description> + </configOption> <configOption name="t38_udptl_nat" default="no"> <synopsis>Whether NAT support is enabled on UDPTL sessions</synopsis> <description><para> @@ -806,7 +813,7 @@ <configOption name="set_var"> <synopsis>Variable set on a channel involving the endpoint.</synopsis> <description><para> - When a new channel is created using the endpoint set the specified + When a new channel is created using the endpoint set the specified variable(s) on that channel. For multiple channel variables specify multiple 'set_var'(s). </para></description> @@ -1447,9 +1454,9 @@ <synopsis>Value used in User-Agent header for SIP requests and Server header for SIP responses.</synopsis> </configOption> <configOption name="regcontext" default=""> - <synopsis>When set, Asterisk will dynamically create and destroy a NoOp priority 1 extension for a given - peer who registers or unregisters with us.</synopsis> - </configOption> + <synopsis>When set, Asterisk will dynamically create and destroy a NoOp priority 1 extension for a given + peer who registers or unregisters with us.</synopsis> + </configOption> <configOption name="default_outbound_endpoint" default="default_outbound_endpoint"> <synopsis>Endpoint to use when sending an outbound request to a URI without a specified endpoint.</synopsis> </configOption> @@ -1458,15 +1465,15 @@ </configOption> <configOption name="debug" default="no"> <synopsis>Enable/Disable SIP debug logging. Valid options include yes|no or - a host address</synopsis> + a host address</synopsis> </configOption> <configOption name="endpoint_identifier_order" default="ip,username,anonymous"> <synopsis>The order by which endpoint identifiers are processed and checked. - Identifier names are usually derived from and can be found in the endpoint - identifier module itself (res_pjsip_endpoint_identifier_*). - You can use the CLI command "pjsip show identifiers" to see the - identifiers currently available.</synopsis> - <description> + Identifier names are usually derived from and can be found in the endpoint + identifier module itself (res_pjsip_endpoint_identifier_*). + You can use the CLI command "pjsip show identifiers" to see the + identifiers currently available.</synopsis> + <description> <note><para> One of the identifiers is "auth_username" which matches on the username in an Authentication header. This method has some security considerations because an @@ -1480,17 +1487,17 @@ how many unmatched requests are received from a single ip address before a security event is generated using the unidentified_request parameters. </para></note> - </description> + </description> </configOption> <configOption name="default_from_user" default="asterisk"> <synopsis>When Asterisk generates an outgoing SIP request, the From header username will be - set to this value if there is no better option (such as CallerID) to be - used.</synopsis> + set to this value if there is no better option (such as CallerID) to be + used.</synopsis> </configOption> <configOption name="default_realm" default="asterisk"> <synopsis>When Asterisk generates an challenge, the digest will be - set to this value if there is no better option (such as auth/realm) to be - used.</synopsis> + set to this value if there is no better option (such as auth/realm) to be + used.</synopsis> </configOption> </configObject> </configFile> @@ -2058,7 +2065,7 @@ Provides a listing of all endpoints. For each endpoint an <literal>EndpointList</literal> event is raised that contains relevant attributes and status information. Once all endpoints have been listed an <literal>EndpointListComplete</literal> event is issued. - </para> + </para> </description> <responses> <list-elements> @@ -2094,7 +2101,7 @@ <literal>IdentifyDetail</literal>. Some events may be listed multiple times if multiple objects are associated (for instance AoRs). Once all detail events have been raised a final <literal>EndpointDetailComplete</literal> event is issued. - </para> + </para> </description> <responses> <list-elements> @@ -4154,6 +4161,7 @@ long ast_sip_threadpool_queue_size(void) return ast_threadpool_queue_size(sip_threadpool); } +#ifdef TEST_FRAMEWORK AST_TEST_DEFINE(xml_sanitization_end_null) { char sanitized[8]; @@ -4204,6 +4212,7 @@ AST_TEST_DEFINE(xml_sanitization_exceeds_buffer) return AST_TEST_PASS; } +#endif /*! * \internal diff --git a/res/res_pjsip/pjsip_configuration.c b/res/res_pjsip/pjsip_configuration.c index d399f0b47..16405ebce 100644 --- a/res/res_pjsip/pjsip_configuration.c +++ b/res/res_pjsip/pjsip_configuration.c @@ -1849,6 +1849,7 @@ int ast_res_pjsip_initialize_configuration(void) ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "t38_udptl_ec", "none", t38udptl_ec_handler, t38udptl_ec_to_str, NULL, 0, 0); ast_sorcery_object_field_register(sip_sorcery, "endpoint", "t38_udptl_maxdatagram", "0", OPT_UINT_T, 0, FLDSET(struct ast_sip_endpoint, media.t38.maxdatagram)); ast_sorcery_object_field_register(sip_sorcery, "endpoint", "fax_detect", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, faxdetect)); + ast_sorcery_object_field_register(sip_sorcery, "endpoint", "fax_detect_timeout", "0", OPT_UINT_T, 0, FLDSET(struct ast_sip_endpoint, faxdetect_timeout)); ast_sorcery_object_field_register(sip_sorcery, "endpoint", "t38_udptl_nat", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.t38.nat)); ast_sorcery_object_field_register(sip_sorcery, "endpoint", "t38_udptl_ipv6", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.t38.ipv6)); ast_sorcery_object_field_register(sip_sorcery, "endpoint", "tone_zone", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, zone)); diff --git a/res/res_pjsip_mwi.c b/res/res_pjsip_mwi.c index 9eba335b5..d86c96c74 100644 --- a/res/res_pjsip_mwi.c +++ b/res/res_pjsip_mwi.c @@ -976,38 +976,12 @@ static int create_mwi_subscriptions_for_endpoint(void *obj, void *arg, int flags { RAII_VAR(struct mwi_subscription *, aggregate_sub, NULL, ao2_cleanup); struct ast_sip_endpoint *endpoint = obj; - char *endpoint_aors, *aor_name, *mailboxes, *mailbox; - struct ao2_container *contacts = NULL; + char *mailboxes, *mailbox; if (ast_strlen_zero(endpoint->subscription.mwi.mailboxes)) { return 0; } - endpoint_aors = ast_strdupa(endpoint->aors); - - while ((aor_name = ast_strip(strsep(&endpoint_aors, ",")))) { - RAII_VAR(struct ast_sip_aor *, aor, ast_sip_location_retrieve_aor(aor_name), ao2_cleanup); - - if (!aor) { - continue; - } - - contacts = ast_sip_location_retrieve_aor_contacts(aor); - if (!contacts || (ao2_container_count(contacts) == 0)) { - ao2_cleanup(contacts); - contacts = NULL; - continue; - } - - break; - } - - if (!contacts) { - return 0; - } - - ao2_ref(contacts, -1); - if (endpoint->subscription.mwi.aggregate) { aggregate_sub = mwi_subscription_alloc(endpoint, 0, NULL); if (!aggregate_sub) { diff --git a/res/res_pjsip_pubsub.c b/res/res_pjsip_pubsub.c index 207fae04c..fe16c613a 100644 --- a/res/res_pjsip_pubsub.c +++ b/res/res_pjsip_pubsub.c @@ -2249,7 +2249,7 @@ static int send_notify(struct sip_subscription_tree *sub_tree, unsigned int forc } if (sip_subscription_send_request(sub_tree, tdata)) { - pjsip_tx_data_dec_ref(tdata); + /* do not call pjsip_tx_data_dec_ref(tdata). The pjsip_dlg_send_request deletes the message on error */ return -1; } diff --git a/res/res_pjsip_sdp_rtp.c b/res/res_pjsip_sdp_rtp.c index 048209ce1..6610ef126 100644 --- a/res/res_pjsip_sdp_rtp.c +++ b/res/res_pjsip_sdp_rtp.c @@ -51,6 +51,7 @@ ASTERISK_REGISTER_FILE() #include "asterisk/acl.h" #include "asterisk/sdp_srtp.h" #include "asterisk/dsp.h" +#include "asterisk/linkedlists.h" /* for AST_LIST_NEXT */ #include "asterisk/res_pjsip.h" #include "asterisk/res_pjsip_session.h" @@ -938,6 +939,7 @@ static int add_crypto_to_stream(struct ast_sip_session *session, enum ast_rtp_dtls_hash hash; const char *crypto_attribute; struct ast_rtp_engine_dtls *dtls; + struct ast_sdp_srtp *tmp; static const pj_str_t STR_NEW = { "new", 3 }; static const pj_str_t STR_EXISTING = { "existing", 8 }; static const pj_str_t STR_ACTIVE = { "active", 6 }; @@ -957,16 +959,22 @@ static int add_crypto_to_stream(struct ast_sip_session *session, } } - crypto_attribute = ast_sdp_srtp_get_attrib(session_media->srtp, - 0 /* DTLS running? No */, - session->endpoint->media.rtp.srtp_tag_32 /* 32 byte tag length? */); - if (!crypto_attribute) { - /* No crypto attribute to add, bad news */ - return -1; - } + tmp = session_media->srtp; + + do { + crypto_attribute = ast_sdp_srtp_get_attrib(tmp, + 0 /* DTLS running? No */, + session->endpoint->media.rtp.srtp_tag_32 /* 32 byte tag length? */); + if (!crypto_attribute) { + /* No crypto attribute to add, bad news */ + return -1; + } + + attr = pjmedia_sdp_attr_create(pool, "crypto", + pj_cstr(&stmp, crypto_attribute)); + media->attr[media->attr_count++] = attr; + } while ((tmp = AST_LIST_NEXT(tmp, sdp_srtp_list))); - attr = pjmedia_sdp_attr_create(pool, "crypto", pj_cstr(&stmp, crypto_attribute)); - media->attr[media->attr_count++] = attr; break; case AST_SIP_MEDIA_ENCRYPT_DTLS: if (setup_dtls_srtp(session, session_media)) { diff --git a/res/res_rtp_asterisk.c b/res/res_rtp_asterisk.c index c8d7f4630..6cf69ef0d 100644 --- a/res/res_rtp_asterisk.c +++ b/res/res_rtp_asterisk.c @@ -2592,7 +2592,7 @@ static int ast_rtp_new(struct ast_rtp_instance *instance, /* Set default parameters on the newly created RTP structure */ rtp->ssrc = ast_random(); - rtp->seqno = ast_random() & 0xffff; + rtp->seqno = ast_random() & 0x7fff; rtp->strict_rtp_state = (strictrtp ? STRICT_RTP_LEARN : STRICT_RTP_OPEN); if (strictrtp) { rtp_learning_seq_init(&rtp->rtp_source_learn, (uint16_t)rtp->seqno); diff --git a/res/res_srtp.c b/res/res_srtp.c index 0b1fb73e7..59fda76dd 100644 --- a/res/res_srtp.c +++ b/res/res_srtp.c @@ -35,7 +35,7 @@ /* See https://wiki.asterisk.org/wiki/display/AST/Secure+Calling */ -#include "asterisk.h" +#include "asterisk.h" /* for NULL, size_t, memcpy, etc */ ASTERISK_REGISTER_FILE() @@ -46,12 +46,13 @@ ASTERISK_REGISTER_FILE() #include <srtp/crypto_kernel.h> #endif -#include "asterisk/lock.h" -#include "asterisk/sched.h" -#include "asterisk/module.h" -#include "asterisk/options.h" -#include "asterisk/rtp_engine.h" -#include "asterisk/astobj2.h" +#include "asterisk/astobj2.h" /* for ao2_t_ref, etc */ +#include "asterisk/frame.h" /* for AST_FRIENDLY_OFFSET */ +#include "asterisk/logger.h" /* for ast_log, ast_debug, etc */ +#include "asterisk/module.h" /* for ast_module_info, etc */ +#include "asterisk/res_srtp.h" /* for ast_srtp_cb, ast_srtp_suite, etc */ +#include "asterisk/rtp_engine.h" /* for ast_rtp_engine_register_srtp, etc */ +#include "asterisk/utils.h" /* for ast_free, ast_calloc */ struct ast_srtp { struct ast_rtp_instance *rtp; @@ -257,23 +258,49 @@ static int policy_set_suite(crypto_policy_t *p, enum ast_srtp_suite suite) { switch (suite) { case AST_AES_CM_128_HMAC_SHA1_80: - p->cipher_type = AES_128_ICM; - p->cipher_key_len = 30; - p->auth_type = HMAC_SHA1; - p->auth_key_len = 20; - p->auth_tag_len = 10; - p->sec_serv = sec_serv_conf_and_auth; + crypto_policy_set_aes_cm_128_hmac_sha1_80(p); return 0; case AST_AES_CM_128_HMAC_SHA1_32: - p->cipher_type = AES_128_ICM; - p->cipher_key_len = 30; - p->auth_type = HMAC_SHA1; - p->auth_key_len = 20; - p->auth_tag_len = 4; - p->sec_serv = sec_serv_conf_and_auth; + crypto_policy_set_aes_cm_128_hmac_sha1_32(p); return 0; +#ifdef HAVE_SRTP_192 + case AST_AES_CM_192_HMAC_SHA1_80: + crypto_policy_set_aes_cm_192_hmac_sha1_80(p); + return 0; + + case AST_AES_CM_192_HMAC_SHA1_32: + crypto_policy_set_aes_cm_192_hmac_sha1_32(p); + return 0; +#endif +#ifdef HAVE_SRTP_256 + case AST_AES_CM_256_HMAC_SHA1_80: + crypto_policy_set_aes_cm_256_hmac_sha1_80(p); + return 0; + + case AST_AES_CM_256_HMAC_SHA1_32: + crypto_policy_set_aes_cm_256_hmac_sha1_32(p); + return 0; +#endif +#ifdef HAVE_SRTP_GCM + case AST_AES_GCM_128: + crypto_policy_set_aes_gcm_128_16_auth(p); + return 0; + + case AST_AES_GCM_256: + crypto_policy_set_aes_gcm_256_16_auth(p); + return 0; + + case AST_AES_GCM_128_8: + crypto_policy_set_aes_gcm_128_8_auth(p); + return 0; + + case AST_AES_GCM_256_8: + crypto_policy_set_aes_gcm_256_8_auth(p); + return 0; +#endif + default: ast_log(LOG_ERROR, "Invalid crypto suite: %u\n", suite); return -1; diff --git a/utils/conf2ael.c b/utils/conf2ael.c index 8b2043082..3136fe378 100644 --- a/utils/conf2ael.c +++ b/utils/conf2ael.c @@ -670,18 +670,6 @@ const struct ast_include *ast_walk_context_includes(const struct ast_context *co return NULL; } -struct ast_ignorepat *ast_walk_context_ignorepats(struct ast_context *con, struct ast_ignorepat *ip); -struct ast_ignorepat *ast_walk_context_ignorepats(struct ast_context *con, struct ast_ignorepat *ip) -{ - return NULL; -} - -struct ast_sw *ast_walk_context_switches(struct ast_context *con, struct ast_sw *sw); -struct ast_sw *ast_walk_context_switches(struct ast_context *con, struct ast_sw *sw) -{ - return NULL; -} - struct ast_exten *pbx_find_extension(struct ast_channel *chan, struct ast_context *bypass, struct pbx_find_info *q, diff --git a/utils/extconf.c b/utils/extconf.c index 3a0b2e97c..8588d1a28 100644 --- a/utils/extconf.c +++ b/utils/extconf.c @@ -4402,6 +4402,31 @@ struct ast_include *localized_walk_context_includes(struct ast_context *con, return ast_walk_context_includes(con, inc); } +static struct ast_ignorepat *ast_walk_context_ignorepats(struct ast_context *con, + struct ast_ignorepat *ip); + +static struct ast_ignorepat *ast_walk_context_ignorepats(struct ast_context *con, + struct ast_ignorepat *ip) +{ + if (!ip) + return con ? con->ignorepats : NULL; + else + return ip->next; +} + +int ast_context_ignorepats_count(struct ast_context *con); +int ast_context_ignorepats_count(struct ast_context *con) +{ + int c = 0; + struct ast_ignorepat *ip = NULL; + + while ((ip = ast_walk_context_ignorepats(con, ip))) { + c++; + } + + return c; +} + static struct ast_sw *ast_walk_context_switches(struct ast_context *con, struct ast_sw *sw); @@ -4423,6 +4448,19 @@ struct ast_sw *localized_walk_context_switches(struct ast_context *con, return ast_walk_context_switches(con, sw); } +int ast_context_switches_count(struct ast_context *con); +int ast_context_switches_count(struct ast_context *con) +{ + int c = 0; + struct ast_sw *sw = NULL; + + while ((sw = ast_walk_context_switches(con, sw))) { + c++; + } + + return c; +} + static struct ast_context *ast_context_find(const char *name); |