diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.c b/src/mod/endpoints/mod_sofia/mod_sofia.c index ee1b04bf8c..19ef5e3b1a 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.c +++ b/src/mod/endpoints/mod_sofia/mod_sofia.c @@ -356,27 +356,7 @@ switch_status_t sofia_on_hangup(switch_core_session_t *session) if (tech_pvt->nh && !sofia_test_flag(tech_pvt, TFLAG_BYE)) { char reason[128] = ""; - switch_stream_handle_t stream = { 0 }; - switch_event_header_t *hi; - char *bye_headers = NULL; - - SWITCH_STANDARD_STREAM(stream); - if ((hi = switch_channel_variable_first(channel))) { - for (; hi; hi = hi->next) { - const char *name = (char *) hi->name; - char *value = (char *) hi->value; - - if (!strncasecmp(name, SOFIA_SIP_BYE_HEADER_PREFIX, strlen(SOFIA_SIP_BYE_HEADER_PREFIX))) { - const char *hname = name + strlen(SOFIA_SIP_BYE_HEADER_PREFIX); - stream.write_function(&stream, "%s: %s\r\n", hname, value); - } - } - switch_channel_variable_last(channel); - } - - if (stream.data) { - bye_headers = stream.data; - } + char *bye_headers = sofia_glue_get_extra_headers(channel, SOFIA_SIP_BYE_HEADER_PREFIX); if (cause > 0 && cause < 128) { switch_snprintf(reason, sizeof(reason), "Q.850;cause=%d;text=\"%s\"", cause, switch_channel_cause2str(cause)); @@ -428,7 +408,7 @@ switch_status_t sofia_on_hangup(switch_core_session_t *session) } sofia_set_flag_locked(tech_pvt, TFLAG_BYE); - switch_safe_free(stream.data); + switch_safe_free(bye_headers); } sofia_clear_flag(tech_pvt, TFLAG_IO); @@ -490,13 +470,17 @@ static switch_status_t sofia_answer_channel(switch_core_session_t *session) if (sofia_test_pflag(tech_pvt->profile, PFLAG_3PCC_PROXY) && sofia_test_flag(tech_pvt, TFLAG_3PCC)) { /* Send the 200 OK */ if (!sofia_test_flag(tech_pvt, TFLAG_BYE)) { + char *extra_headers = sofia_glue_get_extra_headers(channel, SOFIA_SIP_PROGRESS_HEADER_PREFIX); nua_respond(tech_pvt->nh, SIP_200_OK, SIPTAG_CONTACT_STR(tech_pvt->profile->url), SOATAG_USER_SDP_STR(tech_pvt->local_sdp_str), SOATAG_REUSE_REJECTED(1), - SOATAG_ORDERED_USER(1), SOATAG_AUDIO_AUX("cn telephone-event"), NUTAG_INCLUDE_EXTRA_SDP(1), TAG_END()); + SOATAG_ORDERED_USER(1), SOATAG_AUDIO_AUX("cn telephone-event"), NUTAG_INCLUDE_EXTRA_SDP(1), + TAG_IF(!switch_strlen_zero(extra_headers), SIPTAG_HEADER_STR(extra_headers)), + TAG_END()); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "3PCC-PROXY, Sent a 200 OK, waiting for ACK\n"); + switch_safe_free(extra_headers); } /* Unlock the session signal to allow the ack to make it in */ @@ -570,6 +554,7 @@ static switch_status_t sofia_answer_channel(switch_core_session_t *session) } if (!sofia_test_flag(tech_pvt, TFLAG_BYE)) { + char *extra_headers = sofia_glue_get_extra_headers(channel, SOFIA_SIP_PROGRESS_HEADER_PREFIX); nua_respond(tech_pvt->nh, SIP_200_OK, NUTAG_AUTOANSWER(0), TAG_IF(sticky, NUTAG_PROXY(tech_pvt->record_route)), @@ -578,7 +563,10 @@ static switch_status_t sofia_answer_channel(switch_core_session_t *session) SIPTAG_CONTACT_STR(tech_pvt->reply_contact), SIPTAG_CALL_INFO_STR(switch_channel_get_variable(tech_pvt->channel, SOFIA_SIP_HEADER_PREFIX "call_info")), SOATAG_USER_SDP_STR(tech_pvt->local_sdp_str), - SOATAG_REUSE_REJECTED(1), SOATAG_ORDERED_USER(1), SOATAG_AUDIO_AUX("cn telephone-event"), NUTAG_INCLUDE_EXTRA_SDP(1), TAG_END()); + SOATAG_REUSE_REJECTED(1), SOATAG_ORDERED_USER(1), SOATAG_AUDIO_AUX("cn telephone-event"), NUTAG_INCLUDE_EXTRA_SDP(1), + TAG_IF(!switch_strlen_zero(extra_headers), SIPTAG_HEADER_STR(extra_headers)), + TAG_END()); + switch_safe_free(extra_headers); sofia_set_flag_locked(tech_pvt, TFLAG_ANS); } @@ -1443,9 +1431,13 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi case SWITCH_MESSAGE_INDICATE_RINGING: if (!switch_channel_test_flag(channel, CF_RING_READY) && !sofia_test_flag(tech_pvt, TFLAG_BYE) && !switch_channel_test_flag(channel, CF_EARLY_MEDIA) && !switch_channel_test_flag(channel, CF_ANSWERED)) { + char *extra_headers = sofia_glue_get_extra_headers(channel, SOFIA_SIP_PROGRESS_HEADER_PREFIX); nua_respond(tech_pvt->nh, SIP_180_RINGING, SIPTAG_CONTACT_STR(tech_pvt->reply_contact), - SIPTAG_HEADER_STR(generate_pai_str(session)), TAG_END()); + SIPTAG_HEADER_STR(generate_pai_str(session)), + TAG_IF(!switch_strlen_zero(extra_headers), SIPTAG_HEADER_STR(extra_headers)), + TAG_END()); + switch_safe_free(extra_headers); switch_channel_mark_ring_ready(channel); } break; @@ -1517,6 +1509,7 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi } if (!sofia_test_flag(tech_pvt, TFLAG_BYE)) { + char *extra_headers = sofia_glue_get_extra_headers(channel, SOFIA_SIP_PROGRESS_HEADER_PREFIX); nua_respond(tech_pvt->nh, SIP_183_SESSION_PROGRESS, NUTAG_AUTOANSWER(0), @@ -1526,7 +1519,10 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi SOATAG_REUSE_REJECTED(1), SOATAG_ORDERED_USER(1), SOATAG_ADDRESS(tech_pvt->adv_sdp_audio_ip), - SOATAG_USER_SDP_STR(tech_pvt->local_sdp_str), SOATAG_AUDIO_AUX("cn telephone-event"), TAG_END()); + SOATAG_USER_SDP_STR(tech_pvt->local_sdp_str), SOATAG_AUDIO_AUX("cn telephone-event"), + TAG_IF(!switch_strlen_zero(extra_headers), SIPTAG_HEADER_STR(extra_headers)), + TAG_END()); + switch_safe_free(extra_headers); } } } diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.h b/src/mod/endpoints/mod_sofia/mod_sofia.h index fd79cce211..99fd7409c7 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.h +++ b/src/mod/endpoints/mod_sofia/mod_sofia.h @@ -86,6 +86,7 @@ typedef struct private_object private_object_t; #define SOFIA_CHAT_PROTO "sip" #define SOFIA_SIP_HEADER_PREFIX "sip_h_" #define SOFIA_SIP_BYE_HEADER_PREFIX "sip_bye_h_" +#define SOFIA_SIP_PROGRESS_HEADER_PREFIX "sip_ph_" #define SOFIA_SIP_HEADER_PREFIX_T "~sip_h_" #define SOFIA_DEFAULT_PORT "5060" #define SOFIA_DEFAULT_TLS_PORT "5061" @@ -901,3 +902,5 @@ void sofia_glue_set_rtp_stats(private_object_t *tech_pvt); void sofia_glue_get_addr(msg_t *msg, char *buf, size_t buflen, int *port); sofia_destination_t* sofia_glue_get_destination(char *data); void sofia_glue_free_destination(sofia_destination_t *dst); +char *sofia_glue_get_extra_headers(switch_channel_t *channel, const char *prefix); +void sofia_glue_set_extra_headers(switch_channel_t *channel, sip_t const *sip, const char *prefix); \ No newline at end of file diff --git a/src/mod/endpoints/mod_sofia/sofia.c b/src/mod/endpoints/mod_sofia/sofia.c index ccd8f43da3..8c93bd5c5f 100644 --- a/src/mod/endpoints/mod_sofia/sofia.c +++ b/src/mod/endpoints/mod_sofia/sofia.c @@ -281,6 +281,7 @@ void sofia_handle_sip_i_bye(switch_core_session_t *session, int status, const char *tmp; switch_channel_t *channel; private_object_t *tech_pvt; + char *extra_headers; #ifdef MANUAL_BYE int cause; char st[80] = ""; @@ -319,8 +320,15 @@ void sofia_handle_sip_i_bye(switch_core_session_t *session, int status, switch_snprintf(st, sizeof(st), "%d", cause); switch_channel_set_variable(channel, "sip_term_cause", st); + + extra_headers = sofia_glue_get_extra_headers(channel, SOFIA_SIP_BYE_HEADER_PREFIX); + sofia_glue_set_extra_headers(channel, sip, SOFIA_SIP_BYE_HEADER_PREFIX); + switch_channel_hangup(channel, cause); - nua_respond(nh, SIP_200_OK, NUTAG_WITH_THIS(nua), TAG_END()); + nua_respond(nh, SIP_200_OK, NUTAG_WITH_THIS(nua), + TAG_IF(!switch_strlen_zero(extra_headers), SIPTAG_HEADER_STR(extra_headers)), TAG_END()); + + switch_safe_free(extra_headers); if (sofia_private) { sofia_private->destroy_me = 1; @@ -2938,6 +2946,8 @@ static void sofia_handle_sip_r_invite(switch_core_session_t *session, int status } else if (sip->sip_server && sip->sip_server->g_string) { switch_channel_set_variable(channel, "sip_user_agent", sip->sip_server->g_string); } + + sofia_glue_set_extra_headers(channel, sip, SOFIA_SIP_PROGRESS_HEADER_PREFIX); } if (switch_channel_test_flag(channel, CF_PROXY_MODE) || switch_channel_test_flag(channel, CF_PROXY_MEDIA)) { @@ -3843,6 +3853,7 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status, if (phrase) { switch_channel_set_variable_partner(channel, "sip_hangup_phrase", phrase); } + sofia_glue_set_extra_headers(channel, sip, SOFIA_SIP_BYE_HEADER_PREFIX); } switch_snprintf(st, sizeof(st), "%d", cause); switch_channel_set_variable(channel, "sip_term_cause", st); diff --git a/src/mod/endpoints/mod_sofia/sofia_glue.c b/src/mod/endpoints/mod_sofia/sofia_glue.c index b5de963bae..8e8569a3e3 100644 --- a/src/mod/endpoints/mod_sofia/sofia_glue.c +++ b/src/mod/endpoints/mod_sofia/sofia_glue.c @@ -1302,6 +1302,54 @@ void sofia_glue_tech_set_local_sdp(private_object_t *tech_pvt, const char *sdp_s switch_mutex_unlock(tech_pvt->sofia_mutex); } +char* sofia_glue_get_extra_headers(switch_channel_t *channel, const char *prefix) +{ + char *extra_headers = NULL; + switch_stream_handle_t stream = { 0 }; + switch_event_header_t *hi = NULL; + + SWITCH_STANDARD_STREAM(stream); + if ((hi = switch_channel_variable_first(channel))) { + for (; hi; hi = hi->next) { + const char *name = (char *) hi->name; + char *value = (char *) hi->value; + + if (!strncasecmp(name, prefix, strlen(prefix))) { + const char *hname = name + strlen(prefix); + stream.write_function(&stream, "%s: %s\r\n", hname, value); + } + } + switch_channel_variable_last(channel); + } + + if (!switch_strlen_zero((char*)stream.data)) { + extra_headers = stream.data; + } else { + switch_safe_free(stream.data); + } + + return extra_headers; +} + +void sofia_glue_set_extra_headers(switch_channel_t *channel, sip_t const *sip, const char *prefix) +{ + sip_unknown_t *un; + char name[512] = ""; + + if (!sip || !channel) { + return; + } + + for (un = sip->sip_unknown; un; un = un->un_next) { + if (!strncasecmp(un->un_name, "X-", 2) || !strncasecmp(un->un_name, "P-", 2)) { + if (!switch_strlen_zero(un->un_value)) { + switch_snprintf(name, sizeof(name), "%s%s", prefix, un->un_name); + switch_channel_set_variable(channel, name, un->un_value); + } + } + } +} + switch_status_t sofia_glue_do_invite(switch_core_session_t *session) { @@ -1314,8 +1362,6 @@ switch_status_t sofia_glue_do_invite(switch_core_session_t *session) const char *cid_name, *cid_num; char *e_dest = NULL; const char *holdstr = ""; - switch_stream_handle_t stream = { 0 }; - switch_event_header_t *hi; char *extra_headers = NULL; switch_status_t status = SWITCH_STATUS_FALSE; uint32_t session_timeout = 0; @@ -1639,23 +1685,7 @@ switch_status_t sofia_glue_do_invite(switch_core_session_t *session) switch_channel_set_variable(channel, "sofia_profile_name", tech_pvt->profile->name); } - SWITCH_STANDARD_STREAM(stream); - if ((hi = switch_channel_variable_first(channel))) { - for (; hi; hi = hi->next) { - const char *name = (char *) hi->name; - char *value = (char *) hi->value; - - if (!strncasecmp(name, SOFIA_SIP_HEADER_PREFIX, strlen(SOFIA_SIP_HEADER_PREFIX))) { - const char *hname = name + strlen(SOFIA_SIP_HEADER_PREFIX); - stream.write_function(&stream, "%s: %s\r\n", hname, value); - } - } - switch_channel_variable_last(channel); - } - - if (stream.data) { - extra_headers = stream.data; - } + extra_headers = sofia_glue_get_extra_headers(channel, SOFIA_SIP_HEADER_PREFIX); session_timeout = tech_pvt->profile->session_timeout; if ((val = switch_channel_get_variable(channel, SOFIA_SESSION_TIMEOUT))) { @@ -1715,8 +1745,8 @@ switch_status_t sofia_glue_do_invite(switch_core_session_t *session) SOATAG_RTP_SORT(SOA_RTP_SORT_REMOTE), SOATAG_RTP_SELECT(SOA_RTP_SELECT_ALL), TAG_IF(rep, SIPTAG_REPLACES_STR(rep)), SOATAG_HOLD(holdstr), TAG_END()); - switch_safe_free(stream.data); sofia_glue_free_destination(dst); + switch_safe_free(extra_headers); tech_pvt->redirected = NULL; return SWITCH_STATUS_SUCCESS;