summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES11
-rw-r--r--apps/app_chanspy.c62
-rw-r--r--apps/app_mixmonitor.c21
-rw-r--r--apps/app_queue.c70
-rw-r--r--bridges/bridge_softmix.c3
-rw-r--r--configs/samples/pjsip.conf.sample1
-rw-r--r--contrib/ast-db-manage/config/versions/8fce4c573e15_add_pjsip_allow_overlap.py31
-rw-r--r--funcs/func_channel.c15
-rw-r--r--include/asterisk/autochan.h20
-rw-r--r--include/asterisk/manager.h2
-rw-r--r--include/asterisk/res_hep.h2
-rw-r--r--include/asterisk/res_pjsip.h2
-rw-r--r--main/autochan.c16
-rw-r--r--main/message.c6
-rw-r--r--res/res_hep.c5
-rw-r--r--res/res_hep_pjsip.c12
-rw-r--r--res/res_pjsip.c6
-rw-r--r--res/res_pjsip/pjsip_configuration.c1
-rw-r--r--res/res_pjsip_messaging.c10
-rw-r--r--res/res_pjsip_nat.c43
-rw-r--r--res/res_pjsip_sdp_rtp.c5
-rw-r--r--res/res_pjsip_session.c29
-rw-r--r--res/res_pjsip_t38.c5
-rw-r--r--third-party/pjproject/patches/0025-fix-print-xml-crash.patch24
24 files changed, 269 insertions, 133 deletions
diff --git a/CHANGES b/CHANGES
index 08c9185b6..86dfe76a1 100644
--- a/CHANGES
+++ b/CHANGES
@@ -41,6 +41,13 @@ app_voicemail
* Added 'fromstring' field to the voicemail boxes. If set, it will override
the global 'fromstring' field on a per-mailbox basis.
+func_channel
+------------------
+ * Added CHANNEL(callid) to retrieve the call log tag associated with the
+ channel. e.g., [C-00000000] Dialplan now has access to the call log
+ search key associated with the channel so it can be saved in case there
+ is a problem with the call.
+
res_pjsip
------------------
* A new transport parameter 'symmetric_transport' has been added.
@@ -57,6 +64,10 @@ res_pjsip
added to both transport and subscription_persistence, an alembic upgrade
should be run to bring the database tables up to date.
+ * A new option, allow_overlap, has been added to endpoints which allows
+ overlap dialing functionality to be enabled or disabled. The option defaults
+ to enabled.
+
res_pjsip_transport_websocket
------------------
* Removed non-secure websocket support. Firefox and Chrome have not allowed
diff --git a/apps/app_chanspy.c b/apps/app_chanspy.c
index 19675fb28..608eb6be1 100644
--- a/apps/app_chanspy.c
+++ b/apps/app_chanspy.c
@@ -498,10 +498,15 @@ static struct ast_generator spygen = {
static int start_spying(struct ast_autochan *autochan, const char *spychan_name, struct ast_audiohook *audiohook)
{
+ int res;
+
+ ast_autochan_channel_lock(autochan);
ast_log(LOG_NOTICE, "Attaching %s to %s\n", spychan_name, ast_channel_name(autochan->chan));
ast_set_flag(audiohook, AST_AUDIOHOOK_TRIGGER_SYNC | AST_AUDIOHOOK_SMALL_QUEUE);
- return ast_audiohook_attach(autochan->chan, audiohook);
+ res = ast_audiohook_attach(autochan->chan, audiohook);
+ ast_autochan_channel_unlock(autochan);
+ return res;
}
static void change_spy_mode(const char digit, struct ast_flags *flags)
@@ -585,8 +590,14 @@ static int attach_barge(struct ast_autochan *spyee_autochan,
{
int retval = 0;
struct ast_autochan *internal_bridge_autochan;
- RAII_VAR(struct ast_channel *, bridged, ast_channel_bridge_peer(spyee_autochan->chan), ast_channel_cleanup);
+ struct ast_channel *spyee_chan;
+ RAII_VAR(struct ast_channel *, bridged, NULL, ast_channel_cleanup);
+ ast_autochan_channel_lock(spyee_autochan);
+ spyee_chan = ast_channel_ref(spyee_autochan->chan);
+ ast_autochan_channel_unlock(spyee_autochan);
+ bridged = ast_channel_bridge_peer(spyee_chan);
+ ast_channel_unref(spyee_chan);
if (!bridged) {
return -1;
}
@@ -598,12 +609,10 @@ static int attach_barge(struct ast_autochan *spyee_autochan,
return -1;
}
- ast_autochan_channel_lock(internal_bridge_autochan);
if (start_spying(internal_bridge_autochan, spyer_name, bridge_whisper_audiohook)) {
ast_log(LOG_WARNING, "Unable to attach barge audiohook on spyee '%s'. Barge mode disabled.\n", name);
retval = -1;
}
- ast_autochan_channel_unlock(internal_bridge_autochan);
*spyee_bridge_autochan = internal_bridge_autochan;
@@ -623,21 +632,25 @@ static int channel_spy(struct ast_channel *chan, struct ast_autochan *spyee_auto
struct ast_autochan *spyee_bridge_autochan = NULL;
const char *spyer_name;
- if (ast_check_hangup(chan) || ast_check_hangup(spyee_autochan->chan) ||
- ast_test_flag(ast_channel_flags(spyee_autochan->chan), AST_FLAG_ZOMBIE)) {
+ ast_channel_lock(chan);
+ if (ast_check_hangup(chan)) {
+ ast_channel_unlock(chan);
return 0;
}
-
- ast_channel_lock(chan);
spyer_name = ast_strdupa(ast_channel_name(chan));
ast_channel_unlock(chan);
ast_autochan_channel_lock(spyee_autochan);
+ if (ast_check_hangup(spyee_autochan->chan)
+ || ast_test_flag(ast_channel_flags(spyee_autochan->chan), AST_FLAG_ZOMBIE)) {
+ ast_autochan_channel_unlock(spyee_autochan);
+ return 0;
+ }
name = ast_strdupa(ast_channel_name(spyee_autochan->chan));
- ast_autochan_channel_unlock(spyee_autochan);
ast_verb(2, "Spying on channel %s\n", name);
publish_chanspy_message(chan, spyee_autochan->chan, 1);
+ ast_autochan_channel_unlock(spyee_autochan);
memset(&csth, 0, sizeof(csth));
ast_copy_flags(&csth.flags, flags, AST_FLAGS_ALL);
@@ -829,7 +842,7 @@ static int channel_spy(struct ast_channel *chan, struct ast_autochan *spyee_auto
}
static struct ast_autochan *next_channel(struct ast_channel_iterator *iter,
- struct ast_autochan *autochan, struct ast_channel *chan)
+ struct ast_channel *chan)
{
struct ast_channel *next;
struct ast_autochan *autochan_store;
@@ -966,11 +979,12 @@ static int common_exec(struct ast_channel *chan, struct ast_flags *flags,
waitms = 100;
num_spyed_upon = 0;
- for (autochan = next_channel(iter, autochan, chan);
- autochan;
- prev = autochan->chan, ast_autochan_destroy(autochan),
- autochan = next_autochan ? next_autochan :
- next_channel(iter, autochan, chan), next_autochan = NULL) {
+ for (autochan = next_channel(iter, chan);
+ autochan;
+ prev = autochan->chan,
+ ast_autochan_destroy(autochan),
+ autochan = next_autochan ?: next_channel(iter, chan),
+ next_autochan = NULL) {
int igrp = !mygroup;
int ienf = !myenforced;
@@ -984,13 +998,19 @@ static int common_exec(struct ast_channel *chan, struct ast_flags *flags,
break;
}
- if (ast_test_flag(flags, OPTION_BRIDGED) && !ast_channel_is_bridged(autochan->chan)) {
+ ast_autochan_channel_lock(autochan);
+ if (ast_test_flag(flags, OPTION_BRIDGED)
+ && !ast_channel_is_bridged(autochan->chan)) {
+ ast_autochan_channel_unlock(autochan);
continue;
}
- if (ast_check_hangup(autochan->chan) || ast_test_flag(ast_channel_flags(autochan->chan), AST_FLAG_SPYING)) {
+ if (ast_check_hangup(autochan->chan)
+ || ast_test_flag(ast_channel_flags(autochan->chan), AST_FLAG_SPYING)) {
+ ast_autochan_channel_unlock(autochan);
continue;
}
+ ast_autochan_channel_unlock(autochan);
if (mygroup) {
int num_groups = 0;
@@ -1008,11 +1028,13 @@ static int common_exec(struct ast_channel *chan, struct ast_flags *flags,
/* Before dahdi scan was part of chanspy, it would use the "GROUP" variable
* rather than "SPYGROUP", this check is done to preserve expected behavior */
+ ast_autochan_channel_lock(autochan);
if (ast_test_flag(flags, OPTION_DAHDI_SCAN)) {
group = pbx_builtin_getvar_helper(autochan->chan, "GROUP");
} else {
group = pbx_builtin_getvar_helper(autochan->chan, "SPYGROUP");
}
+ ast_autochan_channel_unlock(autochan);
if (!ast_strlen_zero(group)) {
ast_copy_string(dup_group, group, sizeof(dup_group));
@@ -1040,7 +1062,9 @@ static int common_exec(struct ast_channel *chan, struct ast_flags *flags,
snprintf(buffer, sizeof(buffer) - 1, ":%s:", myenforced);
+ ast_autochan_channel_lock(autochan);
ast_copy_string(ext + 1, ast_channel_name(autochan->chan), sizeof(ext) - 1);
+ ast_autochan_channel_unlock(autochan);
if ((end = strchr(ext, '-'))) {
*end++ = ':';
*end = '\0';
@@ -1062,7 +1086,9 @@ static int common_exec(struct ast_channel *chan, struct ast_flags *flags,
char *ptr, *s;
strcpy(peer_name, "spy-");
+ ast_autochan_channel_lock(autochan);
strncat(peer_name, ast_channel_name(autochan->chan), AST_NAME_STRLEN - 4 - 1);
+ ast_autochan_channel_unlock(autochan);
if ((ptr = strchr(peer_name, '/'))) {
*ptr++ = '\0';
for (s = peer_name; s < ptr; s++) {
@@ -1127,12 +1153,14 @@ static int common_exec(struct ast_channel *chan, struct ast_flags *flags,
next = ast_channel_unref(next);
} else {
/* stay on this channel, if it is still valid */
+ ast_autochan_channel_lock(autochan);
if (!ast_check_hangup(autochan->chan)) {
next_autochan = ast_autochan_setup(autochan->chan);
} else {
/* the channel is gone */
next_autochan = NULL;
}
+ ast_autochan_channel_unlock(autochan);
}
} else if (res == 0 && ast_test_flag(flags, OPTION_EXITONHANGUP)) {
ast_autochan_destroy(autochan);
diff --git a/apps/app_mixmonitor.c b/apps/app_mixmonitor.c
index 3515f4b8c..979bf2d70 100644
--- a/apps/app_mixmonitor.c
+++ b/apps/app_mixmonitor.c
@@ -622,6 +622,16 @@ static void mixmonitor_save_prep(struct mixmonitor *mixmonitor, char *filename,
}
}
+static int mixmonitor_autochan_is_bridged(struct ast_autochan *autochan)
+{
+ int is_bridged;
+
+ ast_autochan_channel_lock(autochan);
+ is_bridged = ast_channel_is_bridged(autochan->chan);
+ ast_autochan_channel_unlock(autochan);
+ return is_bridged;
+}
+
static void *mixmonitor_thread(void *obj)
{
struct mixmonitor *mixmonitor = obj;
@@ -679,8 +689,7 @@ static void *mixmonitor_thread(void *obj)
ast_audiohook_unlock(&mixmonitor->audiohook);
if (!ast_test_flag(mixmonitor, MUXFLAG_BRIDGED)
- || (mixmonitor->autochan->chan
- && ast_channel_is_bridged(mixmonitor->autochan->chan))) {
+ || mixmonitor_autochan_is_bridged(mixmonitor->autochan)) {
ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock);
/* Write out the frame(s) */
@@ -729,11 +738,11 @@ static void *mixmonitor_thread(void *obj)
ast_audiohook_unlock(&mixmonitor->audiohook);
- ast_autochan_channel_lock(mixmonitor->autochan);
if (ast_test_flag(mixmonitor, MUXFLAG_BEEP_STOP)) {
+ ast_autochan_channel_lock(mixmonitor->autochan);
ast_stream_and_wait(mixmonitor->autochan->chan, "beep", "");
+ ast_autochan_channel_unlock(mixmonitor->autochan);
}
- ast_autochan_channel_unlock(mixmonitor->autochan);
ast_autochan_destroy(mixmonitor->autochan);
@@ -805,11 +814,11 @@ static int setup_mixmonitor_ds(struct mixmonitor *mixmonitor, struct ast_channel
return -1;
}
- ast_autochan_channel_lock(mixmonitor->autochan);
if (ast_test_flag(mixmonitor, MUXFLAG_BEEP_START)) {
+ ast_autochan_channel_lock(mixmonitor->autochan);
ast_stream_and_wait(mixmonitor->autochan->chan, "beep", "");
+ ast_autochan_channel_unlock(mixmonitor->autochan);
}
- ast_autochan_channel_unlock(mixmonitor->autochan);
mixmonitor_ds->samp_rate = 8000;
mixmonitor_ds->audiohook = &mixmonitor->audiohook;
diff --git a/apps/app_queue.c b/apps/app_queue.c
index ddb62d2e0..9eca4ed73 100644
--- a/apps/app_queue.c
+++ b/apps/app_queue.c
@@ -5510,6 +5510,13 @@ static int update_queue(struct call_queue *q, struct member *member, int callcom
member->membername, (long)member->lastcall);
ao2_unlock(q);
}
+ /* Member might never experience any direct status change (local
+ * channel with forwarding in particular). If that's the case,
+ * this is the last chance to remove it from pending or subsequent
+ * calls will not occur.
+ */
+ pending_members_remove(member);
+
ao2_lock(q);
q->callscompleted++;
if (callcompletedinsl) {
@@ -5903,67 +5910,6 @@ static void handle_bridge_enter(void *userdata, struct stasis_subscription *sub,
}
/*!
- * \internal
- * \brief Handle a stasis bridge leave event.
- *
- * We track this event to determine if the caller has left the bridge
- * as the result of a redirect. Transfers and hangups are handled in
- * separate functions.
- *
- * \param userdata Data pertaining to the particular call in the queue.
- * \param sub The stasis subscription on which the message occurred.
- * \param msg The stasis message for the bridge leave event
- */
-static void handle_bridge_left(void *userdata, struct stasis_subscription *sub,
- struct stasis_message *msg)
-{
- struct queue_stasis_data *queue_data = userdata;
- struct ast_bridge_blob *left_blob = stasis_message_data(msg);
- struct ast_channel_snapshot *caller_snapshot, *member_snapshot;
-
- ao2_lock(queue_data);
-
- if (queue_data->dying) {
- ao2_unlock(queue_data);
- return;
- }
-
- if (ast_strlen_zero(queue_data->bridge_uniqueid)) {
- ao2_unlock(queue_data);
- return;
- }
-
- /* Correct channel, correct bridge? */
- if (strcmp(left_blob->channel->uniqueid, queue_data->caller_uniqueid)
- || strcmp(left_blob->bridge->uniqueid, queue_data->bridge_uniqueid)) {
- ao2_unlock(queue_data);
- return;
- }
-
- caller_snapshot = ast_channel_snapshot_get_latest(queue_data->caller_uniqueid);
- member_snapshot = ast_channel_snapshot_get_latest(queue_data->member_uniqueid);
-
- ao2_unlock(queue_data);
-
- ast_debug(3, "Detected redirect of queue caller channel %s\n",
- caller_snapshot->name);
-
- ast_queue_log(queue_data->queue->name, caller_snapshot->uniqueid, queue_data->member->membername,
- "COMPLETECALLER", "%ld|%ld|%d",
- (long) (queue_data->starttime - queue_data->holdstart),
- (long) (time(NULL) - queue_data->starttime), queue_data->caller_pos);
-
- send_agent_complete(queue_data->queue->name, caller_snapshot, member_snapshot, queue_data->member,
- queue_data->holdstart, queue_data->starttime, CALLER);
- update_queue(queue_data->queue, queue_data->member, queue_data->callcompletedinsl,
- time(NULL) - queue_data->starttime);
- remove_stasis_subscriptions(queue_data);
-
- ao2_cleanup(member_snapshot);
- ao2_cleanup(caller_snapshot);
-}
-
-/*!
* \brief Handle a blind transfer event
*
* This event is important in order to be able to log the end of the
@@ -6333,8 +6279,6 @@ static int setup_stasis_subs(struct queue_ent *qe, struct ast_channel *peer, str
stasis_message_router_add(queue_data->bridge_router, ast_channel_entered_bridge_type(),
handle_bridge_enter, queue_data);
- stasis_message_router_add(queue_data->bridge_router, ast_channel_left_bridge_type(),
- handle_bridge_left, queue_data);
stasis_message_router_add(queue_data->bridge_router, ast_blind_transfer_type(),
handle_blind_transfer, queue_data);
stasis_message_router_add(queue_data->bridge_router, ast_attended_transfer_type(),
diff --git a/bridges/bridge_softmix.c b/bridges/bridge_softmix.c
index 436fab7af..486330af0 100644
--- a/bridges/bridge_softmix.c
+++ b/bridges/bridge_softmix.c
@@ -306,7 +306,8 @@ static void softmix_process_write_audio(struct softmix_translate_helper *trans_h
if (entry->trans_pvt && !entry->out_frame) {
entry->out_frame = ast_translate(entry->trans_pvt, &sc->write_frame, 0);
}
- if (entry->out_frame && (entry->out_frame->datalen < MAX_DATALEN)) {
+ if (entry->out_frame && entry->out_frame->frametype == AST_FRAME_VOICE
+ && entry->out_frame->datalen < MAX_DATALEN) {
ao2_replace(sc->write_frame.subclass.format, entry->out_frame->subclass.format);
memcpy(sc->final_buf, entry->out_frame->data.ptr, entry->out_frame->datalen);
sc->write_frame.datalen = entry->out_frame->datalen;
diff --git a/configs/samples/pjsip.conf.sample b/configs/samples/pjsip.conf.sample
index 82da311a0..82cfc09ae 100644
--- a/configs/samples/pjsip.conf.sample
+++ b/configs/samples/pjsip.conf.sample
@@ -595,6 +595,7 @@
; "yes")
;aggregate_mwi=yes ; (default: "yes")
;allow= ; Media Codec s to allow (default: "")
+;allow_overlap=yes ; Enable RFC3578 overlap dialing support. (default: "yes")
;aors= ; AoR s to be used with the endpoint (default: "")
;auth= ; Authentication Object s associated with the endpoint (default: "")
;callerid= ; CallerID information for the endpoint (default: "")
diff --git a/contrib/ast-db-manage/config/versions/8fce4c573e15_add_pjsip_allow_overlap.py b/contrib/ast-db-manage/config/versions/8fce4c573e15_add_pjsip_allow_overlap.py
new file mode 100644
index 000000000..24057ecc8
--- /dev/null
+++ b/contrib/ast-db-manage/config/versions/8fce4c573e15_add_pjsip_allow_overlap.py
@@ -0,0 +1,31 @@
+"""add pjsip allow_overlap
+
+Revision ID: 8fce4c573e15
+Revises: f638dbe2eb23
+Create Date: 2017-03-21 15:14:27.612945
+
+"""
+
+# revision identifiers, used by Alembic.
+revision = '8fce4c573e15'
+down_revision = 'f638dbe2eb23'
+
+from alembic import op
+import sqlalchemy as sa
+from sqlalchemy.dialects.postgresql import ENUM
+
+YESNO_NAME = 'yesno_values'
+YESNO_VALUES = ['yes', 'no']
+
+def upgrade():
+ ############################# Enums ##############################
+
+ # yesno_values have already been created, so use postgres enum object
+ # type to get around "already created" issue - works okay with mysql
+ yesno_values = ENUM(*YESNO_VALUES, name=YESNO_NAME, create_type=False)
+
+ op.add_column('ps_endpoints', sa.Column('allow_overlap', yesno_values))
+
+
+def downgrade():
+ op.drop_column('ps_endpoints', 'allow_overlap')
diff --git a/funcs/func_channel.c b/funcs/func_channel.c
index 673de51d0..3273b78c4 100644
--- a/funcs/func_channel.c
+++ b/funcs/func_channel.c
@@ -232,6 +232,10 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
<enum name="max_forwards">
<para>R/W The maximum number of forwards allowed.</para>
</enum>
+ <enum name="callid">
+ <para>R/O Call identifier log tag associated with the channel
+ e.g., <literal>[C-00000000]</literal>.</para>
+ </enum>
</enumlist>
<xi:include xpointer="xpointer(/docs/info[@name='CHANNEL'])" />
</parameter>
@@ -446,6 +450,17 @@ static int func_channel_read(struct ast_channel *chan, const char *function,
ast_channel_lock(chan);
snprintf(buf, len, "%d", ast_max_forwards_get(chan));
ast_channel_unlock(chan);
+ } else if (!strcasecmp(data, "callid")) {
+ struct ast_callid *callid;
+
+ buf[0] = '\0';
+ ast_channel_lock(chan);
+ callid = ast_channel_callid(chan);
+ if (callid) {
+ ast_callid_strnprint(buf, len, callid);
+ ast_callid_unref(callid);
+ }
+ ast_channel_unlock(chan);
} else if (!ast_channel_tech(chan) || !ast_channel_tech(chan)->func_channel_read || ast_channel_tech(chan)->func_channel_read(chan, function, data, buf, len)) {
ast_log(LOG_WARNING, "Unknown or unavailable item requested: '%s'\n", data);
ret = -1;
diff --git a/include/asterisk/autochan.h b/include/asterisk/autochan.h
index 319c203ab..128377b57 100644
--- a/include/asterisk/autochan.h
+++ b/include/asterisk/autochan.h
@@ -32,6 +32,7 @@
struct ast_autochan {
struct ast_channel *chan;
AST_LIST_ENTRY(ast_autochan) list;
+ ast_mutex_t lock;
};
/*!
@@ -61,19 +62,24 @@ struct ast_autochan {
* ast_autochan_channel_lock and ast_autochan_channel_unlock. An attempt to lock
* the autochan->chan directly may result in it being changed after you've
* retrieved the value of chan, but before you've had a chance to lock it.
- * First when chan is locked, the autochan structure is guaranteed to keep the
+ * While chan is locked, the autochan structure is guaranteed to keep the
* same channel.
*/
+/*!
+ * \brief Lock the autochan's channel lock.
+ *
+ * \note We must do deadlock avoidance because the channel lock is
+ * superior to the autochan lock in locking order.
+ */
#define ast_autochan_channel_lock(autochan) \
do { \
- struct ast_channel *autochan_chan = autochan->chan; \
- ast_channel_lock(autochan_chan); \
- if (autochan->chan == autochan_chan) { \
- break; \
+ ast_mutex_lock(&(autochan)->lock); \
+ while (ast_channel_trylock((autochan)->chan)) { \
+ DEADLOCK_AVOIDANCE(&(autochan)->lock); \
} \
- ast_channel_unlock(autochan_chan); \
- } while (1)
+ ast_mutex_unlock(&(autochan)->lock); \
+ } while (0)
#define ast_autochan_channel_unlock(autochan) \
ast_channel_unlock(autochan->chan)
diff --git a/include/asterisk/manager.h b/include/asterisk/manager.h
index 3f22d5f4b..afd9ca148 100644
--- a/include/asterisk/manager.h
+++ b/include/asterisk/manager.h
@@ -54,7 +54,7 @@
- \ref manager.c Main manager code file
*/
-#define AMI_VERSION "2.9.0"
+#define AMI_VERSION "2.10.0"
#define DEFAULT_MANAGER_PORT 5038 /* Default port for Asterisk management via TCP */
#define DEFAULT_MANAGER_TLS_PORT 5039 /* Default port for Asterisk management via TCP */
diff --git a/include/asterisk/res_hep.h b/include/asterisk/res_hep.h
index cfd213ad7..dba86e88b 100644
--- a/include/asterisk/res_hep.h
+++ b/include/asterisk/res_hep.h
@@ -72,6 +72,8 @@ struct hepv3_capture_info {
size_t len;
/*! If non-zero, the payload accompanying this capture info will be compressed */
unsigned int zipped:1;
+ /*! The IPPROTO_* protocol where we captured the packet */
+ int protocol_id;
};
/*!
diff --git a/include/asterisk/res_pjsip.h b/include/asterisk/res_pjsip.h
index 05a3eea44..59122b987 100644
--- a/include/asterisk/res_pjsip.h
+++ b/include/asterisk/res_pjsip.h
@@ -759,6 +759,8 @@ struct ast_sip_endpoint {
unsigned int asymmetric_rtp_codec;
/*! Use RTCP-MUX */
unsigned int rtcp_mux;
+ /*! Do we allow overlap dialling? */
+ unsigned int allow_overlap;
};
/*! URI parameter for symmetric transport */
diff --git a/main/autochan.c b/main/autochan.c
index c1e8b83f3..cf80d8f9b 100644
--- a/main/autochan.c
+++ b/main/autochan.c
@@ -48,15 +48,18 @@ struct ast_autochan *ast_autochan_setup(struct ast_channel *chan)
if (!(autochan = ast_calloc(1, sizeof(*autochan)))) {
return NULL;
}
+ ast_mutex_init(&autochan->lock);
autochan->chan = ast_channel_ref(chan);
- ast_channel_lock(autochan->chan); /* autochan is still private, no need for ast_autochan_channel_lock() */
+ ast_debug(1, "Created autochan %p to hold channel %s (%p)\n",
+ autochan, ast_channel_name(chan), chan);
+
+ /* autochan is still private, no need for ast_autochan_channel_lock() */
+ ast_channel_lock(autochan->chan);
AST_LIST_INSERT_TAIL(ast_channel_autochans(autochan->chan), autochan, list);
ast_channel_unlock(autochan->chan);
- ast_debug(1, "Created autochan %p to hold channel %s (%p)\n", autochan, ast_channel_name(chan), chan);
-
return autochan;
}
@@ -77,6 +80,8 @@ void ast_autochan_destroy(struct ast_autochan *autochan)
autochan->chan = ast_channel_unref(autochan->chan);
+ ast_mutex_destroy(&autochan->lock);
+
ast_free(autochan);
}
@@ -86,13 +91,16 @@ void ast_autochan_new_channel(struct ast_channel *old_chan, struct ast_channel *
AST_LIST_APPEND_LIST(ast_channel_autochans(new_chan), ast_channel_autochans(old_chan), list);
+ /* Deadlock avoidance is not needed since the channels are already locked. */
AST_LIST_TRAVERSE(ast_channel_autochans(new_chan), autochan, list) {
+ ast_mutex_lock(&autochan->lock);
if (autochan->chan == old_chan) {
- autochan->chan = ast_channel_unref(old_chan);
autochan->chan = ast_channel_ref(new_chan);
+ ast_channel_unref(old_chan);
ast_debug(1, "Autochan %p used to hold channel %s (%p) but now holds channel %s (%p)\n",
autochan, ast_channel_name(old_chan), old_chan, ast_channel_name(new_chan), new_chan);
}
+ ast_mutex_unlock(&autochan->lock);
}
}
diff --git a/main/message.c b/main/message.c
index 594853f3f..be0035d30 100644
--- a/main/message.c
+++ b/main/message.c
@@ -127,8 +127,10 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
</parameter>
<parameter name="from" required="false">
<para>A From URI for the message if needed for the
- message technology being used to send this message.</para>
- <xi:include xpointer="xpointer(/docs/info[@name='MessageFromInfo'])" />
+ message technology being used to send this message. This can be a
+ SIP(S) URI, such as <literal>Alice &lt;sip:alice@atlanta.com&gt;</literal>,
+ a string in the format <literal>alice@atlanta.com</literal>, or simply
+ a username such as <literal>alice</literal>.</para>
</parameter>
</syntax>
<description>
diff --git a/res/res_hep.c b/res/res_hep.c
index 15e779012..8d4987c03 100644
--- a/res/res_hep.c
+++ b/res/res_hep.c
@@ -441,6 +441,9 @@ struct hepv3_capture_info *hepv3_create_capture_info(const void *payload, size_t
memcpy(info->payload, payload, len);
info->len = len;
+ /* Set a reasonable default */
+ info->protocol_id = IPPROTO_UDP;
+
return info;
}
@@ -472,7 +475,7 @@ static int hep_queue_cb(void *data)
/* Build HEPv3 header, capture info, and calculate the total packet size */
memcpy(hg_pkt.header.id, "\x48\x45\x50\x33", 4);
- INITIALIZE_GENERIC_HEP_CHUNK_DATA(&hg_pkt.ip_proto, CHUNK_TYPE_IP_PROTOCOL_ID, 0x11);
+ INITIALIZE_GENERIC_HEP_CHUNK_DATA(&hg_pkt.ip_proto, CHUNK_TYPE_IP_PROTOCOL_ID, capture_info->protocol_id);
INITIALIZE_GENERIC_HEP_CHUNK_DATA(&hg_pkt.src_port, CHUNK_TYPE_SRC_PORT, htons(ast_sockaddr_port(&capture_info->src_addr)));
INITIALIZE_GENERIC_HEP_CHUNK_DATA(&hg_pkt.dst_port, CHUNK_TYPE_DST_PORT, htons(ast_sockaddr_port(&capture_info->dst_addr)));
INITIALIZE_GENERIC_HEP_CHUNK_DATA(&hg_pkt.time_sec, CHUNK_TYPE_TIMESTAMP_SEC, htonl(capture_info->capture_time.tv_sec));
diff --git a/res/res_hep_pjsip.c b/res/res_hep_pjsip.c
index 8f5baa2cb..1614b4319 100644
--- a/res/res_hep_pjsip.c
+++ b/res/res_hep_pjsip.c
@@ -73,6 +73,15 @@ static char *assign_uuid(const pj_str_t *call_id, const pj_str_t *local_tag, con
return uuid;
}
+static int transport_to_protocol_id(pjsip_transport *tp)
+{
+ /* XXX If we ever add SCTP support, we'll need to revisit */
+ if (tp->flag & PJSIP_TRANSPORT_RELIABLE) {
+ return IPPROTO_TCP;
+ }
+ return IPPROTO_UDP;
+}
+
static pj_status_t logging_on_tx_msg(pjsip_tx_data *tdata)
{
char local_buf[256];
@@ -126,6 +135,7 @@ static pj_status_t logging_on_tx_msg(pjsip_tx_data *tdata)
ast_sockaddr_parse(&capture_info->src_addr, local_buf, PARSE_PORT_REQUIRE);
ast_sockaddr_parse(&capture_info->dst_addr, remote_buf, PARSE_PORT_REQUIRE);
+ capture_info->protocol_id = transport_to_protocol_id(tdata->tp_info.transport);
capture_info->capture_time = ast_tvnow();
capture_info->capture_type = HEPV3_CAPTURE_TYPE_SIP;
capture_info->uuid = uuid;
@@ -185,6 +195,8 @@ static pj_bool_t logging_on_rx_msg(pjsip_rx_data *rdata)
ast_sockaddr_parse(&capture_info->src_addr, remote_buf, PARSE_PORT_REQUIRE);
ast_sockaddr_parse(&capture_info->dst_addr, local_buf, PARSE_PORT_REQUIRE);
+
+ capture_info->protocol_id = transport_to_protocol_id(rdata->tp_info.transport);
capture_info->capture_time.tv_sec = rdata->pkt_info.timestamp.sec;
capture_info->capture_time.tv_usec = rdata->pkt_info.timestamp.msec * 1000;
capture_info->capture_type = HEPV3_CAPTURE_TYPE_SIP;
diff --git a/res/res_pjsip.c b/res/res_pjsip.c
index 7b10f47f6..fc4985657 100644
--- a/res/res_pjsip.c
+++ b/res/res_pjsip.c
@@ -100,6 +100,9 @@
<configOption name="allow">
<synopsis>Media Codec(s) to allow</synopsis>
</configOption>
+ <configOption name="allow_overlap" default="yes">
+ <synopsis>Enable RFC3578 overlap dialing support.</synopsis>
+ </configOption>
<configOption name="aors">
<synopsis>AoR(s) to be used with the endpoint</synopsis>
<description><para>
@@ -2122,6 +2125,9 @@
<parameter name="SubscribeContext">
<para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='endpoint']/configOption[@name='subscribe_context']/synopsis/node())"/></para>
</parameter>
+ <parameter name="Allowoverlap">
+ <para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='endpoint']/configOption[@name='allow_overlap']/synopsis/node())"/></para>
+ </parameter>
</syntax>
</managerEventInstance>
</managerEvent>
diff --git a/res/res_pjsip/pjsip_configuration.c b/res/res_pjsip/pjsip_configuration.c
index eb8e19712..511ea41c1 100644
--- a/res/res_pjsip/pjsip_configuration.c
+++ b/res/res_pjsip/pjsip_configuration.c
@@ -1939,6 +1939,7 @@ int ast_res_pjsip_initialize_configuration(const struct ast_module_info *ast_mod
ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "contact_user", "", contact_user_handler, contact_user_to_str, NULL, 0, 0);
ast_sorcery_object_field_register(sip_sorcery, "endpoint", "asymmetric_rtp_codec", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, asymmetric_rtp_codec));
ast_sorcery_object_field_register(sip_sorcery, "endpoint", "rtcp_mux", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, rtcp_mux));
+ ast_sorcery_object_field_register(sip_sorcery, "endpoint", "allow_overlap", "yes", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, allow_overlap));
if (ast_sip_initialize_sorcery_transport()) {
ast_log(LOG_ERROR, "Failed to register SIP transport support with sorcery\n");
diff --git a/res/res_pjsip_messaging.c b/res/res_pjsip_messaging.c
index 835a38393..8b465e007 100644
--- a/res/res_pjsip_messaging.c
+++ b/res/res_pjsip_messaging.c
@@ -235,7 +235,15 @@ static void update_from(pjsip_tx_data *tdata, char *from)
parsed_name_addr = (pjsip_name_addr *) pjsip_parse_uri(tdata->pool, from,
strlen(from), PJSIP_PARSE_URI_AS_NAMEADDR);
if (parsed_name_addr) {
- pjsip_sip_uri *parsed_uri = pjsip_uri_get_uri(parsed_name_addr->uri);
+ pjsip_sip_uri *parsed_uri;
+
+ if (!PJSIP_URI_SCHEME_IS_SIP(parsed_name_addr->uri)
+ && !PJSIP_URI_SCHEME_IS_SIPS(parsed_name_addr->uri)) {
+ ast_log(LOG_WARNING, "From address '%s' is not a valid SIP/SIPS URI\n", from);
+ return;
+ }
+
+ parsed_uri = pjsip_uri_get_uri(parsed_name_addr->uri);
if (pj_strlen(&parsed_name_addr->display)) {
pj_strdup(tdata->pool, &name_addr->display, &parsed_name_addr->display);
diff --git a/res/res_pjsip_nat.c b/res/res_pjsip_nat.c
index 7404ef5f0..5fcab6378 100644
--- a/res/res_pjsip_nat.c
+++ b/res/res_pjsip_nat.c
@@ -262,32 +262,33 @@ static pj_status_t nat_on_tx_message(pjsip_tx_data *tdata)
return PJ_SUCCESS;
}
- if ( !transport_state->localnet || ast_sockaddr_isnull(&transport_state->external_address)) {
- return PJ_SUCCESS;
- }
-
- ast_sockaddr_parse(&addr, tdata->tp_info.dst_name, PARSE_PORT_FORBID);
- ast_sockaddr_set_port(&addr, tdata->tp_info.dst_port);
+ if (transport_state->localnet) {
+ ast_sockaddr_parse(&addr, tdata->tp_info.dst_name, PARSE_PORT_FORBID);
+ ast_sockaddr_set_port(&addr, tdata->tp_info.dst_port);
- /* See if where we are sending this request is local or not, and if not that we can get a Contact URI to modify */
- if (ast_apply_ha(transport_state->localnet, &addr) != AST_SENSE_ALLOW) {
- return PJ_SUCCESS;
+ /* See if where we are sending this request is local or not, and if not that we can get a Contact URI to modify */
+ if (ast_apply_ha(transport_state->localnet, &addr) != AST_SENSE_ALLOW) {
+ ast_debug(5, "Request is being sent to local address, skipping NAT manipulation\n");
+ return PJ_SUCCESS;
+ }
}
- /* Update the contact header with the external address */
- if (uri || (uri = nat_get_contact_sip_uri(tdata))) {
- pj_strdup2(tdata->pool, &uri->host, ast_sockaddr_stringify_host(&transport_state->external_address));
- if (transport->external_signaling_port) {
- uri->port = transport->external_signaling_port;
- ast_debug(4, "Re-wrote Contact URI port to %d\n", uri->port);
+ if (!ast_sockaddr_isnull(&transport_state->external_address)) {
+ /* Update the contact header with the external address */
+ if (uri || (uri = nat_get_contact_sip_uri(tdata))) {
+ pj_strdup2(tdata->pool, &uri->host, ast_sockaddr_stringify_host(&transport_state->external_address));
+ if (transport->external_signaling_port) {
+ uri->port = transport->external_signaling_port;
+ ast_debug(4, "Re-wrote Contact URI port to %d\n", uri->port);
+ }
}
- }
- /* Update the via header if relevant */
- if ((tdata->msg->type == PJSIP_REQUEST_MSG) && (via || (via = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_VIA, NULL)))) {
- pj_strdup2(tdata->pool, &via->sent_by.host, ast_sockaddr_stringify_host(&transport_state->external_address));
- if (transport->external_signaling_port) {
- via->sent_by.port = transport->external_signaling_port;
+ /* Update the via header if relevant */
+ if ((tdata->msg->type == PJSIP_REQUEST_MSG) && (via || (via = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_VIA, NULL)))) {
+ pj_strdup2(tdata->pool, &via->sent_by.host, ast_sockaddr_stringify_host(&transport_state->external_address));
+ if (transport->external_signaling_port) {
+ via->sent_by.port = transport->external_signaling_port;
+ }
}
}
diff --git a/res/res_pjsip_sdp_rtp.c b/res/res_pjsip_sdp_rtp.c
index ecc39d87d..d44171cf8 100644
--- a/res/res_pjsip_sdp_rtp.c
+++ b/res/res_pjsip_sdp_rtp.c
@@ -1465,10 +1465,11 @@ static void change_outgoing_sdp_stream_media_address(pjsip_tx_data *tdata, struc
ast_sockaddr_parse(&addr, host, PARSE_PORT_FORBID);
/* Is the address within the SDP inside the same network? */
- if (ast_apply_ha(transport_state->localnet, &addr) == AST_SENSE_ALLOW) {
+ if (transport_state->localnet
+ && ast_apply_ha(transport_state->localnet, &addr) == AST_SENSE_ALLOW) {
return;
}
-
+ ast_debug(5, "Setting media address to %s\n", transport->external_media_address);
pj_strdup2(tdata->pool, &stream->conn->addr, transport->external_media_address);
}
diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c
index 98ee87209..53841c44a 100644
--- a/res/res_pjsip_session.c
+++ b/res/res_pjsip_session.c
@@ -1984,10 +1984,17 @@ static enum sip_get_destination_result get_destination(struct ast_sip_session *s
return SIP_GET_DEST_EXTEN_FOUND;
}
- /* XXX In reality, we'll likely have further options so that partial matches
- * can be indicated here, but for getting something up and running, we're going
- * to return a "not exists" error here.
+
+ /*
+ * Check for partial match via overlap dialling (if enabled)
*/
+ if (session->endpoint->allow_overlap && (
+ !strncmp(session->exten, pickupexten, strlen(session->exten)) ||
+ ast_canmatch_extension(NULL, session->endpoint->context, session->exten, 1, NULL))) {
+ /* Overlap partial match */
+ return SIP_GET_DEST_EXTEN_PARTIAL;
+ }
+
return SIP_GET_DEST_EXTEN_NOT_FOUND;
}
@@ -2104,8 +2111,17 @@ static int new_invite(void *data)
pjsip_inv_terminate(invite->session->inv_session, 416, PJ_TRUE);
}
goto end;
- case SIP_GET_DEST_EXTEN_NOT_FOUND:
case SIP_GET_DEST_EXTEN_PARTIAL:
+ ast_debug(1, "Call from '%s' (%s:%s:%d) to extension '%s' - partial match\n", ast_sorcery_object_get_id(invite->session->endpoint),
+ invite->rdata->tp_info.transport->type_name, invite->rdata->pkt_info.src_name, invite->rdata->pkt_info.src_port, invite->session->exten);
+
+ if (pjsip_inv_initial_answer(invite->session->inv_session, invite->rdata, 484, NULL, NULL, &tdata) == PJ_SUCCESS) {
+ ast_sip_session_send_response(invite->session, tdata);
+ } else {
+ pjsip_inv_terminate(invite->session->inv_session, 484, PJ_TRUE);
+ }
+ goto end;
+ case SIP_GET_DEST_EXTEN_NOT_FOUND:
default:
ast_log(LOG_NOTICE, "Call from '%s' (%s:%s:%d) to extension '%s' rejected because extension not found in context '%s'.\n",
ast_sorcery_object_get_id(invite->session->endpoint), invite->rdata->tp_info.transport->type_name, invite->rdata->pkt_info.src_name,
@@ -3090,7 +3106,10 @@ static void session_outgoing_nat_hook(pjsip_tx_data *tdata, struct ast_sip_trans
ast_copy_pj_str(host, &sdp->conn->addr, sizeof(host));
ast_sockaddr_parse(&addr, host, PARSE_PORT_FORBID);
- if (ast_apply_ha(transport_state->localnet, &addr) != AST_SENSE_ALLOW) {
+ if (!transport_state->localnet
+ || (transport_state->localnet
+ && ast_apply_ha(transport_state->localnet, &addr) == AST_SENSE_ALLOW)) {
+ ast_debug(5, "Setting external media address to %s\n", transport->external_media_address);
pj_strdup2(tdata->pool, &sdp->conn->addr, transport->external_media_address);
}
}
diff --git a/res/res_pjsip_t38.c b/res/res_pjsip_t38.c
index 0787f0763..16d50cd27 100644
--- a/res/res_pjsip_t38.c
+++ b/res/res_pjsip_t38.c
@@ -869,10 +869,11 @@ static void change_outgoing_sdp_stream_media_address(pjsip_tx_data *tdata, struc
ast_sockaddr_parse(&addr, host, PARSE_PORT_FORBID);
/* Is the address within the SDP inside the same network? */
- if (ast_apply_ha(transport_state->localnet, &addr) == AST_SENSE_ALLOW) {
+ if (transport_state->localnet
+ && ast_apply_ha(transport_state->localnet, &addr) == AST_SENSE_ALLOW) {
return;
}
-
+ ast_debug(5, "Setting media address to %s\n", transport->external_media_address);
pj_strdup2(tdata->pool, &stream->conn->addr, transport->external_media_address);
}
diff --git a/third-party/pjproject/patches/0025-fix-print-xml-crash.patch b/third-party/pjproject/patches/0025-fix-print-xml-crash.patch
new file mode 100644
index 000000000..eafc38906
--- /dev/null
+++ b/third-party/pjproject/patches/0025-fix-print-xml-crash.patch
@@ -0,0 +1,24 @@
+From 1bc5ca699f523bd8e910203a3eb4dee58f366976 Mon Sep 17 00:00:00 2001
+From: Joshua Elson <joshelson@gmail.com>
+Date: Mon, 20 Mar 2017 19:28:47 -0600
+Subject: [PATCH] Prevent memory corruption on xml tag write
+
+---
+ pjlib-util/src/pjlib-util/xml.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/pjlib-util/src/pjlib-util/xml.c b/pjlib-util/src/pjlib-util/xml.c
+index 296b232..b0aad26 100644
+--- a/pjlib-util/src/pjlib-util/xml.c
++++ b/pjlib-util/src/pjlib-util/xml.c
+@@ -248,6 +248,7 @@ static int xml_print_node( const pj_xml_node *node, int indent,
+ if (node->content.slen==0 &&
+ node->node_head.next==(pj_xml_node*)&node->node_head)
+ {
++ if (SIZE_LEFT() < 3) return -1;
+ *p++ = ' ';
+ *p++ = '/';
+ *p++ = '>';
+--
+2.10.1 (Apple Git-78)
+