diff options
-rw-r--r-- | CHANGES | 6 | ||||
-rw-r--r-- | apps/app_confbridge.c | 370 | ||||
-rw-r--r-- | apps/app_followme.c | 26 | ||||
-rw-r--r-- | apps/app_queue.c | 2 | ||||
-rw-r--r-- | apps/confbridge/conf_state_multi_marked.c | 9 | ||||
-rw-r--r-- | apps/confbridge/include/confbridge.h | 31 | ||||
-rw-r--r-- | channels/chan_sip.c | 61 | ||||
-rw-r--r-- | contrib/scripts/safe_asterisk | 13 | ||||
-rw-r--r-- | res/res_pjsip/pjsip_distributor.c | 12 | ||||
-rw-r--r-- | res/res_pjsip/pjsip_global_headers.c | 8 |
10 files changed, 455 insertions, 83 deletions
@@ -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; |