summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES6
-rw-r--r--apps/app_dial.c56
-rw-r--r--cel/cel_odbc.c1
-rw-r--r--channels/chan_sip.c2
l---------[-rwxr-xr-x]contrib/ast-db-manage/cdr/env.py75
l---------[-rwxr-xr-x]contrib/ast-db-manage/config/env.py75
-rwxr-xr-xcontrib/ast-db-manage/env.py140
l---------[-rwxr-xr-x]contrib/ast-db-manage/voicemail/env.py75
-rw-r--r--include/asterisk/utils.h4
-rw-r--r--include/asterisk/vector.h54
-rw-r--r--main/astobj2.c25
-rw-r--r--main/astobj2_container.c36
-rw-r--r--main/astobj2_hash.c4
-rw-r--r--main/astobj2_rbtree.c4
-rw-r--r--main/utils.c6
-rw-r--r--res/res_pjsip_config_wizard.c4
-rw-r--r--res/res_rtp_asterisk.c17
-rw-r--r--third-party/Makefile.rules2
-rw-r--r--third-party/pjproject/.gitignore1
-rw-r--r--third-party/pjproject/Makefile105
-rw-r--r--third-party/pjproject/patches/asterisk_malloc_debug.c72
-rw-r--r--third-party/pjproject/patches/asterisk_malloc_debug.h78
-rw-r--r--third-party/pjproject/patches/config_site.h8
23 files changed, 547 insertions, 303 deletions
diff --git a/CHANGES b/CHANGES
index 4a866829a..11b357419 100644
--- a/CHANGES
+++ b/CHANGES
@@ -83,6 +83,12 @@ Core
notify systemd of its state using sd_notify. Use 'Type=notify' in
asterisk.service.
+app_dial
+------------------
+ * Added the "Q" option which sets the Q.850/Q.931 cause on unanswered channels
+ when another channel answers the call. The default of ANSWERED_ELSEWHERE
+ is unchanged.
+
------------------------------------------------------------------------------
--- Functionality changes from Asterisk 13.10.0 to Asterisk 13.11.0 ----------
------------------------------------------------------------------------------
diff --git a/apps/app_dial.c b/apps/app_dial.c
index 7b7c70201..893898100 100644
--- a/apps/app_dial.c
+++ b/apps/app_dial.c
@@ -375,6 +375,25 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
<para>Enable privacy mode. Use <replaceable>x</replaceable> as the family/key in the AstDB database if
it is provided. The current extension is used if a database family/key is not specified.</para>
</option>
+ <option name="Q">
+ <argument name="cause" required="true"/>
+ <para>Specify the Q.850/Q.931 <replaceable>cause</replaceable> to send on
+ unanswered channels when another channel answers the call.
+ As with <literal>Hangup()</literal>, <replaceable>cause</replaceable>
+ can be a numeric cause code or a name such as
+ <literal>NO_ANSWER</literal>,
+ <literal>USER_BUSY</literal>,
+ <literal>CALL_REJECTED</literal> or
+ <literal>ANSWERED_ELSEWHERE</literal> (the default if Q isn't specified).
+ You can also specify <literal>0</literal> or <literal>NONE</literal>
+ to send no cause. See the <filename>causes.h</filename> file for the
+ full list of valid causes and names.
+ </para>
+ <note>
+ <para>chan_sip does not support setting the cause on a CANCEL to anything
+ other than ANSWERED_ELSEWHERE.</para>
+ </note>
+ </option>
<option name="r">
<para>Default: Indicate ringing to the calling party, even if the called party isn't actually ringing. Pass no audio to the calling
party until the called channel has answered.</para>
@@ -520,6 +539,9 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
<example title="Dial with call length limit">
same => n,Dial(PJSIP/alice,,L(60000:30000:10000))
</example>
+ <example title="Dial alice and bob and send NO_ANSWER to bob instead of ANSWERED_ELSEWHERE when alice answers">
+ same => n,Dial(PJSIP/alice&amp;PJSIP/bob,,Q(NO_ANSWER))
+ </example>
<example title="Dial with pre-dial subroutines">
[default]
@@ -684,6 +706,7 @@ enum {
#define OPT_PREDIAL_CALLEE (1LLU << 41)
#define OPT_PREDIAL_CALLER (1LLU << 42)
#define OPT_RING_WITH_EARLY_MEDIA (1LLU << 43)
+#define OPT_HANGUPCAUSE (1LLU << 44)
enum {
OPT_ARG_ANNOUNCE = 0,
@@ -705,6 +728,7 @@ enum {
OPT_ARG_FORCE_CID_PRES,
OPT_ARG_PREDIAL_CALLEE,
OPT_ARG_PREDIAL_CALLER,
+ OPT_ARG_HANGUPCAUSE,
/* note: this entry _MUST_ be the last one in the enum */
OPT_ARG_ARRAY_SIZE
};
@@ -738,6 +762,7 @@ AST_APP_OPTIONS(dial_exec_options, BEGIN_OPTIONS
AST_APP_OPTION_ARG('O', OPT_OPERMODE, OPT_ARG_OPERMODE),
AST_APP_OPTION('p', OPT_SCREENING),
AST_APP_OPTION_ARG('P', OPT_PRIVACY, OPT_ARG_PRIVACY),
+ AST_APP_OPTION_ARG('Q', OPT_HANGUPCAUSE, OPT_ARG_HANGUPCAUSE),
AST_APP_OPTION_ARG('r', OPT_RINGBACK, OPT_ARG_RINGBACK),
AST_APP_OPTION('R', OPT_RING_WITH_EARLY_MEDIA),
AST_APP_OPTION_ARG('S', OPT_DURATION_STOP, OPT_ARG_DURATION_STOP),
@@ -796,7 +821,7 @@ static void chanlist_free(struct chanlist *outgoing)
ast_free(outgoing);
}
-static void hanguptree(struct dial_head *out_chans, struct ast_channel *exception, int answered_elsewhere)
+static void hanguptree(struct dial_head *out_chans, struct ast_channel *exception, int hangupcause)
{
/* Hang up a tree of stuff */
struct chanlist *outgoing;
@@ -804,9 +829,9 @@ static void hanguptree(struct dial_head *out_chans, struct ast_channel *exceptio
while ((outgoing = AST_LIST_REMOVE_HEAD(out_chans, node))) {
/* Hangup any existing lines we have open */
if (outgoing->chan && (outgoing->chan != exception)) {
- if (answered_elsewhere) {
+ if (hangupcause >= 0) {
/* This is for the channel drivers */
- ast_channel_hangupcause_set(outgoing->chan, AST_CAUSE_ANSWERED_ELSEWHERE);
+ ast_channel_hangupcause_set(outgoing->chan, hangupcause);
}
ast_hangup(outgoing->chan);
}
@@ -2763,6 +2788,7 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
} else {
const char *number;
int dial_end_raised = 0;
+ int cause = -1;
if (ast_test_flag64(&opts, OPT_CALLER_ANSWER))
ast_answer(chan);
@@ -2773,7 +2799,23 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
/* Ah ha! Someone answered within the desired timeframe. Of course after this
we will always return with -1 so that it is hung up properly after the
conversation. */
- hanguptree(&out_chans, peer, 1);
+
+ if (ast_test_flag64(&opts, OPT_HANGUPCAUSE)
+ && !ast_strlen_zero(opt_args[OPT_ARG_HANGUPCAUSE])) {
+ cause = ast_str2cause(opt_args[OPT_ARG_HANGUPCAUSE]);
+ if (cause <= 0) {
+ if (!strcasecmp(opt_args[OPT_ARG_HANGUPCAUSE], "NONE")) {
+ cause = 0;
+ } else if (sscanf(opt_args[OPT_ARG_HANGUPCAUSE], "%30d", &cause) != 1
+ || cause < 0) {
+ ast_log(LOG_WARNING, "Invalid cause given to Dial(...Q(<cause>)): \"%s\"\n",
+ opt_args[OPT_ARG_HANGUPCAUSE]);
+ cause = -1;
+ }
+ }
+ }
+ hanguptree(&out_chans, peer, cause >= 0 ? cause : AST_CAUSE_ANSWERED_ELSEWHERE);
+
/* If appropriate, log that we have a destination channel and set the answer time */
if (ast_channel_name(peer))
pbx_builtin_setvar_helper(chan, "DIALEDPEERNAME", ast_channel_name(peer));
@@ -3177,7 +3219,11 @@ out:
}
ast_channel_early_bridge(chan, NULL);
- hanguptree(&out_chans, NULL, ast_channel_hangupcause(chan)==AST_CAUSE_ANSWERED_ELSEWHERE || ast_test_flag64(&opts, OPT_CANCEL_ELSEWHERE) ? 1 : 0 ); /* forward 'answered elsewhere' if we received it */
+ /* forward 'answered elsewhere' if we received it */
+ hanguptree(&out_chans, NULL,
+ ast_channel_hangupcause(chan) == AST_CAUSE_ANSWERED_ELSEWHERE
+ || ast_test_flag64(&opts, OPT_CANCEL_ELSEWHERE)
+ ? AST_CAUSE_ANSWERED_ELSEWHERE : -1);
pbx_builtin_setvar_helper(chan, "DIALSTATUS", pa.status);
ast_debug(1, "Exiting with DIALSTATUS=%s.\n", pa.status);
diff --git a/cel/cel_odbc.c b/cel/cel_odbc.c
index 11e333097..701883bce 100644
--- a/cel/cel_odbc.c
+++ b/cel/cel_odbc.c
@@ -291,6 +291,7 @@ static int load_config(void)
else
ast_free(tableptr);
}
+ ast_config_destroy(cfg);
return res;
}
diff --git a/channels/chan_sip.c b/channels/chan_sip.c
index 92b5bdc95..50183c288 100644
--- a/channels/chan_sip.c
+++ b/channels/chan_sip.c
@@ -16754,7 +16754,7 @@ static enum parse_register_result parse_register_contact(struct sip_pvt *pvt, st
}
if ((transport_type != AST_TRANSPORT_WS) && (transport_type != AST_TRANSPORT_WSS) &&
- (!ast_test_flag(&peer->flags[0], SIP_NAT_FORCE_RPORT) && !ast_test_flag(&peer->flags[0], SIP_NAT_RPORT_PRESENT))) {
+ (!ast_test_flag(&peer->flags[0], SIP_NAT_FORCE_RPORT) && !ast_test_flag(&pvt->flags[0], SIP_NAT_RPORT_PRESENT))) {
/* use the data provided in the Contact header for call routing */
ast_debug(1, "Store REGISTER's Contact header for call routing.\n");
/* XXX This could block for a long time XXX */
diff --git a/contrib/ast-db-manage/cdr/env.py b/contrib/ast-db-manage/cdr/env.py
index 6740d5906..74b15c930 100755..120000
--- a/contrib/ast-db-manage/cdr/env.py
+++ b/contrib/ast-db-manage/cdr/env.py
@@ -1,74 +1 @@
-from __future__ import with_statement
-from alembic import context
-from sqlalchemy import engine_from_config, pool
-from logging.config import fileConfig
-
-# this is the Alembic Config object, which provides
-# access to the values within the .ini file in use.
-config = context.config
-
-# Interpret the config file for Python logging.
-# This line sets up loggers basically.
-try:
- fileConfig(config.config_file_name)
-except:
- pass
-
-# add your model's MetaData object here
-# for 'autogenerate' support
-# from myapp import mymodel
-# target_metadata = mymodel.Base.metadata
-target_metadata = None
-
-# other values from the config, defined by the needs of env.py,
-# can be acquired:
-# my_important_option = config.get_main_option("my_important_option")
-# ... etc.
-
-def run_migrations_offline():
- """Run migrations in 'offline' mode.
-
- This configures the context with just a URL
- and not an Engine, though an Engine is acceptable
- here as well. By skipping the Engine creation
- we don't even need a DBAPI to be available.
-
- Calls to context.execute() here emit the given string to the
- script output.
-
- """
- url = config.get_main_option("sqlalchemy.url")
- context.configure(url=url)
-
- with context.begin_transaction():
- context.run_migrations()
-
-def run_migrations_online():
- """Run migrations in 'online' mode.
-
- In this scenario we need to create an Engine
- and associate a connection with the context.
-
- """
- engine = engine_from_config(
- config.get_section(config.config_ini_section),
- prefix='sqlalchemy.',
- poolclass=pool.NullPool)
-
- connection = engine.connect()
- context.configure(
- connection=connection,
- target_metadata=target_metadata
- )
-
- try:
- with context.begin_transaction():
- context.run_migrations()
- finally:
- connection.close()
-
-if context.is_offline_mode():
- run_migrations_offline()
-else:
- run_migrations_online()
-
+../env.py \ No newline at end of file
diff --git a/contrib/ast-db-manage/config/env.py b/contrib/ast-db-manage/config/env.py
index 6740d5906..74b15c930 100755..120000
--- a/contrib/ast-db-manage/config/env.py
+++ b/contrib/ast-db-manage/config/env.py
@@ -1,74 +1 @@
-from __future__ import with_statement
-from alembic import context
-from sqlalchemy import engine_from_config, pool
-from logging.config import fileConfig
-
-# this is the Alembic Config object, which provides
-# access to the values within the .ini file in use.
-config = context.config
-
-# Interpret the config file for Python logging.
-# This line sets up loggers basically.
-try:
- fileConfig(config.config_file_name)
-except:
- pass
-
-# add your model's MetaData object here
-# for 'autogenerate' support
-# from myapp import mymodel
-# target_metadata = mymodel.Base.metadata
-target_metadata = None
-
-# other values from the config, defined by the needs of env.py,
-# can be acquired:
-# my_important_option = config.get_main_option("my_important_option")
-# ... etc.
-
-def run_migrations_offline():
- """Run migrations in 'offline' mode.
-
- This configures the context with just a URL
- and not an Engine, though an Engine is acceptable
- here as well. By skipping the Engine creation
- we don't even need a DBAPI to be available.
-
- Calls to context.execute() here emit the given string to the
- script output.
-
- """
- url = config.get_main_option("sqlalchemy.url")
- context.configure(url=url)
-
- with context.begin_transaction():
- context.run_migrations()
-
-def run_migrations_online():
- """Run migrations in 'online' mode.
-
- In this scenario we need to create an Engine
- and associate a connection with the context.
-
- """
- engine = engine_from_config(
- config.get_section(config.config_ini_section),
- prefix='sqlalchemy.',
- poolclass=pool.NullPool)
-
- connection = engine.connect()
- context.configure(
- connection=connection,
- target_metadata=target_metadata
- )
-
- try:
- with context.begin_transaction():
- context.run_migrations()
- finally:
- connection.close()
-
-if context.is_offline_mode():
- run_migrations_offline()
-else:
- run_migrations_online()
-
+../env.py \ No newline at end of file
diff --git a/contrib/ast-db-manage/env.py b/contrib/ast-db-manage/env.py
new file mode 100755
index 000000000..a903451b4
--- /dev/null
+++ b/contrib/ast-db-manage/env.py
@@ -0,0 +1,140 @@
+from __future__ import with_statement
+from alembic import context
+from alembic.script import ScriptDirectory
+from alembic.operations import Operations
+from sqlalchemy import engine_from_config, pool
+from logging.config import fileConfig
+import logging
+
+# this is the Alembic Config object, which provides
+# access to the values within the .ini file in use.
+config = context.config
+
+# Interpret the config file for Python logging.
+# This line sets up loggers basically.
+try:
+ fileConfig(config.config_file_name)
+except:
+ pass
+
+logger = logging.getLogger('alembic.runtime.setup')
+# add your model's MetaData object here
+# for 'autogenerate' support
+# from myapp import mymodel
+# target_metadata = mymodel.Base.metadata
+target_metadata = None
+
+# other values from the config, defined by the needs of env.py,
+# can be acquired:
+# my_important_option = config.get_main_option("my_important_option")
+# ... etc.
+
+def run_migrations_offline():
+ """Run migrations in 'offline' mode.
+
+ This configures the context with just a URL
+ and not an Engine, though an Engine is acceptable
+ here as well. By skipping the Engine creation
+ we don't even need a DBAPI to be available.
+
+ Calls to context.execute() here emit the given string to the
+ script output.
+
+ """
+ url = config.get_main_option("sqlalchemy.url")
+ context.configure(url=url)
+
+ with context.begin_transaction():
+ context.run_migrations()
+
+def run_migrations_online():
+ """Run migrations in 'online' mode.
+
+ In this scenario we need to create an Engine
+ and associate a connection with the context.
+
+ """
+ engine = engine_from_config(
+ config.get_section(config.config_ini_section),
+ prefix='sqlalchemy.',
+ poolclass=pool.NullPool)
+
+ logger.info('Testing for an old alembic_version table.')
+
+ connection = engine.connect()
+ context.configure(
+ connection=connection,
+ target_metadata=target_metadata,
+ version_table='alembic_version'
+ )
+
+ script_location = config.get_main_option('script_location')
+ found = False
+ mc = context.get_context()
+ current_db_revision = mc.get_current_revision()
+ script = ScriptDirectory.from_config(config)
+ """ If there was an existing alembic_version table, we need to
+ check that it's current revision is in the history for the tree
+ we're working with.
+ """
+ for x in script.iterate_revisions('head', 'base'):
+ if x.revision == current_db_revision:
+ """ An alembic_versions table was found and it belongs to
+ this alembic tree
+ """
+ logger.info(
+ ('An old alembic_version table at revision %s was '
+ 'found for %s. Renaming to alembic_version_%s.'),
+ current_db_revision, script_location,
+ script_location)
+ op = Operations(mc)
+ try:
+ with context.begin_transaction():
+ op.rename_table(
+ 'alembic_version', 'alembic_version_%s'
+ % script_location)
+ found = True
+ except:
+ logger.error(('Unable to rename alembic_version to '
+ 'alembic_version_%s.'),
+ script_location)
+ connection.close()
+ return
+
+ break
+
+ if not found:
+ logger.info('Didn\'t find an old alembic_version table.')
+ logger.info('Trying alembic_version_%s.' % script_location)
+
+ """ We MAY have an alembic_version table that doesn't belong to
+ this tree but if we still don't have an alembic_version_<tree>
+ table, alembic will create it.
+ """
+ context.configure(
+ connection=connection,
+ target_metadata=target_metadata,
+ version_table='alembic_version_' + script_location
+ )
+ mc = context.get_context()
+ current_db_revision = mc.get_current_revision()
+ if current_db_revision:
+ logger.info(
+ 'Using the alembic_version_%s table at revision %s.',
+ script_location, current_db_revision)
+ else:
+ logger.info('Creating new alembic_version_%s table.',
+ script_location)
+
+ try:
+ with context.begin_transaction():
+ context.run_migrations()
+ finally:
+ connection.close()
+
+
+if context.is_offline_mode():
+ run_migrations_offline()
+else:
+ run_migrations_online()
+
diff --git a/contrib/ast-db-manage/voicemail/env.py b/contrib/ast-db-manage/voicemail/env.py
index 6740d5906..74b15c930 100755..120000
--- a/contrib/ast-db-manage/voicemail/env.py
+++ b/contrib/ast-db-manage/voicemail/env.py
@@ -1,74 +1 @@
-from __future__ import with_statement
-from alembic import context
-from sqlalchemy import engine_from_config, pool
-from logging.config import fileConfig
-
-# this is the Alembic Config object, which provides
-# access to the values within the .ini file in use.
-config = context.config
-
-# Interpret the config file for Python logging.
-# This line sets up loggers basically.
-try:
- fileConfig(config.config_file_name)
-except:
- pass
-
-# add your model's MetaData object here
-# for 'autogenerate' support
-# from myapp import mymodel
-# target_metadata = mymodel.Base.metadata
-target_metadata = None
-
-# other values from the config, defined by the needs of env.py,
-# can be acquired:
-# my_important_option = config.get_main_option("my_important_option")
-# ... etc.
-
-def run_migrations_offline():
- """Run migrations in 'offline' mode.
-
- This configures the context with just a URL
- and not an Engine, though an Engine is acceptable
- here as well. By skipping the Engine creation
- we don't even need a DBAPI to be available.
-
- Calls to context.execute() here emit the given string to the
- script output.
-
- """
- url = config.get_main_option("sqlalchemy.url")
- context.configure(url=url)
-
- with context.begin_transaction():
- context.run_migrations()
-
-def run_migrations_online():
- """Run migrations in 'online' mode.
-
- In this scenario we need to create an Engine
- and associate a connection with the context.
-
- """
- engine = engine_from_config(
- config.get_section(config.config_ini_section),
- prefix='sqlalchemy.',
- poolclass=pool.NullPool)
-
- connection = engine.connect()
- context.configure(
- connection=connection,
- target_metadata=target_metadata
- )
-
- try:
- with context.begin_transaction():
- context.run_migrations()
- finally:
- connection.close()
-
-if context.is_offline_mode():
- run_migrations_offline()
-else:
- run_migrations_online()
-
+../env.py \ No newline at end of file
diff --git a/include/asterisk/utils.h b/include/asterisk/utils.h
index c3df4779f..a504a5da1 100644
--- a/include/asterisk/utils.h
+++ b/include/asterisk/utils.h
@@ -849,8 +849,10 @@ int ast_parse_digest(const char *digest, struct ast_http_digest *d, int request,
#define DO_CRASH_NORETURN
#endif
+void DO_CRASH_NORETURN __ast_assert_failed(int condition, const char *condition_str,
+ const char *file, int line, const char *function);
+
#ifdef AST_DEVMODE
-void DO_CRASH_NORETURN __ast_assert_failed(int condition, const char *condition_str, const char *file, int line, const char *function);
#define ast_assert(a) _ast_assert(a, # a, __FILE__, __LINE__, __PRETTY_FUNCTION__)
static void force_inline _ast_assert(int condition, const char *condition_str, const char *file, int line, const char *function)
{
diff --git a/include/asterisk/vector.h b/include/asterisk/vector.h
index 0a13c560b..4306670e7 100644
--- a/include/asterisk/vector.h
+++ b/include/asterisk/vector.h
@@ -354,6 +354,32 @@
AST_VECTOR_REMOVE(vec, idx, 1)
/*!
+ * \brief Remove all elements from a vector that matches the given comparison
+ *
+ * \param vec Vector to remove from.
+ * \param value Value to pass into comparator.
+ * \param cmp Comparator function/macros (called as \c cmp(elem, value))
+ * \param cleanup How to cleanup a removed element macro/function.
+ *
+ * \return the number of deleted elements.
+ */
+#define AST_VECTOR_REMOVE_ALL_CMP_UNORDERED(vec, value, cmp, cleanup) ({ \
+ int count = 0; \
+ size_t idx; \
+ typeof(value) __value = (value); \
+ for (idx = 0; idx < (vec)->current; ) { \
+ if (cmp((vec)->elems[idx], __value)) { \
+ cleanup((vec)->elems[idx]); \
+ AST_VECTOR_REMOVE_UNORDERED((vec), idx); \
+ ++count; \
+ } else { \
+ ++idx; \
+ } \
+ } \
+ count; \
+})
+
+/*!
* \brief Remove an element from a vector that matches the given comparison
*
* \param vec Vector to remove from.
@@ -380,6 +406,32 @@
})
/*!
+ * \brief Remove all elements from a vector that matches the given comparison while maintaining order
+ *
+ * \param vec Vector to remove from.
+ * \param value Value to pass into comparator.
+ * \param cmp Comparator function/macros (called as \c cmp(elem, value))
+ * \param cleanup How to cleanup a removed element macro/function.
+ *
+ * \return the number of deleted elements.
+ */
+#define AST_VECTOR_REMOVE_ALL_CMP_ORDERED(vec, value, cmp, cleanup) ({ \
+ int count = 0; \
+ size_t idx; \
+ typeof(value) __value = (value); \
+ for (idx = 0; idx < (vec)->current; ) { \
+ if (cmp((vec)->elems[idx], __value)) { \
+ cleanup((vec)->elems[idx]); \
+ AST_VECTOR_REMOVE_ORDERED((vec), idx); \
+ ++count; \
+ } else { \
+ ++idx; \
+ } \
+ } \
+ count; \
+})
+
+/*!
* \brief Remove an element from a vector that matches the given comparison while maintaining order
*
* \param vec Vector to remove from.
@@ -397,7 +449,7 @@
for (idx = 0; idx < (vec)->current; ++idx) { \
if (cmp((vec)->elems[idx], __value)) { \
cleanup((vec)->elems[idx]); \
- AST_VECTOR_REMOVE_ORDERED((vec), idx); \
+ AST_VECTOR_REMOVE_ORDERED((vec), idx); \
res = 0; \
break; \
} \
diff --git a/main/astobj2.c b/main/astobj2.c
index 1bb5237f1..f5175ea15 100644
--- a/main/astobj2.c
+++ b/main/astobj2.c
@@ -116,21 +116,17 @@ static struct astobj2 *INTERNAL_OBJ(void *user_data)
struct astobj2 *p;
if (!user_data) {
- ast_log(LOG_ERROR, "user_data is NULL\n");
+ __ast_assert_failed(0, "user_data is NULL", __FILE__, __LINE__, __PRETTY_FUNCTION__);
return NULL;
}
p = (struct astobj2 *) ((char *) user_data - sizeof(*p));
if (AO2_MAGIC != p->priv_data.magic) {
- if (p->priv_data.magic) {
- ast_log(LOG_ERROR, "bad magic number 0x%x for object %p\n",
- p->priv_data.magic, user_data);
- } else {
- ast_log(LOG_ERROR,
- "bad magic number for object %p. Object is likely destroyed.\n",
- user_data);
- }
- ast_assert(0);
+ char bad_magic[100];
+
+ snprintf(bad_magic, sizeof(bad_magic), "bad magic number 0x%x for object %p",
+ p->priv_data.magic, user_data);
+ __ast_assert_failed(0, bad_magic, __FILE__, __LINE__, __PRETTY_FUNCTION__);
return NULL;
}
@@ -157,7 +153,6 @@ int __ao2_lock(void *user_data, enum ao2_lock_req lock_how, const char *file, co
int res = 0;
if (obj == NULL) {
- ast_assert(0);
return -1;
}
@@ -216,7 +211,6 @@ int __ao2_unlock(void *user_data, const char *file, const char *func, int line,
int current_value;
if (obj == NULL) {
- ast_assert(0);
return -1;
}
@@ -265,7 +259,6 @@ int __ao2_trylock(void *user_data, enum ao2_lock_req lock_how, const char *file,
int res = 0;
if (obj == NULL) {
- ast_assert(0);
return -1;
}
@@ -385,7 +378,6 @@ void *ao2_object_get_lockaddr(void *user_data)
struct astobj2_lock *obj_mutex;
if (obj == NULL) {
- ast_assert(0);
return NULL;
}
@@ -409,7 +401,6 @@ static int internal_ao2_ref(void *user_data, int delta, const char *file, int li
int ret;
if (obj == NULL) {
- ast_assert(0);
return -1;
}
@@ -504,10 +495,6 @@ int __ao2_ref_debug(void *user_data, int delta, const char *tag, const char *fil
}
}
- if (obj == NULL) {
- ast_assert(0);
- }
-
return old_refcount;
}
diff --git a/main/astobj2_container.c b/main/astobj2_container.c
index 5a27a0ae5..466c10372 100644
--- a/main/astobj2_container.c
+++ b/main/astobj2_container.c
@@ -103,8 +103,11 @@ static int internal_ao2_link(struct ao2_container *self, void *obj_new, int flag
enum ao2_lock_req orig_lock;
struct ao2_container_node *node;
- if (!is_ao2_object(obj_new) || !is_ao2_object(self)
- || !self->v_table || !self->v_table->new_node || !self->v_table->insert) {
+ if (!is_ao2_object(obj_new) || !is_ao2_object(self)) {
+ return 0;
+ }
+
+ if (!self->v_table || !self->v_table->new_node || !self->v_table->insert) {
/* Sanity checks. */
ast_assert(0);
return 0;
@@ -187,8 +190,6 @@ void *__ao2_unlink_debug(struct ao2_container *c, void *user_data, int flags,
const char *tag, const char *file, int line, const char *func)
{
if (!is_ao2_object(user_data)) {
- /* Sanity checks. */
- ast_assert(0);
return NULL;
}
@@ -202,8 +203,6 @@ void *__ao2_unlink_debug(struct ao2_container *c, void *user_data, int flags,
void *__ao2_unlink(struct ao2_container *c, void *user_data, int flags)
{
if (!is_ao2_object(user_data)) {
- /* Sanity checks. */
- ast_assert(0);
return NULL;
}
@@ -268,7 +267,11 @@ static void *internal_ao2_traverse(struct ao2_container *self, enum search_flags
struct ao2_container *multi_container = NULL;
struct ao2_iterator *multi_iterator = NULL;
- if (!is_ao2_object(self) || !self->v_table || !self->v_table->traverse_first
+ if (!is_ao2_object(self)) {
+ return NULL;
+ }
+
+ if (!self->v_table || !self->v_table->traverse_first
|| !self->v_table->traverse_next) {
/* Sanity checks. */
ast_assert(0);
@@ -512,7 +515,6 @@ void ao2_iterator_restart(struct ao2_iterator *iter)
{
if (!is_ao2_object(iter->c)) {
ast_log(LOG_ERROR, "Iterator container is not valid.\n");
- ast_assert(0);
return;
}
@@ -577,7 +579,11 @@ static void *internal_ao2_iterator_next(struct ao2_iterator *iter, const char *t
struct ao2_container_node *node;
void *ret;
- if (!is_ao2_object(iter->c) || !iter->c->v_table || !iter->c->v_table->iterator_next) {
+ if (!is_ao2_object(iter->c)) {
+ return NULL;
+ }
+
+ if (!iter->c->v_table || !iter->c->v_table->iterator_next) {
/* Sanity checks. */
ast_assert(0);
return NULL;
@@ -748,7 +754,11 @@ struct ao2_container *__ao2_container_clone(struct ao2_container *orig, enum sea
int failed;
/* Create the clone container with the same properties as the original. */
- if (!is_ao2_object(orig) || !orig->v_table || !orig->v_table->alloc_empty_clone) {
+ if (!is_ao2_object(orig)) {
+ return NULL;
+ }
+
+ if (!orig->v_table || !orig->v_table->alloc_empty_clone) {
/* Sanity checks. */
ast_assert(0);
return NULL;
@@ -779,7 +789,11 @@ struct ao2_container *__ao2_container_clone_debug(struct ao2_container *orig, en
int failed;
/* Create the clone container with the same properties as the original. */
- if (!is_ao2_object(orig) || !orig->v_table || !orig->v_table->alloc_empty_clone_debug) {
+ if (!is_ao2_object(orig)) {
+ return NULL;
+ }
+
+ if (!orig->v_table || !orig->v_table->alloc_empty_clone_debug) {
/* Sanity checks. */
ast_assert(0);
return NULL;
diff --git a/main/astobj2_hash.c b/main/astobj2_hash.c
index 341ff79e0..f5c678740 100644
--- a/main/astobj2_hash.c
+++ b/main/astobj2_hash.c
@@ -186,7 +186,9 @@ static void hash_ao2_node_destructor(void *v_doomed)
* same node.
*/
my_container = (struct ao2_container_hash *) doomed->common.my_container;
- ast_assert(is_ao2_object(my_container));
+#if defined(AST_DEVMODE)
+ is_ao2_object(my_container);
+#endif
__adjust_lock(my_container, AO2_LOCK_REQ_WRLOCK, 1);
diff --git a/main/astobj2_rbtree.c b/main/astobj2_rbtree.c
index a8d5e3ac1..4362b83cb 100644
--- a/main/astobj2_rbtree.c
+++ b/main/astobj2_rbtree.c
@@ -878,7 +878,9 @@ static void rb_ao2_node_destructor(void *v_doomed)
* same node.
*/
my_container = (struct ao2_container_rbtree *) doomed->common.my_container;
- ast_assert(is_ao2_object(my_container));
+#if defined(AST_DEVMODE)
+ is_ao2_object(my_container);
+#endif
__adjust_lock(my_container, AO2_LOCK_REQ_WRLOCK, 1);
diff --git a/main/utils.c b/main/utils.c
index 1a034c101..af0ee7f6b 100644
--- a/main/utils.c
+++ b/main/utils.c
@@ -2437,17 +2437,16 @@ void DO_CRASH_NORETURN ast_do_crash(void)
#endif /* defined(DO_CRASH) */
}
-#if defined(AST_DEVMODE)
void DO_CRASH_NORETURN __ast_assert_failed(int condition, const char *condition_str, const char *file, int line, const char *function)
{
/*
* Attempt to put it into the logger, but hope that at least
* someone saw the message on stderr ...
*/
- ast_log(__LOG_ERROR, file, line, function, "FRACK!, Failed assertion %s (%d)\n",
- condition_str, condition);
fprintf(stderr, "FRACK!, Failed assertion %s (%d) at line %d in %s of %s\n",
condition_str, condition, line, function, file);
+ ast_log(__LOG_ERROR, file, line, function, "FRACK!, Failed assertion %s (%d)\n",
+ condition_str, condition);
/* Generate a backtrace for the assert */
ast_log_backtrace();
@@ -2460,7 +2459,6 @@ void DO_CRASH_NORETURN __ast_assert_failed(int condition, const char *condition_
usleep(1);
ast_do_crash();
}
-#endif /* defined(AST_DEVMODE) */
char *ast_eid_to_str(char *s, int maxlen, struct ast_eid *eid)
{
diff --git a/res/res_pjsip_config_wizard.c b/res/res_pjsip_config_wizard.c
index e263437d7..1967d87ab 100644
--- a/res/res_pjsip_config_wizard.c
+++ b/res/res_pjsip_config_wizard.c
@@ -989,7 +989,7 @@ static int wizard_apply_handler(const struct ast_sorcery *sorcery, struct object
rc = handle_registrations(sorcery, otw, wiz, &remote_hosts_vector);
}
- AST_VECTOR_REMOVE_CMP_UNORDERED(&remote_hosts_vector, NULL, NOT_EQUALS, ast_free);
+ AST_VECTOR_REMOVE_ALL_CMP_UNORDERED(&remote_hosts_vector, NULL, NOT_EQUALS, ast_free);
AST_VECTOR_FREE(&remote_hosts_vector);
ast_debug(4, "%s handler complete. rc: %d\n", otw->object_type, rc);
@@ -1293,7 +1293,7 @@ static int unload_module(void)
{
ast_cli_unregister_multiple(config_wizard_cli, ARRAY_LEN(config_wizard_cli));
ast_sorcery_global_observer_remove(&global_observer);
- AST_VECTOR_REMOVE_CMP_UNORDERED(&object_type_wizards, NULL, NOT_EQUALS, OTW_DELETE_CB);
+ AST_VECTOR_REMOVE_ALL_CMP_UNORDERED(&object_type_wizards, NULL, NOT_EQUALS, OTW_DELETE_CB);
AST_VECTOR_RW_FREE(&object_type_wizards);
return 0;
diff --git a/res/res_rtp_asterisk.c b/res/res_rtp_asterisk.c
index 627f800a4..95fe6d3ea 100644
--- a/res/res_rtp_asterisk.c
+++ b/res/res_rtp_asterisk.c
@@ -4286,6 +4286,7 @@ static int bridge_p2p_rtp_write(struct ast_rtp_instance *instance, unsigned int
int reconstruct = ntohl(rtpheader[0]);
struct ast_sockaddr remote_address = { {0,} };
int ice;
+ unsigned int timestamp = ntohl(rtpheader[1]);
/* Get fields from packet */
payload = (reconstruct & 0x7f0000) >> 16;
@@ -4314,6 +4315,22 @@ static int bridge_p2p_rtp_write(struct ast_rtp_instance *instance, unsigned int
return -1;
}
+ /* If bridged peer is in dtmf, feed all packets to core until it finishes to avoid infinite dtmf */
+ if (bridged->sending_digit) {
+ ast_debug(1, "Feeding packets to core until DTMF finishes\n");
+ return -1;
+ }
+
+ /*
+ * Even if we are no longer in dtmf, we could still be receiving
+ * re-transmissions of the last dtmf end still. Feed those to the
+ * core so they can be filtered accordingly.
+ */
+ if (rtp->last_end_timestamp == timestamp) {
+ ast_debug(1, "Feeding packet with duplicate timestamp to core\n");
+ return -1;
+ }
+
/* If the marker bit has been explicitly set turn it on */
if (ast_test_flag(rtp, FLAG_NEED_MARKER_BIT)) {
mark = 1;
diff --git a/third-party/Makefile.rules b/third-party/Makefile.rules
index e633e0e98..92e4ebc85 100644
--- a/third-party/Makefile.rules
+++ b/third-party/Makefile.rules
@@ -4,7 +4,7 @@ SUBMAKE?=$(MAKE) --quiet --no-print-directory
ECHO_PREFIX?=@
CMD_PREFIX?=@
QUIET_CONFIGURE=-q
-REALLY_QUIET=&>/dev/null
+REALLY_QUIET=>/dev/null 2>&1
else
SUBMAKE?=$(MAKE)
ECHO_PREFIX?=@\#
diff --git a/third-party/pjproject/.gitignore b/third-party/pjproject/.gitignore
index 5079deeb3..6904ebfb6 100644
--- a/third-party/pjproject/.gitignore
+++ b/third-party/pjproject/.gitignore
@@ -2,3 +2,4 @@ source/
**.bz2
build.mak
pjproject.symbols
+.rebuild_needed
diff --git a/third-party/pjproject/Makefile b/third-party/pjproject/Makefile
index 7349db62f..bb98a09e3 100644
--- a/third-party/pjproject/Makefile
+++ b/third-party/pjproject/Makefile
@@ -1,4 +1,3 @@
-.SUFFIXES:
.PHONY: _all all _install install clean distclean echo_cflags configure
include ../versions.mak
@@ -40,18 +39,28 @@ ifeq ($(SPECIAL_TARGETS),)
include ../../Makefile.rules
include Makefile.rules
- include build.mak
+ include source/user.mak
+ include source/build.mak
CF := $(filter-out -W%,$(CC_CFLAGS))
CF := $(filter-out -I%,$(CF))
- export CFLAGS += $(CF)
- export LDFLAGS += $(CC_LDFLAGS)
- TARGETS := pjproject.symbols
ifeq ($(findstring TEST_FRAMEWORK,$(MENUSELECT_CFLAGS)),TEST_FRAMEWORK)
- TARGETS += source/pjsip-apps/bin/pjsua-$(TARGET_NAME)
+ apps := source/pjsip-apps/bin/pjsua-$(TARGET_NAME) source/pjsip-apps/bin/pjsystest-$(TARGET_NAME)
+ TARGETS += $(apps)
ifneq ($(PYTHONDEV_LIB),)
- TARGETS += source/pjsip-apps/src/python/build/_pjsua.so
+ TARGETS += source/pjsip-apps/src/python/_pjsua.so
endif
endif
+ ifeq ($(findstring MALLOC_DEBUG,$(MENUSELECT_CFLAGS)),MALLOC_DEBUG)
+ CF += -DMALLOC_DEBUG
+ MALLOC_DEBUG = yes
+ $(apps): export LDFLAGS += -L$(PJDIR)/pjsip-apps/lib -Wl,-whole-archive -lasterisk_malloc_debug -Wl,-no-whole-archive
+ $(apps): source/pjsip-apps/lib/libasterisk_malloc_debug.a
+ source/pjsip-apps/src/python/_pjsua.so: LDFLAGS += -L$(PJDIR)/pjsip-apps/lib -Wl,-whole-archive -lasterisk_malloc_debug -Wl,-no-whole-archive
+ source/pjsip-apps/src/python/_pjsua.so: source/pjsip-apps/lib/libasterisk_malloc_debug.a
+ endif
+ TARGETS += pjproject.symbols
+ export CFLAGS += $(CF)
+ export LDFLAGS += $(CC_LDFLAGS)
else
all install:
endif
@@ -73,8 +82,8 @@ $(TMPDIR)/pjproject-$(PJPROJECT_VERSION).tar.bz2 : ../versions.mak
source/.unpacked: $(TMPDIR)/pjproject-$(PJPROJECT_VERSION).tar.bz2
$(ECHO_PREFIX) Unpacking $<
- -@rm -rf source &>/dev/null
- -@mkdir source &>/dev/null
+ -@rm -rf source >/dev/null 2>&1
+ -@mkdir source >/dev/null 2>&1
$(CMD_PREFIX) tar --strip-components=1 -C source -xjf $<
$(ECHO_PREFIX) Applying patches
$(CMD_PREFIX) ./apply_patches $(QUIET_CONFIGURE) ./patches ./source
@@ -84,11 +93,11 @@ source/user.mak: source/.unpacked ./patches/user.mak
$(ECHO_PREFIX) Applying user.mak
$(CMD_PREFIX) cp -f ./patches/user.mak ./source/
-source/pjlib/include/pj/config_site.h: source/.unpacked ./patches/config_site.h
- $(ECHO_PREFIX) Applying config_site.h
- $(CMD_PREFIX) cp -f ./patches/config_site.h ./source/pjlib/include/pj/
+source/pjlib/include/pj/%.h : ./patches/%.h
+ $(ECHO_PREFIX) Applying custom include file $<
+ $(CMD_PREFIX) cp -f $< ./source/pjlib/include/pj/
-build.mak: source/.unpacked source/pjlib/include/pj/config_site.h source/user.mak Makefile.rules
+build.mak: source/.unpacked $(addprefix source/pjlib/include/pj/,$(notdir $(wildcard ./patches/*.h))) source/user.mak Makefile.rules
$(ECHO_PREFIX) Configuring with $(PJPROJECT_CONFIG_OPTS)
$(CMD_PREFIX) (cd source ; autoconf aconfigure.ac > aconfigure && ./aconfigure $(QUIET_CONFIGURE) $(PJPROJECT_CONFIG_OPTS))
@sed -r -e "/prefix|export PJ_SHARED_LIBRARIES|MACHINE_NAME|OS_NAME|HOST_NAME|CC_NAME|CROSS_COMPILE|LINUX_POLL/d" source/build.mak > build.mak
@@ -98,29 +107,53 @@ configure: build.mak
echo_cflags: build.mak
@echo $(PJ_CFLAGS)
-source/pjlib/build/.pjlib-$(TARGET_NAME).depend: build.mak
- $(ECHO_PREFIX) "Making dependencies"
- +$(CMD_PREFIX) $(SUBMAKE) -C source dep
+.rebuild_needed: ../../menuselect.makeopts
+ $(ECHO_PREFIX) Rebuilding
+ $(CMD_PREFIX)$(MAKE) clean $(REALLY_QUIET)
+ @touch .rebuild_needed
-menuselect: ../../menuselect.makeopts ../../makeopts
- -$(CMD_PREFIX) test -d source && ($(SUBMAKE) -C source clean ; find source -name *.a -delete ; rm -rf source/pjsip-apps/src/python/build) || :
- -$(CMD_PREFIX) rm -rf pjproject.symbols
+libpj%.a: .rebuild_needed build.mak
+ $(ECHO_PREFIX) Compiling lib $(@F)
+ $(CMD_PREFIX)$(MAKE) -C $(dir $(shell dirname $@))/build $(@F) $(REALLY_QUIET)
-source/pjlib/lib/libpj-$(TARGET_NAME).a: menuselect source/pjlib/build/.pjlib-$(TARGET_NAME).depend
- $(ECHO_PREFIX) Compiling libs
- +$(CMD_PREFIX) $(SUBMAKE) -C source lib $(REALLY_QUIET)
+# We need to compile pjlib, then pjlib-util, then the rest
+# so we separate them out and create the dependencies
+PJLIB_LIB_FILES = $(foreach lib,$(PJ_LIB_FILES),$(if $(findstring libpj-,$(lib)),$(lib),))
+PJLIB_UTIL_LIB_FILES = $(foreach lib,$(PJ_LIB_FILES),$(if $(findstring libpjlib-util,$(lib)),$(lib),))
+LIB_FILES = $(filter-out $(PJLIB_LIB_FILES) $(PJLIB_UTIL_LIB_FILES),$(PJ_LIB_FILES))
+ALL_LIB_FILES = $(PJLIB_LIB_FILES) $(PJLIB_UTIL_LIB_FILES) $(LIB_FILES)
-pjproject.symbols: source/pjlib/lib/libpj-$(TARGET_NAME).a
+$(PJLIB_UTIL_LIB_FILES): $(PJLIB_LIB_FILES)
+$(LIB_FILES): $(PJLIB_UTIL_LIB_FILES)
+
+pjproject.symbols: $(ALL_LIB_FILES)
$(ECHO_PREFIX) Generating symbols
- $(CMD_PREFIX) nm -Pog $(PJ_LIB_FILES) | sed -n -r -e "s/.+: ([pP][jJ][^ ]+) .+/\1/gp" | sort -u > pjproject.symbols
+ $(CMD_PREFIX) nm -Pog $(ALL_LIB_FILES) | sed -n -r -e "s/.+: ([pP][jJ][^ ]+) .+/\1/gp" | sort -u > pjproject.symbols
+
+source/pjsip-apps/src/asterisk_malloc_debug.c: patches/asterisk_malloc_debug.c
+ $(ECHO_PREFIX) Copying $< to $@
+ $(CMD_PREFIX) cp -f $< $@
+
+source/pjsip-apps/lib/asterisk_malloc_debug.o: source/pjsip-apps/src/asterisk_malloc_debug.c .rebuild_needed
+ $(ECHO_PREFIX) Compiling asterisk debug malloc stubs
+ $(CMD_PREFIX) $(CC) -fPIC $(PJ_CFLAGS) -c $< -o $@
-source/pjsip-apps/bin/pjsua-$(TARGET_NAME): source/pjlib/lib/libpj-$(TARGET_NAME).a
- $(ECHO_PREFIX) Compiling apps
- $(CMD_PREFIX) $(SUBMAKE) -C source/pjsip-apps/build pjsua pjsystest $(REALLY_QUIET)
+source/pjsip-apps/lib/libasterisk_malloc_debug.a: source/pjsip-apps/lib/asterisk_malloc_debug.o
+ $(ECHO_PREFIX) Creating archive $(@F)
+ $(CMD_PREFIX) ar qs $@ $< >/dev/null 2>&1
-source/pjsip-apps/src/python/build/_pjsua.so: source/pjlib/lib/libpj-$(TARGET_NAME).a
+$(apps): APP = $(filter pj%,$(subst -, ,$(notdir $@)))
+$(apps): pjproject.symbols
+ $(ECHO_PREFIX) Compiling $(APP)
+ $(CMD_PREFIX) +$(MAKE) -C source/pjsip-apps/build $(filter pj%,$(subst -, ,$(notdir $@))) $(REALLY_QUIET)
+
+source/pjsip-apps/src/python/_pjsua.o: source/pjsip-apps/src/python/_pjsua.c $(apps)
$(ECHO_PREFIX) Compiling python bindings
- $(CMD_PREFIX) (cd source/pjsip-apps/src/python ; MAKE=$(MAKE) python setup.py build --build-platlib=./build $(REALLY_QUIET))
+ $(CMD_PREFIX) $(CC) -o $@ -c $< $(PYTHONDEV_INCLUDE) $(CFLAGS) $(PJ_CFLAGS)
+
+source/pjsip-apps/src/python/_pjsua.so: source/pjsip-apps/src/python/_pjsua.o
+ $(ECHO_PREFIX) Linking python bindings $(@F)
+ $(CMD_PREFIX) gcc -shared -pthread -o $@ $< $(LDFLAGS) $(PJ_LDFLAGS) $(APP_LDLIBS) $(PYTHONDEV_LIB) $(REALLY_QUIET)
_all: $(TARGETS)
@@ -133,10 +166,10 @@ ifneq ($(findstring source/pjsip-apps/bin/pjsua-$(TARGET_NAME),$(TARGETS)),)
$(CMD_PREFIX) $(INSTALL) -m 755 source/pjsip-apps/bin/pjsua-$(TARGET_NAME) "$(DESTDIR)$(ASTDATADIR)/third-party/pjproject/pjsua"
$(CMD_PREFIX) $(INSTALL) -m 755 source/pjsip-apps/bin/pjsystest-$(TARGET_NAME) "$(DESTDIR)$(ASTDATADIR)/third-party/pjproject/pjsystest"
endif
-ifneq ($(findstring source/pjsip-apps/src/python/build/_pjsua.so,$(TARGETS)),)
+ifneq ($(findstring _pjsua.so,$(TARGETS)),)
$(ECHO_PREFIX) Installing python bindings
- $(CMD_PREFIX) $(INSTALL) -m 755 source/pjsip-apps/src/python/build/_pjsua.so "$(DESTDIR)$(ASTDATADIR)/third-party/pjproject/"
- $(CMD_PREFIX) $(INSTALL) -m 644 source/pjsip-apps/src/python/build/pjsua.py "$(DESTDIR)$(ASTDATADIR)/third-party/pjproject/"
+ $(CMD_PREFIX) $(INSTALL) -m 755 source/pjsip-apps/src/python/_pjsua.so "$(DESTDIR)$(ASTDATADIR)/third-party/pjproject/"
+ $(CMD_PREFIX) $(INSTALL) -m 644 source/pjsip-apps/src/python/pjsua.py "$(DESTDIR)$(ASTDATADIR)/third-party/pjproject/"
endif
uninstall:
@@ -145,10 +178,14 @@ uninstall:
clean:
$(ECHO_PREFIX) Cleaning
- -$(CMD_PREFIX) test -d source && ($(SUBMAKE) -C source clean ; find source -name *.a -delete ; rm -rf source/pjsip-apps/src/python/build ; rm -rf source/pjsip-apps/bin/* ) || :
+ +-$(CMD_PREFIX) test -d source && ($(SUBMAKE) -C source clean || : ;\
+ rm -rf source/pjsip-apps/bin/* || : ;\
+ find source -name *.a -delete ;\
+ find source -name *.o -delete ;\
+ find source -name *.so -delete ; ) || :
-$(CMD_PREFIX) rm -rf pjproject.symbols
distclean:
$(ECHO_PREFIX) Distcleaning
- -$(CMD_PREFIX) rm -rf source pjproject.symbols pjproject-*.tar.bz2 build.mak
+ -$(CMD_PREFIX) rm -rf source pjproject.symbols pjproject-*.tar.bz2 build.mak .rebuild_needed
diff --git a/third-party/pjproject/patches/asterisk_malloc_debug.c b/third-party/pjproject/patches/asterisk_malloc_debug.c
new file mode 100644
index 000000000..c41767bd8
--- /dev/null
+++ b/third-party/pjproject/patches/asterisk_malloc_debug.c
@@ -0,0 +1,72 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2016, Digium, Inc
+ *
+ * George Joseph <gjoseph@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+#define _GNU_SOURCE
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+
+int __ast_asprintf(const char *file, int lineno, const char *func, char **strp, const char *format, ...)
+{
+ va_list ap;
+ int rc = 0;
+
+ va_start(ap, format);
+ rc = vasprintf(strp, format, ap);
+ va_end(ap);
+
+ return rc;
+}
+
+void *__ast_calloc(size_t nmemb, size_t size, const char *file, int lineno, const char *func)
+{
+ return calloc(nmemb, size);
+}
+
+void __ast_free(void *ptr, const char *file, int lineno, const char *func)
+{
+ free(ptr);
+}
+
+void *__ast_malloc(size_t size, const char *file, int lineno, const char *func)
+{
+ return malloc(size);
+}
+
+void *__ast_realloc(void *ptr, size_t size, const char *file, int lineno, const char *func)
+{
+ return realloc(ptr, size);
+}
+
+char *__ast_strdup(const char *s, const char *file, int lineno, const char *func)
+{
+ return strdup(s);
+}
+
+char *__ast_strndup(const char *s, size_t n, const char *file, int lineno, const char *func)
+{
+ return strndup(s, n);
+}
+
+int __ast_vasprintf(char **strp, const char *format, va_list ap, const char *file, int lineno, const char *func)
+{
+ return vasprintf(strp, format, ap);
+}
+
+
diff --git a/third-party/pjproject/patches/asterisk_malloc_debug.h b/third-party/pjproject/patches/asterisk_malloc_debug.h
new file mode 100644
index 000000000..44c473758
--- /dev/null
+++ b/third-party/pjproject/patches/asterisk_malloc_debug.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2016 George Joseph <gjoseph@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+#ifndef ASTERISK_MALLOC_DEBUG_H_
+#define ASTERISK_MALLOC_DEBUG_H_
+
+/* Include these now to prevent them from messing up MALLOC_DEBUG */
+#include <sys/types.h>
+#include <pj/compat/string.h>
+#include <pj/compat/stdarg.h>
+#include <pj/compat/malloc.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int __ast_asprintf(const char *file, int lineno, const char *func, char **strp, const char *format, ...)
+ __attribute__((format(printf, 5, 6)));
+void *__ast_calloc(size_t nmemb, size_t size, const char *file, int lineno, const char *func);
+void __ast_free(void *ptr, const char *file, int lineno, const char *func);
+void *__ast_malloc(size_t size, const char *file, int lineno, const char *func);
+void *__ast_realloc(void *ptr, size_t size, const char *file, int lineno, const char *func);
+char *__ast_strdup(const char *s, const char *file, int lineno, const char *func);
+char *__ast_strndup(const char *s, size_t n, const char *file, int lineno, const char *func);
+int __ast_vasprintf(char **strp, const char *format, va_list ap, const char *file, int lineno, const char *func)
+ __attribute__((format(printf, 2, 0)));
+
+/* Undefine any macros */
+#undef asprintf
+#undef calloc
+#undef free
+#undef malloc
+#undef realloc
+#undef strdup
+#undef strndup
+#undef vasprintf
+
+ /* Provide our own definitions */
+#define asprintf(a, b, c...) \
+ __ast_asprintf(__FILE__, __LINE__, __PRETTY_FUNCTION__, a, b, c)
+
+#define calloc(a,b) \
+ __ast_calloc(a,b,__FILE__, __LINE__, __PRETTY_FUNCTION__)
+
+#define free(a) \
+ __ast_free(a,__FILE__, __LINE__, __PRETTY_FUNCTION__)
+
+#define malloc(a) \
+ __ast_malloc(a,__FILE__, __LINE__, __PRETTY_FUNCTION__)
+
+#define realloc(a,b) \
+ __ast_realloc(a,b,__FILE__, __LINE__, __PRETTY_FUNCTION__)
+
+#define strdup(a) \
+ __ast_strdup(a,__FILE__, __LINE__, __PRETTY_FUNCTION__)
+
+#define strndup(a,b) \
+ __ast_strndup(a,b,__FILE__, __LINE__, __PRETTY_FUNCTION__)
+
+#define vasprintf(a,b,c) \
+ __ast_vasprintf(a,b,c,__FILE__, __LINE__, __PRETTY_FUNCTION__)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ASTERISK_MALLOC_DEBUG_H_ */
diff --git a/third-party/pjproject/patches/config_site.h b/third-party/pjproject/patches/config_site.h
index f9f76dc6c..0694f120e 100644
--- a/third-party/pjproject/patches/config_site.h
+++ b/third-party/pjproject/patches/config_site.h
@@ -5,6 +5,14 @@
#include <sys/select.h>
/*
+ * Since both pjproject and asterisk source files will include config_site.h,
+ * we need to make sure that only pjproject source files include asterisk_malloc_debug.h.
+ */
+#if defined(MALLOC_DEBUG) && !defined(_ASTERISK_ASTMM_H)
+#include "asterisk_malloc_debug.h"
+#endif
+
+/*
* Defining PJMEDIA_HAS_SRTP to 0 does NOT disable Asterisk's ability to use srtp.
* It only disables the pjmedia srtp transport which Asterisk doesn't use.
* The reason for the disable is that while Asterisk works fine with older libsrtp