diff options
-rw-r--r-- | CHANGES | 11 | ||||
-rw-r--r-- | apps/app_chanspy.c | 62 | ||||
-rw-r--r-- | apps/app_mixmonitor.c | 21 | ||||
-rw-r--r-- | apps/app_queue.c | 70 | ||||
-rw-r--r-- | bridges/bridge_softmix.c | 3 | ||||
-rw-r--r-- | configs/samples/pjsip.conf.sample | 1 | ||||
-rw-r--r-- | contrib/ast-db-manage/config/versions/8fce4c573e15_add_pjsip_allow_overlap.py | 31 | ||||
-rw-r--r-- | funcs/func_channel.c | 15 | ||||
-rw-r--r-- | include/asterisk/autochan.h | 20 | ||||
-rw-r--r-- | include/asterisk/manager.h | 2 | ||||
-rw-r--r-- | include/asterisk/res_hep.h | 2 | ||||
-rw-r--r-- | include/asterisk/res_pjsip.h | 2 | ||||
-rw-r--r-- | main/autochan.c | 16 | ||||
-rw-r--r-- | main/message.c | 6 | ||||
-rw-r--r-- | res/res_hep.c | 5 | ||||
-rw-r--r-- | res/res_hep_pjsip.c | 12 | ||||
-rw-r--r-- | res/res_pjsip.c | 6 | ||||
-rw-r--r-- | res/res_pjsip/pjsip_configuration.c | 1 | ||||
-rw-r--r-- | res/res_pjsip_messaging.c | 10 | ||||
-rw-r--r-- | res/res_pjsip_nat.c | 43 | ||||
-rw-r--r-- | res/res_pjsip_sdp_rtp.c | 5 | ||||
-rw-r--r-- | res/res_pjsip_session.c | 29 | ||||
-rw-r--r-- | res/res_pjsip_t38.c | 5 | ||||
-rw-r--r-- | third-party/pjproject/patches/0025-fix-print-xml-crash.patch | 24 |
24 files changed, 269 insertions, 133 deletions
@@ -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 <sip:alice@atlanta.com></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) + |