summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES6
-rw-r--r--apps/app_confbridge.c370
-rw-r--r--apps/app_followme.c26
-rw-r--r--apps/app_queue.c2
-rw-r--r--apps/confbridge/conf_state_multi_marked.c9
-rw-r--r--apps/confbridge/include/confbridge.h31
-rw-r--r--channels/chan_sip.c61
-rw-r--r--contrib/scripts/safe_asterisk13
-rw-r--r--res/res_pjsip/pjsip_distributor.c12
-rw-r--r--res/res_pjsip/pjsip_global_headers.c8
10 files changed, 455 insertions, 83 deletions
diff --git a/CHANGES b/CHANGES
index d36da1f99..0703b38d7 100644
--- a/CHANGES
+++ b/CHANGES
@@ -60,6 +60,12 @@ res_pjsip
configure these options then you already had to do a reload after making
changes.
+app_confbridge
+------------------
+ * Some sounds played into the bridge are played asynchronously. This, for
+ instance, allows a channel to immediately exit the ConfBridge without having
+ to wait for a leave announcement to play.
+
------------------------------------------------------------------------------
--- Functionality changes from Asterisk 13.10.0 to Asterisk 13.11.0 ----------
------------------------------------------------------------------------------
diff --git a/apps/app_confbridge.c b/apps/app_confbridge.c
index ec4136580..f3b697635 100644
--- a/apps/app_confbridge.c
+++ b/apps/app_confbridge.c
@@ -1627,6 +1627,26 @@ static void leave_conference(struct confbridge_user *user)
user->conference = NULL;
}
+static void playback_common(struct confbridge_conference *conference, const char *filename, int say_number)
+{
+ /* Don't try to play if the playback channel has been hung up */
+ if (!conference->playback_chan) {
+ return;
+ }
+
+ ast_autoservice_stop(conference->playback_chan);
+
+ /* The channel is all under our control, in goes the prompt */
+ if (!ast_strlen_zero(filename)) {
+ ast_stream_and_wait(conference->playback_chan, filename, "");
+ } else if (say_number >= 0) {
+ ast_say_number(conference->playback_chan, say_number, "",
+ ast_channel_language(conference->playback_chan), NULL);
+ }
+
+ ast_autoservice_start(conference->playback_chan);
+}
+
struct playback_task_data {
struct confbridge_conference *conference;
const char *filename;
@@ -1653,23 +1673,8 @@ static int playback_task(void *data)
{
struct playback_task_data *ptd = data;
- /* Don't try to play if the playback channel has been hung up */
- if (!ptd->conference->playback_chan) {
- goto end;
- }
-
- ast_autoservice_stop(ptd->conference->playback_chan);
+ playback_common(ptd->conference, ptd->filename, ptd->say_number);
- /* The channel is all under our control, in goes the prompt */
- if (!ast_strlen_zero(ptd->filename)) {
- ast_stream_and_wait(ptd->conference->playback_chan, ptd->filename, "");
- } else if (ptd->say_number >= 0) {
- ast_say_number(ptd->conference->playback_chan, ptd->say_number, "",
- ast_channel_language(ptd->conference->playback_chan), NULL);
- }
- ast_autoservice_start(ptd->conference->playback_chan);
-
-end:
ast_mutex_lock(&ptd->lock);
ptd->playback_finished = 1;
ast_cond_signal(&ptd->cond);
@@ -1701,7 +1706,11 @@ static int play_sound_helper(struct confbridge_conference *conference, const cha
struct playback_task_data ptd;
/* Do not waste resources trying to play files that do not exist */
- if (!ast_strlen_zero(filename) && !sound_file_exists(filename)) {
+ if (ast_strlen_zero(filename)) {
+ if (say_number < 0) {
+ return 0;
+ }
+ } else if (!sound_file_exists(filename)) {
return 0;
}
@@ -1735,6 +1744,274 @@ int play_sound_file(struct confbridge_conference *conference, const char *filena
return play_sound_helper(conference, filename, -1);
}
+struct async_playback_task_data {
+ struct confbridge_conference *conference;
+ int say_number;
+ struct ast_channel *initiator;
+ char filename[0];
+};
+
+struct async_datastore_data {
+ ast_mutex_t lock;
+ ast_cond_t cond;
+ int wait;
+};
+
+static void async_datastore_data_destroy(void *data)
+{
+ struct async_datastore_data *add = data;
+
+ ast_mutex_destroy(&add->lock);
+ ast_cond_destroy(&add->cond);
+
+ ast_free(add);
+}
+
+/*!
+ * \brief Datastore used for timing of async announcement playback
+ *
+ * Announcements that are played to the entire conference can be played
+ * asynchronously (i.e. The channel that queues the playback does not wait
+ * for the playback to complete before continuing)
+ *
+ * The thing about async announcements is that the channel that queues the
+ * announcement is either not in the bridge or is in some other way "occupied"
+ * at the time the announcement is queued. Because of that, the initiator of
+ * the announcement may enter after the announcement has already started,
+ * resulting in the sound being "clipped".
+ *
+ * This datastore makes it so that the channel that queues the async announcement
+ * can say "I'm ready now". This way the announcement does not start until the
+ * initiator of the announcement is ready to hear the sound.
+ */
+static struct ast_datastore_info async_datastore_info = {
+ .type = "Confbridge async playback",
+ .destroy = async_datastore_data_destroy,
+};
+
+static struct async_datastore_data *async_datastore_data_alloc(void)
+{
+ struct async_datastore_data *add;
+
+ add = ast_malloc(sizeof(*add));
+ if (!add) {
+ return NULL;
+ }
+
+ ast_mutex_init(&add->lock);
+ ast_cond_init(&add->cond, NULL);
+ add->wait = 1;
+
+ return add;
+}
+
+/*!
+ * \brief Prepare the async playback datastore
+ *
+ * This is done prior to queuing an async announcement. If the
+ * datastore has not yet been created, it is allocated and initialized.
+ * If it already exists, we set it to be in "waiting" mode.
+ *
+ * \param initiator The channel that is queuing the async playback
+ * \retval 0 Success
+ * \retval -1 Failure :(
+ */
+static int setup_async_playback_datastore(struct ast_channel *initiator)
+{
+ struct ast_datastore *async_datastore;
+
+ async_datastore = ast_channel_datastore_find(initiator, &async_datastore_info, NULL);
+ if (async_datastore) {
+ struct async_datastore_data *add;
+
+ add = async_datastore->data;
+ add->wait = 1;
+
+ return 0;
+ }
+
+ async_datastore = ast_datastore_alloc(&async_datastore_info, NULL);
+ if (!async_datastore) {
+ return -1;
+ }
+
+ async_datastore->data = async_datastore_data_alloc();
+ if (!async_datastore->data) {
+ ast_datastore_free(async_datastore);
+ return -1;
+ }
+
+ ast_channel_datastore_add(initiator, async_datastore);
+ return 0;
+}
+
+static struct async_playback_task_data *async_playback_task_data_alloc(
+ struct confbridge_conference *conference, const char *filename, int say_number,
+ struct ast_channel *initiator)
+{
+ struct async_playback_task_data *aptd;
+
+ aptd = ast_malloc(sizeof(*aptd) + strlen(filename) + 1);
+ if (!aptd) {
+ return NULL;
+ }
+
+ /* Safe */
+ strcpy(aptd->filename, filename);
+ aptd->say_number = say_number;
+
+ /* You may think that we need to bump the conference refcount since we are pushing
+ * this task to the taskprocessor.
+ *
+ * In this case, that actually causes a problem. The destructor for the conference
+ * pushes a hangup task into the taskprocessor and waits for it to complete before
+ * continuing. If the destructor gets called from a taskprocessor task, we're
+ * deadlocked.
+ *
+ * So is there a risk of the conference being freed out from under us? No. Since
+ * the destructor pushes a task into the taskprocessor and waits for it to complete,
+ * the destructor cannot free the conference out from under us. No further tasks
+ * can be queued onto the taskprocessor after the hangup since no channels are referencing
+ * the conference at that point any more.
+ */
+ aptd->conference = conference;
+
+ aptd->initiator = initiator;
+ if (initiator) {
+ ast_channel_ref(initiator);
+ ast_channel_lock(aptd->initiator);
+ /* We don't really care if this fails. If the datastore fails to get set up
+ * we'll still play the announcement. It's possible that the sound will be
+ * clipped for the initiator, but that's not the end of the world.
+ */
+ setup_async_playback_datastore(aptd->initiator);
+ ast_channel_unlock(aptd->initiator);
+ }
+
+ return aptd;
+}
+
+static void async_playback_task_data_destroy(struct async_playback_task_data *aptd)
+{
+ ast_channel_cleanup(aptd->initiator);
+ ast_free(aptd);
+}
+
+/*!
+ * \brief Wait for the initiator of an async playback to be ready
+ *
+ * See the description on the async_datastore_info structure for more
+ * information about what this is about.
+ *
+ * \param initiator The channel that queued the async announcement
+ */
+static void wait_for_initiator(struct ast_channel *initiator)
+{
+ struct ast_datastore *async_datastore;
+ struct async_datastore_data *add;
+
+ ast_channel_lock(initiator);
+ async_datastore = ast_channel_datastore_find(initiator, &async_datastore_info, NULL);
+ ast_channel_unlock(initiator);
+
+ if (!async_datastore) {
+ return;
+ }
+
+ add = async_datastore->data;
+
+ ast_mutex_lock(&add->lock);
+ while (add->wait) {
+ ast_cond_wait(&add->cond, &add->lock);
+ }
+ ast_mutex_unlock(&add->lock);
+}
+
+/*!
+ * \brief Play an announcement into a confbridge asynchronously
+ *
+ * This runs in the playback queue taskprocessor. This ensures that
+ * all playbacks are handled in sequence and do not play over top one
+ * another.
+ *
+ * \param data An async_playback_task_data
+ * \return 0
+ */
+static int async_playback_task(void *data)
+{
+ struct async_playback_task_data *aptd = data;
+
+ /* Wait for the initiator to get back in the bridge or be hung up */
+ if (aptd->initiator) {
+ wait_for_initiator(aptd->initiator);
+ }
+
+ playback_common(aptd->conference, aptd->filename, aptd->say_number);
+
+ async_playback_task_data_destroy(aptd);
+ return 0;
+}
+
+static int async_play_sound_helper(struct confbridge_conference *conference,
+ const char *filename, int say_number, struct ast_channel *initiator)
+{
+ struct async_playback_task_data *aptd;
+
+ /* Do not waste resources trying to play files that do not exist */
+ if (ast_strlen_zero(filename)) {
+ if (say_number < 0) {
+ return 0;
+ }
+ } else if (!sound_file_exists(filename)) {
+ return 0;
+ }
+
+ aptd = async_playback_task_data_alloc(conference, filename, say_number, initiator);
+ if (!aptd) {
+ return -1;
+ }
+
+ if (ast_taskprocessor_push(conference->playback_queue, async_playback_task, aptd)) {
+ if (!ast_strlen_zero(filename)) {
+ ast_log(LOG_WARNING, "Unable to play file '%s' to conference '%s'\n",
+ filename, conference->name);
+ } else {
+ ast_log(LOG_WARNING, "Unable to say number '%d' to conference '%s'\n",
+ say_number, conference->name);
+ }
+ async_playback_task_data_destroy(aptd);
+ return -1;
+ }
+
+ return 0;
+}
+
+int async_play_sound_file(struct confbridge_conference *conference,
+ const char *filename, struct ast_channel *initiator)
+{
+ return async_play_sound_helper(conference, filename, -1, initiator);
+}
+
+void async_play_sound_ready(struct ast_channel *chan)
+{
+ struct ast_datastore *async_datastore;
+ struct async_datastore_data *add;
+
+ ast_channel_lock(chan);
+ async_datastore = ast_channel_datastore_find(chan, &async_datastore_info, NULL);
+ ast_channel_unlock(chan);
+ if (!async_datastore) {
+ return;
+ }
+
+ add = async_datastore->data;
+
+ ast_mutex_lock(&add->lock);
+ add->wait = 0;
+ ast_cond_signal(&add->cond);
+ ast_mutex_unlock(&add->lock);
+}
+
/*!
* \brief Play number into the conference bridge
*
@@ -1866,6 +2143,12 @@ static int conf_rec_name(struct confbridge_user *user, const char *conf_name)
return 0;
}
+static int join_callback(struct ast_bridge_channel *bridge_channel, void *ignore)
+{
+ async_play_sound_ready(bridge_channel->chan);
+ return 0;
+}
+
/*! \brief The ConfBridge application */
static int confbridge_exec(struct ast_channel *chan, const char *data)
{
@@ -2044,10 +2327,14 @@ static int confbridge_exec(struct ast_channel *chan, const char *data)
if (!quiet) {
const char *join_sound = conf_get_sound(CONF_SOUND_JOIN, conference->b_profile.sounds);
- ast_stream_and_wait(chan, join_sound, "");
- ast_autoservice_start(chan);
- play_sound_file(conference, join_sound);
- ast_autoservice_stop(chan);
+ if (strcmp(conference->b_profile.language, ast_channel_language(chan))) {
+ ast_stream_and_wait(chan, join_sound, "");
+ ast_autoservice_start(chan);
+ play_sound_file(conference, join_sound);
+ ast_autoservice_stop(chan);
+ } else {
+ async_play_sound_file(conference, join_sound, chan);
+ }
}
if (user.u_profile.timeout) {
@@ -2067,6 +2354,11 @@ static int confbridge_exec(struct ast_channel *chan, const char *data)
/* Join our conference bridge for real */
send_join_event(&user, conference);
+
+ if (ast_bridge_join_hook(&user.features, join_callback, NULL, NULL, 0)) {
+ async_play_sound_ready(user.chan);
+ }
+
ast_bridge_join(conference->bridge,
chan,
NULL,
@@ -2074,6 +2366,11 @@ static int confbridge_exec(struct ast_channel *chan, const char *data)
&user.tech_args,
0);
+ /* This is a catch-all in case joining the bridge failed or for some reason
+ * an async announcement got queued up and hasn't been told to play yet
+ */
+ async_play_sound_ready(chan);
+
if (!user.kicked && ast_check_hangup(chan)) {
pbx_builtin_setvar_helper(chan, "CONFBRIDGE_RESULT", "HANGUP");
}
@@ -2098,19 +2395,15 @@ static int confbridge_exec(struct ast_channel *chan, const char *data)
/* if this user has a intro, play it when leaving */
if (!quiet && !ast_strlen_zero(user.name_rec_location)) {
- ast_autoservice_start(chan);
- play_sound_file(conference, user.name_rec_location);
- play_sound_file(conference,
- conf_get_sound(CONF_SOUND_HAS_LEFT, conference->b_profile.sounds));
- ast_autoservice_stop(chan);
+ async_play_sound_file(conference, user.name_rec_location, NULL);
+ async_play_sound_file(conference,
+ conf_get_sound(CONF_SOUND_HAS_LEFT, conference->b_profile.sounds), NULL);
}
/* play the leave sound */
if (!quiet) {
const char *leave_sound = conf_get_sound(CONF_SOUND_LEAVE, conference->b_profile.sounds);
- ast_autoservice_start(chan);
- play_sound_file(conference, leave_sound);
- ast_autoservice_stop(chan);
+ async_play_sound_file(conference, leave_sound, NULL);
}
/* If the user was kicked from the conference play back the audio prompt for it */
@@ -2183,13 +2476,18 @@ static int action_toggle_mute_participants(struct confbridge_conference *confere
mute ? CONF_SOUND_PARTICIPANTS_MUTED : CONF_SOUND_PARTICIPANTS_UNMUTED,
conference->b_profile.sounds);
- /* The host needs to hear it seperately, as they don't get the audio from play_sound_helper */
- ast_stream_and_wait(user->chan, sound_to_play, "");
+ if (strcmp(conference->b_profile.language, ast_channel_language(user->chan))) {
+ /* The host needs to hear it seperately, as they don't get the audio from play_sound_helper */
+ ast_stream_and_wait(user->chan, sound_to_play, "");
- /* Announce to the group that all participants are muted */
- ast_autoservice_start(user->chan);
- play_sound_helper(conference, sound_to_play, 0);
- ast_autoservice_stop(user->chan);
+ /* Announce to the group that all participants are muted */
+ ast_autoservice_start(user->chan);
+ play_sound_file(conference, sound_to_play);
+ ast_autoservice_stop(user->chan);
+ } else {
+ /* Playing the sound asynchronously lets the sound be heard by everyone at once */
+ async_play_sound_file(conference, sound_to_play, user->chan);
+ }
return 0;
}
@@ -2474,6 +2772,8 @@ int conf_handle_dtmf(struct ast_bridge_channel *bridge_channel,
/* See if music on hold needs to be started back up again */
conf_moh_unsuspend(user);
+ async_play_sound_ready(bridge_channel->chan);
+
return 0;
}
diff --git a/apps/app_followme.c b/apps/app_followme.c
index af6bb1039..602806b39 100644
--- a/apps/app_followme.c
+++ b/apps/app_followme.c
@@ -311,8 +311,16 @@ static struct call_followme *alloc_profile(const char *fmname)
ast_mutex_init(&f->lock);
ast_copy_string(f->name, fmname, sizeof(f->name));
- f->moh[0] = '\0';
+ AST_LIST_HEAD_INIT_NOLOCK(&f->numbers);
+ AST_LIST_HEAD_INIT_NOLOCK(&f->blnumbers);
+ AST_LIST_HEAD_INIT_NOLOCK(&f->wlnumbers);
+ return f;
+}
+
+static void init_profile(struct call_followme *f, int activate)
+{
f->context[0] = '\0';
+ ast_copy_string(f->moh, defaultmoh, sizeof(f->moh));
ast_copy_string(f->takecall, takecall, sizeof(f->takecall));
ast_copy_string(f->nextindp, nextindp, sizeof(f->nextindp));
ast_copy_string(f->callfromprompt, callfromprompt, sizeof(f->callfromprompt));
@@ -321,16 +329,9 @@ static struct call_followme *alloc_profile(const char *fmname)
ast_copy_string(f->plsholdprompt, plsholdprompt, sizeof(f->plsholdprompt));
ast_copy_string(f->statusprompt, statusprompt, sizeof(f->statusprompt));
ast_copy_string(f->sorryprompt, sorryprompt, sizeof(f->sorryprompt));
- AST_LIST_HEAD_INIT_NOLOCK(&f->numbers);
- AST_LIST_HEAD_INIT_NOLOCK(&f->blnumbers);
- AST_LIST_HEAD_INIT_NOLOCK(&f->wlnumbers);
- return f;
-}
-
-static void init_profile(struct call_followme *f)
-{
- f->active = 1;
- ast_copy_string(f->moh, defaultmoh, sizeof(f->moh));
+ if (activate) {
+ f->active = 1;
+ }
}
@@ -503,7 +504,7 @@ static int reload_followme(int reload)
if (!new)
ast_mutex_lock(&f->lock);
/* Re-initialize the profile */
- init_profile(f);
+ init_profile(f, 1);
free_numbers(f);
var = ast_variable_browse(cfg, cat);
while (var) {
@@ -1216,6 +1217,7 @@ static struct call_followme *find_realtime(const char *name)
ast_free(str);
return NULL;
}
+ init_profile(new_follower, 0);
for (v = var; v; v = v->next) {
if (!strcasecmp(v->name, "active")) {
diff --git a/apps/app_queue.c b/apps/app_queue.c
index 9b283d467..45b5683ed 100644
--- a/apps/app_queue.c
+++ b/apps/app_queue.c
@@ -9197,7 +9197,7 @@ static void do_print(struct mansession *s, int fd, const char *str)
static char *__queues_show(struct mansession *s, int fd, int argc, const char * const *argv)
{
struct call_queue *q;
- struct ast_str *out = ast_str_alloca(240);
+ struct ast_str *out = ast_str_alloca(512);
int found = 0;
time_t now = time(NULL);
struct ao2_iterator queue_iter;
diff --git a/apps/confbridge/conf_state_multi_marked.c b/apps/confbridge/conf_state_multi_marked.c
index fabe99b90..17ca65cc2 100644
--- a/apps/confbridge/conf_state_multi_marked.c
+++ b/apps/confbridge/conf_state_multi_marked.c
@@ -160,12 +160,9 @@ static void leave_marked(struct confbridge_user *user)
if (need_prompt) {
/* Play back the audio prompt saying the leader has left the conference */
if (!ast_test_flag(&user->u_profile, USER_OPT_QUIET)) {
- ao2_unlock(user->conference);
- ast_autoservice_start(user->chan);
- play_sound_file(user->conference,
- conf_get_sound(CONF_SOUND_LEADER_HAS_LEFT, user->conference->b_profile.sounds));
- ast_autoservice_stop(user->chan);
- ao2_lock(user->conference);
+ async_play_sound_file(user->conference,
+ conf_get_sound(CONF_SOUND_LEADER_HAS_LEFT, user->conference->b_profile.sounds),
+ NULL);
}
AST_LIST_TRAVERSE(&user->conference->waiting_list, user_iter, list) {
diff --git a/apps/confbridge/include/confbridge.h b/apps/confbridge/include/confbridge.h
index 451d81098..5ea3b4527 100644
--- a/apps/confbridge/include/confbridge.h
+++ b/apps/confbridge/include/confbridge.h
@@ -386,6 +386,37 @@ int func_confbridge_helper(struct ast_channel *chan, const char *cmd, char *data
*/
int play_sound_file(struct confbridge_conference *conference, const char *filename);
+/*!
+ * \brief Play sound file into conference bridge asynchronously
+ *
+ * If the initiator parameter is non-NULL, then the playback will wait for
+ * that initiator channel to get back in the bridge before playing the sound
+ * file. This way, the initiator has no danger of hearing a "clipped" file.
+ *
+ * \param conference The conference bridge to play sound file into
+ * \param filename Sound file to play
+ * \param initiator Channel that initiated playback.
+ *
+ * \retval 0 success
+ * \retval -1 failure
+ */
+int async_play_sound_file(struct confbridge_conference *conference, const char *filename,
+ struct ast_channel *initiator);
+
+/*!
+ * \brief Indicate the initiator of an async sound file is ready for it to play.
+ *
+ * When playing an async sound file, the initiator is typically either out of the bridge
+ * or not in a position to hear the queued announcement. This function lets the announcement
+ * thread know that the initiator is now ready for the sound to play.
+ *
+ * If an async announcement was queued and no initiator channel was provided, then this is
+ * a no-op
+ *
+ * \param chan The channel that initiated the async announcement
+ */
+void async_play_sound_ready(struct ast_channel *chan);
+
/*! \brief Callback to be called when the conference has become empty
* \param conference The conference bridge
*/
diff --git a/channels/chan_sip.c b/channels/chan_sip.c
index c8987a00a..b03a3e34d 100644
--- a/channels/chan_sip.c
+++ b/channels/chan_sip.c
@@ -5870,6 +5870,38 @@ static void copy_socket_data(struct sip_socket *to_sock, const struct sip_socket
*to_sock = *from_sock;
}
+/*! Cleanup the RTP and SRTP portions of a dialog
+ *
+ * \note This procedure excludes vsrtp as it is initialized differently.
+ */
+static void dialog_clean_rtp(struct sip_pvt *p)
+{
+ if (p->rtp) {
+ ast_rtp_instance_destroy(p->rtp);
+ p->rtp = NULL;
+ }
+
+ if (p->vrtp) {
+ ast_rtp_instance_destroy(p->vrtp);
+ p->vrtp = NULL;
+ }
+
+ if (p->trtp) {
+ ast_rtp_instance_destroy(p->trtp);
+ p->trtp = NULL;
+ }
+
+ if (p->srtp) {
+ ast_sdp_srtp_destroy(p->srtp);
+ p->srtp = NULL;
+ }
+
+ if (p->tsrtp) {
+ ast_sdp_srtp_destroy(p->tsrtp);
+ p->tsrtp = NULL;
+ }
+}
+
/*! \brief Initialize DTLS-SRTP support on an RTP instance */
static int dialog_initialize_dtls_srtp(const struct sip_pvt *dialog, struct ast_rtp_instance *rtp, struct ast_sdp_srtp **srtp)
{
@@ -5917,6 +5949,9 @@ static int dialog_initialize_rtp(struct sip_pvt *dialog)
return 0;
}
+ /* Make sure previous RTP instances/FD's do not leak */
+ dialog_clean_rtp(dialog);
+
ast_sockaddr_copy(&bindaddr_tmp, &bindaddr);
if (!(dialog->rtp = ast_rtp_instance_new(dialog->engine, sched, &bindaddr_tmp, NULL))) {
return -1;
@@ -6593,18 +6628,10 @@ static void sip_pvt_dtor(void *vdoomed)
ast_free(p->notify);
p->notify = NULL;
}
- if (p->rtp) {
- ast_rtp_instance_destroy(p->rtp);
- p->rtp = NULL;
- }
- if (p->vrtp) {
- ast_rtp_instance_destroy(p->vrtp);
- p->vrtp = NULL;
- }
- if (p->trtp) {
- ast_rtp_instance_destroy(p->trtp);
- p->trtp = NULL;
- }
+
+ /* Free RTP and SRTP instances */
+ dialog_clean_rtp(p);
+
if (p->udptl) {
ast_udptl_destroy(p->udptl);
p->udptl = NULL;
@@ -6637,21 +6664,11 @@ static void sip_pvt_dtor(void *vdoomed)
destroy_msg_headers(p);
- if (p->srtp) {
- ast_sdp_srtp_destroy(p->srtp);
- p->srtp = NULL;
- }
-
if (p->vsrtp) {
ast_sdp_srtp_destroy(p->vsrtp);
p->vsrtp = NULL;
}
- if (p->tsrtp) {
- ast_sdp_srtp_destroy(p->tsrtp);
- p->tsrtp = NULL;
- }
-
if (p->directmediaacl) {
p->directmediaacl = ast_free_acl_list(p->directmediaacl);
}
diff --git a/contrib/scripts/safe_asterisk b/contrib/scripts/safe_asterisk
index 62f3dadc2..66213a530 100644
--- a/contrib/scripts/safe_asterisk
+++ b/contrib/scripts/safe_asterisk
@@ -120,13 +120,20 @@ if test -n "$TTY" && test "$TTY" != "no"; then
TTY=tty${TTY}
elif test -c /dev/vc/${TTY}; then
TTY=vc/${TTY}
+ elif test "$TTY" = "9"; then # ignore default if it was untouched
+ # If there is no /dev/tty9 and not /dev/vc/9 we don't
+ # necessarily want to die at this point. Pretend that
+ # TTY wasn't set.
+ TTY=
else
message "Cannot find specified TTY (${TTY})"
exit 1
fi
- ASTARGS="${ASTARGS} -vvvg"
- if test "$CONSOLE" != "no"; then
- ASTARGS="${ASTARGS} -c"
+ if test -n "$TTY"; then
+ ASTARGS="${ASTARGS} -vvvg"
+ if test "$CONSOLE" != "no"; then
+ ASTARGS="${ASTARGS} -c"
+ fi
fi
fi
diff --git a/res/res_pjsip/pjsip_distributor.c b/res/res_pjsip/pjsip_distributor.c
index 8a9119639..79006110a 100644
--- a/res/res_pjsip/pjsip_distributor.c
+++ b/res/res_pjsip/pjsip_distributor.c
@@ -571,9 +571,7 @@ static pj_bool_t endpoint_lookup(pjsip_rx_data *rdata)
}
}
- if (!endpoint && !is_ack) {
- char name[AST_UUID_STR_LEN] = "";
- pjsip_uri *from = rdata->msg_info.from->uri;
+ if (!endpoint) {
/* always use an artificial endpoint - per discussion no reason
to have "alwaysauthreject" as an option. It is felt using it
@@ -581,6 +579,13 @@ static pj_bool_t endpoint_lookup(pjsip_rx_data *rdata)
breaking old stuff and we really don't want to enable the discovery
of SIP accounts */
endpoint = ast_sip_get_artificial_endpoint();
+ }
+
+ rdata->endpt_info.mod_data[endpoint_mod.id] = endpoint;
+
+ if ((endpoint == artificial_endpoint) && !is_ack) {
+ char name[AST_UUID_STR_LEN] = "";
+ pjsip_uri *from = rdata->msg_info.from->uri;
if (PJSIP_URI_SCHEME_IS_SIP(from) || PJSIP_URI_SCHEME_IS_SIPS(from)) {
pjsip_sip_uri *sip_from = pjsip_uri_get_uri(from);
@@ -614,7 +619,6 @@ static pj_bool_t endpoint_lookup(pjsip_rx_data *rdata)
ast_sip_report_invalid_endpoint(name, rdata);
}
}
- rdata->endpt_info.mod_data[endpoint_mod.id] = endpoint;
return PJ_FALSE;
}
diff --git a/res/res_pjsip/pjsip_global_headers.c b/res/res_pjsip/pjsip_global_headers.c
index 735008dcc..501f5f523 100644
--- a/res/res_pjsip/pjsip_global_headers.c
+++ b/res/res_pjsip/pjsip_global_headers.c
@@ -87,6 +87,14 @@ static void add_headers_to_message(struct header_list *headers, pjsip_tx_data *t
return;
}
AST_LIST_TRAVERSE(headers, iter, next) {
+ pj_str_t name;
+ pjsip_generic_string_hdr *hdr;
+
+ hdr = pjsip_msg_find_hdr_by_name(tdata->msg, pj_cstr(&name, iter->name), NULL);
+ if (hdr) {
+ continue;
+ }
+
ast_sip_add_header(tdata, iter->name, iter->value);
};
tdata->mod_data[global_header_mod.id] = &handled_id;