summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES14
-rw-r--r--Makefile6
-rw-r--r--UPGRADE-14.txt91
-rw-r--r--UPGRADE.txt69
-rw-r--r--apps/app_voicemail.c2
-rw-r--r--channels/chan_dahdi.c43
-rw-r--r--channels/chan_dahdi.h5
-rw-r--r--channels/chan_pjsip.c53
-rw-r--r--channels/chan_sip.c71
-rw-r--r--channels/sip/config_parser.c7
-rw-r--r--channels/sip/reqresp_parser.c23
-rw-r--r--configs/samples/chan_dahdi.conf.sample9
-rw-r--r--configs/samples/pjsip.conf.sample22
-rwxr-xr-xconfigure432
-rw-r--r--configure.ac11
-rw-r--r--contrib/ast-db-manage/config/versions/4a6c67fa9b7a_add_fax_detect_timeout_option.py23
-rw-r--r--funcs/func_curl.c2
-rw-r--r--include/asterisk/autoconfig.h.in13
-rw-r--r--include/asterisk/compiler.h6
-rw-r--r--include/asterisk/pbx.h23
-rw-r--r--include/asterisk/res_fax.h4
-rw-r--r--include/asterisk/res_pjsip.h6
-rw-r--r--include/asterisk/res_pjsip_session.h2
-rw-r--r--include/asterisk/res_srtp.h14
-rw-r--r--include/asterisk/sdp_srtp.h18
-rw-r--r--include/asterisk/utils.h9
-rw-r--r--main/channel.c33
-rw-r--r--main/pbx.c378
-rw-r--r--main/pbx_ignorepat.c82
-rw-r--r--main/pbx_private.h13
-rw-r--r--main/pbx_sw.c107
-rw-r--r--main/sdp_srtp.c373
-rw-r--r--main/utils.c4
-rw-r--r--pbx/pbx_config.c40
-rw-r--r--res/ael/pval.c2
-rw-r--r--res/res_fax.c58
-rw-r--r--res/res_pjsip.c61
-rw-r--r--res/res_pjsip/pjsip_configuration.c1
-rw-r--r--res/res_pjsip_mwi.c28
-rw-r--r--res/res_pjsip_pubsub.c2
-rw-r--r--res/res_pjsip_sdp_rtp.c26
-rw-r--r--res/res_rtp_asterisk.c2
-rw-r--r--res/res_srtp.c65
-rw-r--r--utils/conf2ael.c12
-rw-r--r--utils/extconf.c38
45 files changed, 1753 insertions, 550 deletions
diff --git a/CHANGES b/CHANGES
index 6d7cb4c42..31b521c90 100644
--- a/CHANGES
+++ b/CHANGES
@@ -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,
diff --git a/Makefile b/Makefile
index b988c8ff6..bf8f0f89a 100644
--- a/Makefile
+++ b/Makefile
@@ -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
diff --git a/configure b/configure
index 6d3faf204..8bce35d71 100755
--- a/configure
+++ b/configure
@@ -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);