summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES9
-rw-r--r--Makefile3
-rw-r--r--apps/app_record.c56
-rw-r--r--autoconf/ast_gcc_attribute.m43
-rw-r--r--bridges/bridge_softmix.c2
-rw-r--r--build_tools/menuselect-deps.in1
-rw-r--r--cdr/cdr_beanstalkd.c270
-rw-r--r--cel/cel_beanstalkd.c275
-rw-r--r--channels/chan_pjsip.c27
-rw-r--r--channels/iax2/parser.c4
-rw-r--r--configs/samples/ast_debug_tools.conf.sample6
-rw-r--r--configs/samples/asterisk.conf.sample9
-rw-r--r--configs/samples/cdr_beanstalkd.conf.sample26
-rw-r--r--configs/samples/cel_beanstalkd.conf.sample21
-rwxr-xr-xconfigure186
-rw-r--r--configure.ac10
-rwxr-xr-xcontrib/scripts/ast_coredumper156
-rw-r--r--include/asterisk/alertpipe.h3
-rw-r--r--include/asterisk/autoconfig.h.in3
-rw-r--r--include/asterisk/http_websocket.h9
-rw-r--r--include/asterisk/optional_api.h4
-rw-r--r--include/asterisk/options.h5
-rw-r--r--include/asterisk/sorcery.h24
-rw-r--r--include/asterisk/vector.h23
-rw-r--r--main/aoc.c5
-rw-r--r--main/asterisk.c52
-rw-r--r--main/audiohook.c4
-rw-r--r--main/frame.c29
-rw-r--r--main/plc.c2
-rw-r--r--main/sdp_state.c15
-rw-r--r--main/sorcery.c30
-rw-r--r--main/stasis_bridges.c8
-rw-r--r--makeopts.in3
-rw-r--r--menuselect/.gitignore1
-rw-r--r--menuselect/aclocal.m4296
-rw-r--r--res/res_hep_pjsip.c90
-rw-r--r--res/res_http_websocket.c50
-rw-r--r--res/res_pjsip_history.c30
-rw-r--r--res/res_pjsip_pubsub.c35
-rw-r--r--res/res_pjsip_registrar.c56
-rw-r--r--res/res_pjsip_session.c39
-rw-r--r--res/res_pjsip_t38.c13
-rw-r--r--res/res_pjsip_transport_websocket.c18
-rw-r--r--res/res_sorcery_astdb.c38
-rw-r--r--res/res_sorcery_config.c31
-rw-r--r--res/res_sorcery_memory.c25
-rw-r--r--res/res_sorcery_memory_cache.c46
-rw-r--r--res/res_sorcery_realtime.c20
-rw-r--r--third-party/pjproject/patches/0010-r5665-svn-backport-ICE-Use-STUN-FINGERPRINT-attribut.patch41
-rw-r--r--third-party/pjproject/patches/0020-sip_parser-Add-validity-checking-for-numeric-header-.patch973
-rw-r--r--third-party/pjproject/patches/0021-sip_parser-Fix-return-code-in-pjsip_find_msg-and-add.patch41
-rw-r--r--third-party/pjproject/patches/0030-sip_transport-Destroy-transports-not-in-hash.patch27
-rw-r--r--third-party/versions.mak2
53 files changed, 1606 insertions, 1549 deletions
diff --git a/CHANGES b/CHANGES
index 12fe0fe42..b2b740924 100644
--- a/CHANGES
+++ b/CHANGES
@@ -30,6 +30,15 @@ chan_sip
--- Functionality changes from Asterisk 15.1.0 to Asterisk 15.2.0 ------------
------------------------------------------------------------------------------
+Core
+------------------
+ * Added the "cache_media_frames" option to asterisk.conf. Disabling the option
+ helps track down media frame mismanagement when using valgrind or
+ MALLOC_DEBUG. The cache gets in the way of determining if the frame is
+ used after free and who freed it. NOTE: This option has no effect when
+ Asterisk is compiled with the LOW_MEMORY compile time option enabled because
+ the cache code does not exist.
+
res_rtp_asterisk
------------------
* The X.509 certificate used for DTLS negotation can now be automatically
diff --git a/Makefile b/Makefile
index 8048f5915..e37dd90fd 100644
--- a/Makefile
+++ b/Makefile
@@ -1111,3 +1111,6 @@ check-alembic: makeopts
FORCE:
+# This only stops targets within the root Makefile from building in parallel.
+.NOTPARALLEL:
+
diff --git a/apps/app_record.c b/apps/app_record.c
index 8c3a577ef..b9014fed7 100644
--- a/apps/app_record.c
+++ b/apps/app_record.c
@@ -137,6 +137,12 @@ enum {
OPTION_NO_TRUNCATE = (1 << 9),
};
+enum dtmf_response {
+ RESPONSE_NO_MATCH = 0,
+ RESPONSE_OPERATOR,
+ RESPONSE_DTMF,
+};
+
AST_APP_OPTIONS(app_opts,{
AST_APP_OPTION('a', OPTION_APPEND),
AST_APP_OPTION('k', OPTION_KEEP),
@@ -160,24 +166,22 @@ AST_APP_OPTIONS(app_opts,{
* \param dtmf_integer the integer value of the DTMF key received
* \param terminator key currently set to be pressed for normal termination
*
- * \retval 0 do not exit
- * \retval -1 do exit
+ * \returns One of enum dtmf_response
*/
-static int record_dtmf_response(struct ast_channel *chan, struct ast_flags *flags, int dtmf_integer, int terminator)
+static enum dtmf_response record_dtmf_response(struct ast_channel *chan,
+ struct ast_flags *flags, int dtmf_integer, int terminator)
{
if ((dtmf_integer == OPERATOR_KEY) &&
(ast_test_flag(flags, OPTION_OPERATOR_EXIT))) {
- pbx_builtin_setvar_helper(chan, "RECORD_STATUS", "OPERATOR");
- return -1;
+ return RESPONSE_OPERATOR;
}
if ((dtmf_integer == terminator) ||
(ast_test_flag(flags, OPTION_ANY_TERMINATE))) {
- pbx_builtin_setvar_helper(chan, "RECORD_STATUS", "DTMF");
- return -1;
+ return RESPONSE_DTMF;
}
- return 0;
+ return RESPONSE_NO_MATCH;
}
static int create_destination_directory(const char *path)
@@ -246,6 +250,7 @@ static int record_exec(struct ast_channel *chan, const char *data)
);
int ms;
struct timeval start;
+ const char *status_response = "ERROR";
/* The next few lines of code parse out the filename and header from the input string */
if (ast_strlen_zero(data)) { /* no data implies no filename or anything is present */
@@ -343,7 +348,7 @@ static int record_exec(struct ast_channel *chan, const char *data)
if (res) {
ast_log(LOG_WARNING, "Could not answer channel '%s'\n", ast_channel_name(chan));
- pbx_builtin_setvar_helper(chan, "RECORD_STATUS", "ERROR");
+ status_response = "ERROR";
goto out;
}
@@ -379,7 +384,7 @@ static int record_exec(struct ast_channel *chan, const char *data)
if (create_destination_directory(tmp)) {
ast_log(LOG_WARNING, "Could not create directory for file %s\n", args.filename);
- pbx_builtin_setvar_helper(chan, "RECORD_STATUS", "ERROR");
+ status_response = "ERROR";
goto out;
}
@@ -388,7 +393,7 @@ static int record_exec(struct ast_channel *chan, const char *data)
if (!s) {
ast_log(LOG_WARNING, "Could not create file %s\n", args.filename);
- pbx_builtin_setvar_helper(chan, "RECORD_STATUS", "ERROR");
+ status_response = "ERROR";
goto out;
}
@@ -423,7 +428,7 @@ static int record_exec(struct ast_channel *chan, const char *data)
if (res) {
ast_log(LOG_WARNING, "Problem writing frame\n");
ast_frfree(f);
- pbx_builtin_setvar_helper(chan, "RECORD_STATUS", "ERROR");
+ status_response = "ERROR";
break;
}
@@ -439,7 +444,7 @@ static int record_exec(struct ast_channel *chan, const char *data)
/* Ended happily with silence */
ast_frfree(f);
gotsilence = 1;
- pbx_builtin_setvar_helper(chan, "RECORD_STATUS", "SILENCE");
+ status_response = "SILENCE";
break;
}
}
@@ -448,12 +453,26 @@ static int record_exec(struct ast_channel *chan, const char *data)
if (res) {
ast_log(LOG_WARNING, "Problem writing frame\n");
- pbx_builtin_setvar_helper(chan, "RECORD_STATUS", "ERROR");
+ status_response = "ERROR";
ast_frfree(f);
break;
}
} else if (f->frametype == AST_FRAME_DTMF) {
- if (record_dtmf_response(chan, &flags, f->subclass.integer, terminator)) {
+ enum dtmf_response rc =
+ record_dtmf_response(chan, &flags, f->subclass.integer, terminator);
+ switch(rc) {
+ case RESPONSE_NO_MATCH:
+ break;
+ case RESPONSE_OPERATOR:
+ status_response = "OPERATOR";
+ ast_debug(1, "Got OPERATOR\n");
+ break;
+ case RESPONSE_DTMF:
+ status_response = "DTMF";
+ ast_debug(1, "Got DTMF\n");
+ break;
+ }
+ if (rc != RESPONSE_NO_MATCH) {
ast_frfree(f);
break;
}
@@ -463,13 +482,13 @@ static int record_exec(struct ast_channel *chan, const char *data)
if (maxduration > 0 && !ms) {
gottimeout = 1;
- pbx_builtin_setvar_helper(chan, "RECORD_STATUS", "TIMEOUT");
+ status_response = "TIMEOUT";
}
if (!f) {
ast_debug(1, "Got hangup\n");
res = -1;
- pbx_builtin_setvar_helper(chan, "RECORD_STATUS", "HANGUP");
+ status_response = "HANGUP";
if (!ast_test_flag(&flags, OPTION_KEEP)) {
ast_filedelete(args.filename, NULL);
}
@@ -504,6 +523,9 @@ out:
if (sildet) {
ast_dsp_free(sildet);
}
+
+ pbx_builtin_setvar_helper(chan, "RECORD_STATUS", status_response);
+
return res;
}
diff --git a/autoconf/ast_gcc_attribute.m4 b/autoconf/ast_gcc_attribute.m4
index 4ade81404..b1972bedf 100644
--- a/autoconf/ast_gcc_attribute.m4
+++ b/autoconf/ast_gcc_attribute.m4
@@ -7,6 +7,7 @@ AC_MSG_CHECKING(for compiler 'attribute $1' support)
saved_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS -Wall -Wno-unused -Werror"
m4_ifval([$4],$4=0)
+ax_cv_have_func_attribute_$1=0
if test "x$2" = "x"
then
@@ -15,6 +16,7 @@ AC_COMPILE_IFELSE(
[])],
AC_MSG_RESULT(yes)
m4_ifval([$4],$4=1)
+ ax_cv_have_func_attribute_$1=1
AC_DEFINE_UNQUOTED([HAVE_ATTRIBUTE_$1], 1, [Define to 1 if your GCC C compiler supports the '$1' attribute.]),
AC_MSG_RESULT(no)
)
@@ -24,6 +26,7 @@ AC_COMPILE_IFELSE(
[])],
AC_MSG_RESULT(yes)
m4_ifval([$4],$4=1)
+ ax_cv_have_func_attribute_$1=1
AC_DEFINE_UNQUOTED([HAVE_ATTRIBUTE_$1], 1, [Define to 1 if your GCC C compiler supports the '$1' attribute.]),
AC_MSG_RESULT(no)
)
diff --git a/bridges/bridge_softmix.c b/bridges/bridge_softmix.c
index f490967e2..8de88f257 100644
--- a/bridges/bridge_softmix.c
+++ b/bridges/bridge_softmix.c
@@ -541,6 +541,8 @@ static int append_all_streams(struct ast_stream_topology *dest,
dest_index++;
if (ast_stream_get_state(stream) == AST_STREAM_STATE_REMOVED) {
+ /* This cannot fail because dest_index - 1 is less than the
+ * current count in dest. */
ast_stream_topology_set_stream(dest, dest_index - 1, clone);
added = 1;
break;
diff --git a/build_tools/menuselect-deps.in b/build_tools/menuselect-deps.in
index 9becdb62e..259a8358e 100644
--- a/build_tools/menuselect-deps.in
+++ b/build_tools/menuselect-deps.in
@@ -1,5 +1,6 @@
ALSA=@PBX_ALSA@
BLUETOOTH=@PBX_BLUETOOTH@
+BEANSTALK=@PBX_BEANSTALK@
COROSYNC=@PBX_COROSYNC@
CRYPTO=@PBX_CRYPTO@
BFD=@PBX_BFD@
diff --git a/cdr/cdr_beanstalkd.c b/cdr/cdr_beanstalkd.c
new file mode 100644
index 000000000..4812c91aa
--- /dev/null
+++ b/cdr/cdr_beanstalkd.c
@@ -0,0 +1,270 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2017
+ *
+ * Nir Simionovich <nirs@greenfieldtech.net>
+ *
+ * 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 Asterisk Beanstalkd CDR records.
+ *
+ * This module requires the beanstalk-client library, avaialble from
+ * https://github.com/deepfryed/beanstalk-client
+ *
+ * See also
+ * \arg \ref AstCDR
+ * \ingroup cdr_drivers
+ */
+
+/*! \li \ref cdr_beanstalkd.c uses the configuration file \ref cdr_beanstalkd.conf
+ * \addtogroup configuration_file Configuration Files
+ */
+
+/*!
+ * \page cdr_beanstalkd.conf cdr_beanstalkd.conf
+ * \verbinclude cdr_beanstalkd.conf.sample
+ */
+
+/*** MODULEINFO
+ <depend>beanstalk</depend>
+ <support_level>extended</support_level>
+ ***/
+
+#include "asterisk.h"
+
+#include <time.h>
+#include <stdio.h>
+
+#include "beanstalk.h"
+#include "asterisk/channel.h"
+#include "asterisk/cdr.h"
+#include "asterisk/module.h"
+#include "asterisk/utils.h"
+#include "asterisk/manager.h"
+#include "asterisk/config.h"
+#include "asterisk/pbx.h"
+#include "asterisk/json.h"
+
+#define DATE_FORMAT "%Y-%m-%d %T"
+#define CONF_FILE "cdr_beanstalkd.conf"
+#define BEANSTALK_JOB_SIZE 4096
+#define BEANSTALK_JOB_PRIORITY 99
+#define BEANSTALK_JOB_TTR 60
+#define BEANSTALK_JOB_DELAY 0
+#define DEFAULT_BEANSTALK_HOST "127.0.0.1"
+#define DEFAULT_BEANSTALK_PORT 11300
+#define DEFAULT_BEANSTALK_TUBE "asterisk-cdr"
+
+static const char name[] = "cdr_beanstalkd";
+
+static int enablecdr = 0;
+static char *bs_host;
+static int bs_port;
+static char *bs_tube;
+static int priority;
+
+AST_RWLOCK_DEFINE_STATIC(config_lock);
+
+static int beanstalk_put(struct ast_cdr *cdr);
+
+static int load_config(int reload) {
+ char *cat = NULL;
+ struct ast_config *cfg;
+ struct ast_variable *v;
+ struct ast_flags config_flags = {reload ? CONFIG_FLAG_FILEUNCHANGED : 0};
+ int newenablecdr = 0;
+
+ cfg = ast_config_load(CONF_FILE, config_flags);
+ if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
+ return 0;
+ }
+
+ if (cfg == CONFIG_STATUS_FILEINVALID) {
+ ast_log(LOG_ERROR, "Config file '%s' could not be parsed\n", CONF_FILE);
+ return -1;
+ }
+
+ if (!cfg) {
+ /* Standard configuration */
+ ast_log(LOG_WARNING, "Failed to load configuration file. Module not activated.\n");
+ if (enablecdr) {
+ ast_cdr_backend_suspend(name);
+ }
+ enablecdr = 0;
+ return -1;
+ }
+
+ if (reload) {
+ ast_rwlock_wrlock(&config_lock);
+ ast_free(bs_host);
+ ast_free(bs_tube);
+ }
+
+ /* Bootstrap the default configuration */
+ bs_host = ast_strdup(DEFAULT_BEANSTALK_HOST);
+ bs_port = DEFAULT_BEANSTALK_PORT;
+ bs_tube = ast_strdup(DEFAULT_BEANSTALK_TUBE);
+ priority = BEANSTALK_JOB_PRIORITY;
+
+ while ((cat = ast_category_browse(cfg, cat))) {
+ if (!strcasecmp(cat, "general")) {
+ v = ast_variable_browse(cfg, cat);
+ while (v) {
+
+ if (!strcasecmp(v->name, "enabled")) {
+ newenablecdr = ast_true(v->value);
+ } else if (!strcasecmp(v->name, "host")) {
+ ast_free(bs_host);
+ bs_host = ast_strdup(v->value);
+ } else if (!strcasecmp(v->name, "port")) {
+ bs_port = atoi(v->value);
+ } else if (!strcasecmp(v->name, "tube")) {
+ ast_free(bs_tube);
+ bs_tube = ast_strdup(v->value);
+ } else if (!strcasecmp(v->name, "priority")) {
+ priority = atoi(v->value);
+ }
+ v = v->next;
+
+ }
+ }
+ }
+
+ if (reload) {
+ ast_rwlock_unlock(&config_lock);
+ }
+
+ ast_config_destroy(cfg);
+
+ if (!newenablecdr) {
+ ast_cdr_backend_suspend(name);
+ } else if (newenablecdr) {
+ ast_cdr_backend_unsuspend(name);
+ ast_log(LOG_NOTICE, "Added beanstalkd server %s at port %d with tube %s", bs_host, bs_port, bs_tube);
+ }
+ enablecdr = newenablecdr;
+
+ return 0;
+}
+
+static int beanstalk_put(struct ast_cdr *cdr) {
+ struct ast_tm timeresult;
+ char strAnswerTime[80] = "";
+ char strStartTime[80];
+ char strEndTime[80];
+ char *cdr_buffer;
+ int bs_id;
+ int bs_socket;
+ struct ast_json *t_cdr_json;
+
+ if (!enablecdr) {
+ return 0;
+ }
+
+ ast_rwlock_rdlock(&config_lock);
+ bs_socket = bs_connect(bs_host, bs_port);
+
+ if (bs_use(bs_socket, bs_tube) != BS_STATUS_OK) {
+ ast_log(LOG_ERROR, "Connection to Beanstalk tube %s @ %s:%d had failed", bs_tube, bs_host, bs_port);
+ ast_rwlock_unlock(&config_lock);
+ return 0;
+ }
+
+ ast_localtime(&cdr->start, &timeresult, NULL);
+ ast_strftime(strStartTime, sizeof(strStartTime), DATE_FORMAT, &timeresult);
+
+ if (cdr->answer.tv_sec) {
+ ast_localtime(&cdr->answer, &timeresult, NULL);
+ ast_strftime(strAnswerTime, sizeof(strAnswerTime), DATE_FORMAT, &timeresult);
+ }
+
+ ast_localtime(&cdr->end, &timeresult, NULL);
+ ast_strftime(strEndTime, sizeof(strEndTime), DATE_FORMAT, &timeresult);
+
+ ast_rwlock_unlock(&config_lock);
+
+ t_cdr_json = ast_json_pack("{s:s, s:s, s:s, s:s, s:s, s:s, s:s, s:s, s:s, s:s, s:s, s:s, s:i, s:i, s:s, s:s, s:s, s:s}",
+ "AccountCode", S_OR(cdr->accountcode, ""),
+ "Source", S_OR(cdr->src, ""),
+ "Destination", S_OR(cdr->dst, ""),
+ "DestinationContext", S_OR(cdr->dcontext, ""),
+ "CallerID", S_OR(cdr->clid, ""),
+ "Channel", S_OR(cdr->channel, ""),
+ "DestinationChannel", S_OR(cdr->dstchannel, ""),
+ "LastApplication", S_OR(cdr->lastapp, ""),
+ "LastData", S_OR(cdr->lastdata, ""),
+ "StartTime", S_OR(strStartTime, ""),
+ "AnswerTime", S_OR(strAnswerTime, ""),
+ "EndTime", S_OR(strEndTime, ""),
+ "Duration", cdr->duration,
+ "Billsec", cdr->billsec,
+ "Disposition", S_OR(ast_cdr_disp2str(cdr->disposition), ""),
+ "AMAFlags", S_OR(ast_channel_amaflags2string(cdr->amaflags), ""),
+ "UniqueID", S_OR(cdr->uniqueid, ""),
+ "UserField", S_OR(cdr->userfield, ""));
+
+ cdr_buffer = ast_json_dump_string(t_cdr_json);
+
+ ast_json_unref(t_cdr_json);
+
+ bs_id = bs_put(bs_socket, priority, BEANSTALK_JOB_DELAY, BEANSTALK_JOB_TTR, cdr_buffer, strlen(cdr_buffer));
+
+ if (bs_id > 0) {
+ ast_log(LOG_DEBUG, "Successfully created job %d with %s\n", bs_id, cdr_buffer);
+ } else {
+ ast_log(LOG_ERROR, "CDR job creation failed for %s\n", cdr_buffer);
+ }
+
+ bs_disconnect(bs_socket);
+ ast_json_free(cdr_buffer);
+ return 0;
+}
+
+static int unload_module(void) {
+ if (ast_cdr_unregister(name)) {
+ return -1;
+ }
+
+ ast_free(bs_host);
+ ast_free(bs_tube);
+
+ return 0;
+}
+
+static int load_module(void) {
+ if (ast_cdr_register(name, "Asterisk CDR Beanstalkd Backend", beanstalk_put)) {
+ return AST_MODULE_LOAD_DECLINE;
+ }
+
+ if (load_config(0)) {
+ ast_cdr_unregister(name);
+ return AST_MODULE_LOAD_DECLINE;
+ }
+
+ return AST_MODULE_LOAD_SUCCESS;
+}
+
+static int reload(void) {
+ return load_config(1);
+}
+
+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Asterisk Beanstalkd CDR Backend",
+.support_level = AST_MODULE_SUPPORT_EXTENDED,
+.load = load_module,
+.unload = unload_module,
+.reload = reload,
+.load_pri = AST_MODPRI_CDR_DRIVER,
+);
+
diff --git a/cel/cel_beanstalkd.c b/cel/cel_beanstalkd.c
new file mode 100644
index 000000000..e6f23808c
--- /dev/null
+++ b/cel/cel_beanstalkd.c
@@ -0,0 +1,275 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2017, Greenfield Technologies Ltd.
+ *
+ * Nir Simionovich <nirs@greenfieldtech.net>
+ * who freely borrowed code from the cel manager equivalents
+ * (see cel/cel_manager.c)
+ *
+ * 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 Asterisk Channel Event Beanstalkd backend
+ *
+ * This module requires the beanstalk-client library, avaialble from
+ * https://github.com/deepfryed/beanstalk-client
+ *
+ * See also
+ * \arg \ref AstCEL
+ * \ingroup cel_drivers
+ */
+
+/*! \li \ref cek_beanstalkd.c uses the configuration file \ref cel.conf
+ * \addtogroup configuration_file Configuration Files
+ */
+
+/*!
+ * \page cel.conf cel.conf
+ * \verbinclude cel.conf.sample
+ */
+
+/*** MODULEINFO
+ <depend>beanstalk</depend>
+ <support_level>extended</support_level>
+ ***/
+
+#include "asterisk.h"
+
+#include "asterisk/channel.h"
+#include "asterisk/cel.h"
+#include "asterisk/module.h"
+#include "asterisk/logger.h"
+#include "asterisk/utils.h"
+#include "asterisk/manager.h"
+#include "asterisk/config.h"
+#include "asterisk/json.h"
+
+#include "beanstalk.h"
+
+static const char DATE_FORMAT[] = "%Y-%m-%d %T";
+
+static const char CONF_FILE[] = "cel_beanstalkd.conf";
+
+/*! \brief Beanstalk CEL is off by default */
+#define CEL_BEANSTALK_ENABLED_DEFAULT 0
+
+static int enablecel;
+
+/*! \brief show_user_def is off by default */
+#define CEL_SHOW_USERDEF_DEFAULT 0
+
+#define CEL_BACKEND_NAME "Beanstalk Event Logging"
+
+#define BEANSTALK_JOB_SIZE 4096
+#define BEANSTALK_JOB_PRIORITY 99
+#define BEANSTALK_JOB_TTR 60
+#define BEANSTALK_JOB_DELAY 0
+#define DEFAULT_BEANSTALK_HOST "127.0.0.1"
+#define DEFAULT_BEANSTALK_PORT 11300
+#define DEFAULT_BEANSTALK_TUBE "asterisk-cel"
+
+static char *bs_host;
+static int bs_port;
+static char *bs_tube;
+static int priority;
+
+AST_RWLOCK_DEFINE_STATIC(config_lock);
+
+static void cel_bs_put(struct ast_event *event)
+{
+ struct ast_tm timeresult;
+ char start_time[80];
+ char *cel_buffer;
+ int bs_id;
+ int bs_socket;
+ struct ast_json *t_cel_json;
+
+ struct ast_cel_event_record record = {
+ .version = AST_CEL_EVENT_RECORD_VERSION,
+ };
+
+ if (!enablecel) {
+ return;
+ }
+
+ if (ast_cel_fill_record(event, &record)) {
+ return;
+ }
+
+ ast_rwlock_rdlock(&config_lock);
+ bs_socket = bs_connect(bs_host, bs_port);
+
+ if (bs_use(bs_socket, bs_tube) != BS_STATUS_OK) {
+ ast_log(LOG_ERROR, "Connection to Beanstalk tube %s @ %s:%d had failed", bs_tube, bs_host, bs_port);
+ ast_rwlock_unlock(&config_lock);
+ return;
+ }
+
+ ast_localtime(&record.event_time, &timeresult, NULL);
+ ast_strftime(start_time, sizeof(start_time), DATE_FORMAT, &timeresult);
+
+ ast_rwlock_unlock(&config_lock);
+
+ t_cel_json = ast_json_pack("{s:s, s:s, s:s, s:s, s:s, s:s, s:s, s:s, s:s, s:s, s:s, s:s, s:s, s:s, s:s, s:s, s:s, s:s, s:s, s:s}",
+ "EventName", S_OR(record.event_name, ""),
+ "AccountCode", S_OR(record.account_code, ""),
+ "CallerIDnum", S_OR(record.caller_id_num, ""),
+ "CallerIDname", S_OR(record.caller_id_name, ""),
+ "CallerIDani", S_OR(record.caller_id_ani, ""),
+ "CallerIDrdnis", S_OR(record.caller_id_rdnis, ""),
+ "CallerIDdnid", S_OR(record.caller_id_dnid, ""),
+ "Exten", S_OR(record.extension, ""),
+ "Context", S_OR(record.context, ""),
+ "Channel", S_OR(record.channel_name, ""),
+ "Application", S_OR(record.application_name, ""),
+ "AppData", S_OR(record.application_data, ""),
+ "EventTime", S_OR(start_time, ""),
+ "AMAFlags", S_OR(ast_channel_amaflags2string(record.amaflag), ""),
+ "UniqueID", S_OR(record.unique_id, ""),
+ "LinkedID", S_OR(record.linked_id, ""),
+ "Userfield", S_OR(record.user_field, ""),
+ "Peer", S_OR(record.peer_account, ""),
+ "PeerAccount", S_OR(record.peer_account, ""),
+ "Extra", S_OR(record.extra, "")
+
+ );
+
+ cel_buffer = ast_json_dump_string(t_cel_json);
+
+ ast_json_unref(t_cel_json);
+
+ bs_id = bs_put(bs_socket, priority, BEANSTALK_JOB_DELAY, BEANSTALK_JOB_TTR, cel_buffer, strlen(cel_buffer));
+
+ if (bs_id > 0) {
+ ast_log(LOG_DEBUG, "Successfully created job %d with %s\n", bs_id, cel_buffer);
+ } else {
+ ast_log(LOG_ERROR, "CDR job creation failed for %s\n", cel_buffer);
+ }
+
+ bs_disconnect(bs_socket);
+ ast_json_free(cel_buffer);
+}
+
+static int load_config(int reload)
+{
+ const char *cat = NULL;
+ struct ast_config *cfg;
+ struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
+ struct ast_variable *v;
+ int newenablecel = CEL_BEANSTALK_ENABLED_DEFAULT;
+
+ cfg = ast_config_load(CONF_FILE, config_flags);
+ if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
+ return 0;
+ }
+
+ if (cfg == CONFIG_STATUS_FILEINVALID) {
+ ast_log(LOG_WARNING, "Configuration file '%s' is invalid. CEL Beanstalkd Module not activated.\n",
+ CONF_FILE);
+ return -1;
+ } else if (!cfg) {
+ ast_log(LOG_WARNING, "Failed to load configuration file. CEL Beanstalkd Module not activated.\n");
+ if (enablecel) {
+ ast_cel_backend_unregister(CEL_BACKEND_NAME);
+ }
+ enablecel = 0;
+ return -1;
+ }
+
+ if (reload) {
+ ast_rwlock_wrlock(&config_lock);
+ ast_free(bs_host);
+ ast_free(bs_tube);
+ }
+
+ /* Bootstrap the default configuration */
+ bs_host = ast_strdup(DEFAULT_BEANSTALK_HOST);
+ bs_port = DEFAULT_BEANSTALK_PORT;
+ bs_tube = ast_strdup(DEFAULT_BEANSTALK_TUBE);
+ priority = BEANSTALK_JOB_PRIORITY;
+
+ while ((cat = ast_category_browse(cfg, cat))) {
+
+ if (strcasecmp(cat, "general")) {
+ continue;
+ }
+
+ for (v = ast_variable_browse(cfg, cat); v; v = v->next) {
+ if (!strcasecmp(v->name, "enabled")) {
+ newenablecel = ast_true(v->value) ? 1 : 0;
+ } else if (!strcasecmp(v->name, "host")) {
+ ast_free(bs_host);
+ bs_host = ast_strdup(v->value);
+ } else if (!strcasecmp(v->name, "port")) {
+ bs_port = atoi(v->value);
+ } else if (!strcasecmp(v->name, "tube")) {
+ ast_free(bs_tube);
+ bs_tube = ast_strdup(v->value);
+ } else if (!strcasecmp(v->name, "priority")) {
+ priority = atoi(v->value);
+ } else {
+ ast_log(LOG_NOTICE, "Unknown option '%s' specified "
+ "for CEL beanstalk backend.\n", v->name);
+ }
+ }
+ }
+
+ if (reload) {
+ ast_rwlock_unlock(&config_lock);
+ }
+
+ ast_config_destroy(cfg);
+
+ if (enablecel && !newenablecel) {
+ ast_cel_backend_unregister(CEL_BACKEND_NAME);
+ } else if (!enablecel && newenablecel) {
+ if (ast_cel_backend_register(CEL_BACKEND_NAME, cel_bs_put)) {
+ ast_log(LOG_ERROR, "Unable to register Beanstalkd CEL handling\n");
+ }
+ }
+
+ enablecel = newenablecel;
+
+ return 0;
+}
+
+static int unload_module(void)
+{
+ ast_cel_backend_unregister(CEL_BACKEND_NAME);
+ ast_free(bs_host);
+ ast_free(bs_tube);
+ return 0;
+}
+
+static int load_module(void)
+{
+ if (load_config(0)) {
+ return AST_MODULE_LOAD_DECLINE;
+ }
+
+ return AST_MODULE_LOAD_SUCCESS;
+}
+
+static int reload(void)
+{
+ return load_config(1);
+}
+
+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Beanstalkd CEL Backend",
+ .support_level = AST_MODULE_SUPPORT_EXTENDED,
+ .load = load_module,
+ .unload = unload_module,
+ .reload = reload,
+ .load_pri = AST_MODPRI_CDR_DRIVER,
+);
diff --git a/channels/chan_pjsip.c b/channels/chan_pjsip.c
index 7520c2b0e..e4e8fa586 100644
--- a/channels/chan_pjsip.c
+++ b/channels/chan_pjsip.c
@@ -672,7 +672,19 @@ static int answer(void *data)
pjsip_inv_dec_ref(session->inv_session);
#endif
- return (status == PJ_SUCCESS) ? 0 : -1;
+ if (status != PJ_SUCCESS) {
+ char err[PJ_ERR_MSG_SIZE];
+
+ pj_strerror(status, err, sizeof(err));
+ ast_log(LOG_WARNING,"Cannot answer '%s': %s\n",
+ ast_channel_name(session->channel), err);
+ /*
+ * Return this value so we can distinguish between this
+ * failure and the threadpool synchronous push failing.
+ */
+ return -2;
+ }
+ return 0;
}
/*! \brief Function called by core when we should answer a PJSIP session */
@@ -680,6 +692,7 @@ static int chan_pjsip_answer(struct ast_channel *ast)
{
struct ast_sip_channel_pvt *channel = ast_channel_tech_pvt(ast);
struct ast_sip_session *session;
+ int res;
if (ast_channel_state(ast) == AST_STATE_UP) {
return 0;
@@ -700,11 +713,15 @@ static int chan_pjsip_answer(struct ast_channel *ast)
can occur between this thread and bridging (specifically when native bridging
attempts to do direct media) */
ast_channel_unlock(ast);
- if (ast_sip_push_task_synchronous(session->serializer, answer, session)) {
- ast_log(LOG_WARNING, "Unable to push answer task to the threadpool. Cannot answer call\n");
+ res = ast_sip_push_task_synchronous(session->serializer, answer, session);
+ if (res) {
+ if (res == -1) {
+ ast_log(LOG_ERROR,"Cannot answer '%s': Unable to push answer task to the threadpool.\n",
+ ast_channel_name(session->channel));
#ifdef HAVE_PJSIP_INV_SESSION_REF
- pjsip_inv_dec_ref(session->inv_session);
+ pjsip_inv_dec_ref(session->inv_session);
#endif
+ }
ao2_ref(session, -1);
ast_channel_lock(ast);
return -1;
@@ -2442,6 +2459,8 @@ static struct ast_channel *chan_pjsip_request_with_stream_topology(const char *t
req_data.topology = topology;
req_data.dest = data;
+ /* Default failure value in case ast_sip_push_task_synchronous() itself fails. */
+ req_data.cause = AST_CAUSE_FAILURE;
if (ast_sip_push_task_synchronous(NULL, request, &req_data)) {
*cause = req_data.cause;
diff --git a/channels/iax2/parser.c b/channels/iax2/parser.c
index ec9d34608..6eda98260 100644
--- a/channels/iax2/parser.c
+++ b/channels/iax2/parser.c
@@ -1296,7 +1296,9 @@ void iax_frame_free(struct iax_frame *fr)
ast_atomic_fetchadd_int(&frames, -1);
#if !defined(LOW_MEMORY)
- if (!fr->cacheable || !(iax_frames = ast_threadstorage_get(&frame_cache, sizeof(*iax_frames)))) {
+ if (!fr->cacheable
+ || !ast_opt_cache_media_frames
+ || !(iax_frames = ast_threadstorage_get(&frame_cache, sizeof(*iax_frames)))) {
ast_free(fr);
return;
}
diff --git a/configs/samples/ast_debug_tools.conf.sample b/configs/samples/ast_debug_tools.conf.sample
index f26626b20..1c4827f91 100644
--- a/configs/samples/ast_debug_tools.conf.sample
+++ b/configs/samples/ast_debug_tools.conf.sample
@@ -20,6 +20,12 @@
# anyway.
COREDUMPS=(/tmp/core[-._]asterisk!(*.txt) /tmp/core[-._]$(hostname)!(*.txt))
+# The directory to contain output files and work directories.
+# For output from existing core files, the default is the
+# directory that the core file is found in. For core files
+# produced from a running process, the default is /tmp.
+OUTPUTDIR=/some/directory
+
# Date command for the "running" coredump and tarballs.
# DATEFORMAT will be executed to get the timestamp.
# Don't put quotes around the format string or they'll be
diff --git a/configs/samples/asterisk.conf.sample b/configs/samples/asterisk.conf.sample
index 30934e4a9..8379b6ef0 100644
--- a/configs/samples/asterisk.conf.sample
+++ b/configs/samples/asterisk.conf.sample
@@ -44,6 +44,15 @@ astsbindir => /usr/sbin
;minmemfree = 1 ; In MBs, Asterisk stops accepting new calls if
; the amount of free memory falls below this
; watermark.
+;cache_media_frames = yes ; Cache media frames for performance
+ ; Disable this option to help track down media frame
+ ; mismanagement when using valgrind or MALLOC_DEBUG.
+ ; The cache gets in the way of determining if the
+ ; frame is used after being freed and who freed it.
+ ; NOTE: This option has no effect when Asterisk is
+ ; compiled with the LOW_MEMORY compile time option
+ ; enabled because the cache code does not exist.
+ ; Default yes
;cache_record_files = yes ; Cache recorded sound files to another
; directory during recording.
;record_cache_dir = /tmp ; Specify cache directory (used in conjunction
diff --git a/configs/samples/cdr_beanstalkd.conf.sample b/configs/samples/cdr_beanstalkd.conf.sample
new file mode 100644
index 000000000..5f45d5d5d
--- /dev/null
+++ b/configs/samples/cdr_beanstalkd.conf.sample
@@ -0,0 +1,26 @@
+;
+; Asterisk Call Management CDR via Beanstalkd job queue
+;
+; Beanstalkd is a simple job queue server, that is highly versatile and simple to use.
+; Beanstalkd includes the capability of using multiple queues at the same time, with priorities.
+;
+; This module requires that your server has the beanstalk-client library installed. The library
+; can be downloaded from - https://github.com/deepfryed/beanstalk-client
+;
+
+[general]
+;enabled = yes
+
+;host = 127.0.0.1 ; Specify the remote IP address of the Beanstalkd server
+;port = 11300 ; Specify the remote PORT of the the Beanstalkd server
+;tube = asterisk-cdr ; Specify the default CDR job queue to use
+;priority = 99 ; Specify the default job priority for the queue. This parameter is useful when building
+ ; platform with multiple Asterisk servers, that are used for different functions. For example,
+ ; none billable CDR records can be inserted with a priority of 99, while billable ones be
+ ; inserted with a priority of 1
+
+
+
+
+
+
diff --git a/configs/samples/cel_beanstalkd.conf.sample b/configs/samples/cel_beanstalkd.conf.sample
new file mode 100644
index 000000000..8cd0134cc
--- /dev/null
+++ b/configs/samples/cel_beanstalkd.conf.sample
@@ -0,0 +1,21 @@
+;
+; Beanstalkd Job Queue Server CEL Backend
+;
+[general]
+
+; Backend Activation
+;
+; Use the 'enabled' keyword to turn CEL logging
+; on or off.
+;
+; Accepted values: yes and no
+; Default value: no
+;enabled = yes
+
+;host = 127.0.0.1 ; Specify the remote IP address of the Beanstalkd server
+;port = 11300 ; Specify the remote PORT of the the Beanstalkd server
+;tube = asterisk-cel ; Specify the default CDR job queue to use
+;priority = 99 ; Specify the default job priority for the queue. This parameter is useful when building
+ ; platform with multiple Asterisk servers, that are used for different functions. For example,
+ ; none billable CDR records can be inserted with a priority of 99, while billable ones be
+ ; inserted with a priority of 1
diff --git a/configure b/configure
index 9a8fb403c..358e6264c 100755
--- a/configure
+++ b/configure
@@ -996,6 +996,10 @@ PBX_PJSIP_DLG_CREATE_UAS_AND_INC_LOCK
PJSIP_DLG_CREATE_UAS_AND_INC_LOCK_DIR
PJSIP_DLG_CREATE_UAS_AND_INC_LOCK_INCLUDE
PJSIP_DLG_CREATE_UAS_AND_INC_LOCK_LIB
+PBX_BEANSTALK
+BEANSTALK_DIR
+BEANSTALK_INCLUDE
+BEANSTALK_LIB
PBX_PGSQL
PGSQL_DIR
PGSQL_INCLUDE
@@ -1443,6 +1447,7 @@ with_opusfile
with_osptk
with_oss
with_postgres
+with_beanstalk
with_pjproject
with_popt
with_portaudio
@@ -2200,6 +2205,7 @@ Optional Packages:
--with-osptk=PATH use OSP Toolkit files in PATH
--with-oss=PATH use Open Sound System files in PATH
--with-postgres=PATH use PostgreSQL files in PATH
+ --with-beanstalk=PATH use Beanstalk Job Queue files in PATH
--with-pjproject=PATH use PJPROJECT files in PATH
--with-popt=PATH use popt files in PATH
--with-portaudio=PATH use PortAudio files in PATH
@@ -11491,6 +11497,38 @@ fi
+ BEANSTALK_DESCRIP="Beanstalk Job Queue"
+ BEANSTALK_OPTION="beanstalk"
+ PBX_BEANSTALK=0
+
+# Check whether --with-beanstalk was given.
+if test "${with_beanstalk+set}" = set; then :
+ withval=$with_beanstalk;
+ case ${withval} in
+ n|no)
+ USE_BEANSTALK=no
+ # -1 is a magic value used by menuselect to know that the package
+ # was disabled, other than 'not found'
+ PBX_BEANSTALK=-1
+ ;;
+ y|ye|yes)
+ ac_mandatory_list="${ac_mandatory_list} BEANSTALK"
+ ;;
+ *)
+ BEANSTALK_DIR="${withval}"
+ ac_mandatory_list="${ac_mandatory_list} BEANSTALK"
+ ;;
+ esac
+
+fi
+
+
+
+
+
+
+
+
if test "x${PBX_PJPROJECT}" != "x1" ; then
PJPROJECT_DESCRIP="PJPROJECT"
@@ -18139,6 +18177,7 @@ $as_echo_n "checking for compiler 'attribute pure' support... " >&6; }
saved_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS -Wall -Wno-unused -Werror"
+ax_cv_have_func_attribute_pure=0
if test "x" = "x"
then
@@ -18157,6 +18196,7 @@ if ac_fn_c_try_compile "$LINENO"; then :
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
+ ax_cv_have_func_attribute_pure=1
cat >>confdefs.h <<_ACEOF
#define HAVE_ATTRIBUTE_pure 1
@@ -18184,6 +18224,7 @@ if ac_fn_c_try_compile "$LINENO"; then :
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
+ ax_cv_have_func_attribute_pure=1
cat >>confdefs.h <<_ACEOF
#define HAVE_ATTRIBUTE_pure 1
@@ -18207,6 +18248,7 @@ $as_echo_n "checking for compiler 'attribute malloc' support... " >&6; }
saved_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS -Wall -Wno-unused -Werror"
+ax_cv_have_func_attribute_malloc=0
if test "x" = "x"
then
@@ -18225,6 +18267,7 @@ if ac_fn_c_try_compile "$LINENO"; then :
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
+ ax_cv_have_func_attribute_malloc=1
cat >>confdefs.h <<_ACEOF
#define HAVE_ATTRIBUTE_malloc 1
@@ -18252,6 +18295,7 @@ if ac_fn_c_try_compile "$LINENO"; then :
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
+ ax_cv_have_func_attribute_malloc=1
cat >>confdefs.h <<_ACEOF
#define HAVE_ATTRIBUTE_malloc 1
@@ -18275,6 +18319,7 @@ $as_echo_n "checking for compiler 'attribute const' support... " >&6; }
saved_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS -Wall -Wno-unused -Werror"
+ax_cv_have_func_attribute_const=0
if test "x" = "x"
then
@@ -18293,6 +18338,7 @@ if ac_fn_c_try_compile "$LINENO"; then :
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
+ ax_cv_have_func_attribute_const=1
cat >>confdefs.h <<_ACEOF
#define HAVE_ATTRIBUTE_const 1
@@ -18320,6 +18366,7 @@ if ac_fn_c_try_compile "$LINENO"; then :
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
+ ax_cv_have_func_attribute_const=1
cat >>confdefs.h <<_ACEOF
#define HAVE_ATTRIBUTE_const 1
@@ -18343,6 +18390,7 @@ $as_echo_n "checking for compiler 'attribute unused' support... " >&6; }
saved_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS -Wall -Wno-unused -Werror"
+ax_cv_have_func_attribute_unused=0
if test "x" = "x"
then
@@ -18361,6 +18409,7 @@ if ac_fn_c_try_compile "$LINENO"; then :
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
+ ax_cv_have_func_attribute_unused=1
cat >>confdefs.h <<_ACEOF
#define HAVE_ATTRIBUTE_unused 1
@@ -18388,6 +18437,7 @@ if ac_fn_c_try_compile "$LINENO"; then :
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
+ ax_cv_have_func_attribute_unused=1
cat >>confdefs.h <<_ACEOF
#define HAVE_ATTRIBUTE_unused 1
@@ -18411,6 +18461,7 @@ $as_echo_n "checking for compiler 'attribute always_inline' support... " >&6; }
saved_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS -Wall -Wno-unused -Werror"
+ax_cv_have_func_attribute_always_inline=0
if test "x" = "x"
then
@@ -18429,6 +18480,7 @@ if ac_fn_c_try_compile "$LINENO"; then :
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
+ ax_cv_have_func_attribute_always_inline=1
cat >>confdefs.h <<_ACEOF
#define HAVE_ATTRIBUTE_always_inline 1
@@ -18456,6 +18508,7 @@ if ac_fn_c_try_compile "$LINENO"; then :
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
+ ax_cv_have_func_attribute_always_inline=1
cat >>confdefs.h <<_ACEOF
#define HAVE_ATTRIBUTE_always_inline 1
@@ -18479,6 +18532,7 @@ $as_echo_n "checking for compiler 'attribute deprecated' support... " >&6; }
saved_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS -Wall -Wno-unused -Werror"
+ax_cv_have_func_attribute_deprecated=0
if test "x" = "x"
then
@@ -18497,6 +18551,7 @@ if ac_fn_c_try_compile "$LINENO"; then :
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
+ ax_cv_have_func_attribute_deprecated=1
cat >>confdefs.h <<_ACEOF
#define HAVE_ATTRIBUTE_deprecated 1
@@ -18524,6 +18579,7 @@ if ac_fn_c_try_compile "$LINENO"; then :
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
+ ax_cv_have_func_attribute_deprecated=1
cat >>confdefs.h <<_ACEOF
#define HAVE_ATTRIBUTE_deprecated 1
@@ -18547,6 +18603,7 @@ $as_echo_n "checking for compiler 'attribute sentinel' support... " >&6; }
saved_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS -Wall -Wno-unused -Werror"
+ax_cv_have_func_attribute_sentinel=0
if test "x" = "x"
then
@@ -18565,6 +18622,7 @@ if ac_fn_c_try_compile "$LINENO"; then :
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
+ ax_cv_have_func_attribute_sentinel=1
cat >>confdefs.h <<_ACEOF
#define HAVE_ATTRIBUTE_sentinel 1
@@ -18592,6 +18650,7 @@ if ac_fn_c_try_compile "$LINENO"; then :
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
+ ax_cv_have_func_attribute_sentinel=1
cat >>confdefs.h <<_ACEOF
#define HAVE_ATTRIBUTE_sentinel 1
@@ -18615,6 +18674,7 @@ $as_echo_n "checking for compiler 'attribute warn_unused_result' support... " >&
saved_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS -Wall -Wno-unused -Werror"
+ax_cv_have_func_attribute_warn_unused_result=0
if test "x" = "x"
then
@@ -18633,6 +18693,7 @@ if ac_fn_c_try_compile "$LINENO"; then :
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
+ ax_cv_have_func_attribute_warn_unused_result=1
cat >>confdefs.h <<_ACEOF
#define HAVE_ATTRIBUTE_warn_unused_result 1
@@ -18660,6 +18721,7 @@ if ac_fn_c_try_compile "$LINENO"; then :
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
+ ax_cv_have_func_attribute_warn_unused_result=1
cat >>confdefs.h <<_ACEOF
#define HAVE_ATTRIBUTE_warn_unused_result 1
@@ -18683,6 +18745,7 @@ $as_echo_n "checking for compiler 'attribute may_alias' support... " >&6; }
saved_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS -Wall -Wno-unused -Werror"
+ax_cv_have_func_attribute_may_alias=0
if test "x" = "x"
then
@@ -18701,6 +18764,7 @@ if ac_fn_c_try_compile "$LINENO"; then :
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
+ ax_cv_have_func_attribute_may_alias=1
cat >>confdefs.h <<_ACEOF
#define HAVE_ATTRIBUTE_may_alias 1
@@ -18728,6 +18792,7 @@ if ac_fn_c_try_compile "$LINENO"; then :
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
+ ax_cv_have_func_attribute_may_alias=1
cat >>confdefs.h <<_ACEOF
#define HAVE_ATTRIBUTE_may_alias 1
@@ -18751,6 +18816,7 @@ $as_echo_n "checking for compiler 'attribute constructor' support... " >&6; }
saved_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS -Wall -Wno-unused -Werror"
+ax_cv_have_func_attribute_constructor=0
if test "x" = "x"
then
@@ -18769,6 +18835,7 @@ if ac_fn_c_try_compile "$LINENO"; then :
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
+ ax_cv_have_func_attribute_constructor=1
cat >>confdefs.h <<_ACEOF
#define HAVE_ATTRIBUTE_constructor 1
@@ -18796,6 +18863,7 @@ if ac_fn_c_try_compile "$LINENO"; then :
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
+ ax_cv_have_func_attribute_constructor=1
cat >>confdefs.h <<_ACEOF
#define HAVE_ATTRIBUTE_constructor 1
@@ -18813,12 +18881,17 @@ fi
CFLAGS="$saved_CFLAGS"
+if test "$ax_cv_have_func_attribute_constructor" != "1"; then
+ as_fn_error $? "*** Function constructor attribute is not supported by your compiler." "$LINENO" 5
+fi
+
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for compiler 'attribute destructor' support" >&5
$as_echo_n "checking for compiler 'attribute destructor' support... " >&6; }
saved_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS -Wall -Wno-unused -Werror"
+ax_cv_have_func_attribute_destructor=0
if test "x" = "x"
then
@@ -18837,6 +18910,7 @@ if ac_fn_c_try_compile "$LINENO"; then :
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
+ ax_cv_have_func_attribute_destructor=1
cat >>confdefs.h <<_ACEOF
#define HAVE_ATTRIBUTE_destructor 1
@@ -18864,6 +18938,7 @@ if ac_fn_c_try_compile "$LINENO"; then :
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
+ ax_cv_have_func_attribute_destructor=1
cat >>confdefs.h <<_ACEOF
#define HAVE_ATTRIBUTE_destructor 1
@@ -18881,12 +18956,16 @@ fi
CFLAGS="$saved_CFLAGS"
+if test "$ax_cv_have_func_attribute_destructor" != "1"; then
+ as_fn_error $? "*** Function destructor attribute is not supported by your compiler." "$LINENO" 5
+fi
{ $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"
+ax_cv_have_func_attribute_noreturn=0
if test "xnoreturn" = "x"
then
@@ -18905,6 +18984,7 @@ if ac_fn_c_try_compile "$LINENO"; then :
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
+ ax_cv_have_func_attribute_noreturn=1
cat >>confdefs.h <<_ACEOF
#define HAVE_ATTRIBUTE_noreturn 1
@@ -18932,6 +19012,7 @@ if ac_fn_c_try_compile "$LINENO"; then :
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
+ ax_cv_have_func_attribute_noreturn=1
cat >>confdefs.h <<_ACEOF
#define HAVE_ATTRIBUTE_noreturn 1
@@ -25185,6 +25266,111 @@ fi
+
+if test "x${PBX_BEANSTALK}" != "x1" -a "${USE_BEANSTALK}" != "no"; then
+ pbxlibdir=""
+ # if --with-BEANSTALK=DIR has been specified, use it.
+ if test "x${BEANSTALK_DIR}" != "x"; then
+ if test -d ${BEANSTALK_DIR}/lib; then
+ pbxlibdir="-L${BEANSTALK_DIR}/lib"
+ else
+ pbxlibdir="-L${BEANSTALK_DIR}"
+ fi
+ fi
+ pbxfuncname="bs_version"
+ if test "x${pbxfuncname}" = "x" ; then # empty lib, assume only headers
+ AST_BEANSTALK_FOUND=yes
+ else
+ ast_ext_lib_check_save_CFLAGS="${CFLAGS}"
+ CFLAGS="${CFLAGS} "
+ as_ac_Lib=`$as_echo "ac_cv_lib_beanstalk_${pbxfuncname}" | $as_tr_sh`
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${pbxfuncname} in -lbeanstalk" >&5
+$as_echo_n "checking for ${pbxfuncname} in -lbeanstalk... " >&6; }
+if eval \${$as_ac_Lib+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lbeanstalk ${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_BEANSTALK_FOUND=yes
+else
+ AST_BEANSTALK_FOUND=no
+fi
+
+ CFLAGS="${ast_ext_lib_check_save_CFLAGS}"
+ fi
+
+ # now check for the header.
+ if test "${AST_BEANSTALK_FOUND}" = "yes"; then
+ BEANSTALK_LIB="${pbxlibdir} -lbeanstalk "
+ # if --with-BEANSTALK=DIR has been specified, use it.
+ if test "x${BEANSTALK_DIR}" != "x"; then
+ BEANSTALK_INCLUDE="-I${BEANSTALK_DIR}/include"
+ fi
+ BEANSTALK_INCLUDE="${BEANSTALK_INCLUDE} "
+ if test "xbeanstalk.h" = "x" ; then # no header, assume found
+ BEANSTALK_HEADER_FOUND="1"
+ else # check for the header
+ ast_ext_lib_check_saved_CPPFLAGS="${CPPFLAGS}"
+ CPPFLAGS="${CPPFLAGS} ${BEANSTALK_INCLUDE}"
+ ac_fn_c_check_header_mongrel "$LINENO" "beanstalk.h" "ac_cv_header_beanstalk_h" "$ac_includes_default"
+if test "x$ac_cv_header_beanstalk_h" = xyes; then :
+ BEANSTALK_HEADER_FOUND=1
+else
+ BEANSTALK_HEADER_FOUND=0
+fi
+
+
+ CPPFLAGS="${ast_ext_lib_check_saved_CPPFLAGS}"
+ fi
+ if test "x${BEANSTALK_HEADER_FOUND}" = "x0" ; then
+ BEANSTALK_LIB=""
+ BEANSTALK_INCLUDE=""
+ else
+ if test "x${pbxfuncname}" = "x" ; then # only checking headers -> no library
+ BEANSTALK_LIB=""
+ fi
+ PBX_BEANSTALK=1
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_BEANSTALK 1
+_ACEOF
+
+ fi
+ fi
+fi
+
+
+
# possible places for oss definitions
if test "x${PBX_OSS}" != "x1" -a "${USE_OSS}" != "no"; then
diff --git a/configure.ac b/configure.ac
index 23ff5265a..47c6b26d4 100644
--- a/configure.ac
+++ b/configure.ac
@@ -507,6 +507,7 @@ AST_EXT_LIB_SETUP([OPUSFILE], [Opusfile], [opusfile])
AST_EXT_LIB_SETUP([OSPTK], [OSP Toolkit], [osptk])
AST_EXT_LIB_SETUP([OSS], [Open Sound System], [oss])
AST_EXT_LIB_SETUP([PGSQL], [PostgreSQL], [postgres])
+AST_EXT_LIB_SETUP([BEANSTALK], [Beanstalk Job Queue], [beanstalk])
if test "x${PBX_PJPROJECT}" != "x1" ; then
AST_EXT_LIB_SETUP([PJPROJECT], [PJPROJECT], [pjproject])
@@ -1149,7 +1150,14 @@ AST_GCC_ATTRIBUTE(sentinel)
AST_GCC_ATTRIBUTE(warn_unused_result)
AST_GCC_ATTRIBUTE(may_alias)
AST_GCC_ATTRIBUTE(constructor)
+if test "$ax_cv_have_func_attribute_constructor" != "1"; then
+ AC_MSG_ERROR([*** Function constructor attribute is not supported by your compiler.])
+fi
+
AST_GCC_ATTRIBUTE(destructor)
+if test "$ax_cv_have_func_attribute_destructor" != "1"; then
+ AC_MSG_ERROR([*** Function destructor attribute is not supported by your compiler.])
+fi
AST_GCC_ATTRIBUTE(noreturn,noreturn)
AC_MSG_CHECKING(for -fsanitize=address support)
@@ -2188,6 +2196,8 @@ AST_EXT_LIB_CHECK([BKTR], [c], [backtrace], [execinfo.h])
AST_EXT_LIB_CHECK([BLUETOOTH], [bluetooth], [ba2str], [bluetooth/bluetooth.h])
+AST_EXT_LIB_CHECK([BEANSTALK], [beanstalk], [bs_version], [beanstalk.h])
+
# possible places for oss definitions
AST_EXT_LIB_CHECK([OSS], [ossaudio], [], [linux/soundcard.h])
AST_EXT_LIB_CHECK([OSS], [ossaudio], [], [sys/soundcard.h])
diff --git a/contrib/scripts/ast_coredumper b/contrib/scripts/ast_coredumper
index 9b01a4239..884ede71f 100755
--- a/contrib/scripts/ast_coredumper
+++ b/contrib/scripts/ast_coredumper
@@ -15,7 +15,7 @@ SYNOPSIS
$prog [ --help ] [ --running | --RUNNING ] [ --latest ]
[ --tarball-coredumps ] [ --delete-coredumps-after ]
[ --tarball-results ] [ --delete-results-after ]
- [ --tarball-uniqueid="<uniqueid>" ]
+ [ --tarball-config ] [ --tarball-uniqueid="<uniqueid>" ]
[ --no-default-search ] [ --append-coredumps ]
[ --asterisk-bin="path" ]
[ <coredump> | <pattern> ... ]
@@ -51,7 +51,8 @@ DESCRIPTION
Create a coredump from the running asterisk instance and
process it along with any other coredumps found (if any).
WARNING: This WILL interrupt call processing. You will be
- asked to confirm.
+ asked to confirm. The coredump will be written to /tmp if
+ $OUTPUTDIR is not defined.
--RUNNING
Same as --running but without the confirmation prompt.
@@ -69,10 +70,11 @@ DESCRIPTION
/usr/sbin/asterisk, /usr/lib(64)/libasterisk* and
/usr/lib(64)/asterisk as those files are needed to properly
examine the coredump. The file will be named
- /tmp/asterisk.<timestamp>.coredumps.tar.gz or
- /tmp/asterisk-<uniqueid>.coredumps.tar.gz if
+ $OUTPUTDIR/asterisk.<timestamp>.coredumps.tar.gz or
+ $OUTPUTDIR/asterisk-<uniqueid>.coredumps.tar.gz if
--tarball-uniqueid was specified.
WARNING: This file could 1gb in size!
+ Mutually exclusive with --tartball-results
--delete-coredumps-after
Deletes all processed coredumps regardless of whether
@@ -81,7 +83,8 @@ DESCRIPTION
--tarball-results
Creates a gzipped tarball of all result files produced.
The tarball name will be:
- /tmp/asterisk.<timestamp>.results.tar.gz
+ $OUTPUTDIR/asterisk.<timestamp>.results.tar.gz
+ Mutually exclusive with --tartball-coredumps
--delete-results-after
Deletes all processed results regardless of whether
@@ -89,6 +92,10 @@ DESCRIPTION
to use this option unless you have also specified
--tarball-results.
+ --tarball-config
+ Adds the contents of /etc/asterisk to the tarball created
+ with --tarball-coredumps or --tarball-results.
+
--tarball-uniqueid="<uniqueid>"
Normally DATEFORMAT is used to make the tarballs unique
but you can use your own unique id in the tarball names
@@ -130,6 +137,10 @@ DESCRIPTION
NOTES
You must be root to use $prog.
+ $OUTPUTDIR can be read from the current environment or from the
+ ast_debug_tools.conf file described below. If not specified,
+ work products are placed in the same directory as the core file.
+
The script relies on not only bash, but also recent GNU date and
gdb with python support. *BSD operating systems may require
installation of the 'coreutils' and 'devel/gdb' packagess and minor
@@ -166,6 +177,12 @@ FILES
# anyway.
COREDUMPS=(/tmp/core[-._]asterisk!(*.txt) /tmp/core[-._]\$(hostname)!(*.txt))
+ # The directory to contain output files and work directories.
+ # For output from existing core files, the default is the
+ # directory that the core file is found in. For core files
+ # produced from a running process, the default is /tmp.
+ OUTPUTDIR=/some/directory
+
# Date command for the "running" coredump and tarballs.
# DATEFORMAT will be executed to get the timestamp.
# Don't put quotes around the format string or they'll be
@@ -227,6 +244,13 @@ if [ -z "$GDB" ] ; then
exit 1
fi
+if [ -n "$OUTPUTDIR" ] ; then
+ if [ ! -d "$OUTPUTDIR" ] ; then
+ echo "OUTPUTDIR $OUTPUTDIR doesn't exists or is not a directory"
+ exit 1
+ fi
+fi
+
if [ ${#COREDUMPS[@]} -eq 0 ] ; then
COREDUMPS+=(/tmp/core[-._]asterisk!(*.txt) /tmp/core[-._]$(hostname)!(*.txt))
fi
@@ -326,6 +350,10 @@ fi
# Timestamp to use for output files
df=${tarball_uniqueid:-$(${DATEFORMAT})}
+if [ -z "$asterisk_bin" ]; then
+ asterisk_bin=$(which asterisk)
+fi
+
if $running || $RUNNING ; then
# We need to go through some gyrations to find the pid of the running
# MAIN asterisk process and not someone or something running asterisk -r.
@@ -351,9 +379,9 @@ if $running || $RUNNING ; then
read -p "WARNING: Taking a core dump of the running asterisk instance will suspend call processing while the dump is saved. Do you wish to continue? (y/N) " answer
fi
if [[ "$answer" =~ ^[Yy] ]] ; then
- cf="/tmp/core-asterisk-running-$df"
+ cf="${OUTPUTDIR:-/tmp}/core-asterisk-running-$df"
echo "Dumping running asterisk process to $cf"
- ${GDB} -p $pid -q --batch --ex "gcore $cf" >/dev/null 2>&1
+ ${GDB} ${asterisk_bin} -p $pid -q --batch --ex "gcore $cf" >/dev/null 2>&1
COREDUMPS+=("$cf")
else
echo "Skipping dump of running process"
@@ -370,20 +398,22 @@ fi
# and save them to /tmp/.gdbinit
ss=`egrep -n "^#@@@SCRIPTSTART@@@" $0 |cut -f1 -d:`
-tail -n +${ss} $0 >/tmp/.ast_coredumper.gdbinit
+tail -n +${ss} $0 >${OUTPUTDIR:-/tmp}/.ast_coredumper.gdbinit
# Now iterate over the coredumps and dump the debugging info
for i in ${!COREDUMPS[@]} ; do
cf=${COREDUMPS[$i]}
echo "Processing $cf"
- if [ -z "$asterisk_bin" ]; then
- asterisk_bin=$(which asterisk)
- fi
- ${GDB} -n --batch -q --ex "source /tmp/.ast_coredumper.gdbinit" "$asterisk_bin" "$cf" 2>/dev/null | (
+
+ cfdir=`dirname ${cf}`
+ cfname=`basename ${cf}`
+ outputdir=${OUTPUTDIR:-${cfdir}}
+
+ ${GDB} -n --batch -q --ex "source ${OUTPUTDIR:-/tmp}/.ast_coredumper.gdbinit" "$asterisk_bin" "$cf" 2>/dev/null | (
of=/dev/null
while IFS= read line ; do
if [[ "$line" =~ !@!@!@!\ ([^\ ]+)\ !@!@!@! ]] ; then
- of=${cf}-${BASH_REMATCH[1]}
+ of=${outputdir}/${cfname}-${BASH_REMATCH[1]}
of=${of//:/-}
rm -f "$of"
echo "Creating $of"
@@ -391,50 +421,58 @@ for i in ${!COREDUMPS[@]} ; do
echo -e $"$line" >> "$of"
done
)
-done
-if $tarball_coredumps ; then
- tf=/tmp/asterisk-$df.coredumps.tar.gz
- echo "Creating $tf"
- dest=/tmp/asterisk-$df
- rm -rf $dest 2>/dev/null || :
- libdir=usr/lib
- [ -d /usr/lib64 ] && libdir+=64
- mkdir -p $dest/tmp $dest/$libdir/asterisk $dest/etc $dest/usr/sbin
- for i in ${!COREDUMPS[@]} ; do
- ln -s "${COREDUMPS[@]}" $dest/"${COREDUMPS[@]}"
- cp "${COREDUMPS[@]}"*.txt $dest/tmp/
- done
- cp /etc/os-release $dest/etc/
- cp -a /$libdir/libasterisk* $dest/$libdir/
- cp -a /$libdir/asterisk/* $dest/$libdir/asterisk/
- cp -a /usr/sbin/asterisk $dest/usr/sbin
- rm -rf $tf
- tar -chzf $tf --transform="s/^[.]/$df/" -C $dest .
- rm -rf $dest
- echo "Created $tf"
-fi
+ if $tarball_coredumps ; then
+ cfname=${cfname//:/-}
+ tf=${outputdir}/${cfname}.tar.gz
+ echo "Creating ${tf}"
-if $delete_coredumps_after ; then
- for i in ${!COREDUMPS[@]} ; do
- rm -rf "${COREDUMPS[$i]}"
- done
-fi
+ dest=${outputdir}/${cfname}.output
+ rm -rf ${dest} 2>/dev/null || :
-if $tarball_results ; then
- tf=/tmp/asterisk-$df-results.tar
- echo "Creating $tf.gz"
- for i in ${!COREDUMPS[@]} ; do
- tar -uvf $tf "${COREDUMPS[$i]//:/-}"-{brief,full,thread1,locks}.txt 2>/dev/null
- done
- gzip $tf
-fi
+ libdir=usr/lib
+ [ -d /usr/lib64 ] && libdir+=64
+ mkdir -p ${dest}/tmp ${dest}/${libdir}/asterisk ${dest}/etc ${dest}/usr/sbin
-if $delete_results_after ; then
- for i in ${!COREDUMPS[@]} ; do
- rm -rf "${COREDUMPS[$i]//:/-}"-{brief,full,thread1,locks}.txt
- done
-fi
+ ln -s ${cf} ${dest}/tmp/${cfname}
+ cp ${outputdir}/${cfname}*.txt ${dest}/tmp/
+ cp /etc/os-release ${dest}/etc/
+ if $tarball_config ; then
+ cp -a /etc/asterisk ${dest}/etc/
+ fi
+ cp -a /${libdir}/libasterisk* ${dest}/${libdir}/
+ cp -a /${libdir}/asterisk/* ${dest}/${libdir}/asterisk/
+ cp -a /usr/sbin/asterisk ${dest}/usr/sbin
+ rm -rf ${tf}
+ tar -chzf ${tf} --transform="s/^[.]/${cfname}/" -C ${dest} .
+ rm -rf ${dest}
+ echo "Created $tf"
+ elif $tarball_results ; then
+ cfname=${cfname//:/-}
+ tf=${outputdir}/${cfname}.tar.gz
+ echo "Creating ${tf}"
+
+ dest=${outputdir}/${cfname}.output
+ rm -rf ${dest} 2>/dev/null || :
+ mkdir -p ${dest}
+ cp ${outputdir}/${cfname}*.txt ${dest}/
+ if $tarball_config ; then
+ mkdir -p ${dest}/etc
+ cp -a /etc/asterisk ${dest}/etc/
+ fi
+ tar -chzf ${tf} --transform="s/^[.]/${cfname}/" -C ${dest} .
+ rm -rf ${dest}
+ echo "Created $tf"
+ fi
+
+if $delete_coredumps_after ; then
+ rm -rf "${cf}"
+ fi
+
+ if $delete_results_after ; then
+ rm -rf "${cf//:/-}"-{brief,full,thread1,locks}.txt
+ fi
+done
exit
@@ -463,6 +501,9 @@ class DumpAsteriskCommand(gdb.Command):
try:
gdb.execute("p $_siginfo", from_tty)
gdb.execute("info signal $_siginfo.si_signo")
+ except:
+ pass
+ try:
gdb.execute("thread apply 1 bt full", from_tty)
except:
pass
@@ -470,6 +511,9 @@ class DumpAsteriskCommand(gdb.Command):
try:
gdb.execute("p $_siginfo", from_tty)
gdb.execute("info signal $_siginfo.si_signo")
+ except:
+ pass
+ try:
gdb.execute("thread apply all bt", from_tty)
except:
pass
@@ -477,6 +521,9 @@ class DumpAsteriskCommand(gdb.Command):
try:
gdb.execute("p $_siginfo", from_tty)
gdb.execute("info signal $_siginfo.si_signo")
+ except:
+ pass
+ try:
gdb.execute("thread apply all bt full", from_tty)
except:
pass
@@ -484,6 +531,9 @@ class DumpAsteriskCommand(gdb.Command):
try:
gdb.execute("p $_siginfo", from_tty)
gdb.execute("info signal $_siginfo.si_signo")
+ except:
+ pass
+ try:
gdb.execute("show_locks", from_tty)
except:
pass
diff --git a/include/asterisk/alertpipe.h b/include/asterisk/alertpipe.h
index 5ff854ce8..09c335829 100644
--- a/include/asterisk/alertpipe.h
+++ b/include/asterisk/alertpipe.h
@@ -65,7 +65,8 @@ ast_alert_status_t ast_alertpipe_read(int alert_pipe[2]);
*
* \param p a two-element array containing the alert pipe's file descriptors
*
- * \return see write(2)
+ * \retval 0 Success
+ * \retval 1 Failure
*/
ssize_t ast_alertpipe_write(int alert_pipe[2]);
diff --git a/include/asterisk/autoconfig.h.in b/include/asterisk/autoconfig.h.in
index cfa260b21..4700d4092 100644
--- a/include/asterisk/autoconfig.h.in
+++ b/include/asterisk/autoconfig.h.in
@@ -121,6 +121,9 @@
attribute. */
#undef HAVE_ATTRIBUTE_warn_unused_result
+/* Define to 1 if you have the Beanstalk Job Queue library. */
+#undef HAVE_BEANSTALK
+
/* Define to 1 if you have the Debug symbol decoding library. */
#undef HAVE_BFD
diff --git a/include/asterisk/http_websocket.h b/include/asterisk/http_websocket.h
index cd49dbe48..2180ef46b 100644
--- a/include/asterisk/http_websocket.h
+++ b/include/asterisk/http_websocket.h
@@ -345,6 +345,15 @@ AST_OPTIONAL_API(int, ast_websocket_fd, (struct ast_websocket *session), { errno
AST_OPTIONAL_API(struct ast_sockaddr *, ast_websocket_remote_address, (struct ast_websocket *session), {return NULL;});
/*!
+ * \brief Get the local address for a WebSocket connection session.
+ *
+ * \retval ast_sockaddr Local address
+ *
+ * \since 13.19.0
+ */
+AST_OPTIONAL_API(struct ast_sockaddr *, ast_websocket_local_address, (struct ast_websocket *session), {return NULL;});
+
+/*!
* \brief Get whether the WebSocket session is using a secure transport or not.
*
* \retval 0 if unsecure
diff --git a/include/asterisk/optional_api.h b/include/asterisk/optional_api.h
index 1118dc7cd..1ac765162 100644
--- a/include/asterisk/optional_api.h
+++ b/include/asterisk/optional_api.h
@@ -107,10 +107,6 @@
#if defined(OPTIONAL_API)
-#if !defined(HAVE_ATTRIBUTE_constructor) || !defined(HAVE_ATTRIBUTE_constructor)
-#error OPTIONAL_API requires compiler constructor/destructor support
-#endif
-
/*!
* \internal
* \brief Function pointer to an optional API function.
diff --git a/include/asterisk/options.h b/include/asterisk/options.h
index 0a20f10a8..878748d16 100644
--- a/include/asterisk/options.h
+++ b/include/asterisk/options.h
@@ -66,6 +66,8 @@ enum ast_option_flags {
AST_OPT_FLAG_CACHE_RECORD_FILES = (1 << 13),
/*! Display timestamp in CLI verbose output */
AST_OPT_FLAG_TIMESTAMP = (1 << 14),
+ /*! Cache media frames for performance */
+ AST_OPT_FLAG_CACHE_MEDIA_FRAMES = (1 << 15),
/*! Reconnect */
AST_OPT_FLAG_RECONNECT = (1 << 16),
/*! Transmit Silence during Record() and DTMF Generation */
@@ -99,7 +101,7 @@ enum ast_option_flags {
};
/*! These are the options that set by default when Asterisk starts */
-#define AST_DEFAULT_OPTIONS AST_OPT_FLAG_TRANSCODE_VIA_SLIN
+#define AST_DEFAULT_OPTIONS (AST_OPT_FLAG_TRANSCODE_VIA_SLIN | AST_OPT_FLAG_CACHE_MEDIA_FRAMES)
#define ast_opt_exec_includes ast_test_flag(&ast_options, AST_OPT_FLAG_EXEC_INCLUDES)
#define ast_opt_no_fork ast_test_flag(&ast_options, AST_OPT_FLAG_NO_FORK)
@@ -116,6 +118,7 @@ enum ast_option_flags {
#define ast_opt_stdexten_macro ast_test_flag(&ast_options, AST_OPT_FLAG_STDEXTEN_MACRO)
#define ast_opt_dump_core ast_test_flag(&ast_options, AST_OPT_FLAG_DUMP_CORE)
#define ast_opt_cache_record_files ast_test_flag(&ast_options, AST_OPT_FLAG_CACHE_RECORD_FILES)
+#define ast_opt_cache_media_frames ast_test_flag(&ast_options, AST_OPT_FLAG_CACHE_MEDIA_FRAMES)
#define ast_opt_timestamp ast_test_flag(&ast_options, AST_OPT_FLAG_TIMESTAMP)
#define ast_opt_reconnect ast_test_flag(&ast_options, AST_OPT_FLAG_RECONNECT)
#define ast_opt_transmit_silence ast_test_flag(&ast_options, AST_OPT_FLAG_TRANSMIT_SILENCE)
diff --git a/include/asterisk/sorcery.h b/include/asterisk/sorcery.h
index bfb2c39ad..bafca5fb6 100644
--- a/include/asterisk/sorcery.h
+++ b/include/asterisk/sorcery.h
@@ -298,6 +298,14 @@ struct ast_sorcery_wizard {
/*! \brief Callback for retrieving multiple objects using a regex on their id */
void (*retrieve_regex)(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const char *regex);
+ /*! \brief Optional callback for retrieving multiple objects by matching their id with a prefix */
+ void (*retrieve_prefix)(const struct ast_sorcery *sorcery,
+ void *data,
+ const char *type,
+ struct ao2_container *objects,
+ const char *prefix,
+ const size_t prefix_len);
+
/*! \brief Optional callback for retrieving an object using fields */
void *(*retrieve_fields)(const struct ast_sorcery *sorcery, void *data, const char *type, const struct ast_variable *fields);
@@ -1241,6 +1249,22 @@ void *ast_sorcery_retrieve_by_fields(const struct ast_sorcery *sorcery, const ch
struct ao2_container *ast_sorcery_retrieve_by_regex(const struct ast_sorcery *sorcery, const char *type, const char *regex);
/*!
+ * \brief Retrieve multiple objects whose id begins with the specified prefix
+ * \since 13.19.0
+ *
+ * \param sorcery Pointer to a sorcery structure
+ * \param type Type of object to retrieve
+ * \param prefix Object id prefix
+ * \param prefix_len The length of prefix in bytes
+ *
+ * \retval non-NULL if error occurs
+ * \retval NULL success
+ *
+ * \note The prefix is matched in a case sensitive manner.
+ */
+struct ao2_container *ast_sorcery_retrieve_by_prefix(const struct ast_sorcery *sorcery, const char *type, const char *prefix, const size_t prefix_len);
+
+/*!
* \brief Update an object
*
* \param sorcery Pointer to a sorcery structure
diff --git a/include/asterisk/vector.h b/include/asterisk/vector.h
index 68ce13065..8bd1cefef 100644
--- a/include/asterisk/vector.h
+++ b/include/asterisk/vector.h
@@ -51,6 +51,9 @@
/*! \brief Integer vector definition */
AST_VECTOR(ast_vector_int, int);
+/*! \brief String vector definition */
+AST_VECTOR(ast_vector_string, char *);
+
/*!
* \brief Define a vector structure with a read/write lock
*
@@ -91,6 +94,26 @@ AST_VECTOR(ast_vector_int, int);
})
/*!
+ * \brief Steal the elements from a vector and reinitialize.
+ *
+ * \param vec Vector to operate on.
+ *
+ * This allows you to use vector.h to construct a list and use the
+ * data as a bare array.
+ *
+ * \note The stolen array must eventually be released using ast_free.
+ *
+ * \warning AST_VECTOR_SIZE and AST_VECTOR_MAX_SIZE are both reset
+ * to 0. If either are needed they must be saved to a local
+ * variable before stealing the elements.
+ */
+#define AST_VECTOR_STEAL_ELEMENTS(vec) ({ \
+ typeof((vec)->elems) __elems = (vec)->elems; \
+ AST_VECTOR_INIT((vec), 0); \
+ (__elems); \
+})
+
+/*!
* \brief Initialize a vector with a read/write lock
*
* If \a size is 0, then no space will be allocated until the vector is
diff --git a/main/aoc.c b/main/aoc.c
index 451b21973..3487948df 100644
--- a/main/aoc.c
+++ b/main/aoc.c
@@ -1860,7 +1860,10 @@ static void aoc_publish_blob(struct ast_channel *chan, struct stasis_message_typ
msg = stasis_message_create(msg_type, aoc_event);
ao2_ref(aoc_event, -1);
- stasis_publish(ast_manager_get_topic(), msg);
+ if (msg) {
+ stasis_publish(ast_manager_get_topic(), msg);
+ ao2_ref(msg, -1);
+ }
}
static struct ast_manager_event_blob *aoc_to_ami(struct stasis_message *message,
diff --git a/main/asterisk.c b/main/asterisk.c
index d55594983..77046f272 100644
--- a/main/asterisk.c
+++ b/main/asterisk.c
@@ -607,6 +607,9 @@ static char *handle_show_settings(struct ast_cli_entry *e, int cmd, struct ast_c
ast_cli(a->fd, " Transmit silence during rec: %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_TRANSMIT_SILENCE) ? "Enabled" : "Disabled");
ast_cli(a->fd, " Generic PLC: %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_GENERIC_PLC) ? "Enabled" : "Disabled");
ast_cli(a->fd, " Min DTMF duration:: %u\n", option_dtmfminduration);
+#if !defined(LOW_MEMORY)
+ ast_cli(a->fd, " Cache media frames: %s\n", ast_opt_cache_media_frames ? "Enabled" : "Disabled");
+#endif
ast_cli(a->fd, " RTP use dynamic payloads: %u\n", ast_option_rtpusedynamic);
if (ast_option_rtpptdynamic == AST_RTP_PT_LAST_REASSIGN) {
@@ -1761,15 +1764,13 @@ static struct sigaction urg_handler = {
static void _hup_handler(int num)
{
- int a = 0, save_errno = errno;
+ int save_errno = errno;
printf("Received HUP signal -- Reloading configs\n");
if (restartnow)
execvp(_argv[0], _argv);
sig_flags.need_reload = 1;
- if (sig_alert_pipe[1] != -1) {
- if (write(sig_alert_pipe[1], &a, sizeof(a)) < 0) {
- fprintf(stderr, "hup_handler: write() failed: %s\n", strerror(errno));
- }
+ if (ast_alertpipe_write(sig_alert_pipe)) {
+ fprintf(stderr, "hup_handler: write() failed: %s\n", strerror(errno));
}
errno = save_errno;
}
@@ -2169,10 +2170,7 @@ static void really_quit(int num, shutdown_nice_t niceness, int restart)
close(ast_consock);
if (!ast_opt_remote)
unlink(ast_config_AST_PID);
- if (sig_alert_pipe[0])
- close(sig_alert_pipe[0]);
- if (sig_alert_pipe[1])
- close(sig_alert_pipe[1]);
+ ast_alertpipe_close(sig_alert_pipe);
printf("%s", term_quit());
if (restart) {
int i;
@@ -2208,12 +2206,9 @@ static void really_quit(int num, shutdown_nice_t niceness, int restart)
static void __quit_handler(int num)
{
- int a = 0;
sig_flags.need_quit = 1;
- if (sig_alert_pipe[1] != -1) {
- if (write(sig_alert_pipe[1], &a, sizeof(a)) < 0) {
- fprintf(stderr, "quit_handler: write() failed: %s\n", strerror(errno));
- }
+ if (ast_alertpipe_write(sig_alert_pipe)) {
+ fprintf(stderr, "quit_handler: write() failed: %s\n", strerror(errno));
}
/* There is no need to restore the signal handler here, since the app
* is going to exit */
@@ -2466,16 +2461,6 @@ static char *handle_version(struct ast_cli_entry *e, int cmd, struct ast_cli_arg
return CLI_SUCCESS;
}
-#if 0
-static int handle_quit(int fd, int argc, char *argv[])
-{
- if (argc != 1)
- return RESULT_SHOWUSAGE;
- quit_handler(0, SHUTDOWN_NORMAL, 0);
- return RESULT_SUCCESS;
-}
-#endif
-
static char *handle_stop_now(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
{
switch (cmd) {
@@ -3665,7 +3650,6 @@ static void ast_readconfig(void)
ast_copy_string(cfg_paths.agi_dir, v->value, sizeof(cfg_paths.agi_dir));
} else if (!strcasecmp(v->name, "astrundir")) {
snprintf(cfg_paths.pid_path, sizeof(cfg_paths.pid_path), "%s/%s", v->value, "asterisk.pid");
- snprintf(cfg_paths.socket_path, sizeof(cfg_paths.socket_path), "%s/%s", v->value, ast_config_AST_CTL);
ast_copy_string(cfg_paths.run_dir, v->value, sizeof(cfg_paths.run_dir));
} else if (!strcasecmp(v->name, "astmoddir")) {
ast_copy_string(cfg_paths.module_dir, v->value, sizeof(cfg_paths.module_dir));
@@ -3674,6 +3658,10 @@ static void ast_readconfig(void)
}
}
+ /* Combine astrundir and astctl settings. */
+ snprintf(cfg_paths.socket_path, sizeof(cfg_paths.socket_path), "%s/%s",
+ ast_config_AST_RUN_DIR, ast_config_AST_CTL);
+
for (v = ast_variable_browse(cfg, "options"); v; v = v->next) {
/* verbose level (-v at startup) */
if (!strcasecmp(v->name, "verbose")) {
@@ -3724,6 +3712,11 @@ static void ast_readconfig(void)
/* Cache recorded sound files to another directory during recording */
} else if (!strcasecmp(v->name, "cache_record_files")) {
ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_CACHE_RECORD_FILES);
+#if !defined(LOW_MEMORY)
+ /* Cache media frames for performance */
+ } else if (!strcasecmp(v->name, "cache_media_frames")) {
+ ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_CACHE_MEDIA_FRAMES);
+#endif
/* Specify cache directory */
} else if (!strcasecmp(v->name, "record_cache_dir")) {
ast_copy_string(record_cache_dir, v->value, AST_CACHE_DIR_LEN);
@@ -3887,7 +3880,7 @@ static void *monitor_sig_flags(void *unused)
{
for (;;) {
struct pollfd p = { sig_alert_pipe[0], POLLIN, 0 };
- int a;
+
ast_poll(&p, 1, -1);
if (sig_flags.need_reload) {
sig_flags.need_reload = 0;
@@ -3902,8 +3895,7 @@ static void *monitor_sig_flags(void *unused)
quit_handler(0, SHUTDOWN_NORMAL, 0);
}
}
- if (read(sig_alert_pipe[0], &a, sizeof(a)) != sizeof(a)) {
- }
+ ast_alertpipe_read(sig_alert_pipe);
}
return NULL;
@@ -4710,9 +4702,7 @@ static void asterisk_daemon(int isroot, const char *runuser, const char *rungrou
consolethread = pthread_self();
}
- if (pipe(sig_alert_pipe)) {
- sig_alert_pipe[0] = sig_alert_pipe[1] = -1;
- }
+ ast_alertpipe_init(sig_alert_pipe);
ast_process_pending_reloads();
diff --git a/main/audiohook.c b/main/audiohook.c
index 2cba2de6e..04a379fef 100644
--- a/main/audiohook.c
+++ b/main/audiohook.c
@@ -950,7 +950,9 @@ static struct ast_frame *audio_audiohook_write_list(struct ast_channel *chan, st
* rely on actual media being present to do things.
*/
if (!middle_frame->data.ptr) {
- ast_frfree(middle_frame);
+ if (middle_frame != start_frame) {
+ ast_frfree(middle_frame);
+ }
return start_frame;
}
diff --git a/main/frame.c b/main/frame.c
index c24cc8f78..dd47f42d0 100644
--- a/main/frame.c
+++ b/main/frame.c
@@ -120,14 +120,18 @@ static void __frame_free(struct ast_frame *fr, int cache)
return;
#if !defined(LOW_MEMORY)
- if (cache && fr->mallocd == AST_MALLOCD_HDR) {
+ if (fr->mallocd == AST_MALLOCD_HDR
+ && cache
+ && ast_opt_cache_media_frames) {
/* Cool, only the header is malloc'd, let's just cache those for now
* to keep things simple... */
struct ast_frame_cache *frames;
- if ((frames = ast_threadstorage_get(&frame_cache, sizeof(*frames))) &&
- (frames->size < FRAME_CACHE_MAX_SIZE)) {
- if ((fr->frametype == AST_FRAME_VOICE) || (fr->frametype == AST_FRAME_VIDEO) ||
- (fr->frametype == AST_FRAME_IMAGE)) {
+
+ frames = ast_threadstorage_get(&frame_cache, sizeof(*frames));
+ if (frames && frames->size < FRAME_CACHE_MAX_SIZE) {
+ if (fr->frametype == AST_FRAME_VOICE
+ || fr->frametype == AST_FRAME_VIDEO
+ || fr->frametype == AST_FRAME_IMAGE) {
ao2_cleanup(fr->subclass.format);
}
@@ -147,8 +151,9 @@ static void __frame_free(struct ast_frame *fr, int cache)
ast_free((void *) fr->src);
}
if (fr->mallocd & AST_MALLOCD_HDR) {
- if ((fr->frametype == AST_FRAME_VOICE) || (fr->frametype == AST_FRAME_VIDEO) ||
- (fr->frametype == AST_FRAME_IMAGE)) {
+ if (fr->frametype == AST_FRAME_VOICE
+ || fr->frametype == AST_FRAME_VIDEO
+ || fr->frametype == AST_FRAME_IMAGE) {
ao2_cleanup(fr->subclass.format);
}
@@ -163,18 +168,16 @@ void ast_frame_free(struct ast_frame *frame, int cache)
{
struct ast_frame *next;
- for (next = AST_LIST_NEXT(frame, frame_list);
- frame;
- frame = next, next = frame ? AST_LIST_NEXT(frame, frame_list) : NULL) {
+ while (frame) {
+ next = AST_LIST_NEXT(frame, frame_list);
__frame_free(frame, cache);
+ frame = next;
}
}
void ast_frame_dtor(struct ast_frame *f)
{
- if (f) {
- ast_frfree(f);
- }
+ ast_frfree(f);
}
/*!
diff --git a/main/plc.c b/main/plc.c
index b649357dc..739f7276d 100644
--- a/main/plc.c
+++ b/main/plc.c
@@ -96,7 +96,7 @@ static void normalise_history(plc_state_t *s)
if (s->buf_ptr == 0)
return;
memcpy(tmp, s->history, sizeof(int16_t)*s->buf_ptr);
- memcpy(s->history, s->history + s->buf_ptr, sizeof(int16_t) * (PLC_HISTORY_LEN - s->buf_ptr));
+ memmove(s->history, s->history + s->buf_ptr, sizeof(int16_t) * (PLC_HISTORY_LEN - s->buf_ptr));
memcpy(s->history + PLC_HISTORY_LEN - s->buf_ptr, tmp, sizeof(int16_t) * s->buf_ptr);
s->buf_ptr = 0;
}
diff --git a/main/sdp_state.c b/main/sdp_state.c
index a77d96da5..2b75cc2a1 100644
--- a/main/sdp_state.c
+++ b/main/sdp_state.c
@@ -1255,7 +1255,10 @@ static int sdp_merge_streams_match(
return -1;
}
idx = AST_VECTOR_GET(current_vect, current_idx);
- ast_stream_topology_set_stream(merged_topology, idx, merged_stream);
+ if (ast_stream_topology_set_stream(merged_topology, idx, merged_stream)) {
+ ast_stream_free(merged_stream);
+ return -1;
+ }
/*
* The current_stream cannot be considered a backfill_candidate
@@ -1400,7 +1403,10 @@ static struct ast_stream_topology *merge_local_topologies(
if (!merged_stream) {
goto fail;
}
- ast_stream_topology_set_stream(merged_topology, idx, merged_stream);
+ if (ast_stream_topology_set_stream(merged_topology, idx, merged_stream)) {
+ ast_stream_free(merged_stream);
+ goto fail;
+ }
}
/* Backfill new update stream slots into pre-existing declined current stream slots */
@@ -1438,7 +1444,10 @@ static struct ast_stream_topology *merge_local_topologies(
}
/* Add the new stream into the backfill stream slot. */
- ast_stream_topology_set_stream(merged_topology, current_idx, merged_stream);
+ if (ast_stream_topology_set_stream(merged_topology, current_idx, merged_stream)) {
+ ast_stream_free(merged_stream);
+ goto fail;
+ }
backfill_candidate[current_idx] = 0;
}
diff --git a/main/sorcery.c b/main/sorcery.c
index 01b77918d..51b55c5a2 100644
--- a/main/sorcery.c
+++ b/main/sorcery.c
@@ -2036,6 +2036,36 @@ struct ao2_container *ast_sorcery_retrieve_by_regex(const struct ast_sorcery *so
return objects;
}
+struct ao2_container *ast_sorcery_retrieve_by_prefix(const struct ast_sorcery *sorcery, const char *type, const char *prefix, const size_t prefix_len)
+{
+ RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
+ struct ao2_container *objects;
+ int i;
+
+ if (!object_type || !(objects = ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_NOLOCK, 1, NULL, NULL))) {
+ return NULL;
+ }
+
+ AST_VECTOR_RW_RDLOCK(&object_type->wizards);
+ for (i = 0; i < AST_VECTOR_SIZE(&object_type->wizards); i++) {
+ struct ast_sorcery_object_wizard *wizard =
+ AST_VECTOR_GET(&object_type->wizards, i);
+
+ if (!wizard->wizard->callbacks.retrieve_prefix) {
+ continue;
+ }
+
+ wizard->wizard->callbacks.retrieve_prefix(sorcery, wizard->data, object_type->name, objects, prefix, prefix_len);
+
+ if (wizard->caching && ao2_container_count(objects)) {
+ break;
+ }
+ }
+ AST_VECTOR_RW_UNLOCK(&object_type->wizards);
+
+ return objects;
+}
+
/*! \brief Internal function which returns if the wizard has created the object */
static int sorcery_wizard_create(const struct ast_sorcery_object_wizard *object_wizard, const struct sorcery_details *details)
{
diff --git a/main/stasis_bridges.c b/main/stasis_bridges.c
index 7f53bfe2d..d197e4d2d 100644
--- a/main/stasis_bridges.c
+++ b/main/stasis_bridges.c
@@ -868,6 +868,8 @@ static struct ast_json *attended_transfer_to_json(struct stasis_message *msg,
if (transfer_msg->transferee) {
json_transferee = ast_channel_snapshot_to_json(transfer_msg->transferee, sanitize);
if (!json_transferee) {
+ ast_json_unref(json_transferer2);
+ ast_json_unref(json_transferer1);
return NULL;
}
}
@@ -875,6 +877,9 @@ static struct ast_json *attended_transfer_to_json(struct stasis_message *msg,
if (transfer_msg->target) {
json_target = ast_channel_snapshot_to_json(transfer_msg->target, sanitize);
if (!json_target) {
+ ast_json_unref(json_transferee);
+ ast_json_unref(json_transferer2);
+ ast_json_unref(json_transferer1);
return NULL;
}
}
@@ -887,9 +892,12 @@ static struct ast_json *attended_transfer_to_json(struct stasis_message *msg,
"result", result_strs[transfer_msg->result],
"is_external", ast_json_boolean(transfer_msg->is_external));
if (!out) {
+ ast_json_unref(json_target);
+ ast_json_unref(json_transferee);
return NULL;
}
if (json_transferee && ast_json_object_set(out, "transferee", json_transferee)) {
+ ast_json_unref(json_target);
return NULL;
}
if (json_target && ast_json_object_set(out, "transfer_target", json_target)) {
diff --git a/makeopts.in b/makeopts.in
index e25b614e0..1d31c29f9 100644
--- a/makeopts.in
+++ b/makeopts.in
@@ -388,3 +388,6 @@ TIMERFD_INCLUDE=@TIMERFD_INCLUDE@
SNDFILE_INCLUDE=@SNDFILE_INCLUDE@
SNDFILE_LIB=@SNDFILE_LIB@
+
+BEANSTALK_INCLUDE=@BEANSTALK_INCLUDE@
+BEANSTALK_LIB=@BEANSTALK_LIB@
diff --git a/menuselect/.gitignore b/menuselect/.gitignore
index ded8d2d6e..05f4778ff 100644
--- a/menuselect/.gitignore
+++ b/menuselect/.gitignore
@@ -1,3 +1,4 @@
+aclocal.m4
autoconfig.h
cmenuselect
config.log
diff --git a/menuselect/aclocal.m4 b/menuselect/aclocal.m4
deleted file mode 100644
index e67774c06..000000000
--- a/menuselect/aclocal.m4
+++ /dev/null
@@ -1,296 +0,0 @@
-# generated automatically by aclocal 1.15 -*- Autoconf -*-
-
-# Copyright (C) 1996-2014 Free Software Foundation, Inc.
-
-# This file is free software; the Free Software Foundation
-# gives unlimited permission to copy and/or distribute it,
-# with or without modifications, as long as this notice is preserved.
-
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
-# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
-# PARTICULAR PURPOSE.
-
-m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])])
-dnl pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*-
-dnl serial 11 (pkg-config-0.29)
-dnl
-dnl Copyright © 2004 Scott James Remnant <scott@netsplit.com>.
-dnl Copyright © 2012-2015 Dan Nicholson <dbn.lists@gmail.com>
-dnl
-dnl This program is free software; you can redistribute it and/or modify
-dnl it under the terms of the GNU General Public License as published by
-dnl the Free Software Foundation; either version 2 of the License, or
-dnl (at your option) any later version.
-dnl
-dnl This program is distributed in the hope that it will be useful, but
-dnl WITHOUT ANY WARRANTY; without even the implied warranty of
-dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-dnl General Public License for more details.
-dnl
-dnl You should have received a copy of the GNU General Public License
-dnl along with this program; if not, write to the Free Software
-dnl Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
-dnl 02111-1307, USA.
-dnl
-dnl As a special exception to the GNU General Public License, if you
-dnl distribute this file as part of a program that contains a
-dnl configuration script generated by Autoconf, you may include it under
-dnl the same distribution terms that you use for the rest of that
-dnl program.
-
-dnl PKG_PREREQ(MIN-VERSION)
-dnl -----------------------
-dnl Since: 0.29
-dnl
-dnl Verify that the version of the pkg-config macros are at least
-dnl MIN-VERSION. Unlike PKG_PROG_PKG_CONFIG, which checks the user's
-dnl installed version of pkg-config, this checks the developer's version
-dnl of pkg.m4 when generating configure.
-dnl
-dnl To ensure that this macro is defined, also add:
-dnl m4_ifndef([PKG_PREREQ],
-dnl [m4_fatal([must install pkg-config 0.29 or later before running autoconf/autogen])])
-dnl
-dnl See the "Since" comment for each macro you use to see what version
-dnl of the macros you require.
-m4_defun([PKG_PREREQ],
-[m4_define([PKG_MACROS_VERSION], [0.29])
-m4_if(m4_version_compare(PKG_MACROS_VERSION, [$1]), -1,
- [m4_fatal([pkg.m4 version $1 or higher is required but ]PKG_MACROS_VERSION[ found])])
-])dnl PKG_PREREQ
-
-dnl PKG_PROG_PKG_CONFIG([MIN-VERSION])
-dnl ----------------------------------
-dnl Since: 0.16
-dnl
-dnl Search for the pkg-config tool and set the PKG_CONFIG variable to
-dnl first found in the path. Checks that the version of pkg-config found
-dnl is at least MIN-VERSION. If MIN-VERSION is not specified, 0.9.0 is
-dnl used since that's the first version where most current features of
-dnl pkg-config existed.
-AC_DEFUN([PKG_PROG_PKG_CONFIG],
-[m4_pattern_forbid([^_?PKG_[A-Z_]+$])
-m4_pattern_allow([^PKG_CONFIG(_(PATH|LIBDIR|SYSROOT_DIR|ALLOW_SYSTEM_(CFLAGS|LIBS)))?$])
-m4_pattern_allow([^PKG_CONFIG_(DISABLE_UNINSTALLED|TOP_BUILD_DIR|DEBUG_SPEW)$])
-AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility])
-AC_ARG_VAR([PKG_CONFIG_PATH], [directories to add to pkg-config's search path])
-AC_ARG_VAR([PKG_CONFIG_LIBDIR], [path overriding pkg-config's built-in search path])
-
-if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then
- AC_PATH_TOOL([PKG_CONFIG], [pkg-config])
-fi
-if test -n "$PKG_CONFIG"; then
- _pkg_min_version=m4_default([$1], [0.9.0])
- AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version])
- if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then
- AC_MSG_RESULT([yes])
- else
- AC_MSG_RESULT([no])
- PKG_CONFIG=""
- fi
-fi[]dnl
-])dnl PKG_PROG_PKG_CONFIG
-
-dnl PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
-dnl -------------------------------------------------------------------
-dnl Since: 0.18
-dnl
-dnl Check to see whether a particular set of modules exists. Similar to
-dnl PKG_CHECK_MODULES(), but does not set variables or print errors.
-dnl
-dnl Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG])
-dnl only at the first occurence in configure.ac, so if the first place
-dnl it's called might be skipped (such as if it is within an "if", you
-dnl have to call PKG_CHECK_EXISTS manually
-AC_DEFUN([PKG_CHECK_EXISTS],
-[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
-if test -n "$PKG_CONFIG" && \
- AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then
- m4_default([$2], [:])
-m4_ifvaln([$3], [else
- $3])dnl
-fi])
-
-dnl _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES])
-dnl ---------------------------------------------
-dnl Internal wrapper calling pkg-config via PKG_CONFIG and setting
-dnl pkg_failed based on the result.
-m4_define([_PKG_CONFIG],
-[if test -n "$$1"; then
- pkg_cv_[]$1="$$1"
- elif test -n "$PKG_CONFIG"; then
- PKG_CHECK_EXISTS([$3],
- [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null`
- test "x$?" != "x0" && pkg_failed=yes ],
- [pkg_failed=yes])
- else
- pkg_failed=untried
-fi[]dnl
-])dnl _PKG_CONFIG
-
-dnl _PKG_SHORT_ERRORS_SUPPORTED
-dnl ---------------------------
-dnl Internal check to see if pkg-config supports short errors.
-AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED],
-[AC_REQUIRE([PKG_PROG_PKG_CONFIG])
-if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
- _pkg_short_errors_supported=yes
-else
- _pkg_short_errors_supported=no
-fi[]dnl
-])dnl _PKG_SHORT_ERRORS_SUPPORTED
-
-
-dnl PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND],
-dnl [ACTION-IF-NOT-FOUND])
-dnl --------------------------------------------------------------
-dnl Since: 0.4.0
-dnl
-dnl Note that if there is a possibility the first call to
-dnl PKG_CHECK_MODULES might not happen, you should be sure to include an
-dnl explicit call to PKG_PROG_PKG_CONFIG in your configure.ac
-AC_DEFUN([PKG_CHECK_MODULES],
-[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
-AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl
-AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl
-
-pkg_failed=no
-AC_MSG_CHECKING([for $1])
-
-_PKG_CONFIG([$1][_CFLAGS], [cflags], [$2])
-_PKG_CONFIG([$1][_LIBS], [libs], [$2])
-
-m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS
-and $1[]_LIBS to avoid the need to call pkg-config.
-See the pkg-config man page for more details.])
-
-if test $pkg_failed = yes; then
- AC_MSG_RESULT([no])
- _PKG_SHORT_ERRORS_SUPPORTED
- if test $_pkg_short_errors_supported = yes; then
- $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1`
- else
- $1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$2" 2>&1`
- fi
- # Put the nasty error message in config.log where it belongs
- echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD
-
- m4_default([$4], [AC_MSG_ERROR(
-[Package requirements ($2) were not met:
-
-$$1_PKG_ERRORS
-
-Consider adjusting the PKG_CONFIG_PATH environment variable if you
-installed software in a non-standard prefix.
-
-_PKG_TEXT])[]dnl
- ])
-elif test $pkg_failed = untried; then
- AC_MSG_RESULT([no])
- m4_default([$4], [AC_MSG_FAILURE(
-[The pkg-config script could not be found or is too old. Make sure it
-is in your PATH or set the PKG_CONFIG environment variable to the full
-path to pkg-config.
-
-_PKG_TEXT
-
-To get pkg-config, see <http://pkg-config.freedesktop.org/>.])[]dnl
- ])
-else
- $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS
- $1[]_LIBS=$pkg_cv_[]$1[]_LIBS
- AC_MSG_RESULT([yes])
- $3
-fi[]dnl
-])dnl PKG_CHECK_MODULES
-
-
-dnl PKG_CHECK_MODULES_STATIC(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND],
-dnl [ACTION-IF-NOT-FOUND])
-dnl ---------------------------------------------------------------------
-dnl Since: 0.29
-dnl
-dnl Checks for existence of MODULES and gathers its build flags with
-dnl static libraries enabled. Sets VARIABLE-PREFIX_CFLAGS from --cflags
-dnl and VARIABLE-PREFIX_LIBS from --libs.
-dnl
-dnl Note that if there is a possibility the first call to
-dnl PKG_CHECK_MODULES_STATIC might not happen, you should be sure to
-dnl include an explicit call to PKG_PROG_PKG_CONFIG in your
-dnl configure.ac.
-AC_DEFUN([PKG_CHECK_MODULES_STATIC],
-[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
-_save_PKG_CONFIG=$PKG_CONFIG
-PKG_CONFIG="$PKG_CONFIG --static"
-PKG_CHECK_MODULES($@)
-PKG_CONFIG=$_save_PKG_CONFIG[]dnl
-])dnl PKG_CHECK_MODULES_STATIC
-
-
-dnl PKG_INSTALLDIR([DIRECTORY])
-dnl -------------------------
-dnl Since: 0.27
-dnl
-dnl Substitutes the variable pkgconfigdir as the location where a module
-dnl should install pkg-config .pc files. By default the directory is
-dnl $libdir/pkgconfig, but the default can be changed by passing
-dnl DIRECTORY. The user can override through the --with-pkgconfigdir
-dnl parameter.
-AC_DEFUN([PKG_INSTALLDIR],
-[m4_pushdef([pkg_default], [m4_default([$1], ['${libdir}/pkgconfig'])])
-m4_pushdef([pkg_description],
- [pkg-config installation directory @<:@]pkg_default[@:>@])
-AC_ARG_WITH([pkgconfigdir],
- [AS_HELP_STRING([--with-pkgconfigdir], pkg_description)],,
- [with_pkgconfigdir=]pkg_default)
-AC_SUBST([pkgconfigdir], [$with_pkgconfigdir])
-m4_popdef([pkg_default])
-m4_popdef([pkg_description])
-])dnl PKG_INSTALLDIR
-
-
-dnl PKG_NOARCH_INSTALLDIR([DIRECTORY])
-dnl --------------------------------
-dnl Since: 0.27
-dnl
-dnl Substitutes the variable noarch_pkgconfigdir as the location where a
-dnl module should install arch-independent pkg-config .pc files. By
-dnl default the directory is $datadir/pkgconfig, but the default can be
-dnl changed by passing DIRECTORY. The user can override through the
-dnl --with-noarch-pkgconfigdir parameter.
-AC_DEFUN([PKG_NOARCH_INSTALLDIR],
-[m4_pushdef([pkg_default], [m4_default([$1], ['${datadir}/pkgconfig'])])
-m4_pushdef([pkg_description],
- [pkg-config arch-independent installation directory @<:@]pkg_default[@:>@])
-AC_ARG_WITH([noarch-pkgconfigdir],
- [AS_HELP_STRING([--with-noarch-pkgconfigdir], pkg_description)],,
- [with_noarch_pkgconfigdir=]pkg_default)
-AC_SUBST([noarch_pkgconfigdir], [$with_noarch_pkgconfigdir])
-m4_popdef([pkg_default])
-m4_popdef([pkg_description])
-])dnl PKG_NOARCH_INSTALLDIR
-
-
-dnl PKG_CHECK_VAR(VARIABLE, MODULE, CONFIG-VARIABLE,
-dnl [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
-dnl -------------------------------------------
-dnl Since: 0.28
-dnl
-dnl Retrieves the value of the pkg-config variable for the given module.
-AC_DEFUN([PKG_CHECK_VAR],
-[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
-AC_ARG_VAR([$1], [value of $3 for $2, overriding pkg-config])dnl
-
-_PKG_CONFIG([$1], [variable="][$3]["], [$2])
-AS_VAR_COPY([$1], [pkg_cv_][$1])
-
-AS_VAR_IF([$1], [""], [$5], [$4])dnl
-])dnl PKG_CHECK_VAR
-
-m4_include([../autoconf/ast_check_gnu_make.m4])
-m4_include([../autoconf/ast_ext_lib.m4])
-m4_include([../autoconf/ast_ext_tool_check.m4])
-m4_include([../autoconf/ast_gcc_attribute.m4])
-m4_include([../autoconf/ast_pkgconfig.m4])
-m4_include([../autoconf/ast_prog_sed.m4])
diff --git a/res/res_hep_pjsip.c b/res/res_hep_pjsip.c
index 13efbfa6a..b5be4a102 100644
--- a/res/res_hep_pjsip.c
+++ b/res/res_hep_pjsip.c
@@ -89,35 +89,44 @@ static pj_status_t logging_on_tx_msg(pjsip_tx_data *tdata)
pjsip_cid_hdr *cid_hdr;
pjsip_from_hdr *from_hdr;
pjsip_to_hdr *to_hdr;
- pjsip_tpmgr_fla2_param prm;
capture_info = hepv3_create_capture_info(tdata->buf.start, (size_t)(tdata->buf.cur - tdata->buf.start));
if (!capture_info) {
return PJ_SUCCESS;
}
- /* Attempt to determine what IP address will we send this packet out of */
- pjsip_tpmgr_fla2_param_default(&prm);
- prm.tp_type = tdata->tp_info.transport->key.type;
- pj_strset2(&prm.dst_host, tdata->tp_info.dst_name);
- prm.local_if = PJ_TRUE;
+ if (!(tdata->tp_info.transport->flag & PJSIP_TRANSPORT_RELIABLE)) {
+ pjsip_tpmgr_fla2_param prm;
- /* If we can't get the local address use what we have already */
- if (pjsip_tpmgr_find_local_addr2(pjsip_endpt_get_tpmgr(ast_sip_get_pjsip_endpoint()), tdata->pool, &prm) != PJ_SUCCESS) {
- pj_sockaddr_print(&tdata->tp_info.transport->local_addr, local_buf, sizeof(local_buf), 3);
- } else {
- if (prm.tp_type & PJSIP_TRANSPORT_IPV6) {
- snprintf(local_buf, sizeof(local_buf), "[%.*s]:%hu",
- (int)pj_strlen(&prm.ret_addr),
- pj_strbuf(&prm.ret_addr),
- prm.ret_port);
+ /* Attempt to determine what IP address will we send this packet out of */
+ pjsip_tpmgr_fla2_param_default(&prm);
+ prm.tp_type = tdata->tp_info.transport->key.type;
+ pj_strset2(&prm.dst_host, tdata->tp_info.dst_name);
+ prm.local_if = PJ_TRUE;
+
+ /* If we can't get the local address use what we have already */
+ if (pjsip_tpmgr_find_local_addr2(pjsip_endpt_get_tpmgr(ast_sip_get_pjsip_endpoint()), tdata->pool, &prm) != PJ_SUCCESS) {
+ pj_sockaddr_print(&tdata->tp_info.transport->local_addr, local_buf, sizeof(local_buf), 3);
} else {
- snprintf(local_buf, sizeof(local_buf), "%.*s:%hu",
- (int)pj_strlen(&prm.ret_addr),
- pj_strbuf(&prm.ret_addr),
- prm.ret_port);
+ if (prm.tp_type & PJSIP_TRANSPORT_IPV6) {
+ snprintf(local_buf, sizeof(local_buf), "[%.*s]:%hu",
+ (int)pj_strlen(&prm.ret_addr),
+ pj_strbuf(&prm.ret_addr),
+ prm.ret_port);
+ } else {
+ snprintf(local_buf, sizeof(local_buf), "%.*s:%hu",
+ (int)pj_strlen(&prm.ret_addr),
+ pj_strbuf(&prm.ret_addr),
+ prm.ret_port);
+ }
}
+ } else {
+ /* For reliable transports they can only ever come from the transport
+ * local address.
+ */
+ pj_sockaddr_print(&tdata->tp_info.transport->local_addr, local_buf, sizeof(local_buf), 3);
}
+
pj_sockaddr_print(&tdata->tp_info.dst_addr, remote_buf, sizeof(remote_buf), 3);
cid_hdr = PJSIP_MSG_CID_HDR(tdata->msg);
@@ -150,7 +159,6 @@ static pj_bool_t logging_on_rx_msg(pjsip_rx_data *rdata)
char remote_buf[256];
char *uuid;
struct hepv3_capture_info *capture_info;
- pjsip_tpmgr_fla2_param prm;
capture_info = hepv3_create_capture_info(&rdata->pkt_info.packet, rdata->pkt_info.len);
if (!capture_info) {
@@ -162,27 +170,33 @@ static pj_bool_t logging_on_rx_msg(pjsip_rx_data *rdata)
}
pj_sockaddr_print(&rdata->pkt_info.src_addr, remote_buf, sizeof(remote_buf), 3);
- /* Attempt to determine what IP address we probably received this packet on */
- pjsip_tpmgr_fla2_param_default(&prm);
- prm.tp_type = rdata->tp_info.transport->key.type;
- pj_strset2(&prm.dst_host, rdata->pkt_info.src_name);
- prm.local_if = PJ_TRUE;
+ if (!(rdata->tp_info.transport->flag & PJSIP_TRANSPORT_RELIABLE)) {
+ pjsip_tpmgr_fla2_param prm;
- /* If we can't get the local address use what we have already */
- if (pjsip_tpmgr_find_local_addr2(pjsip_endpt_get_tpmgr(ast_sip_get_pjsip_endpoint()), rdata->tp_info.pool, &prm) != PJ_SUCCESS) {
- pj_sockaddr_print(&rdata->tp_info.transport->local_addr, local_buf, sizeof(local_buf), 3);
- } else {
- if (prm.tp_type & PJSIP_TRANSPORT_IPV6) {
- snprintf(local_buf, sizeof(local_buf), "[%.*s]:%hu",
- (int)pj_strlen(&prm.ret_addr),
- pj_strbuf(&prm.ret_addr),
- prm.ret_port);
+ /* Attempt to determine what IP address we probably received this packet on */
+ pjsip_tpmgr_fla2_param_default(&prm);
+ prm.tp_type = rdata->tp_info.transport->key.type;
+ pj_strset2(&prm.dst_host, rdata->pkt_info.src_name);
+ prm.local_if = PJ_TRUE;
+
+ /* If we can't get the local address use what we have already */
+ if (pjsip_tpmgr_find_local_addr2(pjsip_endpt_get_tpmgr(ast_sip_get_pjsip_endpoint()), rdata->tp_info.pool, &prm) != PJ_SUCCESS) {
+ pj_sockaddr_print(&rdata->tp_info.transport->local_addr, local_buf, sizeof(local_buf), 3);
} else {
- snprintf(local_buf, sizeof(local_buf), "%.*s:%hu",
- (int)pj_strlen(&prm.ret_addr),
- pj_strbuf(&prm.ret_addr),
- prm.ret_port);
+ if (prm.tp_type & PJSIP_TRANSPORT_IPV6) {
+ snprintf(local_buf, sizeof(local_buf), "[%.*s]:%hu",
+ (int)pj_strlen(&prm.ret_addr),
+ pj_strbuf(&prm.ret_addr),
+ prm.ret_port);
+ } else {
+ snprintf(local_buf, sizeof(local_buf), "%.*s:%hu",
+ (int)pj_strlen(&prm.ret_addr),
+ pj_strbuf(&prm.ret_addr),
+ prm.ret_port);
+ }
}
+ } else {
+ pj_sockaddr_print(&rdata->tp_info.transport->local_addr, local_buf, sizeof(local_buf), 3);
}
uuid = assign_uuid(&rdata->msg_info.cid->id, &rdata->msg_info.to->tag, &rdata->msg_info.from->tag);
diff --git a/res/res_http_websocket.c b/res/res_http_websocket.c
index 8e9aae9dd..c1f9a29d6 100644
--- a/res/res_http_websocket.c
+++ b/res/res_http_websocket.c
@@ -86,18 +86,19 @@
/*! \brief Structure definition for session */
struct ast_websocket {
- struct ast_iostream *stream; /*!< iostream of the connection */
- struct ast_sockaddr address; /*!< Address of the remote client */
- enum ast_websocket_opcode opcode; /*!< Cached opcode for multi-frame messages */
- size_t payload_len; /*!< Length of the payload */
- char *payload; /*!< Pointer to the payload */
- size_t reconstruct; /*!< Number of bytes before a reconstructed payload will be returned and a new one started */
- int timeout; /*!< The timeout for operations on the socket */
- unsigned int secure:1; /*!< Bit to indicate that the transport is secure */
- unsigned int closing:1; /*!< Bit to indicate that the session is in the process of being closed */
- unsigned int close_sent:1; /*!< Bit to indicate that the session close opcode has been sent and no further data will be sent */
- struct websocket_client *client; /*!< Client object when connected as a client websocket */
- char session_id[AST_UUID_STR_LEN]; /*!< The identifier for the websocket session */
+ struct ast_iostream *stream; /*!< iostream of the connection */
+ struct ast_sockaddr remote_address; /*!< Address of the remote client */
+ struct ast_sockaddr local_address; /*!< Our local address */
+ enum ast_websocket_opcode opcode; /*!< Cached opcode for multi-frame messages */
+ size_t payload_len; /*!< Length of the payload */
+ char *payload; /*!< Pointer to the payload */
+ size_t reconstruct; /*!< Number of bytes before a reconstructed payload will be returned and a new one started */
+ int timeout; /*!< The timeout for operations on the socket */
+ unsigned int secure:1; /*!< Bit to indicate that the transport is secure */
+ unsigned int closing:1; /*!< Bit to indicate that the session is in the process of being closed */
+ unsigned int close_sent:1; /*!< Bit to indicate that the session close opcode has been sent and no further data will be sent */
+ struct websocket_client *client; /*!< Client object when connected as a client websocket */
+ char session_id[AST_UUID_STR_LEN]; /*!< The identifier for the websocket session */
};
/*! \brief Hashing function for protocols */
@@ -183,7 +184,7 @@ static void session_destroy_fn(void *obj)
ast_iostream_close(session->stream);
session->stream = NULL;
ast_verb(2, "WebSocket connection %s '%s' closed\n", session->client ? "to" : "from",
- ast_sockaddr_stringify(&session->address));
+ ast_sockaddr_stringify(&session->remote_address));
}
}
@@ -318,7 +319,7 @@ int AST_OPTIONAL_API_NAME(ast_websocket_close)(struct ast_websocket *session, ui
ast_iostream_close(session->stream);
session->stream = NULL;
ast_verb(2, "WebSocket connection %s '%s' forcefully closed due to fatal write error\n",
- session->client ? "to" : "from", ast_sockaddr_stringify(&session->address));
+ session->client ? "to" : "from", ast_sockaddr_stringify(&session->remote_address));
}
ao2_unlock(session);
@@ -432,7 +433,12 @@ int AST_OPTIONAL_API_NAME(ast_websocket_fd)(struct ast_websocket *session)
struct ast_sockaddr * AST_OPTIONAL_API_NAME(ast_websocket_remote_address)(struct ast_websocket *session)
{
- return &session->address;
+ return &session->remote_address;
+}
+
+struct ast_sockaddr * AST_OPTIONAL_API_NAME(ast_websocket_local_address)(struct ast_websocket *session)
+{
+ return &session->local_address;
}
int AST_OPTIONAL_API_NAME(ast_websocket_is_secure)(struct ast_websocket *session)
@@ -899,11 +905,21 @@ int AST_OPTIONAL_API_NAME(ast_websocket_uri_cb)(struct ast_tcptls_session_instan
return 0;
}
+ /* Get our local address for the connected socket */
+ if (ast_getsockname(ast_iostream_get_fd(ser->stream), &session->local_address)) {
+ ast_log(LOG_WARNING, "WebSocket connection from '%s' could not be accepted - failed to get local address\n",
+ ast_sockaddr_stringify(&ser->remote_address));
+ websocket_bad_request(ser);
+ ao2_ref(session, -1);
+ ao2_ref(protocol_handler, -1);
+ return 0;
+ }
+
ast_verb(2, "WebSocket connection from '%s' for protocol '%s' accepted using version '%d'\n", ast_sockaddr_stringify(&ser->remote_address), protocol ? : "", version);
/* Populate the session with all the needed details */
session->stream = ser->stream;
- ast_sockaddr_copy(&session->address, &ser->remote_address);
+ ast_sockaddr_copy(&session->remote_address, &ser->remote_address);
session->opcode = -1;
session->reconstruct = DEFAULT_RECONSTRUCTION_CEILING;
session->secure = ast_iostream_get_ssl(ser->stream) ? 1 : 0;
@@ -1357,7 +1373,7 @@ static enum ast_websocket_result websocket_client_connect(struct ast_websocket *
ws->stream = ws->client->ser->stream;
ws->secure = ast_iostream_get_ssl(ws->stream) ? 1 : 0;
ws->client->ser->stream = NULL;
- ast_sockaddr_copy(&ws->address, &ws->client->ser->remote_address);
+ ast_sockaddr_copy(&ws->remote_address, &ws->client->ser->remote_address);
return WS_OK;
}
diff --git a/res/res_pjsip_history.c b/res/res_pjsip_history.c
index 4e7dbd007..ed374d605 100644
--- a/res/res_pjsip_history.c
+++ b/res/res_pjsip_history.c
@@ -705,10 +705,13 @@ static pj_status_t history_on_tx_msg(pjsip_tx_data *tdata)
pj_sockaddr_cp(&entry->dst, &tdata->tp_info.dst_addr);
ast_mutex_lock(&history_lock);
- AST_VECTOR_APPEND(&vector_history, entry);
+ if (AST_VECTOR_APPEND(&vector_history, entry)) {
+ ao2_ref(entry, -1);
+ entry = NULL;
+ }
ast_mutex_unlock(&history_lock);
- if (log_level != -1) {
+ if (log_level != -1 && entry) {
char line[256];
sprint_list_entry(entry, line, sizeof(line));
@@ -745,10 +748,13 @@ static pj_bool_t history_on_rx_msg(pjsip_rx_data *rdata)
}
ast_mutex_lock(&history_lock);
- AST_VECTOR_APPEND(&vector_history, entry);
+ if (AST_VECTOR_APPEND(&vector_history, entry)) {
+ ao2_ref(entry, -1);
+ entry = NULL;
+ }
ast_mutex_unlock(&history_lock);
- if (log_level != -1) {
+ if (log_level != -1 && entry) {
char line[256];
sprint_list_entry(entry, line, sizeof(line));
@@ -959,7 +965,9 @@ static int evaluate_history_entry(struct pjsip_history_entry *entry, struct expr
/* If this is not an operator, push it to the stack */
if (!it_queue->op) {
- AST_VECTOR_APPEND(&stack, it_queue);
+ if (AST_VECTOR_APPEND(&stack, it_queue)) {
+ goto error;
+ }
continue;
}
@@ -1035,7 +1043,11 @@ static int evaluate_history_entry(struct pjsip_history_entry *entry, struct expr
if (!result) {
goto error;
}
- AST_VECTOR_APPEND(&stack, result);
+ if (AST_VECTOR_APPEND(&stack, result)) {
+ expression_token_free(result);
+
+ goto error;
+ }
}
/*
@@ -1056,6 +1068,7 @@ static int evaluate_history_entry(struct pjsip_history_entry *entry, struct expr
}
result = final->result;
ast_free(final);
+ AST_VECTOR_FREE(&stack);
return result;
@@ -1098,6 +1111,7 @@ static struct vector_history_t *filter_history(struct ast_cli_args *a)
queue = build_expression_queue(a);
if (!queue) {
+ AST_VECTOR_PTR_FREE(output);
return NULL;
}
@@ -1118,7 +1132,9 @@ static struct vector_history_t *filter_history(struct ast_cli_args *a)
} else if (!res) {
continue;
} else {
- AST_VECTOR_APPEND(output, ao2_bump(entry));
+ if (AST_VECTOR_APPEND(output, ao2_bump(entry))) {
+ ao2_cleanup(entry);
+ }
}
}
ast_mutex_unlock(&history_lock);
diff --git a/res/res_pjsip_pubsub.c b/res/res_pjsip_pubsub.c
index 62b187951..59418e4a9 100644
--- a/res/res_pjsip_pubsub.c
+++ b/res/res_pjsip_pubsub.c
@@ -938,7 +938,9 @@ static void build_node_children(struct ast_sip_endpoint *endpoint, const struct
}
ast_debug(2, "Subscription to leaf resource %s resulted in success. Adding to parent %s\n",
resource, parent->resource);
- AST_VECTOR_APPEND(&parent->children, current);
+ if (AST_VECTOR_APPEND(&parent->children, current)) {
+ tree_node_destroy(current);
+ }
} else {
ast_debug(2, "Subscription to leaf resource %s resulted in error response %d\n",
resource, resp);
@@ -953,7 +955,9 @@ static void build_node_children(struct ast_sip_endpoint *endpoint, const struct
build_node_children(endpoint, handler, child_list, current, visited);
if (AST_VECTOR_SIZE(&current->children) > 0) {
ast_debug(1, "List %s had no successful children.\n", resource);
- AST_VECTOR_APPEND(&parent->children, current);
+ if (AST_VECTOR_APPEND(&parent->children, current)) {
+ tree_node_destroy(current);
+ }
} else {
ast_debug(2, "List %s had successful children. Adding to parent %s\n",
resource, parent->resource);
@@ -1194,6 +1198,10 @@ static struct ast_sip_subscription *create_virtual_subscriptions(const struct as
if (AST_VECTOR_APPEND(&sub->children, child)) {
ast_debug(1, "Child subscription to resource %s could not be appended\n",
child_node->resource);
+ destroy_subscription(child);
+ /* Have to release tree here too because a ref was added
+ * to child that destroy_subscription() doesn't release. */
+ ao2_cleanup(tree);
}
}
@@ -2139,7 +2147,9 @@ static void build_body_part(pj_pool_t *pool, struct ast_sip_subscription *sub,
bp->part->body = body;
pj_list_insert_before(&bp->part->hdr, bp->cid);
- AST_VECTOR_APPEND(parts, bp);
+ if (AST_VECTOR_APPEND(parts, bp)) {
+ ast_free(bp);
+ }
}
/*!
@@ -2200,6 +2210,7 @@ static pjsip_msg_body *generate_list_body(pj_pool_t *pool, struct ast_sip_subscr
/* This can happen if issuing partial state and no children of the list have changed state */
if (AST_VECTOR_SIZE(&body_parts) == 0) {
+ free_body_parts(&body_parts);
return NULL;
}
@@ -2207,6 +2218,7 @@ static pjsip_msg_body *generate_list_body(pj_pool_t *pool, struct ast_sip_subscr
rlmi_part = build_rlmi_body(pool, sub, &body_parts, use_full_state);
if (!rlmi_part) {
+ free_body_parts(&body_parts);
return NULL;
}
pjsip_multipart_add_part(pool, multipart, rlmi_part);
@@ -2441,9 +2453,14 @@ void ast_sip_subscription_get_local_uri(struct ast_sip_subscription *sub, char *
void ast_sip_subscription_get_remote_uri(struct ast_sip_subscription *sub, char *buf, size_t size)
{
pjsip_dialog *dlg;
+ pjsip_sip_uri *uri;
dlg = sub->tree->dlg;
- ast_copy_pj_str(buf, &dlg->remote.info_str, size);
+ uri = pjsip_uri_get_uri(dlg->remote.info->uri);
+
+ if (pjsip_uri_print(PJSIP_URI_IN_FROMTO_HDR, uri, buf, size) < 0) {
+ *buf = '\0';
+ }
}
const char *ast_sip_subscription_get_resource_name(struct ast_sip_subscription *sub)
@@ -4602,7 +4619,10 @@ static int list_item_handler(const struct aco_option *opt,
ast_log(LOG_WARNING, "Ignoring duplicated list item '%s'\n", item);
continue;
}
- if (AST_VECTOR_APPEND(&list->items, ast_strdup(item))) {
+
+ item = ast_strdup(item);
+ if (!item || AST_VECTOR_APPEND(&list->items, item)) {
+ ast_free(item);
return -1;
}
}
@@ -4738,7 +4758,10 @@ static int populate_list(struct resource_list *list, const char *event, const ch
ast_copy_string(list->event, event, sizeof(list->event));
for (i = 0; i < num_resources; ++i) {
- if (AST_VECTOR_APPEND(&list->items, ast_strdup(resources[i]))) {
+ char *resource = ast_strdup(resources[i]);
+
+ if (!resource || AST_VECTOR_APPEND(&list->items, resource)) {
+ ast_free(resource);
return -1;
}
}
diff --git a/res/res_pjsip_registrar.c b/res/res_pjsip_registrar.c
index 32906011a..f0da6dee2 100644
--- a/res/res_pjsip_registrar.c
+++ b/res/res_pjsip_registrar.c
@@ -447,11 +447,19 @@ static void remove_excess_contacts(struct ao2_container *contacts, unsigned int
AST_VECTOR_FREE(&contact_vec);
}
-static int register_aor_core(pjsip_rx_data *rdata,
+struct aor_core_response {
+ /*! Tx data to use for statefull response. NULL for stateless response. */
+ pjsip_tx_data *tdata;
+ /*! SIP response code to send in stateless response */
+ int code;
+};
+
+static void register_aor_core(pjsip_rx_data *rdata,
struct ast_sip_endpoint *endpoint,
struct ast_sip_aor *aor,
const char *aor_name,
- struct ao2_container *contacts)
+ struct ao2_container *contacts,
+ struct aor_core_response *response)
{
static const pj_str_t USER_AGENT = { "User-Agent", 10 };
@@ -480,19 +488,19 @@ static int register_aor_core(pjsip_rx_data *rdata,
if (registrar_validate_contacts(rdata, contacts, aor, &added, &updated, &deleted)) {
/* The provided Contact headers do not conform to the specification */
- pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 400, NULL, NULL, NULL);
ast_sip_report_failed_acl(endpoint, rdata, "registrar_invalid_contacts_provided");
ast_log(LOG_WARNING, "Failed to validate contacts in REGISTER request from '%s'\n",
ast_sorcery_object_get_id(endpoint));
- return PJ_TRUE;
+ response->code = 400;
+ return;
}
if (registrar_validate_path(rdata, aor, &path_str)) {
/* Ensure that intervening proxies did not make invalid modifications to the request */
- pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 420, NULL, NULL, NULL);
ast_log(LOG_WARNING, "Invalid modifications made to REGISTER request from '%s' by intervening proxy\n",
ast_sorcery_object_get_id(endpoint));
- return PJ_TRUE;
+ response->code = 420;
+ return;
}
if (aor->remove_existing) {
@@ -504,18 +512,18 @@ static int register_aor_core(pjsip_rx_data *rdata,
}
if (contact_count > aor->max_contacts) {
/* Enforce the maximum number of contacts */
- pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 403, NULL, NULL, NULL);
ast_sip_report_failed_acl(endpoint, rdata, "registrar_attempt_exceeds_maximum_configured_contacts");
ast_log(LOG_WARNING, "Registration attempt from endpoint '%s' to AOR '%s' will exceed max contacts of %u\n",
ast_sorcery_object_get_id(endpoint), aor_name, aor->max_contacts);
- return PJ_TRUE;
+ response->code = 403;
+ return;
}
details.pool = pjsip_endpt_create_pool(ast_sip_get_pjsip_endpoint(),
"Contact Comparison", 256, 256);
if (!details.pool) {
- pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 500, NULL, NULL, NULL);
- return PJ_TRUE;
+ response->code = 500;
+ return;
}
user_agent_hdr = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &USER_AGENT, NULL);
@@ -730,8 +738,8 @@ static int register_aor_core(pjsip_rx_data *rdata,
/* Re-retrieve contacts. Caller will clean up the original container. */
contacts = ast_sip_location_retrieve_aor_contacts_nolock(aor);
if (!contacts) {
- pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 500, NULL, NULL, NULL);
- return PJ_TRUE;
+ response->code = 500;
+ return;
}
response_contact = ao2_callback(contacts, 0, NULL, NULL);
@@ -739,7 +747,8 @@ static int register_aor_core(pjsip_rx_data *rdata,
if (ast_sip_create_response(rdata, 200, response_contact, &tdata) != PJ_SUCCESS) {
ao2_cleanup(response_contact);
ao2_cleanup(contacts);
- return PJ_TRUE;
+ response->code = 500;
+ return;
}
ao2_cleanup(response_contact);
@@ -754,9 +763,7 @@ static int register_aor_core(pjsip_rx_data *rdata,
pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)expires_hdr);
}
- ast_sip_send_stateful_response(rdata, tdata, endpoint);
-
- return PJ_TRUE;
+ response->tdata = tdata;
}
static int register_aor(pjsip_rx_data *rdata,
@@ -764,21 +771,32 @@ static int register_aor(pjsip_rx_data *rdata,
struct ast_sip_aor *aor,
const char *aor_name)
{
- int res;
+ struct aor_core_response response = {
+ .code = 500,
+ };
struct ao2_container *contacts = NULL;
ao2_lock(aor);
contacts = ast_sip_location_retrieve_aor_contacts_nolock(aor);
if (!contacts) {
ao2_unlock(aor);
+ pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(),
+ rdata, response.code, NULL, NULL, NULL);
return PJ_TRUE;
}
- res = register_aor_core(rdata, endpoint, aor, aor_name, contacts);
+ register_aor_core(rdata, endpoint, aor, aor_name, contacts, &response);
ao2_cleanup(contacts);
ao2_unlock(aor);
- return res;
+ /* Now send the REGISTER response to the peer */
+ if (response.tdata) {
+ ast_sip_send_stateful_response(rdata, response.tdata, endpoint);
+ } else {
+ pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(),
+ rdata, response.code, NULL, NULL, NULL);
+ }
+ return PJ_TRUE;
}
static int match_aor(const char *aor_name, const char *id)
diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c
index f174f4781..781d3e4eb 100644
--- a/res/res_pjsip_session.c
+++ b/res/res_pjsip_session.c
@@ -174,7 +174,8 @@ void ast_sip_session_unregister_sdp_handler(struct ast_sip_session_sdp_handler *
ao2_callback_data(sdp_handlers, OBJ_KEY | OBJ_UNLINK | OBJ_NODATA, remove_handler, (void *)stream_type, handler);
}
-struct ast_sip_session_media_state *ast_sip_session_media_state_alloc(void)
+static struct ast_sip_session_media_state *internal_sip_session_media_state_alloc(
+ size_t sessions, size_t read_callbacks)
{
struct ast_sip_session_media_state *media_state;
@@ -183,12 +184,12 @@ struct ast_sip_session_media_state *ast_sip_session_media_state_alloc(void)
return NULL;
}
- if (AST_VECTOR_INIT(&media_state->sessions, DEFAULT_NUM_SESSION_MEDIA) < 0) {
+ if (AST_VECTOR_INIT(&media_state->sessions, sessions) < 0) {
ast_free(media_state);
return NULL;
}
- if (AST_VECTOR_INIT(&media_state->read_callbacks, DEFAULT_NUM_SESSION_MEDIA) < 0) {
+ if (AST_VECTOR_INIT(&media_state->read_callbacks, read_callbacks) < 0) {
AST_VECTOR_FREE(&media_state->sessions);
ast_free(media_state);
return NULL;
@@ -197,6 +198,12 @@ struct ast_sip_session_media_state *ast_sip_session_media_state_alloc(void)
return media_state;
}
+struct ast_sip_session_media_state *ast_sip_session_media_state_alloc(void)
+{
+ return internal_sip_session_media_state_alloc(
+ DEFAULT_NUM_SESSION_MEDIA, DEFAULT_NUM_SESSION_MEDIA);
+}
+
void ast_sip_session_media_state_reset(struct ast_sip_session_media_state *media_state)
{
int index;
@@ -225,7 +232,9 @@ struct ast_sip_session_media_state *ast_sip_session_media_state_clone(const stru
return NULL;
}
- cloned = ast_sip_session_media_state_alloc();
+ cloned = internal_sip_session_media_state_alloc(
+ AST_VECTOR_SIZE(&media_state->sessions),
+ AST_VECTOR_SIZE(&media_state->read_callbacks));
if (!cloned) {
return NULL;
}
@@ -452,7 +461,11 @@ struct ast_sip_session_media *ast_sip_session_media_state_add(struct ast_sip_ses
}
}
- AST_VECTOR_REPLACE(&media_state->sessions, position, session_media);
+ if (AST_VECTOR_REPLACE(&media_state->sessions, position, session_media)) {
+ ao2_ref(session_media, -1);
+
+ return NULL;
+ }
/* If this stream will be active in some way and it is the first of this type then consider this the default media session to match */
if (!media_state->default_session[type] && ast_stream_get_state(ast_stream_topology_get_stream(media_state->topology, position)) != AST_STREAM_STATE_REMOVED) {
@@ -678,7 +691,10 @@ static int handle_incoming_sdp(struct ast_sip_session *session, const pjmedia_sd
if (!stream) {
return -1;
}
- ast_stream_topology_set_stream(session->pending_media_state->topology, i, stream);
+ if (ast_stream_topology_set_stream(session->pending_media_state->topology, i, stream)) {
+ ast_stream_free(stream);
+ return -1;
+ }
}
session_media = ast_sip_session_media_state_add(session, session->pending_media_state, ast_media_type_from_str(media), i);
@@ -1588,7 +1604,11 @@ int ast_sip_session_refresh(struct ast_sip_session *session,
}
ast_stream_set_state(cloned, AST_STREAM_STATE_REMOVED);
- ast_stream_topology_append_stream(media_state->topology, cloned);
+ if (ast_stream_topology_append_stream(media_state->topology, cloned) < 0) {
+ ast_stream_free(cloned);
+ ast_sip_session_media_state_free(media_state);
+ return -1;
+ }
}
/* If the resulting media state matches the existing active state don't bother doing a session refresh */
@@ -1745,7 +1765,10 @@ static int sdp_requires_deferral(struct ast_sip_session *session, const pjmedia_
/* As this is only called on an incoming SDP offer before processing it is not possible
* for streams and their media sessions to exist.
*/
- ast_stream_topology_set_stream(session->pending_media_state->topology, i, stream);
+ if (ast_stream_topology_set_stream(session->pending_media_state->topology, i, stream)) {
+ ast_stream_free(stream);
+ return -1;
+ }
session_media = ast_sip_session_media_state_add(session, session->pending_media_state, ast_media_type_from_str(media), i);
if (!session_media) {
diff --git a/res/res_pjsip_t38.c b/res/res_pjsip_t38.c
index 48cbab37b..8f1905f6e 100644
--- a/res/res_pjsip_t38.c
+++ b/res/res_pjsip_t38.c
@@ -363,7 +363,11 @@ static struct ast_sip_session_media_state *t38_create_media_state(struct ast_sip
}
ast_stream_set_state(stream, AST_STREAM_STATE_SENDRECV);
- ast_stream_topology_set_stream(media_state->topology, 0, stream);
+ if (ast_stream_topology_set_stream(media_state->topology, 0, stream)) {
+ ast_stream_free(stream);
+ ast_sip_session_media_state_free(media_state);
+ return NULL;
+ }
caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
if (!caps) {
@@ -371,9 +375,14 @@ static struct ast_sip_session_media_state *t38_create_media_state(struct ast_sip
return NULL;
}
- ast_format_cap_append(caps, ast_format_t38, 0);
ast_stream_set_formats(stream, caps);
+ /* stream holds a reference to cap, release the local reference
+ * now so we don't have to deal with it in the error condition. */
ao2_ref(caps, -1);
+ if (ast_format_cap_append(caps, ast_format_t38, 0)) {
+ ast_sip_session_media_state_free(media_state);
+ return NULL;
+ }
session_media = ast_sip_session_media_state_add(session, media_state, AST_MEDIA_TYPE_IMAGE, 0);
if (!session_media) {
diff --git a/res/res_pjsip_transport_websocket.c b/res/res_pjsip_transport_websocket.c
index 22ec19540..3ce90390c 100644
--- a/res/res_pjsip_transport_websocket.c
+++ b/res/res_pjsip_transport_websocket.c
@@ -203,27 +203,25 @@ static int transport_create(void *data)
ast_debug(4, "Creating websocket transport for %s:%s\n",
newtransport->transport.type_name, ws_addr_str);
+ newtransport->transport.info = (char *) pj_pool_alloc(newtransport->transport.pool,
+ strlen(newtransport->transport.type_name) + strlen(ws_addr_str) + sizeof(" to "));
+ sprintf(newtransport->transport.info, "%s to %s", newtransport->transport.type_name, ws_addr_str);
+
pj_sockaddr_parse(pj_AF_UNSPEC(), 0, pj_cstr(&buf, ws_addr_str), &newtransport->transport.key.rem_addr);
if (newtransport->transport.key.rem_addr.addr.sa_family == pj_AF_INET6()) {
newtransport->transport.key.type = transport_type_wss_ipv6;
- newtransport->transport.local_name.host.ptr = (char *)pj_pool_alloc(pool, PJ_INET6_ADDRSTRLEN);
- pj_sockaddr_print(&newtransport->transport.key.rem_addr, newtransport->transport.local_name.host.ptr, PJ_INET6_ADDRSTRLEN, 0);
} else {
newtransport->transport.key.type = transport_type_wss;
- newtransport->transport.local_name.host.ptr = (char *)pj_pool_alloc(pool, PJ_INET_ADDRSTRLEN);
- pj_sockaddr_print(&newtransport->transport.key.rem_addr, newtransport->transport.local_name.host.ptr, PJ_INET_ADDRSTRLEN, 0);
}
newtransport->transport.addr_len = pj_sockaddr_get_len(&newtransport->transport.key.rem_addr);
- pj_sockaddr_cp(&newtransport->transport.local_addr, &newtransport->transport.key.rem_addr);
-
- newtransport->transport.local_name.host.slen = pj_ansi_strlen(newtransport->transport.local_name.host.ptr);
- newtransport->transport.local_name.port = pj_sockaddr_get_port(&newtransport->transport.key.rem_addr);
+ ws_addr_str = ast_sockaddr_stringify(ast_websocket_local_address(newtransport->ws_session));
+ pj_sockaddr_parse(pj_AF_UNSPEC(), 0, pj_cstr(&buf, ws_addr_str), &newtransport->transport.local_addr);
+ pj_strdup2(pool, &newtransport->transport.local_name.host, ast_sockaddr_stringify_host(ast_websocket_local_address(newtransport->ws_session)));
+ newtransport->transport.local_name.port = ast_sockaddr_port(ast_websocket_local_address(newtransport->ws_session));
newtransport->transport.flag = pjsip_transport_get_flag_from_type((pjsip_transport_type_e)newtransport->transport.key.type);
- newtransport->transport.info = (char *)pj_pool_alloc(newtransport->transport.pool, 64);
-
newtransport->transport.dir = PJSIP_TP_DIR_INCOMING;
newtransport->transport.tpmgr = tpmgr;
newtransport->transport.send_msg = &ws_send_msg;
diff --git a/res/res_sorcery_astdb.c b/res/res_sorcery_astdb.c
index 8d1633511..8b93b57ba 100644
--- a/res/res_sorcery_astdb.c
+++ b/res/res_sorcery_astdb.c
@@ -44,6 +44,7 @@ static void *sorcery_astdb_retrieve_fields(const struct ast_sorcery *sorcery, vo
static void sorcery_astdb_retrieve_multiple(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects,
const struct ast_variable *fields);
static void sorcery_astdb_retrieve_regex(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const char *regex);
+static void sorcery_astdb_retrieve_prefix(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const char *prefix, const size_t prefix_len);
static int sorcery_astdb_update(const struct ast_sorcery *sorcery, void *data, void *object);
static int sorcery_astdb_delete(const struct ast_sorcery *sorcery, void *data, void *object);
static void sorcery_astdb_close(void *data);
@@ -56,6 +57,7 @@ static struct ast_sorcery_wizard astdb_object_wizard = {
.retrieve_fields = sorcery_astdb_retrieve_fields,
.retrieve_multiple = sorcery_astdb_retrieve_multiple,
.retrieve_regex = sorcery_astdb_retrieve_regex,
+ .retrieve_prefix = sorcery_astdb_retrieve_prefix,
.update = sorcery_astdb_update,
.delete = sorcery_astdb_delete,
.close = sorcery_astdb_close,
@@ -327,6 +329,42 @@ static void sorcery_astdb_retrieve_regex(const struct ast_sorcery *sorcery, void
regfree(&expression);
}
+static void sorcery_astdb_retrieve_prefix(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const char *prefix, const size_t prefix_len)
+{
+ const char *family_prefix = data;
+ size_t family_len = strlen(family_prefix) + strlen(type) + 1; /* +1 for slash delimiter */
+ char family[family_len + 1];
+ char tree[prefix_len + sizeof("%")];
+ RAII_VAR(struct ast_db_entry *, entries, NULL, ast_db_freetree);
+ struct ast_db_entry *entry;
+
+ snprintf(tree, sizeof(tree), "%.*s%%", (int) prefix_len, prefix);
+ snprintf(family, sizeof(family), "%s/%s", family_prefix, type);
+
+ if (!(entries = ast_db_gettree(family, tree))) {
+ return;
+ }
+
+ for (entry = entries; entry; entry = entry->next) {
+ /* The key in the entry includes the family, so we need to strip it out */
+ const char *key = entry->key + family_len + 2;
+ RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
+ struct ast_json_error error;
+ RAII_VAR(void *, object, NULL, ao2_cleanup);
+ RAII_VAR(struct ast_variable *, objset, NULL, ast_variables_destroy);
+
+ if (!(json = ast_json_load_string(entry->data, &error))
+ || (ast_json_to_ast_variables(json, &objset) != AST_JSON_TO_AST_VARS_CODE_SUCCESS)
+ || !(objset = sorcery_astdb_filter_objectset(objset, sorcery, type))
+ || !(object = ast_sorcery_alloc(sorcery, type, key))
+ || ast_sorcery_objectset_apply(sorcery, object, objset)) {
+ return;
+ }
+
+ ao2_link(objects, object);
+ }
+}
+
static int sorcery_astdb_update(const struct ast_sorcery *sorcery, void *data, void *object)
{
const char *prefix = data;
diff --git a/res/res_sorcery_config.c b/res/res_sorcery_config.c
index 0de34c640..20178883b 100644
--- a/res/res_sorcery_config.c
+++ b/res/res_sorcery_config.c
@@ -71,6 +71,12 @@ struct sorcery_config_fields_cmp_params {
/*! \brief Regular expression for checking object id */
regex_t *regex;
+ /*! \brief Prefix for matching object id */
+ const char *prefix;
+
+ /*! \brief Prefix length in bytes for matching object id */
+ const size_t prefix_len;
+
/*! \brief Optional container to put object into */
struct ao2_container *container;
};
@@ -83,6 +89,7 @@ static void *sorcery_config_retrieve_fields(const struct ast_sorcery *sorcery, v
static void sorcery_config_retrieve_multiple(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects,
const struct ast_variable *fields);
static void sorcery_config_retrieve_regex(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const char *regex);
+static void sorcery_config_retrieve_prefix(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const char *prefix, const size_t prefix_len);
static void sorcery_config_close(void *data);
static struct ast_sorcery_wizard config_object_wizard = {
@@ -94,6 +101,7 @@ static struct ast_sorcery_wizard config_object_wizard = {
.retrieve_fields = sorcery_config_retrieve_fields,
.retrieve_multiple = sorcery_config_retrieve_multiple,
.retrieve_regex = sorcery_config_retrieve_regex,
+ .retrieve_prefix = sorcery_config_retrieve_prefix,
.close = sorcery_config_close,
};
@@ -118,6 +126,11 @@ static int sorcery_config_fields_cmp(void *obj, void *arg, int flags)
ao2_link(params->container, obj);
}
return 0;
+ } else if (params->prefix) {
+ if (!strncmp(params->prefix, ast_sorcery_object_get_id(obj), params->prefix_len)) {
+ ao2_link(params->container, obj);
+ }
+ return 0;
} else if (params->fields &&
(!(objset = ast_sorcery_objectset_create(params->sorcery, obj)) ||
(!ast_variable_lists_match(objset, params->fields, 0)))) {
@@ -206,6 +219,24 @@ static void sorcery_config_retrieve_regex(const struct ast_sorcery *sorcery, voi
regfree(&expression);
}
+static void sorcery_config_retrieve_prefix(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const char *prefix, const size_t prefix_len)
+{
+ struct sorcery_config *config = data;
+ RAII_VAR(struct ao2_container *, config_objects, ao2_global_obj_ref(config->objects), ao2_cleanup);
+ struct sorcery_config_fields_cmp_params params = {
+ .sorcery = sorcery,
+ .container = objects,
+ .prefix = prefix,
+ .prefix_len = prefix_len,
+ };
+
+ if (!config_objects) {
+ return;
+ }
+
+ ao2_callback(config_objects, OBJ_NODATA | OBJ_MULTIPLE, sorcery_config_fields_cmp, &params);
+}
+
/*! \brief Internal function which determines if criteria has been met for considering an object set applicable */
static int sorcery_is_criteria_met(struct ast_variable *objset, struct ast_variable *criteria)
{
diff --git a/res/res_sorcery_memory.c b/res/res_sorcery_memory.c
index 57d5eace0..6c91dad2d 100644
--- a/res/res_sorcery_memory.c
+++ b/res/res_sorcery_memory.c
@@ -46,6 +46,7 @@ static void *sorcery_memory_retrieve_fields(const struct ast_sorcery *sorcery, v
static void sorcery_memory_retrieve_multiple(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects,
const struct ast_variable *fields);
static void sorcery_memory_retrieve_regex(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const char *regex);
+static void sorcery_memory_retrieve_prefix(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const char *prefix, const size_t prefix_len);
static int sorcery_memory_update(const struct ast_sorcery *sorcery, void *data, void *object);
static int sorcery_memory_delete(const struct ast_sorcery *sorcery, void *data, void *object);
static void sorcery_memory_close(void *data);
@@ -58,6 +59,7 @@ static struct ast_sorcery_wizard memory_object_wizard = {
.retrieve_fields = sorcery_memory_retrieve_fields,
.retrieve_multiple = sorcery_memory_retrieve_multiple,
.retrieve_regex = sorcery_memory_retrieve_regex,
+ .retrieve_prefix = sorcery_memory_retrieve_prefix,
.update = sorcery_memory_update,
.delete = sorcery_memory_delete,
.close = sorcery_memory_close,
@@ -74,6 +76,12 @@ struct sorcery_memory_fields_cmp_params {
/*! \brief Regular expression for checking object id */
regex_t *regex;
+ /*! \brief Prefix for matching object id */
+ const char *prefix;
+
+ /*! \brief Prefix length in bytes for matching object id */
+ const size_t prefix_len;
+
/*! \brief Optional container to put object into */
struct ao2_container *container;
};
@@ -125,6 +133,11 @@ static int sorcery_memory_fields_cmp(void *obj, void *arg, int flags)
ao2_link(params->container, obj);
}
return 0;
+ } else if (params->prefix) {
+ if (!strncmp(params->prefix, ast_sorcery_object_get_id(obj), params->prefix_len)) {
+ ao2_link(params->container, obj);
+ }
+ return 0;
} else if (params->fields &&
(!(objset = ast_sorcery_objectset_create(params->sorcery, obj)) ||
(!ast_variable_lists_match(objset, params->fields, 0)))) {
@@ -198,6 +211,18 @@ static void sorcery_memory_retrieve_regex(const struct ast_sorcery *sorcery, voi
regfree(&expression);
}
+static void sorcery_memory_retrieve_prefix(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const char *prefix, const size_t prefix_len)
+{
+ struct sorcery_memory_fields_cmp_params params = {
+ .sorcery = sorcery,
+ .container = objects,
+ .prefix = prefix,
+ .prefix_len = prefix_len,
+ };
+
+ ao2_callback(data, 0, sorcery_memory_fields_cmp, &params);
+}
+
static int sorcery_memory_update(const struct ast_sorcery *sorcery, void *data, void *object)
{
RAII_VAR(void *, existing, NULL, ao2_cleanup);
diff --git a/res/res_sorcery_memory_cache.c b/res/res_sorcery_memory_cache.c
index bf2347ccd..30e6ef04b 100644
--- a/res/res_sorcery_memory_cache.c
+++ b/res/res_sorcery_memory_cache.c
@@ -185,6 +185,10 @@ struct sorcery_memory_cache_fields_cmp_params {
const struct ast_variable *fields;
/*! \brief Regular expression for checking object id */
regex_t *regex;
+ /*! \brief Prefix for matching object id */
+ const char *prefix;
+ /*! \brief Prefix length in bytes for matching object id */
+ const size_t prefix_len;
/*! \brief Optional container to put object into */
struct ao2_container *container;
};
@@ -201,6 +205,8 @@ static void sorcery_memory_cache_retrieve_multiple(const struct ast_sorcery *sor
struct ao2_container *objects, const struct ast_variable *fields);
static void sorcery_memory_cache_retrieve_regex(const struct ast_sorcery *sorcery, void *data, const char *type,
struct ao2_container *objects, const char *regex);
+static void sorcery_memory_cache_retrieve_prefix(const struct ast_sorcery *sorcery, void *data, const char *type,
+ struct ao2_container *objects, const char *prefix, const size_t prefix_len);
static int sorcery_memory_cache_delete(const struct ast_sorcery *sorcery, void *data, void *object);
static void sorcery_memory_cache_close(void *data);
@@ -216,6 +222,7 @@ static struct ast_sorcery_wizard memory_cache_object_wizard = {
.retrieve_fields = sorcery_memory_cache_retrieve_fields,
.retrieve_multiple = sorcery_memory_cache_retrieve_multiple,
.retrieve_regex = sorcery_memory_cache_retrieve_regex,
+ .retrieve_prefix = sorcery_memory_cache_retrieve_prefix,
.close = sorcery_memory_cache_close,
};
@@ -1253,6 +1260,11 @@ static int sorcery_memory_cache_fields_cmp(void *obj, void *arg, int flags)
ao2_link(params->container, cached->object);
}
return 0;
+ } else if (params->prefix) {
+ if (!strncmp(params->prefix, ast_sorcery_object_get_id(cached->object), params->prefix_len)) {
+ ao2_link(params->container, cached->object);
+ }
+ return 0;
} else if (params->fields &&
(!ast_variable_lists_match(cached->objectset, params->fields, 0))) {
/* If we can't turn the object into an object set OR if differences exist between the fields
@@ -1378,6 +1390,40 @@ static void sorcery_memory_cache_retrieve_regex(const struct ast_sorcery *sorcer
/*!
* \internal
+ * \brief Callback function to retrieve multiple objects whose id matches a prefix
+ *
+ * \param sorcery The sorcery instance
+ * \param data The sorcery memory cache
+ * \param type The type of the object to retrieve
+ * \param objects Container to place the objects into
+ * \param prefix Prefix to match against the object id
+ */
+static void sorcery_memory_cache_retrieve_prefix(const struct ast_sorcery *sorcery, void *data, const char *type,
+ struct ao2_container *objects, const char *prefix, const size_t prefix_len)
+{
+ struct sorcery_memory_cache *cache = data;
+ struct sorcery_memory_cache_fields_cmp_params params = {
+ .sorcery = sorcery,
+ .cache = cache,
+ .container = objects,
+ .prefix = prefix,
+ .prefix_len = prefix_len,
+ };
+
+ if (is_passthru_update() || !cache->full_backend_cache) {
+ return;
+ }
+
+ memory_cache_full_update(sorcery, type, cache);
+ ao2_callback(cache->objects, 0, sorcery_memory_cache_fields_cmp, &params);
+
+ if (ao2_container_count(objects)) {
+ memory_cache_stale_check(sorcery, cache);
+ }
+}
+
+/*!
+ * \internal
* \brief Callback function to finish configuring the memory cache
*
* \param data The sorcery memory cache
diff --git a/res/res_sorcery_realtime.c b/res/res_sorcery_realtime.c
index 3f114046c..a858cbcef 100644
--- a/res/res_sorcery_realtime.c
+++ b/res/res_sorcery_realtime.c
@@ -57,6 +57,8 @@ static void *sorcery_realtime_retrieve_fields(const struct ast_sorcery *sorcery,
static void sorcery_realtime_retrieve_multiple(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects,
const struct ast_variable *fields);
static void sorcery_realtime_retrieve_regex(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const char *regex);
+static void sorcery_realtime_retrieve_prefix(const struct ast_sorcery *sorcery, void *data, const char *type,
+ struct ao2_container *objects, const char *prefix, const size_t prefix_len);
static int sorcery_realtime_update(const struct ast_sorcery *sorcery, void *data, void *object);
static int sorcery_realtime_delete(const struct ast_sorcery *sorcery, void *data, void *object);
static void sorcery_realtime_close(void *data);
@@ -69,6 +71,7 @@ static struct ast_sorcery_wizard realtime_object_wizard = {
.retrieve_fields = sorcery_realtime_retrieve_fields,
.retrieve_multiple = sorcery_realtime_retrieve_multiple,
.retrieve_regex = sorcery_realtime_retrieve_regex,
+ .retrieve_prefix = sorcery_realtime_retrieve_prefix,
.update = sorcery_realtime_update,
.delete = sorcery_realtime_delete,
.close = sorcery_realtime_close,
@@ -260,6 +263,23 @@ static void sorcery_realtime_retrieve_regex(const struct ast_sorcery *sorcery, v
sorcery_realtime_retrieve_multiple(sorcery, data, type, objects, fields);
}
+static void sorcery_realtime_retrieve_prefix(const struct ast_sorcery *sorcery, void *data, const char *type,
+ struct ao2_container *objects, const char *prefix, const size_t prefix_len)
+{
+ char field[strlen(UUID_FIELD) + 6], value[prefix_len + 2];
+ RAII_VAR(struct ast_variable *, fields, NULL, ast_variables_destroy);
+
+ if (prefix_len) {
+ snprintf(field, sizeof(field), "%s LIKE", UUID_FIELD);
+ snprintf(value, sizeof(value), "%.*s%%", (int) prefix_len, prefix);
+ if (!(fields = ast_variable_new(field, value, ""))) {
+ return;
+ }
+ }
+
+ sorcery_realtime_retrieve_multiple(sorcery, data, type, objects, fields);
+}
+
static int sorcery_realtime_update(const struct ast_sorcery *sorcery, void *data, void *object)
{
struct sorcery_config *config = data;
diff --git a/third-party/pjproject/patches/0010-r5665-svn-backport-ICE-Use-STUN-FINGERPRINT-attribut.patch b/third-party/pjproject/patches/0010-r5665-svn-backport-ICE-Use-STUN-FINGERPRINT-attribut.patch
deleted file mode 100644
index 3c83cc502..000000000
--- a/third-party/pjproject/patches/0010-r5665-svn-backport-ICE-Use-STUN-FINGERPRINT-attribut.patch
+++ /dev/null
@@ -1,41 +0,0 @@
-From 06bc834969a34d2c60e05beed3051b4a6d34c125 Mon Sep 17 00:00:00 2001
-From: Richard Mudgett <rmudgett@digium.com>
-Date: Thu, 28 Sep 2017 10:57:23 -0500
-Subject: [PATCH 3/3] r5665 svn backport ICE: Use STUN FINGERPRINT attribute
- when sending keepalives
-
-Fixed #2046: ICE: Use STUN FINGERPRINT attribute when sending keepalives
-
-Per RFC 5245 Section 10:
-
- If STUN is being used for keepalives, a STUN Binding Indication is
- used [RFC5389]. The Indication MUST NOT utilize any authentication
- mechanism. It SHOULD contain the FINGERPRINT attribute to aid in
- demultiplexing, but SHOULD NOT contain any other attributes.
----
- pjnath/src/pjnath/ice_session.c | 8 +++++---
- 1 file changed, 5 insertions(+), 3 deletions(-)
-
-diff --git a/pjnath/src/pjnath/ice_session.c b/pjnath/src/pjnath/ice_session.c
-index 27a2950..63a0d1c 100644
---- a/pjnath/src/pjnath/ice_session.c
-+++ b/pjnath/src/pjnath/ice_session.c
-@@ -1217,10 +1217,12 @@ static void ice_keep_alive(pj_ice_sess *ice, pj_bool_t send_now)
- msg_data = PJ_POOL_ZALLOC_T(tdata->pool, pj_ice_msg_data);
- msg_data->transport_id = the_check->lcand->transport_id;
-
-- /* Temporarily disable FINGERPRINT. The Binding Indication
-- * SHOULD NOT contain any attributes.
-+ /* RFC 5245 Section 10:
-+ * The Binding Indication SHOULD contain the FINGERPRINT attribute
-+ * to aid in demultiplexing, but SHOULD NOT contain any other
-+ * attributes.
- */
-- saved = pj_stun_session_use_fingerprint(comp->stun_sess, PJ_FALSE);
-+ saved = pj_stun_session_use_fingerprint(comp->stun_sess, PJ_TRUE);
-
- /* Send to session */
- addr_len = pj_sockaddr_get_len(&the_check->rcand->addr);
---
-2.7.4
-
diff --git a/third-party/pjproject/patches/0020-sip_parser-Add-validity-checking-for-numeric-header-.patch b/third-party/pjproject/patches/0020-sip_parser-Add-validity-checking-for-numeric-header-.patch
deleted file mode 100644
index dfee4b2c2..000000000
--- a/third-party/pjproject/patches/0020-sip_parser-Add-validity-checking-for-numeric-header-.patch
+++ /dev/null
@@ -1,973 +0,0 @@
-From b21042956dc4d3526052d5030953e5c565bb0895 Mon Sep 17 00:00:00 2001
-From: George Joseph <gjoseph@digium.com>
-Date: Thu, 2 Nov 2017 08:23:00 -0600
-Subject: [PATCH] sip_parser: Add validity checking for numeric header values
-
-Parsing the numeric header fields like cseq, ttl, port, etc. all
-had the potential to overflow, either causing unintended values to
-be captured or, if the values were subsequently converted back to
-strings, a buffer overrun. To address this, new "strto" functions
-have been created that do range checking and those functions are
-used wherever possible in the parser.
-
- * Created pjlib/include/limits.h and pjlib/include/compat/limits.h
- to either include the system limits.h or define common numeric
- limits if there is no system limits.h.
-
- * Created strto*_validate functions in sip_parser that take bounds
- and on failure call the on_str_parse_error function which prints
- an error message and calls PJ_THROW.
-
- * Updated sip_parser to validate the numeric fields.
-
- * Fixed an issue in sip_transport that prevented error messages
- from being properly displayed.
-
- * Added "volatile" to some variables referenced in PJ_CATCH blocks
- as the optimizer was sometimes optimizing them away.
-
- * Fixed length calculation in sip_transaction/create_tsx_key_2543
- to account for signed ints being 11 characters, not 9.
-
-Reported by: Youngsung Kim at LINE Corporation
----
- pjlib/build/pjlib.vcproj | 14 +++-
- pjlib/build/pjlib.vcxproj | 4 +-
- pjlib/build/pjlib.vcxproj.filters | 6 ++
- pjlib/include/pj/compat/limits.h | 65 +++++++++++++++
- pjlib/include/pj/compat/os_win32.h | 1 +
- pjlib/include/pj/limits.h | 51 ++++++++++++
- pjlib/include/pj/string.h | 46 +++++++++-
- pjlib/include/pj/types.h | 3 -
- pjlib/src/pj/string.c | 119 +++++++++++++++++++++++++-
- pjlib/src/pj/timer.c | 1 +
- pjsip/include/pjsip/sip_parser.h | 25 ++++++
- pjsip/src/pjsip/sip_parser.c | 166 +++++++++++++++++++++++++++++--------
- pjsip/src/pjsip/sip_transaction.c | 4 +-
- pjsip/src/pjsip/sip_transport.c | 7 +-
- 14 files changed, 463 insertions(+), 49 deletions(-)
- create mode 100644 pjlib/include/pj/compat/limits.h
- create mode 100644 pjlib/include/pj/limits.h
-
-diff --git a/pjlib/build/pjlib.vcproj b/pjlib/build/pjlib.vcproj
-index 6a217a0b7..12592ef94 100644
---- a/pjlib/build/pjlib.vcproj
-+++ b/pjlib/build/pjlib.vcproj
-@@ -14967,7 +14967,11 @@
- </File>
- <File
- RelativePath="..\include\pj\ip_helper.h"
-- >
-+ >
-+ </File>
-+ <File
-+ RelativePath="..\include\pj\limits.h"
-+ >
- </File>
- <File
- RelativePath="..\include\pj\list.h"
-@@ -15070,8 +15074,12 @@
- </File>
- <File
- RelativePath="..\include\pj\compat\high_precision.h"
-- >
-- </File>
-+ >
-+ </File>
-+ <File
-+ RelativePath="..\include\pj\compat\limits.h"
-+ >
-+ </File>
- <File
- RelativePath="..\include\pj\compat\m_alpha.h"
- >
-diff --git a/pjlib/build/pjlib.vcxproj b/pjlib/build/pjlib.vcxproj
-index abf09ec44..e41731e3c 100644
---- a/pjlib/build/pjlib.vcxproj
-+++ b/pjlib/build/pjlib.vcxproj
-@@ -494,7 +494,7 @@
- <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">true</ExcludedFromBuild>
- <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
- </ClCompile>
-- <ClCompile Include="..\src\pj\file_io_win32.c" />
-+ <ClCompile Include="..\src\pj\file_io_win32.c" />
- <ClCompile Include="..\src\pj\guid.c" />
- <ClCompile Include="..\src\pj\guid_simple.c">
- <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug-Dynamic|Win32'">true</ExcludedFromBuild>
-@@ -890,6 +890,7 @@
- <ClInclude Include="..\include\pj\compat\ctype.h" />
- <ClInclude Include="..\include\pj\compat\errno.h" />
- <ClInclude Include="..\include\pj\compat\high_precision.h" />
-+ <ClInclude Include="..\include\pj\compat\limits.h" />
- <ClInclude Include="..\include\pj\compat\malloc.h" />
- <ClInclude Include="..\include\pj\compat\m_alpha.h" />
- <ClInclude Include="..\include\pj\compat\m_i386.h" />
-@@ -925,6 +926,7 @@
- <ClInclude Include="..\include\pj\hash.h" />
- <ClInclude Include="..\include\pj\ioqueue.h" />
- <ClInclude Include="..\include\pj\ip_helper.h" />
-+ <ClInclude Include="..\include\pj\limits.h" />
- <ClInclude Include="..\include\pj\list.h" />
- <ClInclude Include="..\include\pj\list_i.h" />
- <ClInclude Include="..\include\pj\lock.h" />
-diff --git a/pjlib/build/pjlib.vcxproj.filters b/pjlib/build/pjlib.vcxproj.filters
-index 0b5cbf109..6f343b019 100644
---- a/pjlib/build/pjlib.vcxproj.filters
-+++ b/pjlib/build/pjlib.vcxproj.filters
-@@ -439,5 +439,11 @@
- <ClInclude Include="..\include\pj\compat\os_winuwp.h">
- <Filter>Header Files\compat</Filter>
- </ClInclude>
-+ <ClInclude Include="..\include\pj\limits.h">
-+ <Filter>Header Files</Filter>
-+ </ClInclude>
-+ <ClInclude Include="..\include\pj\compat\limits.h">
-+ <Filter>Header Files\compat</Filter>
-+ </ClInclude>
- </ItemGroup>
- </Project>
-\ No newline at end of file
-diff --git a/pjlib/include/pj/compat/limits.h b/pjlib/include/pj/compat/limits.h
-new file mode 100644
-index 000000000..fba0625df
---- /dev/null
-+++ b/pjlib/include/pj/compat/limits.h
-@@ -0,0 +1,65 @@
-+/* $Id$ */
-+/*
-+ * Copyright (C) 2017 Teluu Inc. (http://www.teluu.com)
-+ * Copyright (C) 2017 George Joseph <gjoseph@digium.com>
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-+ */
-+#ifndef __PJ_COMPAT_LIMITS_H__
-+#define __PJ_COMPAT_LIMITS_H__
-+
-+/**
-+ * @file limits.h
-+ * @brief Provides integer limits normally found in limits.h.
-+ */
-+
-+#if defined(PJ_HAS_LIMITS_H) && PJ_HAS_LIMITS_H != 0
-+# include <limits.h>
-+#else
-+
-+# ifdef _MSC_VER
-+# pragma message("limits.h is not found or not supported. LONG_MIN and "\
-+ "LONG_MAX will be defined by the library in "\
-+ "pj/compats/limits.h and overridable in config_site.h")
-+# else
-+# warning "limits.h is not found or not supported. LONG_MIN and LONG_MAX " \
-+ "will be defined by the library in pj/compats/limits.h and "\
-+ "overridable in config_site.h"
-+# endif
-+
-+/* Minimum and maximum values a `signed long int' can hold. */
-+# ifndef LONG_MAX
-+# if __WORDSIZE == 64
-+# define LONG_MAX 9223372036854775807L
-+# else
-+# define LONG_MAX 2147483647L
-+# endif
-+# endif
-+
-+# ifndef LONG_MIN
-+# define LONG_MIN (-LONG_MAX - 1L)
-+# endif
-+
-+/* Maximum value an `unsigned long int' can hold. (Minimum is 0.) */
-+# ifndef ULONG_MAX
-+# if __WORDSIZE == 64
-+# define ULONG_MAX 18446744073709551615UL
-+# else
-+# define ULONG_MAX 4294967295UL
-+# endif
-+# endif
-+#endif
-+
-+#endif /* __PJ_COMPAT_LIMITS_H__ */
-diff --git a/pjlib/include/pj/compat/os_win32.h b/pjlib/include/pj/compat/os_win32.h
-index 4fa8b21ea..9b18e4eb1 100644
---- a/pjlib/include/pj/compat/os_win32.h
-+++ b/pjlib/include/pj/compat/os_win32.h
-@@ -57,6 +57,7 @@
- #define PJ_HAS_SYS_TYPES_H 1
- #define PJ_HAS_TIME_H 1
- #define PJ_HAS_UNISTD_H 0
-+#define PJ_HAS_LIMITS_H 1
-
- #define PJ_HAS_MSWSOCK_H 1
- #define PJ_HAS_WINSOCK_H 0
-diff --git a/pjlib/include/pj/limits.h b/pjlib/include/pj/limits.h
-new file mode 100644
-index 000000000..8b00ae52a
---- /dev/null
-+++ b/pjlib/include/pj/limits.h
-@@ -0,0 +1,51 @@
-+/* $Id$ */
-+/*
-+ * Copyright (C) 2017 Teluu Inc. (http://www.teluu.com)
-+ * Copyright (C) 2017 George Joseph <gjoseph@digium.com>
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-+ */
-+#ifndef __PJ_LIMITS_H__
-+#define __PJ_LIMITS_H__
-+
-+/**
-+ * @file limits.h
-+ * @brief Common min and max values
-+ */
-+
-+#include <pj/compat/limits.h>
-+
-+/** Maximum value for signed 32-bit integer. */
-+#define PJ_MAXINT32 0x7fffffff
-+
-+/** Minimum value for signed 32-bit integer. */
-+#define PJ_MININT32 0x80000000
-+
-+/** Maximum value for unsigned 16-bit integer. */
-+#define PJ_MAXUINT16 0xffff
-+
-+/** Maximum value for unsigned char. */
-+#define PJ_MAXUINT8 0xff
-+
-+/** Maximum value for long. */
-+#define PJ_MAXLONG LONG_MAX
-+
-+/** Minimum value for long. */
-+#define PJ_MINLONG LONG_MIN
-+
-+/** Minimum value for unsigned long. */
-+#define PJ_MAXULONG ULONG_MAX
-+
-+#endif /* __PJ_LIMITS_H__ */
-diff --git a/pjlib/include/pj/string.h b/pjlib/include/pj/string.h
-index 70a1d6c8c..5de236a65 100644
---- a/pjlib/include/pj/string.h
-+++ b/pjlib/include/pj/string.h
-@@ -28,7 +28,6 @@
- #include <pj/types.h>
- #include <pj/compat/string.h>
-
--
- PJ_BEGIN_DECL
-
- /**
-@@ -636,6 +635,29 @@ PJ_DECL(char*) pj_create_random_string(char *str, pj_size_t length);
- PJ_DECL(long) pj_strtol(const pj_str_t *str);
-
- /**
-+ * Convert string to signed long integer. The conversion will stop as
-+ * soon as non-digit character is found or all the characters have
-+ * been processed.
-+ *
-+ * @param str the string.
-+ * @param value Pointer to a long to receive the value.
-+ *
-+ * @return PJ_SUCCESS if successful. Otherwise:
-+ * PJ_ETOOSMALL if the value was an impossibly long negative number.
-+ * In this case *value will be set to LONG_MIN.
-+ * \n
-+ * PJ_ETOOBIG if the value was an impossibly long positive number.
-+ * In this case, *value will be set to LONG_MAX.
-+ * \n
-+ * PJ_EINVAL if the input string was NULL, the value pointer was NULL
-+ * or the input string could not be parsed at all such as starting with
-+ * a character other than a '+', '-' or not in the '0' - '9' range.
-+ * In this case, *value will be left untouched.
-+ */
-+PJ_DECL(pj_status_t) pj_strtol2(const pj_str_t *str, long *value);
-+
-+
-+/**
- * Convert string to unsigned integer. The conversion will stop as
- * soon as non-digit character is found or all the characters have
- * been processed.
-@@ -664,6 +686,27 @@ PJ_DECL(unsigned long) pj_strtoul2(const pj_str_t *str, pj_str_t *endptr,
- unsigned base);
-
- /**
-+ * Convert string to unsigned long integer. The conversion will stop as
-+ * soon as non-digit character is found or all the characters have
-+ * been processed.
-+ *
-+ * @param str The input string.
-+ * @param value Pointer to an unsigned long to receive the value.
-+ * @param base Number base to use.
-+ *
-+ * @return PJ_SUCCESS if successful. Otherwise:
-+ * PJ_ETOOBIG if the value was an impossibly long positive number.
-+ * In this case, *value will be set to ULONG_MAX.
-+ * \n
-+ * PJ_EINVAL if the input string was NULL, the value pointer was NULL
-+ * or the input string could not be parsed at all such as starting
-+ * with a character outside the base character range. In this case,
-+ * *value will be left untouched.
-+ */
-+PJ_DECL(pj_status_t) pj_strtoul3(const pj_str_t *str, unsigned long *value,
-+ unsigned base);
-+
-+/**
- * Convert string to float.
- *
- * @param str the string.
-@@ -786,7 +829,6 @@ PJ_INLINE(void*) pj_memchr(const void *buf, int c, pj_size_t size)
- return (void*)memchr((void*)buf, c, size);
- }
-
--
- /**
- * @}
- */
-diff --git a/pjlib/include/pj/types.h b/pjlib/include/pj/types.h
-index 0e0e2d9a7..8c9f78238 100644
---- a/pjlib/include/pj/types.h
-+++ b/pjlib/include/pj/types.h
-@@ -280,9 +280,6 @@ typedef int pj_exception_id_t;
- /** Utility macro to compute the number of elements in static array. */
- #define PJ_ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0]))
-
--/** Maximum value for signed 32-bit integer. */
--#define PJ_MAXINT32 0x7FFFFFFFL
--
- /**
- * Length of object names.
- */
-diff --git a/pjlib/src/pj/string.c b/pjlib/src/pj/string.c
-index 307cfb47e..b95f141be 100644
---- a/pjlib/src/pj/string.c
-+++ b/pjlib/src/pj/string.c
-@@ -23,11 +23,14 @@
- #include <pj/ctype.h>
- #include <pj/rand.h>
- #include <pj/os.h>
-+#include <pj/errno.h>
-+#include <pj/limits.h>
-
- #if PJ_FUNCTIONS_ARE_INLINED==0
- # include <pj/string_i.h>
- #endif
-
-+
- PJ_DEF(pj_ssize_t) pj_strspn(const pj_str_t *str, const pj_str_t *set_char)
- {
- pj_ssize_t i, j, count = 0;
-@@ -230,6 +233,55 @@ PJ_DEF(long) pj_strtol(const pj_str_t *str)
- return pj_strtoul(str);
- }
-
-+
-+PJ_DEF(pj_status_t) pj_strtol2(const pj_str_t *str, long *value)
-+{
-+ pj_str_t s;
-+ unsigned long retval = 0;
-+ pj_bool_t is_negative = PJ_FALSE;
-+ int rc = 0;
-+
-+ PJ_CHECK_STACK();
-+
-+ if (!str || !value) {
-+ return PJ_EINVAL;
-+ }
-+
-+ s = *str;
-+ pj_strltrim(&s);
-+
-+ if (s.slen == 0)
-+ return PJ_EINVAL;
-+
-+ if (s.ptr[0] == '+' || s.ptr[0] == '-') {
-+ is_negative = (s.ptr[0] == '-');
-+ s.ptr += 1;
-+ s.slen -= 1;
-+ }
-+
-+ rc = pj_strtoul3(&s, &retval, 10);
-+ if (rc == PJ_EINVAL) {
-+ return rc;
-+ } else if (rc != PJ_SUCCESS) {
-+ *value = is_negative ? PJ_MINLONG : PJ_MAXLONG;
-+ return is_negative ? PJ_ETOOSMALL : PJ_ETOOBIG;
-+ }
-+
-+ if (retval > PJ_MAXLONG && !is_negative) {
-+ *value = PJ_MAXLONG;
-+ return PJ_ETOOBIG;
-+ }
-+
-+ if (retval > (PJ_MAXLONG + 1UL) && is_negative) {
-+ *value = PJ_MINLONG;
-+ return PJ_ETOOSMALL;
-+ }
-+
-+ *value = is_negative ? -(long)retval : retval;
-+
-+ return PJ_SUCCESS;
-+}
-+
- PJ_DEF(unsigned long) pj_strtoul(const pj_str_t *str)
- {
- unsigned long value;
-@@ -282,6 +334,71 @@ PJ_DEF(unsigned long) pj_strtoul2(const pj_str_t *str, pj_str_t *endptr,
- return value;
- }
-
-+PJ_DEF(pj_status_t) pj_strtoul3(const pj_str_t *str, unsigned long *value,
-+ unsigned base)
-+{
-+ pj_str_t s;
-+ unsigned i;
-+
-+ PJ_CHECK_STACK();
-+
-+ if (!str || !value) {
-+ return PJ_EINVAL;
-+ }
-+
-+ s = *str;
-+ pj_strltrim(&s);
-+
-+ if (s.slen == 0 || s.ptr[0] < '0' ||
-+ (base <= 10 && (unsigned)s.ptr[0] > ('0' - 1) + base) ||
-+ (base == 16 && !pj_isxdigit(s.ptr[0])))
-+ {
-+ return PJ_EINVAL;
-+ }
-+
-+ *value = 0;
-+ if (base <= 10) {
-+ for (i=0; i<(unsigned)s.slen; ++i) {
-+ unsigned c = s.ptr[i] - '0';
-+ if (s.ptr[i] < '0' || (unsigned)s.ptr[i] > ('0' - 1) + base) {
-+ break;
-+ }
-+ if (*value > PJ_MAXULONG / base) {
-+ *value = PJ_MAXULONG;
-+ return PJ_ETOOBIG;
-+ }
-+
-+ *value *= base;
-+ if ((PJ_MAXULONG - *value) < c) {
-+ *value = PJ_MAXULONG;
-+ return PJ_ETOOBIG;
-+ }
-+ *value += c;
-+ }
-+ } else if (base == 16) {
-+ for (i=0; i<(unsigned)s.slen; ++i) {
-+ unsigned c = pj_hex_digit_to_val(s.ptr[i]);
-+ if (!pj_isxdigit(s.ptr[i]))
-+ break;
-+
-+ if (*value > PJ_MAXULONG / base) {
-+ *value = PJ_MAXULONG;
-+ return PJ_ETOOBIG;
-+ }
-+ *value *= base;
-+ if ((PJ_MAXULONG - *value) < c) {
-+ *value = PJ_MAXULONG;
-+ return PJ_ETOOBIG;
-+ }
-+ *value += c;
-+ }
-+ } else {
-+ pj_assert(!"Unsupported base");
-+ return PJ_EINVAL;
-+ }
-+ return PJ_SUCCESS;
-+}
-+
- PJ_DEF(float) pj_strtof(const pj_str_t *str)
- {
- pj_str_t part;
-@@ -356,5 +473,3 @@ PJ_DEF(int) pj_utoa_pad( unsigned long val, char *buf, int min_dig, int pad)
-
- return len;
- }
--
--
-diff --git a/pjlib/src/pj/timer.c b/pjlib/src/pj/timer.c
-index 225be4498..399e114a8 100644
---- a/pjlib/src/pj/timer.c
-+++ b/pjlib/src/pj/timer.c
-@@ -36,6 +36,7 @@
- #include <pj/lock.h>
- #include <pj/log.h>
- #include <pj/rand.h>
-+#include <pj/limits.h>
-
- #define THIS_FILE "timer.c"
-
-diff --git a/pjsip/include/pjsip/sip_parser.h b/pjsip/include/pjsip/sip_parser.h
-index 0d767f0ad..5691fed3a 100644
---- a/pjsip/include/pjsip/sip_parser.h
-+++ b/pjsip/include/pjsip/sip_parser.h
-@@ -39,6 +39,26 @@ PJ_BEGIN_DECL
- */
-
- /**
-+ * Contants for limit checks
-+ */
-+#define PJSIP_MIN_CONTENT_LENGTH 0
-+#define PJSIP_MAX_CONTENT_LENGTH PJ_MAXINT32
-+#define PJSIP_MIN_PORT 0
-+#define PJSIP_MAX_PORT PJ_MAXUINT16
-+#define PJSIP_MIN_TTL 0
-+#define PJSIP_MAX_TTL PJ_MAXUINT8
-+#define PJSIP_MIN_STATUS_CODE 100
-+#define PJSIP_MAX_STATUS_CODE 999
-+#define PJSIP_MIN_Q1000 0
-+#define PJSIP_MAX_Q1000 PJ_MAXINT32 / 1000
-+#define PJSIP_MIN_EXPIRES 0
-+#define PJSIP_MAX_EXPIRES PJ_MAXINT32
-+#define PJSIP_MIN_CSEQ 0
-+#define PJSIP_MAX_CSEQ PJ_MAXINT32
-+#define PJSIP_MIN_RETRY_AFTER 0
-+#define PJSIP_MAX_RETRY_AFTER PJ_MAXINT32
-+
-+/**
- * URI Parsing options.
- */
- enum
-@@ -64,6 +84,11 @@ enum
- extern int PJSIP_SYN_ERR_EXCEPTION;
-
- /**
-+ * Invalid value error exception value.
-+ */
-+extern int PJSIP_EINVAL_ERR_EXCEPTION;
-+
-+/**
- * This structure is used to get error reporting from parser.
- */
- typedef struct pjsip_parser_err_report
-diff --git a/pjsip/src/pjsip/sip_parser.c b/pjsip/src/pjsip/sip_parser.c
-index cf3b879f6..f9a0e65b5 100644
---- a/pjsip/src/pjsip/sip_parser.c
-+++ b/pjsip/src/pjsip/sip_parser.c
-@@ -34,6 +34,7 @@
- #include <pj/string.h>
- #include <pj/ctype.h>
- #include <pj/assert.h>
-+#include <pj/limits.h>
-
- #define THIS_FILE "sip_parser.c"
-
-@@ -93,6 +94,7 @@ static unsigned uri_handler_count;
- * Global vars (also extern).
- */
- int PJSIP_SYN_ERR_EXCEPTION = -1;
-+int PJSIP_EINVAL_ERR_EXCEPTION = -2;
-
- /* Parser constants */
- static pjsip_parser_const_t pconst =
-@@ -205,7 +207,6 @@ static unsigned long pj_strtoul_mindigit(const pj_str_t *str,
- /* Case insensitive comparison */
- #define parser_stricmp(s1, s2) (s1.slen!=s2.slen || pj_stricmp_alnum(&s1, &s2))
-
--
- /* Get a token and unescape */
- PJ_INLINE(void) parser_get_and_unescape(pj_scanner *scanner, pj_pool_t *pool,
- const pj_cis_t *spec,
-@@ -223,8 +224,6 @@ PJ_INLINE(void) parser_get_and_unescape(pj_scanner *scanner, pj_pool_t *pool,
- #endif
- }
-
--
--
- /* Syntax error handler for parser. */
- static void on_syntax_error(pj_scanner *scanner)
- {
-@@ -232,6 +231,60 @@ static void on_syntax_error(pj_scanner *scanner)
- PJ_THROW(PJSIP_SYN_ERR_EXCEPTION);
- }
-
-+/* Syntax error handler for parser. */
-+static void on_str_parse_error(const pj_str_t *str, int rc)
-+{
-+ char *s;
-+
-+ switch(rc) {
-+ case PJ_EINVAL:
-+ s = "NULL input string, invalid input string, or NULL return "\
-+ "value pointer";
-+ break;
-+ case PJ_ETOOSMALL:
-+ s = "String value was less than the minimum allowed value.";
-+ break;
-+ case PJ_ETOOBIG:
-+ s = "String value was greater than the maximum allowed value.";
-+ break;
-+ default:
-+ s = "Unknown error";
-+ }
-+
-+ if (str) {
-+ PJ_LOG(1, (THIS_FILE, "Error parsing '%.*s': %s",
-+ (int)str->slen, str->ptr, s));
-+ } else {
-+ PJ_LOG(1, (THIS_FILE, "Can't parse input string: %s", s));
-+ }
-+ PJ_THROW(PJSIP_EINVAL_ERR_EXCEPTION);
-+}
-+
-+static void strtoi_validate(const pj_str_t *str, int min_val,
-+ int max_val, int *value)
-+{
-+ long retval;
-+ pj_status_t status;
-+
-+ if (!str || !value) {
-+ on_str_parse_error(str, PJ_EINVAL);
-+ }
-+ status = pj_strtol2(str, &retval);
-+ if (status != PJ_EINVAL) {
-+ if (min_val > retval) {
-+ *value = min_val;
-+ status = PJ_ETOOSMALL;
-+ } else if (retval > max_val) {
-+ *value = max_val;
-+ status = PJ_ETOOBIG;
-+ } else
-+ *value = (int)retval;
-+ }
-+
-+ if (status != PJ_SUCCESS)
-+ on_str_parse_error(str, status);
-+}
-+
- /* Get parser constants. */
- PJ_DEF(const pjsip_parser_const_t*) pjsip_parser_const(void)
- {
-@@ -285,6 +338,14 @@ static pj_status_t init_parser()
- PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
-
- /*
-+ * Invalid value exception.
-+ */
-+ pj_assert (PJSIP_EINVAL_ERR_EXCEPTION == -2);
-+ status = pj_exception_id_alloc("PJSIP invalid value error",
-+ &PJSIP_EINVAL_ERR_EXCEPTION);
-+ PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
-+
-+ /*
- * Init character input spec (cis)
- */
-
-@@ -502,6 +563,9 @@ void deinit_sip_parser(void)
- /* Deregister exception ID */
- pj_exception_id_free(PJSIP_SYN_ERR_EXCEPTION);
- PJSIP_SYN_ERR_EXCEPTION = -1;
-+
-+ pj_exception_id_free(PJSIP_EINVAL_ERR_EXCEPTION);
-+ PJSIP_EINVAL_ERR_EXCEPTION = -2;
- }
- pj_leave_critical_section();
- }
-@@ -766,7 +830,7 @@ PJ_DEF(pjsip_msg *) pjsip_parse_rdata( char *buf, pj_size_t size,
- }
-
- /* Determine if a message has been received. */
--PJ_DEF(pj_bool_t) pjsip_find_msg( const char *buf, pj_size_t size,
-+PJ_DEF(pj_status_t) pjsip_find_msg( const char *buf, pj_size_t size,
- pj_bool_t is_datagram, pj_size_t *msg_size)
- {
- #if PJ_HAS_TCP
-@@ -776,6 +840,7 @@ PJ_DEF(pj_bool_t) pjsip_find_msg( const char *buf, pj_size_t size,
- const char *line;
- int content_length = -1;
- pj_str_t cur_msg;
-+ pj_status_t status = PJ_SUCCESS;
- const pj_str_t end_hdr = { "\n\r\n", 3};
-
- *msg_size = size;
-@@ -836,9 +901,16 @@ PJ_DEF(pj_bool_t) pjsip_find_msg( const char *buf, pj_size_t size,
- pj_scan_get_newline(&scanner);
-
- /* Found a valid Content-Length header. */
-- content_length = pj_strtoul(&str_clen);
-+ strtoi_validate(&str_clen, PJSIP_MIN_CONTENT_LENGTH,
-+ PJSIP_MAX_CONTENT_LENGTH, &content_length);
- }
- PJ_CATCH_ANY {
-+ int eid = PJ_GET_EXCEPTION();
-+ if (eid == PJSIP_SYN_ERR_EXCEPTION) {
-+ status = PJSIP_EMISSINGHDR;
-+ } else if (eid == PJSIP_EINVAL_ERR_EXCEPTION) {
-+ status = PJSIP_EINVALIDHDR;
-+ }
- content_length = -1;
- }
- PJ_END
-@@ -858,7 +930,7 @@ PJ_DEF(pj_bool_t) pjsip_find_msg( const char *buf, pj_size_t size,
-
- /* Found Content-Length? */
- if (content_length == -1) {
-- return PJSIP_EMISSINGHDR;
-+ return status;
- }
-
- /* Enough packet received? */
-@@ -938,10 +1010,14 @@ static pj_bool_t is_next_sip_version(pj_scanner *scanner)
- static pjsip_msg *int_parse_msg( pjsip_parse_ctx *ctx,
- pjsip_parser_err_report *err_list)
- {
-- pj_bool_t parsing_headers;
-- pjsip_msg *msg = NULL;
-+ /* These variables require "volatile" so their values get
-+ * preserved when re-entering the PJ_TRY block after an error.
-+ */
-+ volatile pj_bool_t parsing_headers;
-+ pjsip_msg *volatile msg = NULL;
-+ pjsip_ctype_hdr *volatile ctype_hdr = NULL;
-+
- pj_str_t hname;
-- pjsip_ctype_hdr *ctype_hdr = NULL;
- pj_scanner *scanner = ctx->scanner;
- pj_pool_t *pool = ctx->pool;
- PJ_USE_EXCEPTION;
-@@ -1023,7 +1099,6 @@ parse_headers:
- hdr->name = hdr->sname = hname;
- }
-
--
- /* Single parse of header line can produce multiple headers.
- * For example, if one Contact: header contains Contact list
- * separated by comma, then these Contacts will be split into
-@@ -1267,7 +1342,7 @@ static void int_parse_uri_host_port( pj_scanner *scanner,
- pj_str_t port;
- pj_scan_get_char(scanner);
- pj_scan_get(scanner, &pconst.pjsip_DIGIT_SPEC, &port);
-- *p_port = pj_strtoul(&port);
-+ strtoi_validate(&port, PJSIP_MIN_PORT, PJSIP_MAX_PORT, p_port);
- } else {
- *p_port = 0;
- }
-@@ -1458,8 +1533,8 @@ static void* int_parse_sip_url( pj_scanner *scanner,
- url->transport_param = pvalue;
-
- } else if (!parser_stricmp(pname, pconst.pjsip_TTL_STR) && pvalue.slen) {
-- url->ttl_param = pj_strtoul(&pvalue);
--
-+ strtoi_validate(&pvalue, PJSIP_MIN_TTL, PJSIP_MAX_TTL,
-+ &url->ttl_param);
- } else if (!parser_stricmp(pname, pconst.pjsip_MADDR_STR) && pvalue.slen) {
- url->maddr_param = pvalue;
-
-@@ -1595,7 +1670,8 @@ static void int_parse_status_line( pj_scanner *scanner,
-
- parse_sip_version(scanner);
- pj_scan_get( scanner, &pconst.pjsip_DIGIT_SPEC, &token);
-- status_line->code = pj_strtoul(&token);
-+ strtoi_validate(&token, PJSIP_MIN_STATUS_CODE, PJSIP_MAX_STATUS_CODE,
-+ &status_line->code);
- if (*scanner->curptr != '\r' && *scanner->curptr != '\n')
- pj_scan_get( scanner, &pconst.pjsip_NOT_NEWLINE, &status_line->reason);
- else
-@@ -1780,20 +1856,34 @@ static void int_parse_contact_param( pjsip_contact_hdr *hdr,
- if (!parser_stricmp(pname, pconst.pjsip_Q_STR) && pvalue.slen) {
- char *dot_pos = (char*) pj_memchr(pvalue.ptr, '.', pvalue.slen);
- if (!dot_pos) {
-- hdr->q1000 = pj_strtoul(&pvalue) * 1000;
-+ strtoi_validate(&pvalue, PJSIP_MIN_Q1000, PJSIP_MAX_Q1000,
-+ &hdr->q1000);
-+ hdr->q1000 *= 1000;
- } else {
- pj_str_t tmp = pvalue;
-+ unsigned long qval_frac;
-
- tmp.slen = dot_pos - pvalue.ptr;
-- hdr->q1000 = pj_strtoul(&tmp) * 1000;
-+ strtoi_validate(&tmp, PJSIP_MIN_Q1000, PJSIP_MAX_Q1000,
-+ &hdr->q1000);
-+ hdr->q1000 *= 1000;
-
- pvalue.slen = (pvalue.ptr+pvalue.slen) - (dot_pos+1);
- pvalue.ptr = dot_pos + 1;
-- hdr->q1000 += pj_strtoul_mindigit(&pvalue, 3);
-+ if (pvalue.slen > 3) {
-+ pvalue.slen = 3;
-+ }
-+ qval_frac = pj_strtoul_mindigit(&pvalue, 3);
-+ if ((unsigned)hdr->q1000 > (PJ_MAXINT32 - qval_frac)) {
-+ PJ_THROW(PJSIP_SYN_ERR_EXCEPTION);
-+ }
-+ hdr->q1000 += qval_frac;
- }
-- } else if (!parser_stricmp(pname, pconst.pjsip_EXPIRES_STR) && pvalue.slen) {
-- hdr->expires = pj_strtoul(&pvalue);
--
-+ } else if (!parser_stricmp(pname, pconst.pjsip_EXPIRES_STR) &&
-+ pvalue.slen)
-+ {
-+ strtoi_validate(&pvalue, PJSIP_MIN_EXPIRES, PJSIP_MAX_EXPIRES,
-+ &hdr->expires);
- } else {
- pjsip_param *p = PJ_POOL_ALLOC_T(pool, pjsip_param);
- p->name = pname;
-@@ -1890,19 +1980,22 @@ static pjsip_hdr* parse_hdr_content_type( pjsip_parse_ctx *ctx )
- static pjsip_hdr* parse_hdr_cseq( pjsip_parse_ctx *ctx )
- {
- pj_str_t cseq, method;
-- pjsip_cseq_hdr *hdr;
-+ pjsip_cseq_hdr *hdr = NULL;
-+ int cseq_val = 0;
-
-- hdr = pjsip_cseq_hdr_create(ctx->pool);
- pj_scan_get( ctx->scanner, &pconst.pjsip_DIGIT_SPEC, &cseq);
-- hdr->cseq = pj_strtoul(&cseq);
-+ strtoi_validate(&cseq, PJSIP_MIN_CSEQ, PJSIP_MAX_CSEQ, &cseq_val);
-
-- pj_scan_get( ctx->scanner, &pconst.pjsip_TOKEN_SPEC, &method);
-- pjsip_method_init_np(&hdr->method, &method);
-+ hdr = pjsip_cseq_hdr_create(ctx->pool);
-+ hdr->cseq = cseq_val;
-
-+ pj_scan_get( ctx->scanner, &pconst.pjsip_TOKEN_SPEC, &method);
- parse_hdr_end( ctx->scanner );
-
-- if (ctx->rdata)
-+ pjsip_method_init_np(&hdr->method, &method);
-+ if (ctx->rdata) {
- ctx->rdata->msg_info.cseq = hdr;
-+ }
-
- return (pjsip_hdr*)hdr;
- }
-@@ -1984,7 +2077,8 @@ static pjsip_hdr* parse_hdr_retry_after(pjsip_parse_ctx *ctx)
- hdr = pjsip_retry_after_hdr_create(ctx->pool, 0);
-
- pj_scan_get(scanner, &pconst.pjsip_DIGIT_SPEC, &tmp);
-- hdr->ivalue = pj_strtoul(&tmp);
-+ strtoi_validate(&tmp, PJSIP_MIN_RETRY_AFTER, PJSIP_MAX_RETRY_AFTER,
-+ &hdr->ivalue);
-
- while (!pj_scan_is_eof(scanner) && *scanner->curptr!='\r' &&
- *scanner->curptr!='\n')
-@@ -2073,7 +2167,8 @@ static void int_parse_via_param( pjsip_via_hdr *hdr, pj_scanner *scanner,
- hdr->branch_param = pvalue;
-
- } else if (!parser_stricmp(pname, pconst.pjsip_TTL_STR) && pvalue.slen) {
-- hdr->ttl_param = pj_strtoul(&pvalue);
-+ strtoi_validate(&pvalue, PJSIP_MIN_TTL, PJSIP_MAX_TTL,
-+ &hdr->ttl_param);
-
- } else if (!parser_stricmp(pname, pconst.pjsip_MADDR_STR) && pvalue.slen) {
- hdr->maddr_param = pvalue;
-@@ -2082,9 +2177,10 @@ static void int_parse_via_param( pjsip_via_hdr *hdr, pj_scanner *scanner,
- hdr->recvd_param = pvalue;
-
- } else if (!parser_stricmp(pname, pconst.pjsip_RPORT_STR)) {
-- if (pvalue.slen)
-- hdr->rport_param = pj_strtoul(&pvalue);
-- else
-+ if (pvalue.slen) {
-+ strtoi_validate(&pvalue, PJSIP_MIN_PORT, PJSIP_MAX_PORT,
-+ &hdr->rport_param);
-+ } else
- hdr->rport_param = 0;
- } else {
- pjsip_param *p = PJ_POOL_ALLOC_T(pool, pjsip_param);
-@@ -2213,7 +2309,8 @@ static pjsip_hdr* parse_hdr_via( pjsip_parse_ctx *ctx )
- pj_str_t digit;
- pj_scan_get_char(scanner);
- pj_scan_get(scanner, &pconst.pjsip_DIGIT_SPEC, &digit);
-- hdr->sent_by.port = pj_strtoul(&digit);
-+ strtoi_validate(&digit, PJSIP_MIN_PORT, PJSIP_MAX_PORT,
-+ &hdr->sent_by.port);
- }
-
- int_parse_via_param(hdr, scanner, ctx->pool);
-@@ -2298,9 +2395,10 @@ PJ_DEF(pj_status_t) pjsip_parse_headers( pj_pool_t *pool, char *input,
- unsigned options)
- {
- enum { STOP_ON_ERROR = 1 };
-+ pj_str_t hname;
- pj_scanner scanner;
- pjsip_parse_ctx ctx;
-- pj_str_t hname;
-+
- PJ_USE_EXCEPTION;
-
- pj_scan_init(&scanner, input, size, PJ_SCAN_AUTOSKIP_WS_HEADER,
-@@ -2323,7 +2421,7 @@ retry_parse:
- */
- hname.slen = 0;
-
-- /* Get hname. */
-+ /* Get hname. */
- pj_scan_get( &scanner, &pconst.pjsip_TOKEN_SPEC, &hname);
- if (pj_scan_get_char( &scanner ) != ':') {
- PJ_THROW(PJSIP_SYN_ERR_EXCEPTION);
-diff --git a/pjsip/src/pjsip/sip_transaction.c b/pjsip/src/pjsip/sip_transaction.c
-index f3be93beb..7ac3d1b76 100644
---- a/pjsip/src/pjsip/sip_transaction.c
-+++ b/pjsip/src/pjsip/sip_transaction.c
-@@ -289,11 +289,11 @@ static pj_status_t create_tsx_key_2543( pj_pool_t *pool,
-
- /* Calculate length required. */
- len_required = method->name.slen + /* Method */
-- 9 + /* CSeq number */
-+ 11 + /* CSeq number */
- rdata->msg_info.from->tag.slen + /* From tag. */
- rdata->msg_info.cid->id.slen + /* Call-ID */
- host->slen + /* Via host. */
-- 9 + /* Via port. */
-+ 11 + /* Via port. */
- 16; /* Separator+Allowance. */
- key = p = (char*) pj_pool_alloc(pool, len_required);
-
-diff --git a/pjsip/src/pjsip/sip_transport.c b/pjsip/src/pjsip/sip_transport.c
-index 0c338e8fd..b24cbb411 100644
---- a/pjsip/src/pjsip/sip_transport.c
-+++ b/pjsip/src/pjsip/sip_transport.c
-@@ -1848,7 +1848,7 @@ PJ_DEF(pj_ssize_t) pjsip_tpmgr_receive_packet( pjsip_tpmgr *mgr,
- /* Check for parsing syntax error */
- if (msg==NULL || !pj_list_empty(&rdata->msg_info.parse_err)) {
- pjsip_parser_err_report *err;
-- char buf[128];
-+ char buf[256];
- pj_str_t tmp;
-
- /* Gather syntax error information */
-@@ -1862,7 +1862,10 @@ PJ_DEF(pj_ssize_t) pjsip_tpmgr_receive_packet( pjsip_tpmgr *mgr,
- pj_exception_id_name(err->except_code),
- (int)err->hname.slen, err->hname.ptr,
- err->line, err->col);
-- if (len > 0 && len < (int) (sizeof(buf)-tmp.slen)) {
-+ if (len >= (int)sizeof(buf)-tmp.slen) {
-+ len = (int)sizeof(buf)-tmp.slen;
-+ }
-+ if (len > 0) {
- tmp.slen += len;
- }
- err = err->next;
---
-2.13.6
-
diff --git a/third-party/pjproject/patches/0021-sip_parser-Fix-return-code-in-pjsip_find_msg-and-add.patch b/third-party/pjproject/patches/0021-sip_parser-Fix-return-code-in-pjsip_find_msg-and-add.patch
new file mode 100644
index 000000000..86d5aa7dd
--- /dev/null
+++ b/third-party/pjproject/patches/0021-sip_parser-Fix-return-code-in-pjsip_find_msg-and-add.patch
@@ -0,0 +1,41 @@
+From 186f82627c40d0c3a56a6a94ce55c055ad1f7620 Mon Sep 17 00:00:00 2001
+From: George Joseph <gjoseph@digium.com>
+Date: Fri, 10 Nov 2017 09:26:29 -0700
+Subject: [PATCH] sip_parser: Fix return code in pjsip_find_msg and add
+ "volatile"
+
+The default return code for pjsip_find_msg was PJ_SUCCESS so if
+a Content-Length header wasn't found at all, pjsip_find_msg was
+returning PJ_SUCCESS instead of PJSIP_EMISSINGHDR.
+
+Also added the volatile keyword to a few variables what are used
+both insude and outsude the PJ_TRY/PJ_CATCH block.
+---
+ pjsip/src/pjsip/sip_parser.c | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+diff --git a/pjsip/src/pjsip/sip_parser.c b/pjsip/src/pjsip/sip_parser.c
+index f9a0e65b5..f65ffca5a 100644
+--- a/pjsip/src/pjsip/sip_parser.c
++++ b/pjsip/src/pjsip/sip_parser.c
+@@ -834,13 +834,13 @@ PJ_DEF(pj_status_t) pjsip_find_msg( const char *buf, pj_size_t size,
+ pj_bool_t is_datagram, pj_size_t *msg_size)
+ {
+ #if PJ_HAS_TCP
+- const char *hdr_end;
+- const char *body_start;
++ const char *volatile hdr_end;
++ const char *volatile body_start;
+ const char *pos;
+- const char *line;
++ const char *volatile line;
+ int content_length = -1;
+ pj_str_t cur_msg;
+- pj_status_t status = PJ_SUCCESS;
++ volatile pj_status_t status = PJSIP_EMISSINGHDR;
+ const pj_str_t end_hdr = { "\n\r\n", 3};
+
+ *msg_size = size;
+--
+2.13.6
+
diff --git a/third-party/pjproject/patches/0030-sip_transport-Destroy-transports-not-in-hash.patch b/third-party/pjproject/patches/0030-sip_transport-Destroy-transports-not-in-hash.patch
new file mode 100644
index 000000000..e42b0f7c6
--- /dev/null
+++ b/third-party/pjproject/patches/0030-sip_transport-Destroy-transports-not-in-hash.patch
@@ -0,0 +1,27 @@
+diff --git a/pjsip/src/pjsip/sip_transport.c b/pjsip/src/pjsip/sip_transport.c
+index e4bec24..a39b56e 100644
+--- a/pjsip/src/pjsip/sip_transport.c
++++ b/pjsip/src/pjsip/sip_transport.c
+@@ -957,7 +957,21 @@ static pj_bool_t is_transport_valid(pjsip_tpmgr *tpmgr, pjsip_transport *tp,
+ const pjsip_transport_key *key,
+ int key_len)
+ {
+- return (pj_hash_get(tpmgr->table, key, key_len, NULL) == (void*)tp);
++ transport *tp_iter;
++
++ if (pj_hash_get(tpmgr->table, key, key_len, NULL) == (void*)tp) {
++ return PJ_TRUE;
++ }
++
++ tp_iter = tpmgr->tp_list.next;
++ while (tp_iter != &tpmgr->tp_list) {
++ if (tp_iter->tp == tp) {
++ return PJ_TRUE;
++ }
++ tp_iter = tp_iter->next;
++ }
++
++ return PJ_FALSE;
+ }
+
+ /*
diff --git a/third-party/versions.mak b/third-party/versions.mak
index 4f645f1bb..a90a52348 100644
--- a/third-party/versions.mak
+++ b/third-party/versions.mak
@@ -1,2 +1,2 @@
-PJPROJECT_VERSION = 2.7
+PJPROJECT_VERSION = 2.7.1