diff --git a/conf/vanilla/dialplan/default.xml b/conf/vanilla/dialplan/default.xml index d4ae8e711a..a6e26c1928 100644 --- a/conf/vanilla/dialplan/default.xml +++ b/conf/vanilla/dialplan/default.xml @@ -828,5 +828,13 @@ + + + + + + + + diff --git a/conf/vanilla/sip_profiles/internal.xml b/conf/vanilla/sip_profiles/internal.xml index 1529248097..1da1e0470c 100644 --- a/conf/vanilla/sip_profiles/internal.xml +++ b/conf/vanilla/sip_profiles/internal.xml @@ -418,5 +418,9 @@ --> + + diff --git a/libs/sofia-sip/libsofia-sip-ua/nta/nta.c b/libs/sofia-sip/libsofia-sip-ua/nta/nta.c index bb68025749..9b2e295007 100644 --- a/libs/sofia-sip/libsofia-sip-ua/nta/nta.c +++ b/libs/sofia-sip/libsofia-sip-ua/nta/nta.c @@ -6460,8 +6460,14 @@ static int nta_incoming_response_headers(nta_incoming_t *irq, clone = 1, sip->sip_call_id = sip_call_id_copy(home, irq->irq_call_id); if (!sip->sip_cseq) clone = 1, sip->sip_cseq = sip_cseq_copy(home, irq->irq_cseq); - if (!sip->sip_via) - clone = 1, sip->sip_via = sip_via_copy(home, irq->irq_via); + if (!sip->sip_via) { + clone = 1; + /* 100 responses are not forwarded by proxies, so only include the topmost Via header */ + if (sip->sip_status && sip->sip_status->st_status == 100) + sip->sip_via = (sip_via_t *)msg_header_copy_one(home, (msg_header_t const *)irq->irq_via); + else + sip->sip_via = sip_via_copy(home, irq->irq_via); + } if (clone) msg_set_parent(msg, (msg_t *)irq->irq_home); @@ -6530,7 +6536,7 @@ int nta_incoming_complete_response(nta_incoming_t *irq, if (sip_to_tag(home, sip->sip_to, irq->irq_tag) < 0) return -1; - if (status < 300 && !sip->sip_record_route && irq->irq_record_route) + if (status > 100 && status < 300 && !sip->sip_record_route && irq->irq_record_route) if (sip_add_dup(msg, sip, (sip_header_t *)irq->irq_record_route) < 0) return -1; diff --git a/libs/sofia-sip/libsofia-sip-ua/nua/nua_params.c b/libs/sofia-sip/libsofia-sip-ua/nua/nua_params.c index 8ff2684881..2d21acbaa2 100644 --- a/libs/sofia-sip/libsofia-sip-ua/nua/nua_params.c +++ b/libs/sofia-sip/libsofia-sip-ua/nua/nua_params.c @@ -173,6 +173,8 @@ int nua_stack_set_defaults(nua_handle_t *nh, NHP_SET(nhp, keepalive, 120000); + NHP_SET(nhp, auto_invite_100, 1); + NHP_SET(nhp, appl_method, sip_allow_make(home, "INVITE, REGISTER, PUBLISH, SUBSCRIBE")); @@ -1013,6 +1015,10 @@ static int nhp_set_tags(su_home_t *home, else if (tag == ntatag_default_proxy) { NHP_SET_STR_BY_URL(nhp, url_string_t, proxy, value); } + /* NUTAG_AUTO_INVITE_100() */ + else if (tag == nutag_auto_invite_100) { + NHP_SET(nhp, auto_invite_100, value != 0); + } /* NUTAG_DETECT_NETWORK_UPDATES(detect_network_updates) */ else if (ngp && tag == nutag_detect_network_updates) { int detector = (int)value; diff --git a/libs/sofia-sip/libsofia-sip-ua/nua/nua_params.h b/libs/sofia-sip/libsofia-sip-ua/nua/nua_params.h index 5c26e4ef13..d48ceca155 100644 --- a/libs/sofia-sip/libsofia-sip-ua/nua/nua_params.h +++ b/libs/sofia-sip/libsofia-sip-ua/nua/nua_params.h @@ -115,6 +115,9 @@ struct nua_handle_preferences /** Enable Retry-After */ unsigned nhp_retry_after_enable:1; + /** Enable/Disable automatic 100 Trying when receiving INVITE */ + unsigned nhp_auto_invite_100:1; + unsigned:0; /* Default lifetime for implicit subscriptions created by REFER */ @@ -215,6 +218,7 @@ struct nua_handle_preferences unsigned nhb_proxy:1; unsigned nhb_timer_autorequire:1; unsigned nhb_retry_after_enable:1; + unsigned nhb_auto_invite_100:1; unsigned :0; } set_bits; unsigned set_unsigned[2]; diff --git a/libs/sofia-sip/libsofia-sip-ua/nua/nua_server.c b/libs/sofia-sip/libsofia-sip-ua/nua/nua_server.c index deae102ca2..cf8e23577d 100644 --- a/libs/sofia-sip/libsofia-sip-ua/nua/nua_server.c +++ b/libs/sofia-sip/libsofia-sip-ua/nua/nua_server.c @@ -262,7 +262,8 @@ int nua_stack_process_request(nua_handle_t *nh, if (sr->sr_status <= 100) { SR_STATUS1(sr, SIP_100_TRYING); - if (method == sip_method_invite || sip->sip_timestamp) { + if ((method == sip_method_invite && nh->nh_prefs->nhp_auto_invite_100) || + sip->sip_timestamp) { nta_incoming_treply(irq, SIP_100_TRYING, SIPTAG_USER_AGENT_STR(user_agent), TAG_END()); @@ -459,7 +460,12 @@ nua_stack_respond(nua_t *nua, nua_handle_t *nh, nua_server_params(sr, tags); nua_server_respond(sr, tags); - nua_server_report(sr); + + if (!(sr->sr_method == sip_method_invite && status == 100)) { + /* Since we don't change state, do not notify application when + we send 100 Trying for INVITE */ + nua_server_report(sr); + } } int nua_server_params(nua_server_request_t *sr, tagi_t const *tags) @@ -528,6 +534,13 @@ int nua_server_respond(nua_server_request_t *sr, tagi_t const *tags) goto internal_error; } + if (sr->sr_status == 100) { + return nta_incoming_treply(sr->sr_irq, SIP_100_TRYING, + SIPTAG_USER_AGENT_STR(NH_PGET(nh, user_agent)), + TAG_END()); + return 0; + } + if (sr->sr_status < 200) { next.msg = nta_incoming_create_response(sr->sr_irq, 0, NULL); next.sip = sip_object(next.msg); diff --git a/libs/sofia-sip/libsofia-sip-ua/nua/nua_tag.c b/libs/sofia-sip/libsofia-sip-ua/nua/nua_tag.c index 7670b93268..21dede4343 100644 --- a/libs/sofia-sip/libsofia-sip-ua/nua/nua_tag.c +++ b/libs/sofia-sip/libsofia-sip-ua/nua/nua_tag.c @@ -2796,6 +2796,13 @@ tag_typedef_t nutag_auth_cache = INTTAG_TYPEDEF(auth_cache); * Reference tag for NUTAG_AUTH_CACHE(). */ +/**@def NUTAG_AUTO_INVITE_100(x) + */ +tag_typedef_t nutag_auto_invite_100 = INTTAG_TYPEDEF(auto_invite_100); + +/**@def NUTAG_AUTO_INVITE_100(x) + * Reference tag for NUTAG_AUTO_INVITE_100(). + */ /**@def NUTAG_DETECT_NETWORK_UPDATES(x) * diff --git a/libs/sofia-sip/libsofia-sip-ua/nua/sofia-sip/nua_tag.h b/libs/sofia-sip/libsofia-sip-ua/nua/sofia-sip/nua_tag.h index 2c3a72ca04..3a3f96e02b 100644 --- a/libs/sofia-sip/libsofia-sip-ua/nua/sofia-sip/nua_tag.h +++ b/libs/sofia-sip/libsofia-sip-ua/nua/sofia-sip/nua_tag.h @@ -611,6 +611,13 @@ SOFIAPUBVAR tag_typedef_t nutag_shutdown_events; nutag_shutdown_events_ref, tag_bool_vr(&(x)) SOFIAPUBVAR tag_typedef_t nutag_shutdown_events_ref; +#define NUTAG_AUTO_INVITE_100(x) \ + nutag_auto_invite_100, tag_bool_v(x) +SOFIAPUBVAR tag_typedef_t nutag_auto_invite_100; +#define NUTAG_AUTO_INVITE_100_REF(x) \ + nutag_auto_invite_100_ref, tag_bool_vr(&(x)) +SOFIAPUBVAR tag_typedef_t nutag_auto_invite_100_ref; + /* Pass nua handle as tagged argument */ #if SU_INLINE_TAG_CAST su_inline tag_value_t nutag_handle_v(nua_handle_t *v) { return (tag_value_t)v; } diff --git a/src/include/switch_channel.h b/src/include/switch_channel.h index b348dccc51..bc37dd2e6c 100644 --- a/src/include/switch_channel.h +++ b/src/include/switch_channel.h @@ -447,6 +447,10 @@ SWITCH_DECLARE(void) switch_channel_check_zrtp(switch_channel_t *channel); */ #define switch_channel_mark_pre_answered(channel) switch_channel_perform_mark_pre_answered(channel, __FILE__, __SWITCH_FUNC__, __LINE__) +SWITCH_DECLARE(switch_status_t) switch_channel_perform_acknowledge_call(switch_channel_t *channel, + const char *file, const char *func, int line); +#define switch_channel_acknowledge_call(channel) switch_channel_perform_acknowledge_call(channel, __FILE__, __SWITCH_FUNC__, __LINE__) + SWITCH_DECLARE(switch_status_t) switch_channel_perform_ring_ready_value(switch_channel_t *channel, switch_ring_ready_t rv, const char *file, const char *func, int line); diff --git a/src/include/switch_types.h b/src/include/switch_types.h index 0ebcef406e..fff02cfcb0 100644 --- a/src/include/switch_types.h +++ b/src/include/switch_types.h @@ -1052,6 +1052,7 @@ typedef enum { SWITCH_MESSAGE_REDIRECT_AUDIO, SWITCH_MESSAGE_TRANSMIT_TEXT, SWITCH_MESSAGE_INDICATE_ANSWER, + SWITCH_MESSAGE_INDICATE_ACKNOWLEDGE_CALL, SWITCH_MESSAGE_INDICATE_PROGRESS, SWITCH_MESSAGE_INDICATE_BRIDGE, SWITCH_MESSAGE_INDICATE_UNBRIDGE, diff --git a/src/mod/applications/mod_dptools/mod_dptools.c b/src/mod/applications/mod_dptools/mod_dptools.c index 9e9f446549..937d214827 100644 --- a/src/mod/applications/mod_dptools/mod_dptools.c +++ b/src/mod/applications/mod_dptools/mod_dptools.c @@ -1048,6 +1048,11 @@ SWITCH_STANDARD_APP(capture_text_function) switch_ivr_capture_text(session, switch_true((char *)data)); } +SWITCH_STANDARD_APP(acknowledge_call_function) +{ + switch_channel_acknowledge_call(switch_core_session_get_channel(session)); +} + SWITCH_STANDARD_APP(ring_ready_function) { if (!zstr(data)) { @@ -6298,6 +6303,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_dptools_load) SAF_SUPPORT_NOMEDIA | SAF_ROUTING_EXEC | SAF_ZOMBIE_EXEC); SWITCH_ADD_APP(app_interface, "capture_text", "capture text", "capture text", capture_text_function, "", SAF_NONE); + SWITCH_ADD_APP(app_interface, "acknowledge_call", "Indicate Call Acknowledged", "Indicate Call Acknowledged on a channel.", acknowledge_call_function, "", SAF_SUPPORT_NOMEDIA); SWITCH_ADD_APP(app_interface, "ring_ready", "Indicate Ring_Ready", "Indicate Ring_Ready on a channel.", ring_ready_function, "", SAF_SUPPORT_NOMEDIA); SWITCH_ADD_APP(app_interface, "remove_bugs", "Remove media bugs", "Remove all media bugs from a channel.", remove_bugs_function, "[]", SAF_NONE); SWITCH_ADD_APP(app_interface, "break", "Break", "Set the break flag.", break_function, "", SAF_SUPPORT_NOMEDIA); diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.c b/src/mod/endpoints/mod_sofia/mod_sofia.c index 1c5d0e48a1..96a13be7f7 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.c +++ b/src/mod/endpoints/mod_sofia/mod_sofia.c @@ -55,6 +55,7 @@ static switch_status_t sofia_on_init(switch_core_session_t *session); static switch_status_t sofia_on_exchange_media(switch_core_session_t *session); static switch_status_t sofia_on_soft_execute(switch_core_session_t *session); +static switch_status_t sofia_acknowledge_call(switch_core_session_t *session); static switch_call_cause_t sofia_outgoing_channel(switch_core_session_t *session, switch_event_t *var_event, switch_caller_profile_t *outbound_profile, switch_core_session_t **new_session, switch_memory_pool_t **pool, switch_originate_flag_t flags, switch_call_cause_t *cancel_cause); @@ -137,6 +138,14 @@ static switch_status_t sofia_on_routing(switch_core_session_t *session) switch_channel_t *channel = switch_core_session_get_channel(session); switch_assert(tech_pvt != NULL); + if (sofia_test_pflag(tech_pvt->profile, PFLAG_AUTO_INVITE_100) && + !switch_channel_test_flag(channel, CF_ANSWERED) && + switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_INBOUND) { + if (sofia_acknowledge_call(session) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Call appears to be already acknowledged\n"); + } + } + if (!sofia_test_flag(tech_pvt, TFLAG_HOLD_LOCK)) { sofia_clear_flag_locked(tech_pvt, TFLAG_SIP_HOLD); switch_channel_clear_flag(channel, CF_LEG_HOLDING); @@ -642,6 +651,19 @@ static switch_status_t sofia_on_soft_execute(switch_core_session_t *session) return SWITCH_STATUS_SUCCESS; } +static switch_status_t sofia_acknowledge_call(switch_core_session_t *session) +{ + struct private_object *tech_pvt = switch_core_session_get_private(session); + + if (!tech_pvt->sent_100) { + nua_respond(tech_pvt->nh, SIP_100_TRYING, TAG_END()); + tech_pvt->sent_100 = 1; + return SWITCH_STATUS_SUCCESS; + } + + return SWITCH_STATUS_FALSE; +} + static switch_status_t sofia_answer_channel(switch_core_session_t *session) { private_object_t *tech_pvt = (private_object_t *) switch_core_session_get_private(session); @@ -656,6 +678,10 @@ static switch_status_t sofia_answer_channel(switch_core_session_t *session) char *sticky = NULL; const char *call_info = switch_channel_get_variable(channel, "presence_call_info_full"); + if(sofia_acknowledge_call(session) == SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Dialplan did not acknowledge_call; sent 100 Trying"); + } + if (switch_channel_test_flag(channel, CF_CONFERENCE) && !switch_stristr(";isfocus", tech_pvt->reply_contact)) { tech_pvt->reply_contact = switch_core_session_sprintf(session, "%s;isfocus", tech_pvt->reply_contact); } @@ -2176,6 +2202,12 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi } } + /* Dialplan should really use acknowledge_call application instead of respond application to send 100 */ + if (code == 100) { + status = sofia_acknowledge_call(session); + goto end_lock; + } + if (tech_pvt->proxy_refer_uuid) { if (tech_pvt->proxy_refer_msg) { nua_respond(tech_pvt->nh, code, su_strdup(nua_handle_home(tech_pvt->nh), reason), SIPTAG_CONTACT_STR(tech_pvt->reply_contact), @@ -2295,10 +2327,17 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi SIPTAG_HEADER_STR("X-FS-Support: " FREESWITCH_SUPPORT)), TAG_END()); } break; + case SWITCH_MESSAGE_INDICATE_ACKNOWLEDGE_CALL: + status = sofia_acknowledge_call(session); + break; case SWITCH_MESSAGE_INDICATE_RINGING: { switch_ring_ready_t ring_ready_val = msg->numeric_arg; + if(sofia_acknowledge_call(session) == SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Dialplan did not acknowledge_call; sent 100 Trying"); + } + if (!switch_channel_test_flag(channel, CF_RING_READY) && !sofia_test_flag(tech_pvt, TFLAG_BYE) && !switch_channel_test_flag(channel, CF_EARLY_MEDIA) && !switch_channel_test_flag(channel, CF_ANSWERED)) { char *extra_header = sofia_glue_get_extra_headers(channel, SOFIA_SIP_PROGRESS_HEADER_PREFIX); @@ -2360,6 +2399,10 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi int send_sip_code = 183; const char * p_send_sip_msg = sip_183_Session_progress; + if(sofia_acknowledge_call(session) == SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Dialplan did not acknowledge_call; sent 100 Trying"); + } + b_sdp = switch_channel_get_variable(channel, SWITCH_B_SDP_VARIABLE); is_proxy = (switch_channel_test_flag(channel, CF_PROXY_MODE) || switch_channel_test_flag(channel, CF_PROXY_MEDIA)); is_3pcc_proxy = (sofia_test_pflag(tech_pvt->profile, PFLAG_3PCC_PROXY) && sofia_test_flag(tech_pvt, TFLAG_3PCC)); diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.h b/src/mod/endpoints/mod_sofia/mod_sofia.h index a66fc92420..b8d1a32a0c 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.h +++ b/src/mod/endpoints/mod_sofia/mod_sofia.h @@ -307,6 +307,7 @@ typedef enum { PFLAG_PROXY_INFO, PFLAG_PROXY_MESSAGE, PFLAG_FIRE_BYE_RESPONSE_EVENTS, + PFLAG_AUTO_INVITE_100, /* No new flags below this line */ PFLAG_MAX @@ -839,6 +840,7 @@ struct private_object { sip_contact_t *contact; int q850_cause; int got_bye; + int sent_100; nua_event_t want_event; switch_rtp_bug_flag_t rtp_bugs; char *user_via; diff --git a/src/mod/endpoints/mod_sofia/sofia.c b/src/mod/endpoints/mod_sofia/sofia.c index 27750e25ba..c8311dc828 100644 --- a/src/mod/endpoints/mod_sofia/sofia.c +++ b/src/mod/endpoints/mod_sofia/sofia.c @@ -3155,6 +3155,7 @@ void *SWITCH_THREAD_FUNC sofia_profile_thread_run(switch_thread_t *thread, void NTATAG_TCP_RPORT(0), NTATAG_TLS_RPORT(0), NUTAG_RETRY_AFTER_ENABLE(0), + NUTAG_AUTO_INVITE_100(0), TAG_IF(!strchr(profile->sipip, ':'), SOATAG_AF(SOA_AF_IP4_ONLY)), TAG_IF(strchr(profile->sipip, ':'), @@ -4517,6 +4518,7 @@ switch_status_t config_sofia(sofia_config_t reload, char *profile_name) } profile->tls_verify_policy = TPTLS_VERIFY_NONE; + sofia_set_pflag(profile, PFLAG_AUTO_INVITE_100); /* lib default */ profile->tls_verify_depth = 2; @@ -5326,6 +5328,12 @@ switch_status_t config_sofia(sofia_config_t reload, char *profile_name) } else { sofia_clear_pflag(profile, PFLAG_SECURE); } + } else if (!strcasecmp(var, "auto-invite-100")) { + if (switch_true(val)) { + sofia_set_pflag(profile, PFLAG_AUTO_INVITE_100); + } else { + sofia_clear_pflag(profile, PFLAG_AUTO_INVITE_100); + } } else { found = 0; } @@ -9833,6 +9841,8 @@ void sofia_handle_sip_i_reinvite(switch_core_session_t *session, switch_channel_t *channel = NULL; private_object_t *tech_pvt = NULL; + nua_respond(nh, SIP_100_TRYING, TAG_END()); + if (session) { channel = switch_core_session_get_channel(session); tech_pvt = switch_core_session_get_private(session); diff --git a/src/switch_channel.c b/src/switch_channel.c index 8086944190..44ed2ee685 100644 --- a/src/switch_channel.c +++ b/src/switch_channel.c @@ -3305,6 +3305,13 @@ static switch_status_t send_ind(switch_channel_t *channel, switch_core_session_m return switch_core_session_perform_receive_message(channel->session, &msg, file, func, line); } +SWITCH_DECLARE(switch_status_t) switch_channel_perform_acknowledge_call(switch_channel_t *channel, + const char *file, const char *func, int line) +{ + send_ind(channel, SWITCH_MESSAGE_INDICATE_ACKNOWLEDGE_CALL, file, func, line); + + return SWITCH_STATUS_SUCCESS; +} SWITCH_DECLARE(switch_status_t) switch_channel_perform_mark_ring_ready_value(switch_channel_t *channel, switch_ring_ready_t rv,