From 0335cc32914ba8e9e89c21ac13ee71ff628fc73c Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Mon, 28 Mar 2016 13:14:38 -0500 Subject: [PATCH] FS-8918 #resolve [10 Second timeout after Notify during Proxy refer.] --- src/mod/endpoints/mod_sofia/mod_sofia.c | 81 ++++++++----- src/mod/endpoints/mod_sofia/mod_sofia.h | 2 + src/mod/endpoints/mod_sofia/sofia.c | 153 ++++++++++++++++++------ 3 files changed, 173 insertions(+), 63 deletions(-) diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.c b/src/mod/endpoints/mod_sofia/mod_sofia.c index 9fc3ccd47f..6f2b0cee2c 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.c +++ b/src/mod/endpoints/mod_sofia/mod_sofia.c @@ -343,6 +343,11 @@ switch_status_t sofia_on_destroy(switch_core_session_t *session) if (tech_pvt) { + if (tech_pvt->proxy_refer_msg) { + msg_ref_destroy(tech_pvt->proxy_refer_msg); + tech_pvt->proxy_refer_msg = NULL; + } + if (tech_pvt->respond_phrase) { switch_yield(100000); } @@ -1318,6 +1323,44 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi switch (msg->message_id) { + case SWITCH_MESSAGE_INDICATE_DEFLECT: { + + char *extra_headers = sofia_glue_get_extra_headers(channel, SOFIA_SIP_HEADER_PREFIX); + char ref_to[1024] = ""; + const char *var; + + if (!strcasecmp(msg->string_arg, "sip:")) { + const char *format = strchr(tech_pvt->profile->sipip, ':') ? "sip:%s@[%s]" : "sip:%s@%s"; + + switch_snprintf(ref_to, sizeof(ref_to), format, msg->string_arg, tech_pvt->profile->sipip); + } else { + switch_set_string(ref_to, msg->string_arg); + } + + 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_END()); + + if (msg->string_array_arg[0]) { + tech_pvt->proxy_refer_uuid = (char *)msg->string_array_arg[0]; + } else { + switch_mutex_unlock(tech_pvt->sofia_mutex); + sofia_wait_for_reply(tech_pvt, 9999, 10); + switch_mutex_lock(tech_pvt->sofia_mutex); + + if ((var = switch_channel_get_variable(tech_pvt->channel, "sip_refer_reply"))) { + msg->string_reply = switch_core_session_strdup(session, var); + } else { + msg->string_reply = "no reply"; + } + + switch_channel_hangup(tech_pvt->channel, SWITCH_CAUSE_BLIND_TRANSFER); + } + + switch_safe_free(extra_headers); + } + break; + case SWITCH_MESSAGE_INDICATE_VIDEO_REFRESH_REQ: if (!switch_channel_test_flag(channel, CF_AVPF)) { //const char *ua = switch_channel_get_variable(tech_pvt->channel, "sip_user_agent"); @@ -1943,34 +1986,6 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi } } break; - case SWITCH_MESSAGE_INDICATE_DEFLECT: - { - char *extra_headers = sofia_glue_get_extra_headers(channel, SOFIA_SIP_HEADER_PREFIX); - char ref_to[1024] = ""; - const char *var; - - if (!strcasecmp(msg->string_arg, "sip:")) { - const char *format = strchr(tech_pvt->profile->sipip, ':') ? "sip:%s@[%s]" : "sip:%s@%s"; - switch_snprintf(ref_to, sizeof(ref_to), format, msg->string_arg, tech_pvt->profile->sipip); - } else { - switch_set_string(ref_to, msg->string_arg); - } - 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_END()); - switch_mutex_unlock(tech_pvt->sofia_mutex); - sofia_wait_for_reply(tech_pvt, 9999, 10); - switch_mutex_lock(tech_pvt->sofia_mutex); - if ((var = switch_channel_get_variable(tech_pvt->channel, "sip_refer_reply"))) { - msg->string_reply = switch_core_session_strdup(session, var); - } else { - msg->string_reply = "no reply"; - } - switch_channel_hangup(tech_pvt->channel, SWITCH_CAUSE_BLIND_TRANSFER); - switch_safe_free(extra_headers); - } - break; - case SWITCH_MESSAGE_INDICATE_RESPOND: { @@ -2007,6 +2022,16 @@ 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()); + msg_ref_destroy(tech_pvt->proxy_refer_msg); + tech_pvt->proxy_refer_msg = NULL; + } + goto end_lock; + } + if (code == 302 && !zstr(msg->string_arg)) { char *p; diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.h b/src/mod/endpoints/mod_sofia/mod_sofia.h index a41e75abee..63c8a6d5d0 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.h +++ b/src/mod/endpoints/mod_sofia/mod_sofia.h @@ -801,6 +801,8 @@ struct private_object { char *x_freeswitch_support_local; char *last_sent_callee_id_name; char *last_sent_callee_id_number; + char *proxy_refer_uuid; + msg_t *proxy_refer_msg; switch_mutex_t *flag_mutex; switch_mutex_t *sofia_mutex; switch_payload_t te; diff --git a/src/mod/endpoints/mod_sofia/sofia.c b/src/mod/endpoints/mod_sofia/sofia.c index 1ef255ca1f..e1688b3863 100644 --- a/src/mod/endpoints/mod_sofia/sofia.c +++ b/src/mod/endpoints/mod_sofia/sofia.c @@ -84,12 +84,30 @@ static void sofia_handle_sip_r_options(switch_core_session_t *session, int statu nua_handle_t *nh, sofia_private_t *sofia_private, sip_t const *sip, sofia_dispatch_event_t *de, tagi_t tags[]); + void sofia_handle_sip_r_notify(switch_core_session_t *session, int status, char const *phrase, nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, sofia_private_t *sofia_private, sip_t const *sip, sofia_dispatch_event_t *de, tagi_t tags[]) { + private_object_t *tech_pvt = switch_core_session_get_private(session); + switch_core_session_t *other_session; + + if (tech_pvt->proxy_refer_uuid && (other_session = switch_core_session_locate(tech_pvt->proxy_refer_uuid))) { + switch_core_session_message_t *msg; + + msg = switch_core_session_alloc(other_session, sizeof(*msg)); + msg->message_id = SWITCH_MESSAGE_INDICATE_RESPOND; + msg->from = __FILE__; + msg->numeric_arg = status; + msg->string_arg = switch_core_session_strdup(other_session, phrase); + switch_core_session_queue_message(other_session, msg); + switch_core_session_rwunlock(other_session); + } else { + tech_pvt->proxy_refer_uuid = NULL; + } + if (status == 481 && sip && !sip->sip_retry_after && sip->sip_call_id && (!sofia_private || !sofia_private->is_call)) { char *sql; @@ -517,6 +535,27 @@ static void sofia_parse_all_invite_headers(sip_t const *sip, switch_core_session } } +static switch_status_t sofia_pass_notify(switch_core_session_t *session, const char *uuid, const char *payload) +{ + switch_core_session_t *other_session; + + if ((other_session = switch_core_session_locate(uuid))) { + switch_core_session_message_t *msg; + + msg = switch_core_session_alloc(other_session, sizeof(*msg)); + MESSAGE_STAMP_FFL(msg); + msg->message_id = SWITCH_MESSAGE_INDICATE_BLIND_TRANSFER_RESPONSE; + msg->string_arg = switch_core_session_strdup(other_session, payload); + msg->from = __FILE__; + switch_core_session_queue_message(other_session, msg); + switch_core_session_rwunlock(other_session); + return SWITCH_STATUS_SUCCESS; + } + + return SWITCH_STATUS_FALSE; +} + + void sofia_handle_sip_i_notify(switch_core_session_t *session, int status, char const *phrase, nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, sofia_private_t *sofia_private, sip_t const *sip, @@ -551,24 +590,21 @@ void sofia_handle_sip_i_notify(switch_core_session_t *session, int status, } - if (sofia_test_pflag(profile, PFLAG_PROXY_REFER) && sip->sip_payload && sip->sip_payload->pl_data && - sip->sip_content_type && sip->sip_content_type->c_type && - switch_stristr("sipfrag", sip->sip_content_type->c_type)) { - switch_core_session_t *other_session; - if (switch_core_session_get_partner(session, &other_session) == SWITCH_STATUS_SUCCESS) { - switch_core_session_message_t *msg; - - msg = switch_core_session_alloc(other_session, sizeof(*msg)); - MESSAGE_STAMP_FFL(msg); - msg->message_id = SWITCH_MESSAGE_INDICATE_BLIND_TRANSFER_RESPONSE; - msg->string_arg = switch_core_session_strdup(other_session, sip->sip_payload->pl_data); - msg->from = __FILE__; - switch_core_session_queue_message(other_session, msg); - switch_core_session_rwunlock(other_session); - - nua_respond(nh, SIP_202_ACCEPTED, NUTAG_WITH_THIS_MSG(de->data->e_msg), TAG_END()); - goto end; + if (tech_pvt && tech_pvt->proxy_refer_uuid && sofia_test_pflag(profile, PFLAG_PROXY_REFER) && sip->sip_payload && sip->sip_payload->pl_data && + sip->sip_content_type && sip->sip_content_type->c_type && switch_stristr("sipfrag", sip->sip_content_type->c_type)) { + + if (sofia_pass_notify(session, tech_pvt->proxy_refer_uuid, sip->sip_payload->pl_data) == SWITCH_STATUS_SUCCESS) { + if (tech_pvt->proxy_refer_msg) { + msg_ref_destroy(tech_pvt->proxy_refer_msg); + tech_pvt->proxy_refer_msg = NULL; + } + tech_pvt->proxy_refer_msg = msg_ref_create(de->data->e_msg); + //nua_respond(nh, SIP_202_ACCEPTED, NUTAG_WITH_THIS_MSG(de->data->e_msg), TAG_END()); + } else { + switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); } + + goto end; } /* For additional NOTIFY event packages see http://www.iana.org/assignments/sip-events. */ @@ -1288,6 +1324,34 @@ static void notify_watched_header(switch_core_session_t *session, const char *ms } } + +static void sofia_handle_sip_r_refer(nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, switch_core_session_t *session, int status, const char *phrase, sip_t const *sip, sofia_dispatch_event_t *de, tagi_t tags[]) +{ + private_object_t *tech_pvt = switch_core_session_get_private(session); + switch_core_session_t *other_session; + + if (status < 200) { + return; + } + + if (tech_pvt->proxy_refer_uuid && (other_session = switch_core_session_locate(tech_pvt->proxy_refer_uuid))) { + switch_core_session_message_t *msg; + + msg = switch_core_session_alloc(other_session, sizeof(*msg)); + msg->message_id = SWITCH_MESSAGE_INDICATE_RESPOND; + msg->from = __FILE__; + msg->numeric_arg = status; + msg->string_arg = switch_core_session_strdup(other_session, phrase); + switch_core_session_queue_message(other_session, msg); + switch_core_session_rwunlock(other_session); + } else { + tech_pvt->proxy_refer_uuid = NULL; + } +} + + + + //sofia_dispatch_event_t *de static void our_sofia_event_callback(nua_event_t event, int status, @@ -1552,7 +1616,9 @@ static void our_sofia_event_callback(nua_event_t event, sofia_handle_sip_i_bye(session, status, phrase, nua, profile, nh, sofia_private, sip, de, tags); break; case nua_r_notify: - sofia_handle_sip_r_notify(session, status, phrase, nua, profile, nh, sofia_private, sip, de, tags); + if (session) { + sofia_handle_sip_r_notify(session, status, phrase, nua, profile, nh, sofia_private, sip, de, tags); + } break; case nua_i_notify: sofia_handle_sip_i_notify(session, status, phrase, nua, profile, nh, sofia_private, sip, de, tags); @@ -1601,6 +1667,9 @@ static void our_sofia_event_callback(nua_event_t event, } break; case nua_r_refer: + if (session) { + sofia_handle_sip_r_refer(nua, profile, nh, session, status, phrase, sip, de, tags); + } break; case nua_i_refer: if (session) { @@ -7986,6 +8055,29 @@ nua_handle_t *sofia_global_nua_handle_by_replaces(sip_replaces_t *replaces) } +static switch_status_t sofia_process_proxy_refer(switch_core_session_t *session, const char *refer_to) +{ + switch_core_session_t *other_session; + private_object_t *tech_pvt = switch_core_session_get_private(session); + + if (switch_core_session_get_partner(session, &other_session) == SWITCH_STATUS_SUCCESS) { + switch_core_session_message_t *msg; + + tech_pvt->proxy_refer_uuid = switch_core_session_strdup(session, switch_core_session_get_uuid(other_session)); + msg = switch_core_session_alloc(other_session, sizeof(*msg)); + MESSAGE_STAMP_FFL(msg); + msg->message_id = SWITCH_MESSAGE_INDICATE_DEFLECT; + msg->string_arg = switch_core_session_strdup(other_session, refer_to); + msg->string_array_arg[0] = switch_core_session_strdup(other_session, switch_core_session_get_uuid(session)); + msg->from = __FILE__; + switch_core_session_queue_message(other_session, msg); + switch_core_session_rwunlock(other_session); + return SWITCH_STATUS_SUCCESS; + } + + return SWITCH_STATUS_FALSE; +} + void sofia_handle_sip_i_refer(nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, switch_core_session_t *session, sip_t const *sip, sofia_dispatch_event_t *de, tagi_t tags[]) { @@ -8018,27 +8110,18 @@ void sofia_handle_sip_i_refer(nua_t *nua, sofia_profile_t *profile, nua_handle_t full_ref_to = sip_header_as_string(home, (void *) sip->sip_refer_to); } - - if (sofia_test_pflag(profile, PFLAG_PROXY_REFER)) { - switch_core_session_t *other_session; - - if (switch_core_session_get_partner(session, &other_session) == SWITCH_STATUS_SUCCESS) { - switch_core_session_message_t *msg; - - msg = switch_core_session_alloc(other_session, sizeof(*msg)); - MESSAGE_STAMP_FFL(msg); - msg->message_id = SWITCH_MESSAGE_INDICATE_DEFLECT; - msg->string_arg = switch_core_session_strdup(other_session, full_ref_to); - msg->from = __FILE__; - switch_core_session_queue_message(other_session, msg); - switch_core_session_rwunlock(other_session); - - nua_respond(nh, SIP_202_ACCEPTED, NUTAG_WITH_THIS_MSG(de->data->e_msg), SIPTAG_EXPIRES_STR("60"), TAG_END()); + if (full_ref_to && sofia_test_pflag(profile, PFLAG_PROXY_REFER)) { + if (sofia_process_proxy_refer(session, full_ref_to) == SWITCH_STATUS_SUCCESS) { + if (tech_pvt->proxy_refer_msg) { + msg_ref_destroy(tech_pvt->proxy_refer_msg); + tech_pvt->proxy_refer_msg = NULL; + } + tech_pvt->proxy_refer_msg = msg_ref_create(de->data->e_msg); + //nua_respond(nh, SIP_202_ACCEPTED, NUTAG_WITH_THIS_MSG(de->data->e_msg), SIPTAG_EXPIRES_STR("60"), TAG_END()); goto done; } } - from = sip->sip_from; //to = sip->sip_to;