From: Mike Jerris Date: Wed, 5 Dec 2018 22:58:25 +0000 (+0400) Subject: FS-11557: [mod_sofia] add support for RFC 7989 Session-ID header X-Git-Tag: v1.10.0~186 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=a9e634b6640478ccf4a6c50e0e951730acf7ce60;p=thirdparty%2Ffreeswitch.git FS-11557: [mod_sofia] add support for RFC 7989 Session-ID header (enable with sofia profile param rfc-7989=true) FS-11557 [mod_sofia, mod_conference, core] Add support for re-INVITE when setting Session-ID in conference after call has been answered. FS-11557 [mod_conference] Missed a spot where APP_SESSION_ID needed to be set. FS-11557: set session id for outbound (initial requests) FS-11557: [mod_sofia] rename vars and functions "session id" -> "session uuid" to reflect the real meaning for rfc7989. FS-11557: fix bug - colliding chan var names (session_id) FS-11557: check nil session uuid FS-11557 : replace CS_NEW with CS_INIT for when originating calls, generate new uuid. FS-11557: handle inbound (UAS mode, one leg) FS-11557: generic param handling and filter via new sip profile option "rfc-7989-filter", eg: FS-11557: renamed chan vars (reflect meaning only for RFC7989) FS-11557: fallback to RFC7329 - "old" Session-ID FS-11557: distinguish between request and replies when we read the header (to provide compatibility with old RFC7329 - section 11 of RFC7989) FS-11557: change more vars/consts names FS-11557: move compat flag on the channel. FS-11557: add Session-ID header in REFER FS-11557: needs extra condition on received initial request FS-11557: handle NOTIFY FS-11557: support answer() in dialplan - it was sending back a 200 OK with Session-ID invalid, eg: A=NIL;B=X FS-11557: add Session-ID for NOTIFY (more cases) FS-11557: handle reply to SIP INFO (add Session-ID header) FS-11557: handle case of BYE after REFER, when the channel is destroyed already (save the uuid on sofia_private) FS-11557: handle more SIP reply cases (eg: 202 Accepted , more negative replies) FS-11557: handle ACK (UAS role) FS-11557: added "rfc-7989-force-old" profile param - to enforce old rfc7329 for the UAC role. default off. enabled with "". FS-11557: fallback to rfc7329 fixes. FS-11557: set flag CF_RFC7329_COMPAT on partner channel where needed FS-11557: fix crash (mod_conference) --- diff --git a/src/include/switch_types.h b/src/include/switch_types.h index 1f6f673b9d..43bbf12d03 100644 --- a/src/include/switch_types.h +++ b/src/include/switch_types.h @@ -225,6 +225,10 @@ SWITCH_BEGIN_EXTERN_C #define SWITCH_EXEC_AFTER_BRIDGE_APP_VARIABLE "exec_after_bridge_app" #define SWITCH_EXEC_AFTER_BRIDGE_ARG_VARIABLE "exec_after_bridge_arg" #define SWITCH_MAX_FORWARDS_VARIABLE "max_forwards" +#define SWITCH_RFC7989_SESSION_ID_VARIABLE "session_uuid" +#define SWITCH_RFC7989_REMOTE_SESSION_ID_VARIABLE "remote_session_uuid" +#define SWITCH_RFC7989_APP_SESSION_ID_VARIABLE "app_session_uuid" +#define SWITCH_RFC7989_GENERIC_PARAM_VARIABLE "generic_param_session_uuid" #define SWITCH_MAX_SESSION_TRANSFERS_VARIABLE "max_session_transfers" #define SWITCH_DISABLE_APP_LOG_VARIABLE "disable_app_log" #define SWITCH_SPEECH_KEY "speech" @@ -1159,6 +1163,7 @@ typedef enum { SWITCH_MESSAGE_RING_EVENT, SWITCH_MESSAGE_RESAMPLE_EVENT, SWITCH_MESSAGE_HEARTBEAT_EVENT, + SWITCH_MESSAGE_INDICATE_SESSION_ID, SWITCH_MESSAGE_INVALID } switch_core_session_message_types_t; @@ -1607,6 +1612,7 @@ typedef enum { CF_ARRANGED_BRIDGE, CF_STATE_REPEAT, CF_WANT_DTLSv1_2, + CF_RFC7329_COMPAT, /* WARNING: DO NOT ADD ANY FLAGS BELOW THIS LINE */ /* IF YOU ADD NEW ONES CHECK IF THEY SHOULD PERSIST OR ZERO THEM IN switch_core_session.c switch_core_session_request_xml() */ CF_FLAG_MAX diff --git a/src/mod/applications/mod_conference/mod_conference.c b/src/mod/applications/mod_conference/mod_conference.c index 4337f83698..36c71f7dd6 100644 --- a/src/mod/applications/mod_conference/mod_conference.c +++ b/src/mod/applications/mod_conference/mod_conference.c @@ -1911,8 +1911,8 @@ SWITCH_STANDARD_APP(conference_function) switch_channel_set_flag(channel, CF_CONFERENCE); - if (switch_channel_answer(channel) != SWITCH_STATUS_SUCCESS) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Channel answer failed.\n"); + if (switch_channel_pre_answer(channel) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Channel pre answer failed.\n"); goto end; } @@ -2060,6 +2060,7 @@ SWITCH_STANDARD_APP(conference_function) locked = 0; switch_channel_set_variable(channel, "conference_name", conference->name); + switch_channel_set_variable(channel, SWITCH_RFC7989_APP_SESSION_ID_VARIABLE, conference->uuid_str); /* Set the minimum number of members (once you go above it you cannot go below it) */ conference->min = 2; @@ -2144,6 +2145,7 @@ SWITCH_STANDARD_APP(conference_function) } switch_channel_set_variable(channel, "conference_name", conference->name); + switch_channel_set_variable(channel, SWITCH_RFC7989_APP_SESSION_ID_VARIABLE, conference->uuid_str); /* Set MOH from variable if not set */ if (zstr(conference->moh_sound)) { @@ -2210,6 +2212,7 @@ SWITCH_STANDARD_APP(conference_function) switch_channel_api_on(channel, "api_on_conference_create"); } else { /* setup user variable */ switch_channel_set_variable(channel, "conference_name", conference->name); + switch_channel_set_variable(channel, SWITCH_RFC7989_APP_SESSION_ID_VARIABLE, conference->uuid_str); rl++; } @@ -2223,6 +2226,12 @@ SWITCH_STANDARD_APP(conference_function) mdpin = conference->mpin; } + /* Tell the channel we have a new Session-ID */ + msg.from = __FILE__; + msg.message_id = SWITCH_MESSAGE_INDICATE_SESSION_ID; + switch_core_session_receive_message(session, &msg); + + switch_channel_answer(channel); /* if this is not an outbound call, deal with conference pins */ if (enforce_security && (!zstr(dpin) || !zstr(mdpin))) { @@ -2233,9 +2242,6 @@ SWITCH_STANDARD_APP(conference_function) switch_status_t status = SWITCH_STATUS_SUCCESS; char *supplied_pin_value; - /* Answer the channel */ - switch_channel_answer(channel); - /* look for PIN in channel variable first. If not present or invalid revert to prompting user */ supplied_pin_value = switch_core_strdup(conference->pool, switch_channel_get_variable(channel, "supplied_pin")); if (!zstr(supplied_pin_value)) { diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.c b/src/mod/endpoints/mod_sofia/mod_sofia.c index c203e5c114..6b9a9d7d84 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.c +++ b/src/mod/endpoints/mod_sofia/mod_sofia.c @@ -484,6 +484,7 @@ switch_status_t sofia_on_hangup(switch_core_session_t *session) const char *val = NULL; const char *max_forwards = switch_channel_get_variable(channel, SWITCH_MAX_FORWARDS_VARIABLE); const char *call_info = switch_channel_get_variable(channel, "presence_call_info_full"); + const char *session_id_header = sofia_glue_session_id_header(session, tech_pvt->profile); val = switch_channel_get_variable(tech_pvt->channel, "disable_q850_reason"); @@ -518,7 +519,9 @@ switch_status_t sofia_on_hangup(switch_core_session_t *session) TAG_IF(!zstr(reason), SIPTAG_REASON_STR(reason)), TAG_IF(call_info, SIPTAG_CALL_INFO_STR(call_info)), TAG_IF(!zstr(tech_pvt->user_via), SIPTAG_VIA_STR(tech_pvt->user_via)), - TAG_IF(!zstr(bye_headers), SIPTAG_HEADER_STR(bye_headers)), TAG_END()); + TAG_IF(!zstr(bye_headers), SIPTAG_HEADER_STR(bye_headers)), + TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), + TAG_END()); } } else { if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) { @@ -532,7 +535,9 @@ switch_status_t sofia_on_hangup(switch_core_session_t *session) nua_cancel(tech_pvt->nh, SIPTAG_CONTACT(SIP_NONE), TAG_IF(call_info, SIPTAG_CALL_INFO_STR(call_info)), - TAG_IF(!zstr(reason), SIPTAG_REASON_STR(reason)), TAG_IF(!zstr(bye_headers), SIPTAG_HEADER_STR(bye_headers)), TAG_END()); + TAG_IF(!zstr(reason), SIPTAG_REASON_STR(reason)), TAG_IF(!zstr(bye_headers), SIPTAG_HEADER_STR(bye_headers)), + TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), + TAG_END()); } } else { char *resp_headers = sofia_glue_get_extra_headers(channel, SOFIA_SIP_RESPONSE_HEADER_PREFIX); @@ -618,6 +623,7 @@ switch_status_t sofia_on_hangup(switch_core_session_t *session) TAG_IF(!zstr(added_headers), SIPTAG_HEADER_STR(added_headers)), TAG_IF(tech_pvt->respond_dest, SIPTAG_CONTACT_STR(tech_pvt->respond_dest)), TAG_IF(!zstr(max_forwards), SIPTAG_MAX_FORWARDS_STR(max_forwards)), + TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), TAG_END()); switch_safe_free(resp_headers); @@ -667,9 +673,10 @@ 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) { struct private_object *tech_pvt = switch_core_session_get_private(session); + const char *session_id_header = sofia_glue_session_id_header(session, tech_pvt->profile); if (!tech_pvt->sent_100) { - nua_respond(tech_pvt->nh, SIP_100_TRYING, TAG_END()); + nua_respond(tech_pvt->nh, SIP_100_TRYING, TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), TAG_END()); tech_pvt->sent_100 = 1; return SWITCH_STATUS_SUCCESS; } @@ -690,6 +697,7 @@ static switch_status_t sofia_answer_channel(switch_core_session_t *session) int is_3pcc = 0; char *sticky = NULL; const char *call_info = switch_channel_get_variable(channel, "presence_call_info_full"); + const char *session_id_header = sofia_glue_session_id_header(session, tech_pvt->profile); 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"); @@ -726,6 +734,7 @@ static switch_status_t sofia_answer_channel(switch_core_session_t *session) SOATAG_RTP_SELECT(1), SOATAG_AUDIO_AUX("cn telephone-event"), TAG_IF(sofia_test_pflag(tech_pvt->profile, PFLAG_DISABLE_100REL), NUTAG_INCLUDE_EXTRA_SDP(1)), + TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), TAG_END()); } else { nua_ack(tech_pvt->nh, @@ -734,6 +743,7 @@ static switch_status_t sofia_answer_channel(switch_core_session_t *session) SIPTAG_CONTACT_STR(tech_pvt->reply_contact), TAG_IF(tech_pvt->mparams.local_sdp_str, SIPTAG_CONTENT_TYPE_STR("application/sdp")), TAG_IF(tech_pvt->mparams.local_sdp_str, SIPTAG_PAYLOAD_STR(tech_pvt->mparams.local_sdp_str)), + TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), SOATAG_AUDIO_AUX("cn telephone-event"), TAG_END()); } @@ -811,6 +821,7 @@ static switch_status_t sofia_answer_channel(switch_core_session_t *session) SOATAG_RTP_SELECT(1), SOATAG_AUDIO_AUX("cn telephone-event"), NUTAG_INCLUDE_EXTRA_SDP(1), TAG_IF(!zstr(extra_headers), SIPTAG_HEADER_STR(extra_headers)), + TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), TAG_IF(switch_stristr("update_display", tech_pvt->x_freeswitch_support_remote), SIPTAG_HEADER_STR("X-FS-Support: " FREESWITCH_SUPPORT)), TAG_END()); } else { @@ -821,6 +832,7 @@ static switch_status_t sofia_answer_channel(switch_core_session_t *session) TAG_IF(call_info, SIPTAG_CALL_INFO_STR(call_info)), SIPTAG_CONTENT_TYPE_STR("application/sdp"), SIPTAG_PAYLOAD_STR(tech_pvt->mparams.local_sdp_str), + TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), TAG_IF(switch_stristr("update_display", tech_pvt->x_freeswitch_support_remote), SIPTAG_HEADER_STR("X-FS-Support: " FREESWITCH_SUPPORT)), TAG_END()); } @@ -950,13 +962,13 @@ static switch_status_t sofia_answer_channel(switch_core_session_t *session) tech_pvt->session_refresher = nua_no_refresher; } - if (sofia_use_soa(tech_pvt)) { nua_respond(tech_pvt->nh, SIP_200_OK, NUTAG_AUTOANSWER(0), TAG_IF(call_info, SIPTAG_CALL_INFO_STR(call_info)), TAG_IF(sticky, NUTAG_PROXY(tech_pvt->record_route)), TAG_IF(cid, SIPTAG_HEADER_STR(cid)), + TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), NUTAG_SESSION_TIMER(tech_pvt->session_timeout), NUTAG_SESSION_REFRESHER(tech_pvt->session_refresher), NUTAG_UPDATE_REFRESH(tech_pvt->update_refresher), @@ -977,6 +989,7 @@ static switch_status_t sofia_answer_channel(switch_core_session_t *session) TAG_IF(call_info, SIPTAG_CALL_INFO_STR(call_info)), TAG_IF(sticky, NUTAG_PROXY(tech_pvt->record_route)), TAG_IF(cid, SIPTAG_HEADER_STR(cid)), + TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), NUTAG_SESSION_TIMER(tech_pvt->session_timeout), NUTAG_SESSION_REFRESHER(tech_pvt->session_refresher), NUTAG_UPDATE_REFRESH(tech_pvt->update_refresher), @@ -1399,10 +1412,12 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi char *xdest; if (msg->string_arg) { + const char *session_id_header = sofia_glue_session_id_header(session, tech_pvt->profile); nua_notify(tech_pvt->nh, NUTAG_NEWSUB(1), SIPTAG_CONTENT_TYPE_STR("message/sipfrag;version=2.0"), NUTAG_SUBSTATE(nua_substate_terminated), SIPTAG_SUBSCRIPTION_STATE_STR("terminated;reason=noresource"), SIPTAG_PAYLOAD_STR(msg->string_arg), + TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), SIPTAG_EVENT_STR("refer"), TAG_END()); goto end; } @@ -1412,6 +1427,7 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi if (event && uuid) { char payload_str[255] = "SIP/2.0 403 Forbidden\r\n"; + const char *session_id_header = sofia_glue_session_id_header(session, tech_pvt->profile); if (msg->numeric_arg) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s Completing blind transfer with success\n", switch_channel_get_name(channel)); @@ -1437,6 +1453,7 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi NUTAG_SUBSTATE(nua_substate_terminated), SIPTAG_SUBSCRIPTION_STATE_STR("terminated;reason=noresource"), SIPTAG_PAYLOAD_STR(payload_str), + TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), SIPTAG_EVENT_STR(event), TAG_END()); @@ -1508,6 +1525,7 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi char *extra_headers = sofia_glue_get_extra_headers(channel, SOFIA_SIP_HEADER_PREFIX); char ref_to[1024] = ""; const char *var; + const char *session_id_header = sofia_glue_session_id_header(session, tech_pvt->profile); if (!strcasecmp(msg->string_arg, "sip:")) { const char *format = strchr(tech_pvt->profile->sipip, ':') ? "sip:%s@[%s]" : "sip:%s@%s"; @@ -1519,6 +1537,7 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi nua_refer(tech_pvt->nh, SIPTAG_REFER_TO_STR(ref_to), SIPTAG_REFERRED_BY_STR(tech_pvt->contact_url), TAG_IF(!zstr(extra_headers), SIPTAG_HEADER_STR(extra_headers)), + TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), TAG_END()); if (msg->string_array_arg[0]) { @@ -1570,18 +1589,23 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi } if (!sofia_test_flag(tech_pvt, TFLAG_BYE)) { + const char *session_id_header = sofia_glue_session_id_header(session, tech_pvt->profile); + if (sofia_use_soa(tech_pvt)) { nua_respond(tech_pvt->nh, SIP_200_OK, SIPTAG_CONTACT_STR(tech_pvt->reply_contact), SOATAG_USER_SDP_STR(tech_pvt->mparams.local_sdp_str), SOATAG_REUSE_REJECTED(1), SOATAG_AUDIO_AUX("cn telephone-event"), NUTAG_INCLUDE_EXTRA_SDP(1), + TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), TAG_END()); } else { nua_respond(tech_pvt->nh, SIP_200_OK, NUTAG_MEDIA_ENABLE(0), SIPTAG_CONTACT_STR(tech_pvt->reply_contact), - SIPTAG_CONTENT_TYPE_STR("application/sdp"), SIPTAG_PAYLOAD_STR(tech_pvt->mparams.local_sdp_str), TAG_END()); + SIPTAG_CONTENT_TYPE_STR("application/sdp"), SIPTAG_PAYLOAD_STR(tech_pvt->mparams.local_sdp_str), + TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), + TAG_END()); } switch_channel_mark_answered(channel); } @@ -1629,9 +1653,10 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi case SWITCH_MESSAGE_INDICATE_T38_DESCRIPTION: { switch_t38_options_t *t38_options = switch_channel_get_private(tech_pvt->channel, "t38_options"); + const char *session_id_header = sofia_glue_session_id_header(tech_pvt->session, tech_pvt->profile); if (!t38_options) { - nua_respond(tech_pvt->nh, SIP_488_NOT_ACCEPTABLE, TAG_END()); + nua_respond(tech_pvt->nh, SIP_488_NOT_ACCEPTABLE, TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), TAG_END()); goto end_lock; } @@ -1650,7 +1675,9 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi SOATAG_REUSE_REJECTED(1), SOATAG_ORDERED_USER(1), SOATAG_AUDIO_AUX("cn telephone-event"), NUTAG_INCLUDE_EXTRA_SDP(1), - TAG_IF(!zstr(extra_headers), SIPTAG_HEADER_STR(extra_headers)), TAG_END()); + TAG_IF(!zstr(extra_headers), SIPTAG_HEADER_STR(extra_headers)), + TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), + TAG_END()); } else { nua_respond(tech_pvt->nh, SIP_200_OK, NUTAG_AUTOANSWER(0), @@ -1658,7 +1685,10 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi SIPTAG_CONTACT_STR(tech_pvt->reply_contact), SIPTAG_CALL_INFO_STR(switch_channel_get_variable(tech_pvt->channel, SOFIA_SIP_HEADER_PREFIX "call_info")), SIPTAG_CONTENT_TYPE_STR("application/sdp"), - SIPTAG_PAYLOAD_STR(tech_pvt->mparams.local_sdp_str), TAG_IF(!zstr(extra_headers), SIPTAG_HEADER_STR(extra_headers)), TAG_END()); + SIPTAG_PAYLOAD_STR(tech_pvt->mparams.local_sdp_str), + TAG_IF(!zstr(extra_headers), SIPTAG_HEADER_STR(extra_headers)), + TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), + TAG_END()); } switch_safe_free(extra_headers); sofia_set_flag_locked(tech_pvt, TFLAG_ANS); @@ -1688,6 +1718,7 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi case SWITCH_MESSAGE_INDICATE_3P_NOMEDIA: { char *extra_headers = sofia_glue_get_extra_headers(channel, SOFIA_SIP_HEADER_PREFIX); + const char *session_id_header = sofia_glue_session_id_header(tech_pvt->session, tech_pvt->profile); switch_channel_clear_flag(tech_pvt->channel, CF_MEDIA_ACK); switch_channel_set_flag(tech_pvt->channel, CF_REQ_MEDIA); @@ -1698,7 +1729,9 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi NUTAG_MEDIA_ENABLE(0), TAG_IF(msg->string_arg, SIPTAG_CONTENT_TYPE_STR("application/sdp")), SIPTAG_PAYLOAD_STR(msg->string_arg), - TAG_IF(!zstr(extra_headers), SIPTAG_HEADER_STR(extra_headers)), TAG_END()); + TAG_IF(!zstr(extra_headers), SIPTAG_HEADER_STR(extra_headers)), + TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), + TAG_END()); switch_safe_free(extra_headers); } @@ -1706,6 +1739,7 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi case SWITCH_MESSAGE_INDICATE_3P_MEDIA: { char *extra_headers = sofia_glue_get_extra_headers(channel, SOFIA_SIP_HEADER_PREFIX); + const char *session_id_header = sofia_glue_session_id_header(tech_pvt->session, tech_pvt->profile); sofia_clear_flag(tech_pvt, TFLAG_ENABLE_SOA); @@ -1716,7 +1750,9 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi sofia_glue_clear_soa(session, SWITCH_TRUE); nua_invite(tech_pvt->nh, NUTAG_MEDIA_ENABLE(0), SIPTAG_PAYLOAD_STR(""), - TAG_IF(!zstr(extra_headers), SIPTAG_HEADER_STR(extra_headers)), TAG_END()); + TAG_IF(!zstr(extra_headers), SIPTAG_HEADER_STR(extra_headers)), + TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), + TAG_END()); switch_safe_free(extra_headers); } @@ -1785,10 +1821,13 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Operation not permitted on an inbound non-answered call leg!\n"); } else { + const char *session_id_header = sofia_glue_session_id_header(session, tech_pvt->profile); full_to = switch_str_nil(switch_channel_get_variable(channel, "sip_full_to")); nua_notify(tech_pvt->nh, NUTAG_NEWSUB(1), NUTAG_SUBSTATE(nua_substate_active), TAG_IF((full_to), SIPTAG_TO_STR(full_to)),SIPTAG_SUBSCRIPTION_STATE_STR("active"), - SIPTAG_EVENT_STR(event), TAG_END()); + SIPTAG_EVENT_STR(event), + TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), + TAG_END()); } } @@ -1797,6 +1836,7 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi { char ct[256] = "text/plain"; int ok = 0; + const char *session_id_header = sofia_glue_session_id_header(session, tech_pvt->profile); if (!zstr(msg->string_array_arg[3]) && !strcmp(msg->string_array_arg[3], tech_pvt->caller_profile->uuid)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Not sending message back to sender\n"); @@ -1823,10 +1863,11 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi } nua_message(tech_pvt->nh, - SIPTAG_CONTENT_TYPE_STR(ct), - TAG_IF(!zstr(tech_pvt->user_via), SIPTAG_VIA_STR(tech_pvt->user_via)), - TAG_IF(pl, SIPTAG_PAYLOAD_STR(pl)), - TAG_END()); + SIPTAG_CONTENT_TYPE_STR(ct), + TAG_IF(!zstr(tech_pvt->user_via), SIPTAG_VIA_STR(tech_pvt->user_via)), + TAG_IF(pl, SIPTAG_PAYLOAD_STR(pl)), + TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), + TAG_END()); } else { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s send_message is not supported.\n", switch_channel_get_name(channel)); @@ -1837,6 +1878,7 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi { char ct[256] = "freeswitch/data"; int ok = 0; + const char *session_id_header = sofia_glue_session_id_header(session, tech_pvt->profile); if (switch_stristr("send_info", tech_pvt->x_freeswitch_support_remote)) { ok = 1; @@ -1863,6 +1905,7 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi TAG_IF(!zstr(headers), SIPTAG_HEADER_STR(headers)), TAG_IF(!zstr(tech_pvt->user_via), SIPTAG_VIA_STR(tech_pvt->user_via)), TAG_IF(pl, SIPTAG_PAYLOAD_STR(pl)), + TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), TAG_END()); switch_safe_free(headers); @@ -1905,6 +1948,7 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi if (to_user && to_host && from_user && from_host && call_id && to_tag && from_tag) { char in[512] = "", out[1536] = ""; + const char *session_id_header = sofia_glue_session_id_header(session, tech_pvt->profile); switch_snprintf(in, sizeof(in), "%s;to-tag=%s;from-tag=%s", call_id, to_tag, from_tag); switch_url_encode(in, out, sizeof(out)); @@ -1912,7 +1956,9 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi ref_to = switch_mprintf("", to_user, to_host, out); ref_by = switch_mprintf("", from_user, from_host); - nua_refer(tech_pvt->nh, SIPTAG_REFER_TO_STR(ref_to), SIPTAG_REFERRED_BY_STR(ref_by), TAG_END()); + nua_refer(tech_pvt->nh, SIPTAG_REFER_TO_STR(ref_to), SIPTAG_REFERRED_BY_STR(ref_by), + TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), + TAG_END()); switch_safe_free(ref_to); switch_safe_free(ref_by); } @@ -1937,6 +1983,7 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi const char *allow = switch_channel_get_variable(tech_pvt->channel, "sip_allow"); switch_event_t *event; int update_allowed = 0; + const char *session_id_header = sofia_glue_session_id_header(tech_pvt->session, tech_pvt->profile); check_decode(name, tech_pvt->session); @@ -1970,7 +2017,9 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi nua_info(tech_pvt->nh, SIPTAG_CONTENT_TYPE_STR("message/update_display"), TAG_IF(!zstr_buf(message), SIPTAG_HEADER_STR(message)), - TAG_IF(!zstr(tech_pvt->user_via), SIPTAG_VIA_STR(tech_pvt->user_via)), TAG_END()); + TAG_IF(!zstr(tech_pvt->user_via), SIPTAG_VIA_STR(tech_pvt->user_via)), + TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), + TAG_END()); } else if (ua && switch_stristr("snom", ua)) { const char *ver_str = NULL; int version = 0; @@ -2025,7 +2074,9 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi TAG_IF(call_info, SIPTAG_CALL_INFO_STR(call_info)), TAG_IF(!zstr(tech_pvt->route_uri), NUTAG_PROXY(tech_pvt->route_uri)), TAG_IF(!zstr_buf(message), SIPTAG_HEADER_STR(message)), - TAG_IF(!zstr(tech_pvt->user_via), SIPTAG_VIA_STR(tech_pvt->user_via)), TAG_END()); + TAG_IF(!zstr(tech_pvt->user_via), SIPTAG_VIA_STR(tech_pvt->user_via)), + TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), + TAG_END()); } tech_pvt->last_sent_callee_id_name = switch_core_session_strdup(tech_pvt->session, name); @@ -2070,11 +2121,15 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi if (!zstr(msg->string_arg)) { char message[256] = ""; const char *ua = switch_channel_get_variable(tech_pvt->channel, "sip_user_agent"); + const char *session_id_header = sofia_glue_session_id_header(tech_pvt->session, tech_pvt->profile); if (ua && switch_stristr("snom", ua)) { snprintf(message, sizeof(message), "From:\r\nTo: \"%s\" %s\r\n", msg->string_arg, tech_pvt->caller_profile->destination_number); nua_info(tech_pvt->nh, SIPTAG_CONTENT_TYPE_STR("message/sipfrag"), - TAG_IF(!zstr(tech_pvt->user_via), SIPTAG_VIA_STR(tech_pvt->user_via)), SIPTAG_PAYLOAD_STR(message), TAG_END()); + TAG_IF(!zstr(tech_pvt->user_via), SIPTAG_VIA_STR(tech_pvt->user_via)), + SIPTAG_PAYLOAD_STR(message), + TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), + TAG_END()); } else if (ua && switch_stristr("polycom", ua)) { snprintf(message, sizeof(message), "P-Asserted-Identity: \"%s\" <%s>", msg->string_arg, tech_pvt->caller_profile->destination_number); nua_update(tech_pvt->nh, @@ -2083,7 +2138,9 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi NUTAG_UPDATE_REFRESH(tech_pvt->update_refresher), TAG_IF(!zstr(tech_pvt->route_uri), NUTAG_PROXY(tech_pvt->route_uri)), TAG_IF(!zstr_buf(message), SIPTAG_HEADER_STR(message)), - TAG_IF(!zstr(tech_pvt->user_via), SIPTAG_VIA_STR(tech_pvt->user_via)), TAG_END()); + TAG_IF(!zstr(tech_pvt->user_via), SIPTAG_VIA_STR(tech_pvt->user_via)), + TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), + TAG_END()); } } } @@ -2183,6 +2240,7 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi break; case SWITCH_MESSAGE_INDICATE_RESPOND: { + const char *session_id_header = sofia_glue_session_id_header(tech_pvt->session, tech_pvt->profile); if (switch_channel_test_flag(tech_pvt->channel, CF_AWAITING_STREAM_CHANGE)) { switch_channel_clear_flag(tech_pvt->channel, CF_AWAITING_STREAM_CHANGE); @@ -2195,12 +2253,17 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi SOATAG_USER_SDP_STR(tech_pvt->mparams.local_sdp_str), SOATAG_REUSE_REJECTED(1), SOATAG_AUDIO_AUX("cn telephone-event"), - TAG_IF(sofia_test_pflag(tech_pvt->profile, PFLAG_DISABLE_100REL), NUTAG_INCLUDE_EXTRA_SDP(1)), TAG_END()); + TAG_IF(sofia_test_pflag(tech_pvt->profile, PFLAG_DISABLE_100REL), NUTAG_INCLUDE_EXTRA_SDP(1)), + TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), + TAG_END()); } else { nua_respond(tech_pvt->nh, SIP_200_OK, NUTAG_MEDIA_ENABLE(0), SIPTAG_CONTACT_STR(tech_pvt->reply_contact), - SIPTAG_CONTENT_TYPE_STR("application/sdp"), SIPTAG_PAYLOAD_STR(tech_pvt->mparams.local_sdp_str), TAG_END()); + SIPTAG_CONTENT_TYPE_STR("application/sdp"), + SIPTAG_PAYLOAD_STR(tech_pvt->mparams.local_sdp_str), + TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), + TAG_END()); } } @@ -2245,8 +2308,12 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi 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), - SIPTAG_EXPIRES_STR("60"), NUTAG_WITH_THIS_MSG(tech_pvt->proxy_refer_msg), TAG_END()); + nua_respond(tech_pvt->nh, code, su_strdup(nua_handle_home(tech_pvt->nh), reason), + SIPTAG_CONTACT_STR(tech_pvt->reply_contact), + SIPTAG_EXPIRES_STR("60"), + NUTAG_WITH_THIS_MSG(tech_pvt->proxy_refer_msg), + TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), + TAG_END()); msg_ref_destroy(tech_pvt->proxy_refer_msg); tech_pvt->proxy_refer_msg = NULL; } @@ -2296,13 +2363,17 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi SOATAG_USER_SDP_STR(tech_pvt->mparams.local_sdp_str), SOATAG_REUSE_REJECTED(1), SOATAG_AUDIO_AUX("cn telephone-event"), NUTAG_INCLUDE_EXTRA_SDP(1), - TAG_IF(!zstr(extra_headers), SIPTAG_HEADER_STR(extra_headers)), TAG_END()); + TAG_IF(!zstr(extra_headers), SIPTAG_HEADER_STR(extra_headers)), + TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), + TAG_END()); } else { nua_respond(tech_pvt->nh, code, su_strdup(nua_handle_home(tech_pvt->nh), reason), SIPTAG_CONTACT_STR(tech_pvt->reply_contact), NUTAG_MEDIA_ENABLE(0), SIPTAG_CONTENT_TYPE_STR("application/sdp"), SIPTAG_PAYLOAD_STR(tech_pvt->mparams.local_sdp_str), - TAG_IF(!zstr(extra_headers), SIPTAG_HEADER_STR(extra_headers)), TAG_END()); + TAG_IF(!zstr(extra_headers), SIPTAG_HEADER_STR(extra_headers)), + TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), + TAG_END()); } if (sofia_test_pflag(tech_pvt->profile, PFLAG_3PCC_PROXY) && sofia_test_flag(tech_pvt, TFLAG_3PCC)) { @@ -2336,8 +2407,11 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Cannot respond.\n"); } } else { - nua_respond(tech_pvt->nh, code, su_strdup(nua_handle_home(tech_pvt->nh), reason), SIPTAG_CONTACT_STR(tech_pvt->reply_contact), - TAG_IF(!zstr(extra_headers), SIPTAG_HEADER_STR(extra_headers)), TAG_END()); + nua_respond(tech_pvt->nh, code, su_strdup(nua_handle_home(tech_pvt->nh), reason), + SIPTAG_CONTACT_STR(tech_pvt->reply_contact), + TAG_IF(!zstr(extra_headers), SIPTAG_HEADER_STR(extra_headers)), + TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), + TAG_END()); } } @@ -2353,13 +2427,17 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi char *extra_header = sofia_glue_get_extra_headers(channel, SOFIA_SIP_PROGRESS_HEADER_PREFIX); const char *call_info = switch_channel_get_variable(channel, "presence_call_info_full"); char *cid = generate_pai_str(tech_pvt); + const char *session_id_header = sofia_glue_session_id_header(tech_pvt->session, tech_pvt->profile); + nua_respond(tech_pvt->nh, SIP_180_RINGING, SIPTAG_CONTACT_STR(tech_pvt->reply_contact), TAG_IF(cid, SIPTAG_HEADER_STR(cid)), TAG_IF(call_info, SIPTAG_CALL_INFO_STR(call_info)), TAG_IF(!zstr(extra_header), SIPTAG_HEADER_STR(extra_header)), TAG_IF(switch_stristr("update_display", tech_pvt->x_freeswitch_support_remote), - SIPTAG_HEADER_STR("X-FS-Support: " FREESWITCH_SUPPORT)), TAG_END()); + SIPTAG_HEADER_STR("X-FS-Support: " FREESWITCH_SUPPORT)), + TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), + TAG_END()); } break; case SWITCH_MESSAGE_INDICATE_ACKNOWLEDGE_CALL: @@ -2378,6 +2456,7 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi char *extra_header = sofia_glue_get_extra_headers(channel, SOFIA_SIP_PROGRESS_HEADER_PREFIX); const char *call_info = switch_channel_get_variable(channel, "presence_call_info_full"); char *cid = generate_pai_str(tech_pvt); + const char *session_id_header = sofia_glue_session_id_header(tech_pvt->session, tech_pvt->profile); /* Set sip_to_tag to local tag for inbound channels. */ if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_INBOUND) { @@ -2398,7 +2477,9 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi TAG_IF(call_info, SIPTAG_CALL_INFO_STR(call_info)), TAG_IF(!zstr(extra_header), SIPTAG_HEADER_STR(extra_header)), TAG_IF(switch_stristr("update_display", tech_pvt->x_freeswitch_support_remote), - SIPTAG_HEADER_STR("X-FS-Support: " FREESWITCH_SUPPORT)), TAG_END()); + SIPTAG_HEADER_STR("X-FS-Support: " FREESWITCH_SUPPORT)), + TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), + TAG_END()); break; case SWITCH_RING_READY_RINGING: @@ -2410,7 +2491,9 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi TAG_IF(call_info, SIPTAG_CALL_INFO_STR(call_info)), TAG_IF(!zstr(extra_header), SIPTAG_HEADER_STR(extra_header)), TAG_IF(switch_stristr("update_display", tech_pvt->x_freeswitch_support_remote), - SIPTAG_HEADER_STR("X-FS-Support: " FREESWITCH_SUPPORT)), TAG_END()); + SIPTAG_HEADER_STR("X-FS-Support: " FREESWITCH_SUPPORT)), + TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), + TAG_END()); break; } @@ -2528,6 +2611,7 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi if (!sofia_test_flag(tech_pvt, TFLAG_BYE)) { char *extra_header = sofia_glue_get_extra_headers(channel, SOFIA_SIP_PROGRESS_HEADER_PREFIX); char *cid = NULL; + const char *session_id_header = sofia_glue_session_id_header(session, tech_pvt->profile); cid = generate_pai_str(tech_pvt); @@ -2556,7 +2640,9 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi TAG_IF(call_info, SIPTAG_CALL_INFO_STR(call_info)), TAG_IF(!zstr(extra_header), SIPTAG_HEADER_STR(extra_header)), TAG_IF(switch_stristr("update_display", tech_pvt->x_freeswitch_support_remote), - SIPTAG_HEADER_STR("X-FS-Support: " FREESWITCH_SUPPORT)), TAG_END()); + SIPTAG_HEADER_STR("X-FS-Support: " FREESWITCH_SUPPORT)), + TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), + TAG_END()); } else { nua_respond(tech_pvt->nh, send_sip_code, p_send_sip_msg, @@ -2570,7 +2656,9 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi TAG_IF(call_info, SIPTAG_CALL_INFO_STR(call_info)), TAG_IF(!zstr(extra_header), SIPTAG_HEADER_STR(extra_header)), TAG_IF(switch_stristr("update_display", tech_pvt->x_freeswitch_support_remote), - SIPTAG_HEADER_STR("X-FS-Support: " FREESWITCH_SUPPORT)), TAG_END()); + SIPTAG_HEADER_STR("X-FS-Support: " FREESWITCH_SUPPORT)), + TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), + TAG_END()); } switch_safe_free(extra_header); } @@ -2583,7 +2671,17 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi switch_t38_options_t *t38_options = switch_channel_get_private(channel, "t38_options"); if (!t38_options) { - nua_respond(tech_pvt->nh, SIP_488_NOT_ACCEPTABLE, TAG_END()); + const char *session_id_header = sofia_glue_session_id_header(tech_pvt->session, tech_pvt->profile); + + nua_respond(tech_pvt->nh, SIP_488_NOT_ACCEPTABLE, TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), TAG_END()); + } + } + break; + + case SWITCH_MESSAGE_INDICATE_SESSION_ID: + { + if (sofia_test_pflag(tech_pvt->profile, PFLAG_RFC7989_SESSION_ID) && switch_channel_test_flag(channel, CF_ANSWERED)) { + sofia_glue_do_invite(session); } } break; @@ -5198,7 +5296,8 @@ static int notify_csta_callback(void *pArg, int argc, char **argv, char **column nua_notify(nh, NUTAG_NEWSUB(1), TAG_IF(dst->route_uri, NUTAG_PROXY(route_uri)), TAG_IF(dst->route, SIPTAG_ROUTE_STR(dst->route)), TAG_IF(call_id, SIPTAG_CALL_ID_STR(call_id)), - SIPTAG_EVENT_STR("as-feature-event"), SIPTAG_CONTENT_TYPE_STR(ct), TAG_IF(!zstr(extra_headers), SIPTAG_HEADER_STR(extra_headers)), TAG_IF(!zstr(body), SIPTAG_PAYLOAD_STR(body)), SIPTAG_CSEQ(cseq), TAG_END()); + SIPTAG_EVENT_STR("as-feature-event"), SIPTAG_CONTENT_TYPE_STR(ct), TAG_IF(!zstr(extra_headers), SIPTAG_HEADER_STR(extra_headers)), TAG_IF(!zstr(body), SIPTAG_PAYLOAD_STR(body)), SIPTAG_CSEQ(cseq), + TAG_END()); @@ -5346,7 +5445,8 @@ void general_event_handler(switch_event_t *event) NUTAG_NEWSUB(1), TAG_IF(sip_sub_st, SIPTAG_SUBSCRIPTION_STATE_STR(sip_sub_st)), TAG_IF(dst->route_uri, NUTAG_PROXY(dst->route_uri)), TAG_IF(dst->route, SIPTAG_ROUTE_STR(dst->route)), TAG_IF(call_id, SIPTAG_CALL_ID_STR(call_id)), SIPTAG_EVENT_STR(es), TAG_IF(ct, SIPTAG_CONTENT_TYPE_STR(ct)), TAG_IF(!zstr(body), SIPTAG_PAYLOAD_STR(body)), - TAG_IF(!zstr(extra_headers), SIPTAG_HEADER_STR(extra_headers)), TAG_END()); + TAG_IF(!zstr(extra_headers), SIPTAG_HEADER_STR(extra_headers)), + TAG_END()); switch_safe_free(route_uri); sofia_glue_free_destination(dst); @@ -5399,7 +5499,8 @@ void general_event_handler(switch_event_t *event) NUTAG_NEWSUB(1), SIPTAG_SUBSCRIPTION_STATE_STR("terminated;reason=noresource"), TAG_IF(dst->route_uri, NUTAG_PROXY(dst->route_uri)), TAG_IF(dst->route, SIPTAG_ROUTE_STR(dst->route)), SIPTAG_EVENT_STR(es), TAG_IF(ct, SIPTAG_CONTENT_TYPE_STR(ct)), TAG_IF(!zstr(body), SIPTAG_PAYLOAD_STR(body)), - TAG_IF(!zstr(extra_headers), SIPTAG_HEADER_STR(extra_headers)), TAG_END()); + TAG_IF(!zstr(extra_headers), SIPTAG_HEADER_STR(extra_headers)), + TAG_END()); switch_safe_free(route_uri); @@ -5417,9 +5518,12 @@ void general_event_handler(switch_event_t *event) if ((session = switch_core_session_locate(uuid))) { if ((tech_pvt = switch_core_session_get_private(session))) { + const char *session_id_header = sofia_glue_session_id_header(session, tech_pvt->profile); nua_notify(tech_pvt->nh, NUTAG_NEWSUB(1), SIPTAG_SUBSCRIPTION_STATE_STR("terminated;reason=noresource"), - SIPTAG_EVENT_STR(es), SIPTAG_CONTENT_TYPE_STR(ct), TAG_IF(!zstr(body), SIPTAG_PAYLOAD_STR(body)), TAG_END()); + SIPTAG_EVENT_STR(es), SIPTAG_CONTENT_TYPE_STR(ct), TAG_IF(!zstr(body), SIPTAG_PAYLOAD_STR(body)), + TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), + TAG_END()); } switch_core_session_rwunlock(session); } @@ -5614,9 +5718,13 @@ void general_event_handler(switch_event_t *event) if ((session = switch_core_session_locate(uuid))) { if ((tech_pvt = switch_core_session_get_private(session))) { + const char *session_id_header = sofia_glue_session_id_header(session, tech_pvt->profile); + nua_message(tech_pvt->nh, SIPTAG_CONTENT_TYPE_STR(ct), SIPTAG_PAYLOAD_STR(body), - TAG_IF(!zstr(body), SIPTAG_PAYLOAD_STR(body)), TAG_IF(!zstr(subject), SIPTAG_SUBJECT_STR(subject)), TAG_END()); + TAG_IF(!zstr(body), SIPTAG_PAYLOAD_STR(body)), TAG_IF(!zstr(subject), SIPTAG_SUBJECT_STR(subject)), + TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), + TAG_END()); } switch_core_session_rwunlock(session); } diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.h b/src/mod/endpoints/mod_sofia/mod_sofia.h index de44aac283..5e5feb2d6d 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.h +++ b/src/mod/endpoints/mod_sofia/mod_sofia.h @@ -192,6 +192,7 @@ struct sofia_private { int is_call; int is_static; switch_time_t ping_sent; + char *rfc7989_uuid; }; #define set_param(ptr,val) if (ptr) {free(ptr) ; ptr = NULL;} if (val) {ptr = strdup(val);} @@ -310,6 +311,8 @@ typedef enum { PFLAG_FIRE_BYE_RESPONSE_EVENTS, PFLAG_AUTO_INVITE_100, PFLAG_UPDATE_REFRESHER, + PFLAG_RFC7989_SESSION_ID, + PFLAG_RFC7989_FORCE_OLD, PFLAG_AUTH_REQUIRE_USER, PFLAG_AUTH_CALLS_ACL_ONLY, PFLAG_USE_PORT_FOR_ACL_CHECK, @@ -790,6 +793,7 @@ struct sofia_profile { int bind_attempt_interval; char *proxy_notify_events; char *proxy_info_content_types; + char *rfc7989_filter; char *acl_inbound_x_token_header; char *acl_proxy_x_token_header; }; @@ -989,6 +993,13 @@ void launch_sofia_profile_thread(sofia_profile_t *profile); switch_status_t sofia_presence_chat_send(switch_event_t *message_event); +#define RFC7989_SESSION_UUID_LEN 32 +#define RFC7989_SESSION_UUID_NULL "00000000000000000000000000000000" + +int sofia_glue_is_valid_session_id(const char *session_id); +void sofia_glue_store_session_id(switch_core_session_t *session, sofia_profile_t *profile, sip_t const *sip, switch_bool_t is_reply); +char *sofia_glue_session_id_header(switch_core_session_t *session, sofia_profile_t *profile); + /* * \brief Sets the "ep_codec_string" channel variable, parsing r_sdp and taing codec_string in consideration * \param channel Current channel diff --git a/src/mod/endpoints/mod_sofia/sofia.c b/src/mod/endpoints/mod_sofia/sofia.c index 24c5a2d749..ef6e49a2a5 100644 --- a/src/mod/endpoints/mod_sofia/sofia.c +++ b/src/mod/endpoints/mod_sofia/sofia.c @@ -610,6 +610,7 @@ void sofia_handle_sip_i_notify(switch_core_session_t *session, int status, sofia_gateway_subscription_t *gw_sub_ptr; int sub_state; sofia_gateway_t *gateway = NULL; + const char *session_id_header = sofia_glue_session_id_header(session, profile); tl_gets(tags, NUTAG_SUBSTATE_REF(sub_state), TAG_END()); @@ -621,7 +622,7 @@ void sofia_handle_sip_i_notify(switch_core_session_t *session, int status, /* Automatically return a 200 OK for Event: keep-alive */ if (!strcasecmp(sip->sip_event->o_type, "keep-alive")) { /* XXX MTK - is this right? in this case isn't sofia is already sending a 200 itself also? */ - nua_respond(nh, SIP_200_OK, NUTAG_WITH_THIS_MSG(de->data->e_msg), TAG_END()); + nua_respond(nh, SIP_200_OK, NUTAG_WITH_THIS_MSG(de->data->e_msg), TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), TAG_END()); goto end; } @@ -717,7 +718,7 @@ void sofia_handle_sip_i_notify(switch_core_session_t *session, int status, } } } - nua_respond(nh, SIP_200_OK, NUTAG_WITH_THIS_MSG(de->data->e_msg), TAG_END()); + nua_respond(nh, SIP_200_OK, NUTAG_WITH_THIS_MSG(de->data->e_msg), TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), TAG_END()); } /* if no session, assume it could be an incoming notify from a gateway subscription */ @@ -738,11 +739,14 @@ void sofia_handle_sip_i_notify(switch_core_session_t *session, int status, nua_notify(other_tech_pvt->nh, NUTAG_NEWSUB(1), NUTAG_SUBSTATE(nua_substate_active), TAG_IF((full_to), SIPTAG_TO_STR(full_to)), SIPTAG_SUBSCRIPTION_STATE_STR("active"), SIPTAG_EVENT_STR(sip->sip_event->o_type), TAG_IF(!zstr(unknown), SIPTAG_HEADER_STR(unknown)), - TAG_IF(!zstr(pl), SIPTAG_PAYLOAD_STR(pl)), TAG_END()); + TAG_IF(!zstr(pl), SIPTAG_PAYLOAD_STR(pl)), + TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), + TAG_END()); switch_safe_free(unknown); switch_core_session_rwunlock(other_session); } - nua_respond(nh, SIP_200_OK, NUTAG_WITH_THIS_MSG(de->data->e_msg), TAG_END()); + nua_respond(nh, SIP_200_OK, NUTAG_WITH_THIS_MSG(de->data->e_msg), + TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), TAG_END()); goto end; } /* make sure we have a proper "talk" event */ @@ -754,7 +758,8 @@ void sofia_handle_sip_i_notify(switch_core_session_t *session, int status, switch_channel_answer(channel); switch_channel_set_variable(channel, "auto_answer_destination", switch_channel_get_variable(channel, "destination_number")); switch_ivr_session_transfer(session, "auto_answer", NULL, NULL); - nua_respond(nh, SIP_200_OK, NUTAG_WITH_THIS_MSG(de->data->e_msg), TAG_END()); + nua_respond(nh, SIP_200_OK, NUTAG_WITH_THIS_MSG(de->data->e_msg), + TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), TAG_END()); goto end; } } @@ -841,7 +846,8 @@ void sofia_handle_sip_i_notify(switch_core_session_t *session, int status, if (sip && sip->sip_event && sip->sip_event->o_type && !strcasecmp(sip->sip_event->o_type, "message-summary")) { /* unsolicited mwi, just say ok */ - nua_respond(nh, SIP_200_OK, NUTAG_WITH_THIS_MSG(de->data->e_msg), TAG_END()); + nua_respond(nh, SIP_200_OK, NUTAG_WITH_THIS_MSG(de->data->e_msg), + TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), TAG_END()); if (sofia_test_pflag(profile, PFLAG_FORWARD_MWI_NOTIFY)) { const char *mwi_status = NULL; @@ -890,7 +896,8 @@ void sofia_handle_sip_i_notify(switch_core_session_t *session, int status, } } else { - nua_respond(nh, 481, "Subscription Does Not Exist", NUTAG_WITH_THIS_MSG(de->data->e_msg), TAG_END()); + nua_respond(nh, 481, "Subscription Does Not Exist", NUTAG_WITH_THIS_MSG(de->data->e_msg), + TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), TAG_END()); } end: @@ -942,6 +949,7 @@ void sofia_handle_sip_i_bye(switch_core_session_t *session, int status, char *extra_headers; const char *call_info = NULL; const char *vval = NULL; + const char *session_id_header = sofia_glue_session_id_header(session, profile); #ifdef MANUAL_BYE int cause; char st[80] = ""; @@ -1078,7 +1086,8 @@ void sofia_handle_sip_i_bye(switch_core_session_t *session, int status, switch_channel_hangup(channel, cause); nua_respond(nh, SIP_200_OK, NUTAG_WITH_THIS_MSG(de->data->e_msg), - TAG_IF(call_info, SIPTAG_CALL_INFO_STR(call_info)), TAG_IF(!zstr(extra_headers), SIPTAG_HEADER_STR(extra_headers)), TAG_END()); + TAG_IF(call_info, SIPTAG_CALL_INFO_STR(call_info)), TAG_IF(!zstr(extra_headers), SIPTAG_HEADER_STR(extra_headers)), + TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), TAG_END()); switch_safe_free(extra_headers); @@ -1385,6 +1394,7 @@ static void tech_send_ack(nua_handle_t *nh, private_object_t *tech_pvt, const ch const char *invite_full_from = switch_channel_get_variable(tech_pvt->channel, "sip_invite_full_from"); const char *invite_full_to = switch_channel_get_variable(tech_pvt->channel, "sip_invite_full_to"); int soa = sofia_use_soa(tech_pvt); + const char *session_id_header = sofia_glue_session_id_header(tech_pvt->session, tech_pvt->profile); if (sofia_test_pflag(tech_pvt->profile, PFLAG_TRACK_CALLS)) { const char *invite_full_via = switch_channel_get_variable(tech_pvt->channel, "sip_invite_full_via"); @@ -1402,6 +1412,7 @@ static void tech_send_ack(nua_handle_t *nh, private_object_t *tech_pvt, const ch TAG_IF(r_sdp && !soa, SIPTAG_CONTENT_TYPE_STR("application/sdp")), TAG_IF(r_sdp && !soa, SIPTAG_PAYLOAD_STR(r_sdp)), TAG_IF(r_sdp && !soa, NUTAG_MEDIA_ENABLE(0)), + TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), TAG_END()); } else { nua_ack(nh, @@ -1414,6 +1425,7 @@ static void tech_send_ack(nua_handle_t *nh, private_object_t *tech_pvt, const ch TAG_IF(r_sdp && !soa, SIPTAG_CONTENT_TYPE_STR("application/sdp")), TAG_IF(r_sdp && !soa, SIPTAG_PAYLOAD_STR(r_sdp)), TAG_IF(r_sdp && !soa, NUTAG_MEDIA_ENABLE(0)), + TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), TAG_END()); } @@ -1671,6 +1683,7 @@ static void our_sofia_event_callback(nua_event_t event, { if (channel && sip) { const char *r_sdp = NULL; + sofia_glue_store_session_id(session, profile, sip, 0); if (sip->sip_payload && sip->sip_payload->pl_data) { if (sofia_test_flag(tech_pvt, TFLAG_PASS_ACK)) { @@ -5299,6 +5312,20 @@ switch_status_t config_sofia(sofia_config_t reload, char *profile_name) } else { sofia_clear_pflag(profile, PFLAG_UPDATE_REFRESHER); } + } else if (!strcasecmp(var, "rfc-7989")) { + if (switch_true(val)) { + sofia_set_pflag(profile, PFLAG_RFC7989_SESSION_ID); + } else { + sofia_clear_pflag(profile, PFLAG_RFC7989_SESSION_ID); + } + } else if (!strcasecmp(var, "rfc-7989-filter")) { + profile->rfc7989_filter = switch_core_strdup(profile->pool, val); + } else if (!strcasecmp(var, "rfc-7989-force-old")) { + if (switch_true(val)) { + sofia_set_pflag(profile, PFLAG_RFC7989_FORCE_OLD); + } else { + sofia_clear_pflag(profile, PFLAG_RFC7989_FORCE_OLD); + } } else if (!strcasecmp(var, "manage-shared-appearance")) { if (switch_true(val)) { sofia_set_pflag(profile, PFLAG_MANAGE_SHARED_APPEARANCE); @@ -6616,6 +6643,8 @@ static void sofia_handle_sip_r_invite(switch_core_session_t *session, int status switch_channel_set_flag(channel, CF_MEDIA_ACK); + sofia_glue_store_session_id(session, profile, sip, 1); + if ((x_freeswitch_support = sofia_glue_get_unknown_header(sip, "X-FS-Support"))) { tech_pvt->x_freeswitch_support_remote = switch_core_session_strdup(session, x_freeswitch_support); } @@ -7222,6 +7251,7 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status, switch_event_t *s_event = NULL; char *p; char *patched_sdp = NULL; + const char *session_id_header = sofia_glue_session_id_header(session, profile); tl_gets(tags, NUTAG_CALLSTATE_REF(ss_state), @@ -7389,6 +7419,7 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status, TAG_IF((full_to), SIPTAG_TO_STR(full_to)), SIPTAG_SUBSCRIPTION_STATE_STR("terminated;reason=noresource"), SIPTAG_EVENT_STR("talk"), + TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), TAG_END()); } } @@ -7501,7 +7532,8 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status, switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "PROXY MEDIA"); switch_core_media_patch_sdp(tech_pvt->session); if (sofia_media_activate_rtp(tech_pvt) != SWITCH_STATUS_SUCCESS) { - nua_respond(nh, SIP_488_NOT_ACCEPTABLE, TAG_END()); + nua_respond(nh, SIP_488_NOT_ACCEPTABLE, + TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), TAG_END()); switch_channel_hangup(channel, SWITCH_CAUSE_INCOMPATIBLE_DESTINATION); } else{ switch_channel_mark_pre_answered(channel); @@ -7510,7 +7542,8 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status, } else { if (sofia_media_tech_media(tech_pvt, (char *) r_sdp) != SWITCH_STATUS_SUCCESS) { switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "CODEC NEGOTIATION ERROR"); - nua_respond(nh, SIP_488_NOT_ACCEPTABLE, TAG_END()); + nua_respond(nh, SIP_488_NOT_ACCEPTABLE, + TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)),TAG_END()); switch_channel_hangup(channel, SWITCH_CAUSE_INCOMPATIBLE_DESTINATION); } } @@ -7543,7 +7576,6 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status, } if (switch_channel_test_flag(channel, CF_3P_NOMEDIA_REQUESTED)) { - if (switch_channel_test_flag(channel, CF_3P_NOMEDIA_REQUESTED_BLEG)) { switch_core_session_t *other_session; @@ -7565,6 +7597,7 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status, SOATAG_RTP_SELECT(1), SOATAG_AUDIO_AUX("cn telephone-event"), TAG_IF(sofia_test_pflag(other_tech_pvt->profile, PFLAG_DISABLE_100REL), NUTAG_INCLUDE_EXTRA_SDP(1)), + TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), TAG_END()); } else { nua_ack(other_tech_pvt->nh, @@ -7574,12 +7607,14 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status, TAG_IF(r_sdp, SIPTAG_CONTENT_TYPE_STR("application/sdp")), TAG_IF(r_sdp, SIPTAG_PAYLOAD_STR(r_sdp)), SOATAG_AUDIO_AUX("cn telephone-event"), + TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), TAG_END()); } nua_ack(tech_pvt->nh, TAG_IF(!zstr(tech_pvt->user_via), SIPTAG_VIA_STR(tech_pvt->user_via)), SIPTAG_CONTACT_STR(tech_pvt->reply_contact), + TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), TAG_END()); } @@ -7606,7 +7641,8 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status, if (!match) { if (switch_channel_get_state(channel) != CS_NEW) { - nua_respond(tech_pvt->nh, SIP_488_NOT_ACCEPTABLE, TAG_END()); + nua_respond(tech_pvt->nh, SIP_488_NOT_ACCEPTABLE, + TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)),TAG_END()); } } else { switch_core_media_gen_local_sdp(session, SDP_TYPE_RESPONSE, NULL, 0, NULL, 0); @@ -7632,6 +7668,7 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status, SOATAG_RTP_SELECT(1), SOATAG_AUDIO_AUX("cn telephone-event"), TAG_IF(sofia_test_pflag(tech_pvt->profile, PFLAG_DISABLE_100REL), NUTAG_INCLUDE_EXTRA_SDP(1)), + TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), TAG_END()); } else { nua_ack(tech_pvt->nh, @@ -7641,6 +7678,7 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status, TAG_IF(tech_pvt->mparams.local_sdp_str, SIPTAG_CONTENT_TYPE_STR("application/sdp")), TAG_IF(tech_pvt->mparams.local_sdp_str, SIPTAG_PAYLOAD_STR(tech_pvt->mparams.local_sdp_str)), SOATAG_AUDIO_AUX("cn telephone-event"), + TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), TAG_END()); } @@ -7698,7 +7736,8 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status, switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Other leg already handling a reinvite, so responding with 491\n"); - nua_respond(tech_pvt->nh, SIP_491_REQUEST_PENDING, TAG_END()); + nua_respond(tech_pvt->nh, SIP_491_REQUEST_PENDING, + TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), TAG_END()); sofia_glue_do_invite(session); goto done; } @@ -7747,7 +7786,7 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status, if (switch_channel_get_state(channel) == CS_NEW) { switch_channel_set_state(channel, CS_INIT); } else { - nua_respond(tech_pvt->nh, SIP_200_OK, TAG_END()); + nua_respond(tech_pvt->nh, SIP_200_OK, TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), TAG_END()); } sofia_set_flag(tech_pvt, TFLAG_SDP); if (replaces_str) { @@ -7825,12 +7864,16 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status, SOATAG_USER_SDP_STR(tech_pvt->mparams.local_sdp_str), SOATAG_REUSE_REJECTED(1), SOATAG_AUDIO_AUX("cn telephone-event"), - TAG_IF(sofia_test_pflag(profile, PFLAG_DISABLE_100REL), NUTAG_INCLUDE_EXTRA_SDP(1)), TAG_END()); + TAG_IF(sofia_test_pflag(profile, PFLAG_DISABLE_100REL), NUTAG_INCLUDE_EXTRA_SDP(1)), + TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), + TAG_END()); } else { nua_respond(tech_pvt->nh, SIP_200_OK, NUTAG_MEDIA_ENABLE(0), SIPTAG_CONTACT_STR(tech_pvt->reply_contact), - SIPTAG_CONTENT_TYPE_STR("application/sdp"), SIPTAG_PAYLOAD_STR(tech_pvt->mparams.local_sdp_str), TAG_END()); + SIPTAG_CONTENT_TYPE_STR("application/sdp"), SIPTAG_PAYLOAD_STR(tech_pvt->mparams.local_sdp_str), + TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), + TAG_END()); } } } else if (sofia_test_pflag(profile, PFLAG_3PCC_PROXY)) { @@ -7897,12 +7940,16 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status, SOATAG_USER_SDP_STR(tech_pvt->mparams.local_sdp_str), SOATAG_REUSE_REJECTED(1), SOATAG_AUDIO_AUX("cn telephone-event"), - TAG_IF(sofia_test_pflag(profile, PFLAG_DISABLE_100REL), NUTAG_INCLUDE_EXTRA_SDP(1)), TAG_END()); + TAG_IF(sofia_test_pflag(profile, PFLAG_DISABLE_100REL), NUTAG_INCLUDE_EXTRA_SDP(1)), + TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), + TAG_END()); } else { nua_respond(tech_pvt->nh, SIP_200_OK, NUTAG_MEDIA_ENABLE(0), SIPTAG_CONTACT_STR(tech_pvt->reply_contact), - SIPTAG_CONTENT_TYPE_STR("application/sdp"), SIPTAG_PAYLOAD_STR(tech_pvt->mparams.local_sdp_str), TAG_END()); + SIPTAG_CONTENT_TYPE_STR("application/sdp"), SIPTAG_PAYLOAD_STR(tech_pvt->mparams.local_sdp_str), + TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), + TAG_END()); } } @@ -7945,11 +7992,12 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status, if (r_sdp) { const char *var; uint8_t match = 0, is_ok = 1, is_t38 = 0; + tech_pvt->mparams.hold_laps = 0; if ((var = switch_channel_get_variable(channel, "sip_ignore_reinvites")) && switch_true(var)) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Ignoring Re-invite\n"); - nua_respond(tech_pvt->nh, SIP_200_OK, TAG_END()); + nua_respond(tech_pvt->nh, SIP_200_OK, TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), TAG_END()); goto done; } @@ -7962,7 +8010,7 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status, if ((sofia_test_media_flag(profile, SCMF_DISABLE_HOLD) || ((var = switch_channel_get_variable(channel, "rtp_disable_hold")) && switch_true(var))) && ((switch_stristr("sendonly", r_sdp) || switch_stristr("0.0.0.0", r_sdp) || switch_stristr("inactive", r_sdp)) || tech_pvt->mparams.hold_laps)) { - nua_respond(tech_pvt->nh, SIP_200_OK, TAG_END()); + nua_respond(tech_pvt->nh, SIP_200_OK, TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), TAG_END()); if (tech_pvt->mparams.hold_laps) { tech_pvt->mparams.hold_laps = 0; @@ -8024,12 +8072,16 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status, SOATAG_USER_SDP_STR(tech_pvt->mparams.local_sdp_str), SOATAG_REUSE_REJECTED(1), SOATAG_AUDIO_AUX("cn telephone-event"), - TAG_IF(sofia_test_pflag(profile, PFLAG_DISABLE_100REL), NUTAG_INCLUDE_EXTRA_SDP(1)), TAG_END()); + TAG_IF(sofia_test_pflag(profile, PFLAG_DISABLE_100REL), NUTAG_INCLUDE_EXTRA_SDP(1)), + TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), + TAG_END()); } else { nua_respond(tech_pvt->nh, SIP_200_OK, NUTAG_MEDIA_ENABLE(0), SIPTAG_CONTACT_STR(tech_pvt->reply_contact), - SIPTAG_CONTENT_TYPE_STR("application/sdp"), SIPTAG_PAYLOAD_STR(tech_pvt->mparams.local_sdp_str), TAG_END()); + SIPTAG_CONTENT_TYPE_STR("application/sdp"), SIPTAG_PAYLOAD_STR(tech_pvt->mparams.local_sdp_str), + TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), + TAG_END()); } switch_channel_set_flag(channel, CF_PROXY_MODE); @@ -8046,7 +8098,7 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status, switch_core_media_proxy_remote_addr(session, r_sdp); if ((tech_pvt->profile->mndlb & SM_NDLB_NEVER_PATCH_REINVITE)) { - nua_respond(tech_pvt->nh, SIP_200_OK, TAG_END()); + nua_respond(tech_pvt->nh, SIP_200_OK, TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), TAG_END()); switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "NOT proxying re-invite.\n"); switch_core_session_rwunlock(other_session); goto done; @@ -8058,7 +8110,8 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status, if (sofia_test_flag(other_tech_pvt, TFLAG_REINVITED)) { /* The other leg won the reinvite race */ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Other leg already handling reinvite, so responding with 491\n"); - nua_respond(tech_pvt->nh, SIP_491_REQUEST_PENDING, TAG_END()); + nua_respond(tech_pvt->nh, SIP_491_REQUEST_PENDING, + TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), TAG_END()); switch_core_session_rwunlock(other_session); goto done; } @@ -8127,7 +8180,9 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status, if (!match) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Reinvite Codec Error!\n"); - nua_respond(tech_pvt->nh, SIP_488_NOT_ACCEPTABLE, TAG_END()); + nua_respond(tech_pvt->nh, SIP_488_NOT_ACCEPTABLE, + TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), + TAG_END()); switch_core_session_rwunlock(other_session); goto done; } @@ -8176,12 +8231,16 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status, SOATAG_USER_SDP_STR(tech_pvt->mparams.local_sdp_str), SOATAG_REUSE_REJECTED(1), SOATAG_AUDIO_AUX("cn telephone-event"), - TAG_IF(sofia_test_pflag(profile, PFLAG_DISABLE_100REL), NUTAG_INCLUDE_EXTRA_SDP(1)), TAG_END()); + TAG_IF(sofia_test_pflag(profile, PFLAG_DISABLE_100REL), NUTAG_INCLUDE_EXTRA_SDP(1)), + TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), + TAG_END()); } else { nua_respond(tech_pvt->nh, SIP_200_OK, NUTAG_MEDIA_ENABLE(0), SIPTAG_CONTACT_STR(tech_pvt->reply_contact), - SIPTAG_CONTENT_TYPE_STR("application/sdp"), SIPTAG_PAYLOAD_STR(tech_pvt->mparams.local_sdp_str), TAG_END()); + SIPTAG_CONTENT_TYPE_STR("application/sdp"), SIPTAG_PAYLOAD_STR(tech_pvt->mparams.local_sdp_str), + TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), + TAG_END()); } switch_core_session_rwunlock(other_session); goto done; @@ -8198,12 +8257,16 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status, SOATAG_USER_SDP_STR(tech_pvt->mparams.local_sdp_str), SOATAG_REUSE_REJECTED(1), SOATAG_AUDIO_AUX("cn telephone-event"), - TAG_IF(sofia_test_pflag(profile, PFLAG_DISABLE_100REL), NUTAG_INCLUDE_EXTRA_SDP(1)), TAG_END()); + TAG_IF(sofia_test_pflag(profile, PFLAG_DISABLE_100REL), NUTAG_INCLUDE_EXTRA_SDP(1)), + TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), + TAG_END()); } else { nua_respond(tech_pvt->nh, SIP_200_OK, NUTAG_MEDIA_ENABLE(0), SIPTAG_CONTACT_STR(tech_pvt->reply_contact), - SIPTAG_CONTENT_TYPE_STR("application/sdp"), SIPTAG_PAYLOAD_STR(tech_pvt->mparams.local_sdp_str), TAG_END()); + SIPTAG_CONTENT_TYPE_STR("application/sdp"), SIPTAG_PAYLOAD_STR(tech_pvt->mparams.local_sdp_str), + TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), + TAG_END()); } goto done; } @@ -8216,7 +8279,7 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status, if (switch_channel_test_flag(channel, CF_PROXY_MODE)) { - nua_respond(tech_pvt->nh, SIP_200_OK, TAG_END()); + nua_respond(tech_pvt->nh, SIP_200_OK, TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), TAG_END()); goto done; } @@ -8240,7 +8303,7 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status, switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Processing updated SDP\n"); } else { if (switch_channel_test_flag(channel, CF_PROXY_MODE) || switch_channel_test_flag(channel, CF_PROXY_MEDIA)) { - nua_respond(tech_pvt->nh, SIP_200_OK, TAG_END()); + nua_respond(tech_pvt->nh, SIP_200_OK, TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), TAG_END()); goto done; } @@ -8264,12 +8327,16 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status, SOATAG_USER_SDP_STR(tech_pvt->mparams.local_sdp_str), SOATAG_REUSE_REJECTED(1), SOATAG_AUDIO_AUX("cn telephone-event"), - TAG_IF(sofia_test_pflag(profile, PFLAG_DISABLE_100REL), NUTAG_INCLUDE_EXTRA_SDP(1)), TAG_END()); + TAG_IF(sofia_test_pflag(profile, PFLAG_DISABLE_100REL), NUTAG_INCLUDE_EXTRA_SDP(1)), + TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), + TAG_END()); } else { nua_respond(tech_pvt->nh, SIP_200_OK, NUTAG_MEDIA_ENABLE(0), SIPTAG_CONTACT_STR(tech_pvt->reply_contact), - SIPTAG_CONTENT_TYPE_STR("application/sdp"), SIPTAG_PAYLOAD_STR(tech_pvt->mparams.local_sdp_str), TAG_END()); + SIPTAG_CONTENT_TYPE_STR("application/sdp"), SIPTAG_PAYLOAD_STR(tech_pvt->mparams.local_sdp_str), + TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), + TAG_END()); } } @@ -8278,7 +8345,9 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status, switch_event_fire(&s_event); } } else { - nua_respond(tech_pvt->nh, SIP_488_NOT_ACCEPTABLE, TAG_END()); + nua_respond(tech_pvt->nh, SIP_488_NOT_ACCEPTABLE, + TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), + TAG_END()); } } break; @@ -8371,7 +8440,7 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status, } if (!is_ok) { - nua_respond(nh, SIP_488_NOT_ACCEPTABLE, TAG_END()); + nua_respond(nh, SIP_488_NOT_ACCEPTABLE, TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), TAG_END()); switch_channel_hangup(tech_pvt->channel, SWITCH_CAUSE_INCOMPATIBLE_DESTINATION); } } @@ -8553,6 +8622,7 @@ typedef struct { char *bridge_to_uuid; switch_event_t *vars; switch_memory_pool_t *pool; + sofia_profile_t *profile; } nightmare_xfer_helper_t; void *SWITCH_THREAD_FUNC nightmare_xfer_thread_run(switch_thread_t *thread, void *obj) @@ -8571,6 +8641,7 @@ void *SWITCH_THREAD_FUNC nightmare_xfer_thread_run(switch_thread_t *thread, void if ((session = switch_core_session_locate(nhelper->reply_uuid))) { private_object_t *tech_pvt = switch_core_session_get_private(session); switch_channel_t *channel_a = switch_core_session_get_channel(session); + const char *session_id_header = sofia_glue_session_id_header(session, nhelper->profile); if ((status = switch_ivr_originate(NULL, &tsession, &cause, nhelper->exten_with_params, timeout, NULL, NULL, NULL, switch_channel_get_caller_profile(channel_a), nhelper->vars, SOF_NONE, NULL, NULL)) == SWITCH_STATUS_SUCCESS) { @@ -8602,7 +8673,9 @@ void *SWITCH_THREAD_FUNC nightmare_xfer_thread_run(switch_thread_t *thread, void nua_notify(tech_pvt->nh, NUTAG_NEWSUB(1), SIPTAG_CONTENT_TYPE_STR("message/sipfrag"), NUTAG_SUBSTATE(nua_substate_terminated),SIPTAG_SUBSCRIPTION_STATE_STR("terminated;reason=noresource"), SIPTAG_PAYLOAD_STR(status == SWITCH_STATUS_SUCCESS ? "SIP/2.0 200 OK\r\n" : - "SIP/2.0 403 Forbidden\r\n"), SIPTAG_EVENT_STR(nhelper->event), TAG_END()); + "SIP/2.0 403 Forbidden\r\n"), SIPTAG_EVENT_STR(nhelper->event), + TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), + TAG_END()); switch_core_session_rwunlock(session); } @@ -8727,6 +8800,7 @@ void sofia_handle_sip_i_refer(nua_t *nua, sofia_profile_t *profile, nua_handle_t nightmare_xfer_helper_t *nightmare_xfer_helper; switch_memory_pool_t *npool; switch_event_t *event = NULL; + const char *session_id_header = sofia_glue_session_id_header(session, profile); if (!(profile->mflags & MFLAG_REFER)) { nua_respond(nh, SIP_403_FORBIDDEN, NUTAG_WITH_THIS_MSG(de->data->e_msg), TAG_END()); @@ -8760,7 +8834,8 @@ void sofia_handle_sip_i_refer(nua_t *nua, sofia_profile_t *profile, nua_handle_t from = sip->sip_from; //to = sip->sip_to; - nua_respond(nh, SIP_202_ACCEPTED, NUTAG_WITH_THIS_MSG(de->data->e_msg), SIPTAG_EXPIRES_STR("60"), TAG_END()); + nua_respond(nh, SIP_202_ACCEPTED, NUTAG_WITH_THIS_MSG(de->data->e_msg), SIPTAG_EXPIRES_STR("60"), + TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), TAG_END()); switch_channel_set_variable(tech_pvt->channel, SOFIA_REPLACES_HEADER, NULL); @@ -8889,6 +8964,7 @@ void sofia_handle_sip_i_refer(nua_t *nua, sofia_profile_t *profile, nua_handle_t nua_notify(tech_pvt->nh, NUTAG_NEWSUB(1), SIPTAG_CONTENT_TYPE_STR("message/sipfrag;version=2.0"), NUTAG_SUBSTATE(nua_substate_terminated),SIPTAG_SUBSCRIPTION_STATE_STR("terminated;reason=noresource"), + TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), SIPTAG_PAYLOAD_STR("SIP/2.0 403 Forbidden\r\n"), SIPTAG_EVENT_STR(etmp), TAG_END()); } else if (switch_channel_test_flag(channel_b, CF_ORIGINATOR)) { @@ -8982,6 +9058,7 @@ void sofia_handle_sip_i_refer(nua_t *nua, sofia_profile_t *profile, nua_handle_t nua_notify(tech_pvt->nh, NUTAG_NEWSUB(1), SIPTAG_CONTENT_TYPE_STR("message/sipfrag;version=2.0"), NUTAG_SUBSTATE(nua_substate_terminated),SIPTAG_SUBSCRIPTION_STATE_STR("terminated;reason=noresource"), SIPTAG_PAYLOAD_STR("SIP/2.0 200 OK\r\n"), SIPTAG_EVENT_STR(etmp), + TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), TAG_END()); if (b_tech_pvt && !sofia_test_flag(b_tech_pvt, TFLAG_BYE)) { @@ -8996,13 +9073,17 @@ void sofia_handle_sip_i_refer(nua_t *nua, sofia_profile_t *profile, nua_handle_t nua_bye(b_tech_pvt->nh, SIPTAG_CONTACT(SIP_NONE), TAG_IF(!zstr(q850), SIPTAG_REASON_STR(q850)), - TAG_IF(!zstr(tech_pvt->user_via), SIPTAG_VIA_STR(tech_pvt->user_via)), TAG_END()); + TAG_IF(!zstr(tech_pvt->user_via), SIPTAG_VIA_STR(tech_pvt->user_via)), + TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), + TAG_END()); } } else { nua_notify(tech_pvt->nh, NUTAG_NEWSUB(1), SIPTAG_CONTENT_TYPE_STR("message/sipfrag;version=2.0"), NUTAG_SUBSTATE(nua_substate_terminated),SIPTAG_SUBSCRIPTION_STATE_STR("terminated;reason=noresource"), - SIPTAG_PAYLOAD_STR("SIP/2.0 403 Forbidden\r\n"), SIPTAG_EVENT_STR(etmp), TAG_END()); + SIPTAG_PAYLOAD_STR("SIP/2.0 403 Forbidden\r\n"), SIPTAG_EVENT_STR(etmp), + TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), + TAG_END()); } } else if (br_a && br_b) { @@ -9081,6 +9162,7 @@ void sofia_handle_sip_i_refer(nua_t *nua, sofia_profile_t *profile, nua_handle_t switch_channel_set_variable(channel_b, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "ATTENDED_TRANSFER"); nua_notify(tech_pvt->nh, NUTAG_NEWSUB(1), SIPTAG_CONTENT_TYPE_STR("message/sipfrag;version=2.0"), NUTAG_SUBSTATE(nua_substate_terminated),SIPTAG_SUBSCRIPTION_STATE_STR("terminated;reason=noresource"), SIPTAG_PAYLOAD_STR("SIP/2.0 200 OK\r\n"), SIPTAG_EVENT_STR(etmp), + TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), TAG_END()); sofia_clear_flag_locked(b_tech_pvt, TFLAG_SIP_HOLD); @@ -9096,7 +9178,9 @@ void sofia_handle_sip_i_refer(nua_t *nua, sofia_profile_t *profile, nua_handle_t "Cannot transfer channels that are not in a bridge.\n"); nua_notify(tech_pvt->nh, NUTAG_NEWSUB(1), SIPTAG_CONTENT_TYPE_STR("message/sipfrag;version=2.0"), NUTAG_SUBSTATE(nua_substate_terminated),SIPTAG_SUBSCRIPTION_STATE_STR("terminated;reason=noresource"), SIPTAG_PAYLOAD_STR("SIP/2.0 403 Forbidden\r\n"), - SIPTAG_EVENT_STR(etmp), TAG_END()); + SIPTAG_EVENT_STR(etmp), + TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), + TAG_END()); } else { switch_core_session_t *t_session, *hup_session; switch_channel_t *hup_channel; @@ -9162,14 +9246,18 @@ void sofia_handle_sip_i_refer(nua_t *nua, sofia_profile_t *profile, nua_handle_t NUTAG_NEWSUB(1), SIPTAG_CONTENT_TYPE_STR("message/sipfrag;version=2.0"), NUTAG_SUBSTATE(nua_substate_terminated),SIPTAG_SUBSCRIPTION_STATE_STR("terminated;reason=noresource"), - SIPTAG_PAYLOAD_STR("SIP/2.0 200 OK\r\n"), SIPTAG_EVENT_STR(etmp), TAG_END()); + SIPTAG_PAYLOAD_STR("SIP/2.0 200 OK\r\n"), SIPTAG_EVENT_STR(etmp), + TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), + TAG_END()); switch_core_session_rwunlock(t_session); switch_channel_hangup(hup_channel, SWITCH_CAUSE_ATTENDED_TRANSFER); } else { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Session to transfer to not found.\n"); nua_notify(tech_pvt->nh, NUTAG_NEWSUB(1), SIPTAG_CONTENT_TYPE_STR("message/sipfrag;version=2.0"), NUTAG_SUBSTATE(nua_substate_terminated),SIPTAG_SUBSCRIPTION_STATE_STR("terminated;reason=noresource"), - SIPTAG_PAYLOAD_STR("SIP/2.0 403 Forbidden\r\n"), SIPTAG_EVENT_STR(etmp), TAG_END()); + SIPTAG_PAYLOAD_STR("SIP/2.0 403 Forbidden\r\n"), SIPTAG_EVENT_STR(etmp), + TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), + TAG_END()); } } } @@ -9346,6 +9434,7 @@ void sofia_handle_sip_i_refer(nua_t *nua, sofia_profile_t *profile, nua_handle_t switch_event_add_header_string(nightmare_xfer_helper->vars, SWITCH_STACK_BOTTOM, "sip_h_X-FS-Refer-For", br_a); switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Good Luck, you'll need it......\n"); + nightmare_xfer_helper->profile = profile; launch_nightmare_xfer(nightmare_xfer_helper); switch_core_session_rwunlock(a_session); @@ -9360,6 +9449,7 @@ void sofia_handle_sip_i_refer(nua_t *nua, sofia_profile_t *profile, nua_handle_t switch_channel_set_variable(channel_a, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "ATTENDED_TRANSFER_ERROR"); nua_notify(tech_pvt->nh, NUTAG_NEWSUB(1), SIPTAG_CONTENT_TYPE_STR("message/sipfrag;version=2.0"), NUTAG_SUBSTATE(nua_substate_terminated),SIPTAG_SUBSCRIPTION_STATE_STR("terminated;reason=noresource"), SIPTAG_PAYLOAD_STR("SIP/2.0 403 Forbidden\r\n"), SIPTAG_EVENT_STR(etmp), + TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), TAG_END()); } } @@ -9413,7 +9503,9 @@ void sofia_handle_sip_i_refer(nua_t *nua, sofia_profile_t *profile, nua_handle_t nua_notify(tech_pvt->nh, NUTAG_NEWSUB(1), SIPTAG_CONTENT_TYPE_STR("message/sipfrag;version=2.0"), NUTAG_SUBSTATE(nua_substate_terminated), SIPTAG_SUBSCRIPTION_STATE_STR("terminated;reason=noresource"), - SIPTAG_PAYLOAD_STR("SIP/2.0 200 OK\r\n"), SIPTAG_EVENT_STR(etmp), TAG_END()); + SIPTAG_PAYLOAD_STR("SIP/2.0 200 OK\r\n"), SIPTAG_EVENT_STR(etmp), + TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), + TAG_END()); } if (refer_to->r_url->url_params) { @@ -9450,7 +9542,9 @@ void sofia_handle_sip_i_refer(nua_t *nua, sofia_profile_t *profile, nua_handle_t nua_notify(tech_pvt->nh, NUTAG_NEWSUB(1), SIPTAG_CONTENT_TYPE_STR("message/sipfrag;version=2.0"), NUTAG_SUBSTATE(nua_substate_terminated), SIPTAG_SUBSCRIPTION_STATE_STR("terminated;reason=noresource"), - SIPTAG_PAYLOAD_STR("SIP/2.0 403 Forbidden\r\n"), SIPTAG_EVENT_STR(etmp), TAG_END()); + SIPTAG_PAYLOAD_STR("SIP/2.0 403 Forbidden\r\n"), SIPTAG_EVENT_STR(etmp), + TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), + TAG_END()); } } @@ -9533,6 +9627,7 @@ switch_status_t sofia_proxy_sip_i_message(nua_t *nua, sofia_profile_t *profile, sofia_dispatch_event_t *de, tagi_t tags[]) { switch_core_session_t *other_session = NULL; + const char *session_id_header = sofia_glue_session_id_header(session, profile); if (session && switch_core_session_get_partner(session, &other_session) == SWITCH_STATUS_SUCCESS) { if (switch_core_session_compare(session, other_session)) { @@ -9552,15 +9647,18 @@ switch_status_t sofia_proxy_sip_i_message(nua_t *nua, sofia_profile_t *profile, } nua_message(other_tech_pvt->nh, - TAG_IF(ct, SIPTAG_CONTENT_TYPE_STR(su_strdup(other_tech_pvt->nh->nh_home, ct))), - TAG_IF(!zstr(other_tech_pvt->user_via), SIPTAG_VIA_STR(other_tech_pvt->user_via)), - TAG_IF(pl, SIPTAG_PAYLOAD_STR(su_strdup(other_tech_pvt->nh->nh_home, pl))), - TAG_END()); + TAG_IF(ct, SIPTAG_CONTENT_TYPE_STR(su_strdup(other_tech_pvt->nh->nh_home, ct))), + TAG_IF(!zstr(other_tech_pvt->user_via), SIPTAG_VIA_STR(other_tech_pvt->user_via)), + TAG_IF(pl, SIPTAG_PAYLOAD_STR(su_strdup(other_tech_pvt->nh->nh_home, pl))), + TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), + TAG_END()); } switch_core_session_rwunlock(other_session); - nua_respond(nh, SIP_202_ACCEPTED, NUTAG_WITH_THIS_MSG(de->data->e_msg), TAG_END()); + nua_respond(nh, SIP_202_ACCEPTED, NUTAG_WITH_THIS_MSG(de->data->e_msg), + TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), + TAG_END()); return SWITCH_STATUS_SUCCESS; } @@ -9572,6 +9670,7 @@ switch_status_t sofia_proxy_sip_i_info(nua_t *nua, sofia_profile_t *profile, nua sofia_dispatch_event_t *de, tagi_t tags[]) { switch_core_session_t *other_session = NULL; + const char *session_id_header = sofia_glue_session_id_header(session, profile); if (session && switch_core_session_get_partner(session, &other_session) == SWITCH_STATUS_SUCCESS) { if (switch_core_session_compare(session, other_session)) { @@ -9601,12 +9700,13 @@ switch_status_t sofia_proxy_sip_i_info(nua_t *nua, sofia_profile_t *profile, nua TAG_IF(ct, SIPTAG_CONTENT_TYPE_STR(su_strdup(other_tech_pvt->nh->nh_home, ct))), TAG_IF(!zstr(other_tech_pvt->user_via), SIPTAG_VIA_STR(other_tech_pvt->user_via)), TAG_IF(pl, SIPTAG_PAYLOAD_STR(su_strdup(other_tech_pvt->nh->nh_home, pl))), + TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), TAG_END()); } switch_core_session_rwunlock(other_session); - nua_respond(nh, SIP_200_OK, NUTAG_WITH_THIS_MSG(de->data->e_msg), TAG_END()); + nua_respond(nh, SIP_200_OK, NUTAG_WITH_THIS_MSG(de->data->e_msg), TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), TAG_END()); return SWITCH_STATUS_SUCCESS; } @@ -9626,6 +9726,7 @@ void sofia_handle_sip_i_info(nua_t *nua, sofia_profile_t *profile, nua_handle_t switch_event_t *event; private_object_t *tech_pvt = NULL; switch_channel_t *channel = NULL; + const char *session_id_header = sofia_glue_session_id_header(session, profile); if (session) { tech_pvt = (private_object_t *) switch_core_session_get_private(session); @@ -9640,21 +9741,28 @@ void sofia_handle_sip_i_info(nua_t *nua, sofia_profile_t *profile, nua_handle_t if (!strcasecmp(sip->sip_content_type->c_subtype, "session-event")) { if (session) { + if (create_info_event(sip, nh, &event) == SWITCH_STATUS_SUCCESS) { if (switch_core_session_queue_event(session, &event) == SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "queued freeswitch event for INFO\n"); nua_respond(nh, SIP_200_OK, SIPTAG_CONTENT_TYPE_STR("freeswitch/session-event-response"), - SIPTAG_PAYLOAD_STR("+OK MESSAGE QUEUED"), NUTAG_WITH_THIS_MSG(de->data->e_msg), TAG_END()); + SIPTAG_PAYLOAD_STR("+OK MESSAGE QUEUED"), NUTAG_WITH_THIS_MSG(de->data->e_msg), + TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), + TAG_END()); } else { switch_event_destroy(&event); nua_respond(nh, SIP_200_OK, SIPTAG_CONTENT_TYPE_STR("freeswitch/session-event-response"), - SIPTAG_PAYLOAD_STR("-ERR MESSAGE NOT QUEUED"), NUTAG_WITH_THIS_MSG(de->data->e_msg), TAG_END()); + SIPTAG_PAYLOAD_STR("-ERR MESSAGE NOT QUEUED"), NUTAG_WITH_THIS_MSG(de->data->e_msg), + TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), + TAG_END()); } } } else { nua_respond(nh, SIP_200_OK, SIPTAG_CONTENT_TYPE_STR("freeswitch/session-event-response"), - SIPTAG_PAYLOAD_STR("-ERR INVALID SESSION"), NUTAG_WITH_THIS_MSG(de->data->e_msg), TAG_END()); + SIPTAG_PAYLOAD_STR("-ERR INVALID SESSION"), NUTAG_WITH_THIS_MSG(de->data->e_msg), + TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), + TAG_END()); } @@ -9675,10 +9783,15 @@ void sofia_handle_sip_i_info(nua_t *nua, sofia_profile_t *profile, nua_handle_t if ((status = switch_api_execute(cmd, arg, NULL, &stream)) == SWITCH_STATUS_SUCCESS) { nua_respond(nh, SIP_200_OK, SIPTAG_CONTENT_TYPE_STR("freeswitch/api-response"), - SIPTAG_PAYLOAD_STR(stream.data), NUTAG_WITH_THIS_MSG(de->data->e_msg), TAG_END()); + SIPTAG_PAYLOAD_STR(stream.data), NUTAG_WITH_THIS_MSG(de->data->e_msg), + TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), + TAG_END()); } else { + nua_respond(nh, SIP_200_OK, SIPTAG_CONTENT_TYPE_STR("freeswitch/api-response"), - SIPTAG_PAYLOAD_STR("-ERR INVALID COMMAND"), NUTAG_WITH_THIS_MSG(de->data->e_msg), TAG_END()); + SIPTAG_PAYLOAD_STR("-ERR INVALID COMMAND"), NUTAG_WITH_THIS_MSG(de->data->e_msg), + TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), + TAG_END()); } switch_safe_free(stream.data); @@ -9686,7 +9799,9 @@ void sofia_handle_sip_i_info(nua_t *nua, sofia_profile_t *profile, nua_handle_t return; } - nua_respond(nh, SIP_200_OK, NUTAG_WITH_THIS_MSG(de->data->e_msg), TAG_END()); + nua_respond(nh, SIP_200_OK, NUTAG_WITH_THIS_MSG(de->data->e_msg), + TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), + TAG_END()); return; } @@ -9724,6 +9839,7 @@ void sofia_handle_sip_i_info(nua_t *nua, sofia_profile_t *profile, nua_handle_t TAG_IF(!zstr(extra_headers), SIPTAG_HEADER_STR(extra_headers)), TAG_IF(!zstr(unknown), SIPTAG_HEADER_STR(unknown)), TAG_IF(!zstr(other_tech_pvt->user_via), SIPTAG_VIA_STR(other_tech_pvt->user_via)), + TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), TAG_IF(!zstr(pl), SIPTAG_PAYLOAD_STR(pl)), TAG_END()); switch_safe_free(extra_headers); @@ -9869,7 +9985,9 @@ void sofia_handle_sip_i_info(nua_t *nua, sofia_profile_t *profile, nua_handle_t } /* Send 200 OK response */ - nua_respond(nh, SIP_200_OK, NUTAG_WITH_THIS_MSG(de->data->e_msg), TAG_END()); + nua_respond(nh, SIP_200_OK, NUTAG_WITH_THIS_MSG(de->data->e_msg), + TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), + TAG_END()); } else { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "IGNORE INFO DTMF(%c) (This channel was not configured to use INFO DTMF!)\n", dtmf.digit); @@ -9882,7 +10000,9 @@ void sofia_handle_sip_i_info(nua_t *nua, sofia_profile_t *profile, nua_handle_t if (!zstr(clientcode_header)) { switch_channel_set_variable(channel, "call_clientcode", clientcode_header); switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_NOTICE, "Setting CMC to %s\n", clientcode_header); - nua_respond(nh, SIP_200_OK, NUTAG_WITH_THIS_MSG(de->data->e_msg), TAG_END()); + nua_respond(nh, SIP_200_OK, NUTAG_WITH_THIS_MSG(de->data->e_msg), + TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), + TAG_END()); } goto end; } @@ -9890,14 +10010,17 @@ void sofia_handle_sip_i_info(nua_t *nua, sofia_profile_t *profile, nua_handle_t if ((rec_header = sofia_glue_get_unknown_header(sip, "record"))) { if (zstr(profile->record_template)) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Record attempted but no template defined.\n"); - nua_respond(nh, 488, "Recording not enabled", NUTAG_WITH_THIS_MSG(de->data->e_msg), TAG_END()); + nua_respond(nh, 488, "Recording not enabled", NUTAG_WITH_THIS_MSG(de->data->e_msg), + TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), + TAG_END()); } else { if (!strcasecmp(rec_header, "on")) { char *file = NULL, *tmp = NULL; if (switch_true(switch_channel_get_variable(channel, "sip_disable_recording"))) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Record attempted but is disabled by sip_disable_recording variable.\n"); - nua_respond(nh, 488, "Recording disabled for this channel", NUTAG_WITH_THIS_MSG(de->data->e_msg), TAG_END()); + nua_respond(nh, 488, "Recording disabled for this channel", NUTAG_WITH_THIS_MSG(de->data->e_msg), + TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), TAG_END()); } else { tmp = switch_mprintf("%s%s%s", profile->record_path ? profile->record_path : "${recordings_dir}", @@ -9908,7 +10031,9 @@ void sofia_handle_sip_i_info(nua_t *nua, sofia_profile_t *profile, nua_handle_t switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_NOTICE, "Recording %s to %s\n", switch_channel_get_name(channel), file); switch_safe_free(tmp); - nua_respond(nh, SIP_200_OK, NUTAG_WITH_THIS_MSG(de->data->e_msg), TAG_END()); + nua_respond(nh, SIP_200_OK, NUTAG_WITH_THIS_MSG(de->data->e_msg), + TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), + TAG_END()); if (file != profile->record_template) { free(file); file = NULL; @@ -9921,9 +10046,13 @@ void sofia_handle_sip_i_info(nua_t *nua, sofia_profile_t *profile, nua_handle_t switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_NOTICE, "Done recording %s to %s\n", switch_channel_get_name(channel), file); switch_ivr_stop_record_session(session, file); - nua_respond(nh, SIP_200_OK, NUTAG_WITH_THIS_MSG(de->data->e_msg), TAG_END()); + nua_respond(nh, SIP_200_OK, NUTAG_WITH_THIS_MSG(de->data->e_msg), + TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), + TAG_END()); } else { - nua_respond(nh, 488, "Nothing to stop", NUTAG_WITH_THIS_MSG(de->data->e_msg), TAG_END()); + nua_respond(nh, 488, "Nothing to stop", NUTAG_WITH_THIS_MSG(de->data->e_msg), + TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), + TAG_END()); } } } @@ -9940,7 +10069,9 @@ void sofia_handle_sip_i_info(nua_t *nua, sofia_profile_t *profile, nua_handle_t switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG1, "dispatched freeswitch event for INFO\n"); } - nua_respond(nh, SIP_200_OK, NUTAG_WITH_THIS_MSG(de->data->e_msg), TAG_END()); + nua_respond(nh, SIP_200_OK, NUTAG_WITH_THIS_MSG(de->data->e_msg), + TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), + TAG_END()); return; @@ -9975,6 +10106,8 @@ void sofia_handle_sip_i_reinvite(switch_core_session_t *session, char via_space[2048]; char branch[16] = ""; + sofia_glue_store_session_id(session, profile, sip, 0); + sofia_clear_flag(tech_pvt, TFLAG_GOT_ACK); sofia_glue_get_addr(de->data->e_msg, network_ip, sizeof(network_ip), &network_port); @@ -10115,6 +10248,10 @@ void sofia_handle_sip_i_invite(switch_core_session_t *session, nua_t *nua, sofia const char *req_uri = NULL; char *req_user = NULL; switch_time_t sip_invite_time; + const char *session_id_header; + + sofia_glue_store_session_id(session, profile, sip, 0); + session_id_header = sofia_glue_session_id_header(session, profile); if (sip && sip->sip_contact && sip->sip_contact->m_url->url_params) { uparams = sip->sip_contact->m_url->url_params; @@ -10138,7 +10275,8 @@ void sofia_handle_sip_i_invite(switch_core_session_t *session, nua_t *nua, sofia } if (!session || (sess_count >= sess_max || !sofia_test_pflag(profile, PFLAG_RUNNING))) { - nua_respond(nh, 503, "Maximum Calls In Progress", SIPTAG_RETRY_AFTER_STR("300"), TAG_END()); + nua_respond(nh, 503, "Maximum Calls In Progress", SIPTAG_RETRY_AFTER_STR("300"), + TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), TAG_END()); goto fail; } @@ -10148,13 +10286,15 @@ void sofia_handle_sip_i_invite(switch_core_session_t *session, nua_t *nua, sofia if (!sip || !sip->sip_request || !sip->sip_request->rq_method_name) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Received an invalid packet!\n"); - nua_respond(nh, SIP_503_SERVICE_UNAVAILABLE, TAG_END()); + nua_respond(nh, SIP_503_SERVICE_UNAVAILABLE, + TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), TAG_END()); goto fail; } if (!(sip->sip_contact)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "NO CONTACT!\n"); - nua_respond(nh, 400, "Missing Contact Header", TAG_END()); + nua_respond(nh, 400, "Missing Contact Header", + TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), TAG_END()); goto fail; } @@ -10372,7 +10512,8 @@ void sofia_handle_sip_i_invite(switch_core_session_t *session, nua_t *nua, sofia if (!sofia_test_pflag(profile, PFLAG_AUTH_CALLS)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "IP %s Rejected by acl \"%s\"\n", x_auth_ip, switch_str_nil(last_acl)); if (!acl_context) { - nua_respond(nh, SIP_403_FORBIDDEN, TAG_END()); + nua_respond(nh, SIP_403_FORBIDDEN, + TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), TAG_END()); goto fail; } else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "IP %s Rejected by acl \"%s\". Falling back to Digest auth.\n", @@ -10387,7 +10528,8 @@ void sofia_handle_sip_i_invite(switch_core_session_t *session, nua_t *nua, sofia if (!is_auth && sofia_test_pflag(profile, PFLAG_AUTH_CALLS) && sofia_test_pflag(profile, PFLAG_AUTH_CALLS_ACL_ONLY)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "IP/Port %s %i Rejected by acls and auth-calls-acl-only flag is set, rejecting call\n", network_ip, network_port); - nua_respond(nh, SIP_403_FORBIDDEN, TAG_END()); + nua_respond(nh, SIP_403_FORBIDDEN, + TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), TAG_END()); goto fail; } diff --git a/src/mod/endpoints/mod_sofia/sofia_glue.c b/src/mod/endpoints/mod_sofia/sofia_glue.c index 46853771b9..b5ac9c51ab 100644 --- a/src/mod/endpoints/mod_sofia/sofia_glue.c +++ b/src/mod/endpoints/mod_sofia/sofia_glue.c @@ -338,6 +338,316 @@ enum tport_tls_verify_policy sofia_glue_str2tls_verify_policy(const char * str){ return ret; } +/* create "local-uuid" */ +int sofia_glue_is_valid_session_uuid(const char *session_uuid) +{ + int i; + if (zstr(session_uuid) || strlen(session_uuid) != RFC7989_SESSION_UUID_LEN) { + return 0; + } + for (i = 0; i < RFC7989_SESSION_UUID_LEN; i++) { + char c = session_uuid[i]; + if ((c < '0' || c > '9') && (c < 'a' || c > 'f')) { + return 0; + } + } + return 1; +} + +/* NIL session-uuid: 00000000000000000000000000000000 */ +int sofia_glue_is_nil_session_uuid(const char *session_uuid) +{ + if (zstr(session_uuid)) { + return 0; + } + if (!memcmp(session_uuid, RFC7989_SESSION_UUID_NULL, RFC7989_SESSION_UUID_LEN)) { + return 1; + } + return 0; +} + +const char *sofia_glue_uuid_to_session_uuid(switch_memory_pool_t *pool, const char *uuid) +{ + char *session_uuid = NULL; /*"local-uuid", per rfc7989*/ + if (zstr(uuid) || strlen(uuid) != 36) return NULL; + + session_uuid = switch_core_alloc(pool, RFC7989_SESSION_UUID_LEN + 1); + memcpy(session_uuid, uuid, 8); + memcpy(session_uuid + 8, uuid + 9, 4); + memcpy(session_uuid + 12, uuid + 14, 4); + memcpy(session_uuid + 16, uuid + 19, 4); + memcpy(session_uuid + 20, uuid + 24, 12); + + if (!sofia_glue_is_valid_session_uuid(session_uuid)) return NULL; + + return session_uuid; +} + +/* rfc7989 generic params, return 0 if param is disabled from config or invalid. ALL params allowed by default. */ +/* save updated generic params list in chan var. */ +int sofia_glue_check_filter_generic_params(switch_core_session_t *session, sofia_profile_t *profile, char *param) +{ + + char *tmp = NULL; + switch_channel_t *channel = switch_core_session_get_channel(session); + + if (zstr(param)) { + return 0; + } + if (profile->rfc7989_filter) { + char *found = NULL; char *end = NULL; + char *token_array[100] = { 0 }; + int tokens = switch_separate_string(profile->rfc7989_filter, ',', token_array, (sizeof(token_array) / sizeof(token_array[0]))); + tmp = switch_core_session_strdup(session, param); + if (tokens) { + int i; + for (i = 0; i < tokens && token_array[i]; i++) { + while ((found = strstr(tmp, token_array[i]))) { + end = strchr(found, ';'); + if (!end) end = strchr(found, '\0'); + *found = '\0'; + strcat(tmp, found + (end - found)); + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, + "Session-ID: Dropped generic param: %s\n", token_array[i]); + } + } + } + } + + if (tmp) { + switch_channel_set_variable(channel, SWITCH_RFC7989_GENERIC_PARAM_VARIABLE, tmp); + } else { + switch_channel_set_variable(channel, SWITCH_RFC7989_GENERIC_PARAM_VARIABLE, param); + } + + return 1; +} +/* check and store Session-ID header. */ +/* retrieve "local-uuid" and "remote-uuid" of the remote party. */ +void sofia_glue_store_session_id(switch_core_session_t *session, sofia_profile_t *profile, sip_t const *sip, switch_bool_t is_reply) +{ + char *a_id, *b_id, *duped, *p, *remote_param; + const char *header = sofia_glue_get_unknown_header(sip, "Session-ID"); + switch_channel_t *channel = switch_core_session_get_channel(session); + + if (!sofia_test_pflag(profile, PFLAG_RFC7989_SESSION_ID)) return; + + if (!header) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Session-ID: missing header."); + return; + } + + duped = switch_core_session_strdup(session, header); + + if (zstr(duped)) return; + + a_id = switch_strip_whitespace(duped); + + if (zstr(a_id)) return; + + p = strchr(a_id, ';'); + if (p) *p = '\0'; + + if (!sofia_glue_is_valid_session_uuid(a_id)) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Session-ID: Ignoring \"%s\" parsed as \"%s\"\n", header, a_id); + return; + } + + /* RFC7329 compatibility */ + if (is_reply) { + const char *temp_id = switch_channel_get_variable(channel, SWITCH_RFC7989_APP_SESSION_ID_VARIABLE); + if (!zstr(temp_id) && !memcmp(a_id, temp_id, RFC7989_SESSION_UUID_LEN) ) { + /* 'If a SIP response only contains the "local-uuid" that was sent + * originally, this comes from a pre-standard implementation and MUST + * NOT be discarded for removing the nil "remote-uuid". In this + * case, all future transactions within this dialog MUST contain only + * the UUID received in the first SIP response" */ + switch_channel_set_flag(channel, CF_RFC7329_COMPAT); + switch_channel_set_flag_partner(channel, CF_RFC7329_COMPAT); + } + } + + /* "local-uuid" field retrieved from remote party will become + * SWITCH_RFC7989_APP_SESSION_ID_VARIABLE in a b2bua role. */ + if (!zstr(a_id)) { + struct private_object *tech_pvt = switch_core_session_get_private(session); + switch_channel_set_variable(channel, SWITCH_RFC7989_SESSION_ID_VARIABLE, a_id); + if (tech_pvt && tech_pvt->sofia_private && !tech_pvt->sofia_private->rfc7989_uuid) { + tech_pvt->sofia_private->rfc7989_uuid = su_strdup(tech_pvt->nh->nh_home, a_id); + } + } + + if (!p) { + switch_channel_set_flag(channel, CF_RFC7329_COMPAT); + switch_channel_set_flag_partner(channel, CF_RFC7329_COMPAT); + return; + } + p++; + remote_param = strstr(p, "remote="); + if (!remote_param) { + switch_channel_set_flag(channel, CF_RFC7329_COMPAT); + switch_channel_set_flag_partner(channel, CF_RFC7329_COMPAT); + sofia_glue_check_filter_generic_params(session, profile, p); + return; + } + b_id = remote_param + 7; + if (!zstr(b_id) && strlen(b_id) == RFC7989_SESSION_UUID_LEN /*32*/) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Session-ID: Set remote-uuid: %s\n", b_id); + /*using chan var as placeholder only when UAS or when answer() was called in the dialplan */ + switch_channel_set_variable(channel, SWITCH_RFC7989_REMOTE_SESSION_ID_VARIABLE, b_id); + switch_channel_set_variable_partner(channel, SWITCH_RFC7989_REMOTE_SESSION_ID_VARIABLE, b_id); + + } else { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Session-ID: invalid uuid, ignored.\n"); + } +} + +/* add "Session-ID:" header */ +char *sofia_glue_session_id_header(switch_core_session_t *session, sofia_profile_t *profile) +{ + switch_channel_t *channel; + const char *b_id = NULL; + const char *a_id = NULL; + const char *temp_id = NULL; + const char *generic = NULL; + + if (!session) return NULL; + + if (!profile) return NULL; + + if (!sofia_test_pflag(profile, PFLAG_RFC7989_SESSION_ID)) return NULL; + + channel = switch_core_session_get_channel(session); + + a_id = switch_channel_get_variable_partner(channel, SWITCH_RFC7989_SESSION_ID_VARIABLE); + + if (zstr(a_id)) { + a_id = switch_channel_get_variable(channel, SWITCH_RFC7989_APP_SESSION_ID_VARIABLE); + if (!zstr(a_id) && strlen(a_id) == 36) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "Reformatting app Session-ID: %s\n", a_id); + a_id = sofia_glue_uuid_to_session_uuid(switch_core_session_get_pool(session), a_id); + if (!zstr(a_id)) { + struct private_object *tech_pvt = switch_core_session_get_private(session); + switch_channel_set_variable(channel, SWITCH_RFC7989_APP_SESSION_ID_VARIABLE, a_id); + if (tech_pvt && tech_pvt->sofia_private && !tech_pvt->sofia_private->rfc7989_uuid) { + tech_pvt->sofia_private->rfc7989_uuid = su_strdup(tech_pvt->nh->nh_home, a_id); + } + } + } + } + + if (zstr(a_id)) { + const char *partner_uuid = switch_channel_get_partner_uuid(channel); + if (!zstr(partner_uuid)) { + const char *partner_session_id = sofia_glue_uuid_to_session_uuid(switch_core_session_get_pool(session), partner_uuid); + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "Setting \"Session-ID: %s\" from partner leg\n", partner_session_id); + switch_channel_set_variable_partner(channel, SWITCH_RFC7989_SESSION_ID_VARIABLE, partner_session_id); + a_id = partner_session_id; + } + } + + if (((switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) && zstr(a_id) && + switch_channel_get_state(channel) == CS_INIT) && switch_channel_test_flag(channel, CF_ORIGINATING)) { + /*outbound initial request*/ + char uuid_str[SWITCH_UUID_FORMATTED_LENGTH + 1]; + + switch_uuid_str(uuid_str, sizeof(uuid_str)); + a_id = sofia_glue_uuid_to_session_uuid(switch_core_session_get_pool(session), uuid_str); + if (!zstr(a_id)) { + struct private_object *tech_pvt = switch_core_session_get_private(session); + switch_channel_set_variable(channel, SWITCH_RFC7989_APP_SESSION_ID_VARIABLE, a_id); + if (tech_pvt && tech_pvt->sofia_private && !tech_pvt->sofia_private->rfc7989_uuid) { + tech_pvt->sofia_private->rfc7989_uuid = su_strdup(tech_pvt->nh->nh_home, a_id); + } + } + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, + "Session-ID: Outbound initial request. local-uuid: %s", a_id); + if (sofia_test_pflag(profile, PFLAG_RFC7989_FORCE_OLD)) { + /*for old (and obsolete) Session-ID RFC7329 */ + return switch_core_session_sprintf(session, "Session-ID: %s", a_id); + } + + b_id = RFC7989_SESSION_UUID_NULL; + return switch_core_session_sprintf(session, "Session-ID: %s;remote=%s", a_id, b_id); + } + + temp_id = switch_channel_get_variable(channel, SWITCH_RFC7989_REMOTE_SESSION_ID_VARIABLE); + if ((switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_INBOUND) && + ((switch_channel_get_state(channel) == CS_INIT) || (switch_channel_get_state(channel) == CS_EXECUTE)) && + zstr(temp_id)) { + /* fallback to RFC7329 - "old". */ + /* inbound initial request, no "remote" param. section 11 of RFC7989. */ + a_id = switch_channel_get_variable(channel, SWITCH_RFC7989_SESSION_ID_VARIABLE); + if (zstr(a_id)) { + a_id = RFC7989_SESSION_UUID_NULL; + } else { + switch_channel_set_variable(channel, SWITCH_RFC7989_APP_SESSION_ID_VARIABLE, a_id); + } + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Session-ID: Fallback to RFC7329"); + switch_channel_set_flag(channel, CF_RFC7329_COMPAT); + return switch_core_session_sprintf(session, "Session-ID: %s", a_id); + } + if ((switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_INBOUND) && + ((switch_channel_get_state(channel) == CS_INIT) || (switch_channel_get_state(channel) == CS_EXECUTE)) && + sofia_glue_is_nil_session_uuid(temp_id)) { + /*inbound initial request*/ + char uuid_str[SWITCH_UUID_FORMATTED_LENGTH + 1]; + + switch_uuid_str(uuid_str, sizeof(uuid_str)); + a_id = sofia_glue_uuid_to_session_uuid(switch_core_session_get_pool(session), uuid_str); + if (!zstr(a_id)) { + struct private_object *tech_pvt = switch_core_session_get_private(session); + switch_channel_set_variable(channel, SWITCH_RFC7989_APP_SESSION_ID_VARIABLE, a_id); + if (tech_pvt && tech_pvt->sofia_private) { + tech_pvt->sofia_private->rfc7989_uuid = su_strdup(tech_pvt->nh->nh_home, a_id); + } + } + b_id = switch_channel_get_variable(channel, SWITCH_RFC7989_SESSION_ID_VARIABLE); + if (zstr(b_id)) { + b_id = RFC7989_SESSION_UUID_NULL; + } + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, + "Session-ID: Inbound initial request. local-uuid: %s", a_id); + return switch_core_session_sprintf(session, "Session-ID: %s;remote=%s", a_id, b_id); + } + + if (zstr(a_id)) { + struct private_object *tech_pvt = switch_core_session_get_private(session); + /* setting NIL local-uuid should never happen, + * but in case we don't get to set it properly by here, just set it to NIL */ + if (tech_pvt && tech_pvt->sofia_private && tech_pvt->sofia_private->rfc7989_uuid) { + /* handle BYE after REFER or other cases where the channel is destroyed already and we can't get the chan var */ + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Session-ID: retrieved local-uuid "); + a_id = tech_pvt->sofia_private->rfc7989_uuid; + } else { + a_id = RFC7989_SESSION_UUID_NULL; + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Session-ID: NIL local-uuid "); + } + } + + b_id = switch_channel_get_variable(channel, SWITCH_RFC7989_SESSION_ID_VARIABLE); + + if (zstr(b_id) && switch_channel_test_flag(channel, CF_RFC7329_COMPAT)) { + /* fallback to RFC7329 , only one uuid*/ + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING ,"Session-ID: Fallback to RFC7329, use one uuid"); + return switch_core_session_sprintf(session, "Session-ID: %s", a_id); + } else if (zstr(b_id)) { + b_id = RFC7989_SESSION_UUID_NULL; + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Session-ID: set NIL remote-uuid"); + } + + /* B2B: handle generic params*/ + generic = switch_channel_get_variable_partner(channel, SWITCH_RFC7989_GENERIC_PARAM_VARIABLE); + if (!zstr(generic)) { + /* copy generic param (name and val) */ + return switch_core_session_sprintf(session, "Session-ID: %s;%s", a_id, generic); + } + if (switch_channel_test_flag(channel, CF_RFC7329_COMPAT)) { + return switch_core_session_sprintf(session, "Session-ID: %s", a_id); + } + return switch_core_session_sprintf(session, "Session-ID: %s;remote=%s", a_id, b_id); +} + char *sofia_glue_find_parameter_value(switch_core_session_t *session, const char *str, const char *param) { const char *param_ptr; @@ -757,6 +1067,8 @@ switch_status_t sofia_glue_do_invite(switch_core_session_t *session) int require_timer = 1; uint8_t is_t38 = 0; const char *hold_char = "*"; + const char *session_id_header = sofia_glue_session_id_header(session, tech_pvt->profile); + if (sofia_test_flag(tech_pvt, TFLAG_SIP_HOLD_INACTIVE) || switch_true(switch_channel_get_variable_dup(tech_pvt->channel, "sofia_hold_inactive", SWITCH_FALSE, -1))) { @@ -1326,6 +1638,7 @@ switch_status_t sofia_glue_do_invite(switch_core_session_t *session) is_t38 = 1; } + if (sofia_use_soa(tech_pvt)) { nua_invite(tech_pvt->nh, NUTAG_AUTOANSWER(0), @@ -1336,6 +1649,7 @@ switch_status_t sofia_glue_do_invite(switch_core_session_t *session) NUTAG_SESSION_TIMER(tech_pvt->session_timeout), NUTAG_SESSION_REFRESHER(tech_pvt->session_refresher), NUTAG_UPDATE_REFRESH(tech_pvt->update_refresher), + TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), TAG_IF(sofia_test_flag(tech_pvt, TFLAG_RECOVERED), NUTAG_INVITE_TIMER(UINT_MAX)), TAG_IF(invite_full_from, SIPTAG_FROM_STR(invite_full_from)), TAG_IF(invite_full_to, SIPTAG_TO_STR(invite_full_to)), @@ -1373,6 +1687,7 @@ switch_status_t sofia_glue_do_invite(switch_core_session_t *session) NUTAG_SESSION_TIMER(tech_pvt->session_timeout), NUTAG_SESSION_REFRESHER(tech_pvt->session_refresher), NUTAG_UPDATE_REFRESH(tech_pvt->update_refresher), + TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), TAG_IF(sofia_test_flag(tech_pvt, TFLAG_RECOVERED), NUTAG_INVITE_TIMER(UINT_MAX)), TAG_IF(invite_full_from, SIPTAG_FROM_STR(invite_full_from)), TAG_IF(invite_full_to, SIPTAG_TO_STR(invite_full_to)),