From bf1ad19a0946191a4eec32d891f3df8646bf4c8b Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Fri, 20 Mar 2009 01:52:53 +0000 Subject: [PATCH] FSCORE-322 git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@12676 d0543943-73ff-0310-b7d9-9358b9ac24b2 --- src/mod/endpoints/mod_sofia/mod_sofia.c | 170 +++++++++-------- src/mod/endpoints/mod_sofia/mod_sofia.h | 14 +- src/mod/endpoints/mod_sofia/sofia.c | 97 +++++----- src/mod/endpoints/mod_sofia/sofia_glue.c | 229 +++++++++++++++++------ 4 files changed, 333 insertions(+), 177 deletions(-) diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.c b/src/mod/endpoints/mod_sofia/mod_sofia.c index 3d054297a1..1e9855edb8 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.c +++ b/src/mod/endpoints/mod_sofia/mod_sofia.c @@ -303,14 +303,14 @@ switch_status_t sofia_on_hangup(switch_core_session_t *session) switch_core_session_rwunlock(a_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; + sofia_set_flag_locked(tech_pvt, TFLAG_BYE); + SWITCH_STANDARD_STREAM(stream); if ((hi = switch_channel_variable_first(channel))) { for (; hi; hi = hi->next) { @@ -337,7 +337,7 @@ switch_status_t sofia_on_hangup(switch_core_session_t *session) switch_snprintf(reason, sizeof(reason), "FreeSWITCH;cause=%d;text=\"%s\"", cause, switch_channel_cause2str(cause)); } - if (sofia_test_flag(tech_pvt, TFLAG_ANS)) { + if (switch_channel_test_flag(channel, CF_ANSWERED)) { if (!tech_pvt->got_bye) { switch_channel_set_variable(channel, "sip_hangup_disposition", "send_bye"); } @@ -347,11 +347,12 @@ switch_status_t sofia_on_hangup(switch_core_session_t *session) TAG_IF(!switch_strlen_zero(bye_headers), SIPTAG_HEADER_STR(bye_headers)), TAG_END()); } else { - if (sofia_test_flag(tech_pvt, TFLAG_OUTBOUND)) { + if (switch_channel_test_flag(channel, CF_OUTBOUND)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Sending CANCEL to %s\n", switch_channel_get_name(channel)); if (!tech_pvt->got_bye) { switch_channel_set_variable(channel, "sip_hangup_disposition", "send_cancel"); } + nua_cancel(tech_pvt->nh, SIPTAG_REASON_STR(reason), TAG_IF(!switch_strlen_zero(bye_headers), SIPTAG_HEADER_STR(bye_headers)), @@ -362,14 +363,16 @@ switch_status_t sofia_on_hangup(switch_core_session_t *session) if (!tech_pvt->got_bye) { switch_channel_set_variable(channel, "sip_hangup_disposition", "send_refuse"); } - nua_respond(tech_pvt->nh, sip_cause, sip_status_phrase(sip_cause), - SIPTAG_REASON_STR(reason), - TAG_IF(!switch_strlen_zero(bye_headers), SIPTAG_HEADER_STR(bye_headers)), - TAG_END()); + if (!sofia_test_flag(tech_pvt, TFLAG_BYE)) { + nua_respond(tech_pvt->nh, sip_cause, sip_status_phrase(sip_cause), + SIPTAG_REASON_STR(reason), + TAG_IF(!switch_strlen_zero(bye_headers), SIPTAG_HEADER_STR(bye_headers)), + TAG_END()); + } } } - sofia_set_flag(tech_pvt, TFLAG_BYE); + switch_safe_free(stream.data); } @@ -431,7 +434,7 @@ static switch_status_t sofia_answer_channel(switch_core_session_t *session) is_proxy = (switch_channel_test_flag(channel, CF_PROXY_MODE) || switch_channel_test_flag(channel, CF_PROXY_MEDIA)); if (b_sdp && is_proxy) { - tech_pvt->local_sdp_str = switch_core_session_strdup(session, b_sdp); + sofia_glue_tech_set_local_sdp(tech_pvt, b_sdp, SWITCH_TRUE); if (switch_channel_test_flag(channel, CF_PROXY_MEDIA)) { sofia_glue_tech_patch_sdp(tech_pvt); @@ -443,13 +446,16 @@ static switch_status_t sofia_answer_channel(switch_core_session_t *session) /* This if statement check and handles the 3pcc proxy mode */ if (sofia_test_pflag(tech_pvt->profile, PFLAG_3PCC_PROXY) && sofia_test_flag(tech_pvt, TFLAG_3PCC)) { /* Send the 200 OK */ - 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()); - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "3PCC-PROXY, Sent a 200 OK, waiting for ACK\n"); - + if (!sofia_test_flag(tech_pvt, TFLAG_BYE)) { + 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()); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "3PCC-PROXY, Sent a 200 OK, waiting for ACK\n"); + } + /* Unlock the session signal to allow the ack to make it in */ // Maybe we should timeout? switch_mutex_unlock(tech_pvt->sofia_mutex); @@ -520,15 +526,16 @@ static switch_status_t sofia_answer_channel(switch_core_session_t *session) switch_channel_set_variable(channel, "sip_nat_detected", "true"); } - - nua_respond(tech_pvt->nh, SIP_200_OK, - NUTAG_AUTOANSWER(0), - TAG_IF(sticky, NUTAG_PROXY(tech_pvt->record_route)), - NUTAG_SESSION_TIMER(session_timeout), - SIPTAG_CONTACT_STR(tech_pvt->reply_contact), - 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()); - sofia_set_flag_locked(tech_pvt, TFLAG_ANS); + if (!sofia_test_flag(tech_pvt, TFLAG_BYE)) { + nua_respond(tech_pvt->nh, SIP_200_OK, + NUTAG_AUTOANSWER(0), + TAG_IF(sticky, NUTAG_PROXY(tech_pvt->record_route)), + NUTAG_SESSION_TIMER(session_timeout), + SIPTAG_CONTACT_STR(tech_pvt->reply_contact), + 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()); + sofia_set_flag_locked(tech_pvt, TFLAG_ANS); + } return SWITCH_STATUS_SUCCESS; } @@ -976,7 +983,7 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi private_object_t *tech_pvt = switch_core_session_get_private(session); switch_status_t status = SWITCH_STATUS_SUCCESS; - if (switch_channel_down(channel) || !tech_pvt) { + if (switch_channel_down(channel) || !tech_pvt || sofia_test_flag(tech_pvt, TFLAG_BYE)) { status = SWITCH_STATUS_FALSE; goto end; } @@ -1010,11 +1017,11 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi default: break; } - + /* ones that do need to lock sofia mutex */ switch_mutex_lock(tech_pvt->sofia_mutex); - if (switch_channel_down(channel) || !tech_pvt) { + if (switch_channel_down(channel) || !tech_pvt || sofia_test_flag(tech_pvt, TFLAG_BYE)) { status = SWITCH_STATUS_FALSE; goto end_lock; } @@ -1046,11 +1053,13 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi sofia_glue_set_local_sdp(tech_pvt, ip, atoi(port), msg->string_arg, 1); } - nua_respond(tech_pvt->nh, SIP_200_OK, - SIPTAG_CONTACT_STR(tech_pvt->reply_contact), - 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()); - switch_channel_mark_answered(channel); + if (!sofia_test_flag(tech_pvt, TFLAG_BYE)) { + nua_respond(tech_pvt->nh, SIP_200_OK, + SIPTAG_CONTACT_STR(tech_pvt->reply_contact), + 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()); + switch_channel_mark_answered(channel); + } } break; case SWITCH_MESSAGE_INDICATE_NOMEDIA: @@ -1061,7 +1070,8 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi const char *ip = NULL, *port = NULL; switch_channel_set_flag(channel, CF_PROXY_MODE); - tech_pvt->local_sdp_str = NULL; + sofia_glue_tech_set_local_sdp(tech_pvt, NULL, SWITCH_FALSE); + if ((uuid = switch_channel_get_variable(channel, SWITCH_SIGNAL_BOND_VARIABLE)) && (other_session = switch_core_session_locate(uuid))) { other_channel = switch_core_session_get_channel(other_session); @@ -1085,7 +1095,8 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s Sending media re-direct:\n%s\n", switch_channel_get_name(channel), msg->string_arg); - tech_pvt->local_sdp_str = switch_core_session_strdup(session, msg->string_arg); + sofia_glue_tech_set_local_sdp(tech_pvt, msg->string_arg, SWITCH_TRUE); + sofia_set_flag_locked(tech_pvt, TFLAG_SENT_UPDATE); sofia_glue_do_invite(session); } @@ -1112,7 +1123,7 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi uint32_t send_invite = 1; switch_channel_clear_flag(channel, CF_PROXY_MODE); - tech_pvt->local_sdp_str = NULL; + sofia_glue_tech_set_local_sdp(tech_pvt, NULL, SWITCH_FALSE); if (!switch_channel_media_ready(channel)) { if (!switch_channel_test_flag(tech_pvt->channel, CF_OUTBOUND)) { @@ -1175,7 +1186,7 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi break; case SWITCH_MESSAGE_INDICATE_REDIRECT: if (!switch_strlen_zero(msg->string_arg)) { - if (!switch_channel_test_flag(channel, CF_ANSWERED)) { + if (!switch_channel_test_flag(channel, CF_ANSWERED) && !sofia_test_flag(tech_pvt, TFLAG_BYE)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Redirecting to %s\n", msg->string_arg); nua_respond(tech_pvt->nh, SIP_302_MOVED_TEMPORARILY, SIPTAG_CONTACT_STR(msg->string_arg), TAG_END()); sofia_set_flag_locked(tech_pvt, TFLAG_BYE); @@ -1212,7 +1223,7 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi if (msg->numeric_arg || msg->string_arg) { int code = msg->numeric_arg; const char *reason = NULL; - + if (code) { reason = msg->string_arg; } else { @@ -1229,6 +1240,12 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi code = 488; } + if (!switch_channel_test_flag(channel, CF_ANSWERED) && code >= 300) { + if (sofia_test_flag(tech_pvt, TFLAG_BYE)) { + goto end_lock; + } + } + if (switch_strlen_zero(reason) && code != 407 && code != 302) { reason = sip_status_phrase(code); if (switch_strlen_zero(reason)) { @@ -1260,11 +1277,12 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi } } - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Overlap Dial with %d %s\n", code, reason); - nua_respond(tech_pvt->nh, code, su_strdup(tech_pvt->nh->nh_home, reason), TAG_IF(to_uri, SIPTAG_CONTACT_STR(to_uri)), - SIPTAG_SUPPORTED_STR(NULL), SIPTAG_ACCEPT_STR(NULL), - TAG_IF(!switch_strlen_zero(max_forwards), SIPTAG_MAX_FORWARDS_STR(max_forwards)), TAG_END()); - if (!switch_channel_test_flag(channel, CF_ANSWERED)) { + if (!switch_channel_test_flag(channel, CF_ANSWERED) && !sofia_test_flag(tech_pvt, TFLAG_BYE)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Overlap Dial with %d %s\n", code, reason); + nua_respond(tech_pvt->nh, code, su_strdup(tech_pvt->nh->nh_home, reason), TAG_IF(to_uri, SIPTAG_CONTACT_STR(to_uri)), + SIPTAG_SUPPORTED_STR(NULL), SIPTAG_ACCEPT_STR(NULL), + TAG_IF(!switch_strlen_zero(max_forwards), SIPTAG_MAX_FORWARDS_STR(max_forwards)), TAG_END()); + sofia_set_flag_locked(tech_pvt, TFLAG_BYE); } } else if (code == 302 && !switch_strlen_zero(msg->string_arg)) { @@ -1274,31 +1292,30 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi msg->string_arg = p; switch_core_session_receive_message(session, msg); goto end_lock; - } else { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Responding with %d [%s]\n", code, reason); - - if (!switch_strlen_zero(((char *) msg->pointer_arg))) { - tech_pvt->local_sdp_str = switch_core_session_strdup(tech_pvt->session, (char *) msg->pointer_arg); - if (switch_channel_test_flag(channel, CF_PROXY_MEDIA)) { - sofia_glue_tech_patch_sdp(tech_pvt); - sofia_glue_tech_proxy_remote_addr(tech_pvt); + } else if (!switch_channel_test_flag(channel, CF_ANSWERED)) { + if (!sofia_test_flag(tech_pvt, TFLAG_BYE)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Responding with %d [%s]\n", code, reason); + if (!switch_strlen_zero(((char *) msg->pointer_arg))) { + sofia_glue_tech_set_local_sdp(tech_pvt, (char *) msg->pointer_arg, SWITCH_TRUE); + + if (switch_channel_test_flag(channel, CF_PROXY_MEDIA)) { + sofia_glue_tech_patch_sdp(tech_pvt); + sofia_glue_tech_proxy_remote_addr(tech_pvt); + } + nua_respond(tech_pvt->nh, code, su_strdup(tech_pvt->nh->nh_home, reason), SIPTAG_CONTACT_STR(tech_pvt->reply_contact), + 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()); + } else { + nua_respond(tech_pvt->nh, code, su_strdup(tech_pvt->nh->nh_home, reason), SIPTAG_CONTACT_STR(tech_pvt->reply_contact), TAG_END()); } - nua_respond(tech_pvt->nh, code, su_strdup(tech_pvt->nh->nh_home, reason), SIPTAG_CONTACT_STR(tech_pvt->reply_contact), - 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()); - } else { - nua_respond(tech_pvt->nh, code, su_strdup(tech_pvt->nh->nh_home, reason), SIPTAG_CONTACT_STR(tech_pvt->reply_contact), TAG_END()); - } - if (!switch_channel_test_flag(channel, CF_ANSWERED) && code >= 300) { - sofia_set_flag_locked(tech_pvt, TFLAG_BYE); } } } break; case SWITCH_MESSAGE_INDICATE_RINGING: - if (!switch_channel_test_flag(channel, CF_RING_READY) && + 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)) { nua_respond(tech_pvt->nh, SIP_180_RINGING, SIPTAG_CONTACT_STR(tech_pvt->reply_contact), TAG_END()); switch_channel_mark_ring_ready(channel); @@ -1321,10 +1338,12 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi if (switch_channel_test_flag(channel, CF_PROXY_MODE) || switch_channel_test_flag(channel, CF_PROXY_MEDIA)) { const char *sdp = NULL; if ((sdp = switch_channel_get_variable(channel, SWITCH_B_SDP_VARIABLE))) { - tech_pvt->local_sdp_str = switch_core_session_strdup(session, sdp); + sofia_glue_tech_set_local_sdp(tech_pvt, sdp, SWITCH_TRUE); } if (switch_channel_test_flag(channel, CF_PROXY_MEDIA)) { + sofia_glue_tech_patch_sdp(tech_pvt); + if (sofia_glue_activate_rtp(tech_pvt, 0) != SWITCH_STATUS_SUCCESS) { status = SWITCH_STATUS_FALSE; goto end_lock; @@ -1369,16 +1388,17 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi switch_channel_set_variable(channel, "sip_nat_detected", "true"); } - - nua_respond(tech_pvt->nh, - SIP_183_SESSION_PROGRESS, - NUTAG_AUTOANSWER(0), - TAG_IF(sticky, NUTAG_PROXY(tech_pvt->record_route)), - SIPTAG_CONTACT_STR(tech_pvt->reply_contact), - 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()); + if (!sofia_test_flag(tech_pvt, TFLAG_BYE)) { + nua_respond(tech_pvt->nh, + SIP_183_SESSION_PROGRESS, + NUTAG_AUTOANSWER(0), + TAG_IF(sticky, NUTAG_PROXY(tech_pvt->record_route)), + SIPTAG_CONTACT_STR(tech_pvt->reply_contact), + 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()); + } } } break; @@ -1392,6 +1412,10 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi end: + if (switch_channel_down(channel) || !tech_pvt || sofia_test_flag(tech_pvt, TFLAG_BYE)) { + status = SWITCH_STATUS_FALSE; + } + return status; } diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.h b/src/mod/endpoints/mod_sofia/mod_sofia.h index de8e8ab5e2..8065cbbee4 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.h +++ b/src/mod/endpoints/mod_sofia/mod_sofia.h @@ -510,8 +510,13 @@ struct private_object { char *rm_fmtp; char *fmtp_out; char *remote_sdp_str; + int crypto_tag; + unsigned char local_raw_key[SWITCH_RTP_MAX_CRYPTO_LEN]; + unsigned char remote_raw_key[SWITCH_RTP_MAX_CRYPTO_LEN]; + switch_rtp_crypto_key_type_t crypto_send_type; + switch_rtp_crypto_key_type_t crypto_recv_type; + switch_rtp_crypto_key_type_t crypto_type; char *local_sdp_str; - char *orig_local_sdp_str; char *dest; char *dest_to; char *key; @@ -533,12 +538,6 @@ struct private_object { char *stun_ip; switch_port_t stun_port; uint32_t stun_flags; - int crypto_tag; - unsigned char local_raw_key[SWITCH_RTP_MAX_CRYPTO_LEN]; - unsigned char remote_raw_key[SWITCH_RTP_MAX_CRYPTO_LEN]; - switch_rtp_crypto_key_type_t crypto_send_type; - switch_rtp_crypto_key_type_t crypto_recv_type; - switch_rtp_crypto_key_type_t crypto_type; unsigned long rm_rate; switch_payload_t pt; switch_mutex_t *flag_mutex; @@ -837,3 +836,4 @@ switch_status_t sofia_set_loglevel(const char *name, int level); */ int sofia_get_loglevel(const char *name); sofia_cid_type_t sofia_cid_name2type(const char *name); +void sofia_glue_tech_set_local_sdp(private_object_t *tech_pvt, const char *sdp_str, switch_bool_t dup); diff --git a/src/mod/endpoints/mod_sofia/sofia.c b/src/mod/endpoints/mod_sofia/sofia.c index 5971ad8c2c..fd04e837c4 100644 --- a/src/mod/endpoints/mod_sofia/sofia.c +++ b/src/mod/endpoints/mod_sofia/sofia.c @@ -342,8 +342,21 @@ void sofia_event_callback(nua_event_t event, } else if (!switch_strlen_zero(sofia_private->uuid)) { if ((session = switch_core_session_locate(sofia_private->uuid))) { tech_pvt = switch_core_session_get_private(session); - switch_assert(tech_pvt); - channel = switch_core_session_get_channel(tech_pvt->session); + channel = switch_core_session_get_channel(session); + if (tech_pvt) { + + if (status >= 300) { + sofia_set_flag_locked(tech_pvt, TFLAG_BYE); + } + + switch_mutex_lock(tech_pvt->sofia_mutex); + locked = 1; + } else { + switch_core_session_rwunlock(session); + return; + } + + if (status >= 180 && !*sofia_private->auth_gateway_name) { const char *gwname = switch_channel_get_variable(channel, "sip_use_gateway"); if (!switch_strlen_zero(gwname)) { @@ -369,11 +382,6 @@ void sofia_event_callback(nua_event_t event, switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Channel is already hungup.\n"); goto done; } - - if (tech_pvt) { - switch_mutex_lock(tech_pvt->sofia_mutex); - locked = 1; - } } else if (sofia_private && sofia_private->is_call) { sofia_private->destroy_me = 22; } @@ -542,13 +550,13 @@ void sofia_event_callback(nua_event_t event, sofia_reg_release_gateway(gateway); } + if (locked && tech_pvt) { + switch_mutex_unlock(tech_pvt->sofia_mutex); + } + if (session) { switch_core_session_rwunlock(session); } - - if (tech_pvt && locked) { - switch_mutex_unlock(tech_pvt->sofia_mutex); - } } void event_handler(switch_event_t *event) @@ -697,6 +705,8 @@ void *SWITCH_THREAD_FUNC sofia_profile_thread_run(switch_thread_t *thread, void switch_thread_t *worker_thread; switch_status_t st; + + switch_mutex_lock(mod_sofia_globals.mutex); mod_sofia_globals.threads++; switch_mutex_unlock(mod_sofia_globals.mutex); @@ -2798,13 +2808,13 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status, if (session) { channel = switch_core_session_get_channel(session); tech_pvt = switch_core_session_get_private(session); - switch_assert(tech_pvt != NULL); - if (!tech_pvt->nh) { + + if (!tech_pvt || !tech_pvt->nh) { goto done; } - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Channel %s entering state [%s]\n", - switch_channel_get_name(channel), nua_callstate_name(ss_state)); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Channel %s entering state [%s][%d]\n", + switch_channel_get_name(channel), nua_callstate_name(ss_state), status); if (r_sdp) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Remote SDP:\n%s\n", r_sdp); @@ -2894,7 +2904,6 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status, if (!switch_channel_get_variable(other_channel, SWITCH_B_SDP_VARIABLE)) { switch_channel_set_variable(other_channel, SWITCH_B_SDP_VARIABLE, r_sdp); } - switch_channel_pre_answer(other_channel); switch_core_session_rwunlock(other_session); } @@ -3071,13 +3080,13 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status, if ((uuid = switch_channel_get_variable(channel, SWITCH_SIGNAL_BOND_VARIABLE)) && (other_session = switch_core_session_locate(uuid))) { switch_core_session_message_t msg = { 0 }; - + if (profile->media_options & MEDIA_OPT_MEDIA_ON_HOLD) { tech_pvt->hold_laps = 1; switch_channel_set_variable(channel, SWITCH_R_SDP_VARIABLE, r_sdp); switch_channel_clear_flag(channel, CF_PROXY_MODE); - tech_pvt->local_sdp_str = NULL; - + sofia_glue_tech_set_local_sdp(tech_pvt, NULL, SWITCH_FALSE); + if (!switch_channel_media_ready(channel)) { if (!switch_channel_test_flag(tech_pvt->channel, CF_OUTBOUND)) { //const char *r_sdp = switch_channel_get_variable(channel, SWITCH_R_SDP_VARIABLE); @@ -3329,44 +3338,44 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status, tech_pvt->q850_cause = SWITCH_CAUSE_MANDATORY_IE_MISSING; } case nua_callstate_terminated: - if (!sofia_test_flag(tech_pvt, TFLAG_BYE)) { - sofia_set_flag_locked(tech_pvt, TFLAG_BYE); - if (sofia_test_flag(tech_pvt, TFLAG_NOHUP)) { - sofia_clear_flag_locked(tech_pvt, TFLAG_NOHUP); + if (sofia_test_flag(tech_pvt, TFLAG_NOHUP)) { + sofia_clear_flag_locked(tech_pvt, TFLAG_NOHUP); + } else if (switch_channel_up(channel)) { + int cause; + if (tech_pvt->q850_cause) { + cause = tech_pvt->q850_cause; } else { - int cause; - if (tech_pvt->q850_cause) { - cause = tech_pvt->q850_cause; - } else { - cause = sofia_glue_sip_cause_to_freeswitch(status); - } - if (status) { - switch_snprintf(st, sizeof(st), "%d", status); - switch_channel_set_variable(channel, "sip_term_status", st); - switch_snprintf(st, sizeof(st), "sip:%d", status); - switch_channel_set_variable_partner(channel, SWITCH_PROTO_SPECIFIC_HANGUP_CAUSE_VARIABLE, st); - switch_channel_set_variable(channel, SWITCH_PROTO_SPECIFIC_HANGUP_CAUSE_VARIABLE, st); - if (phrase) { - switch_channel_set_variable_partner(channel, "sip_hangup_phrase", phrase); - } - } - switch_snprintf(st, sizeof(st), "%d", cause); - switch_channel_set_variable(channel, "sip_term_cause", st); - switch_channel_hangup(channel, cause); + cause = sofia_glue_sip_cause_to_freeswitch(status); } + if (status) { + switch_snprintf(st, sizeof(st), "%d", status); + switch_channel_set_variable(channel, "sip_term_status", st); + switch_snprintf(st, sizeof(st), "sip:%d", status); + switch_channel_set_variable_partner(channel, SWITCH_PROTO_SPECIFIC_HANGUP_CAUSE_VARIABLE, st); + switch_channel_set_variable(channel, SWITCH_PROTO_SPECIFIC_HANGUP_CAUSE_VARIABLE, st); + if (phrase) { + switch_channel_set_variable_partner(channel, "sip_hangup_phrase", phrase); + } + } + switch_snprintf(st, sizeof(st), "%d", cause); + switch_channel_set_variable(channel, "sip_term_cause", st); + switch_channel_hangup(channel, cause); } + + if (ss_state == nua_callstate_terminated) { if (tech_pvt->sofia_private) { tech_pvt->sofia_private = NULL; } tech_pvt->nh = NULL; - + if (nh) { nua_handle_bind(nh, NULL); nua_handle_destroy(nh); } } + break; } @@ -4616,7 +4625,7 @@ void sofia_handle_sip_i_invite(nua_t *nua, sofia_profile_t *profile, nua_handle_ switch_channel_set_caller_profile(channel, tech_pvt->caller_profile); } - + if (!(sofia_private = malloc(sizeof(*sofia_private)))) { abort(); } diff --git a/src/mod/endpoints/mod_sofia/sofia_glue.c b/src/mod/endpoints/mod_sofia/sofia_glue.c index b365573da9..82f46c5889 100644 --- a/src/mod/endpoints/mod_sofia/sofia_glue.c +++ b/src/mod/endpoints/mod_sofia/sofia_glue.c @@ -103,8 +103,7 @@ void sofia_glue_set_image_sdp(private_object_t *tech_pvt, switch_t38_options_t * t38_options->T38VendorInfo ); - - tech_pvt->local_sdp_str = switch_core_session_strdup(tech_pvt->session, buf); + sofia_glue_tech_set_local_sdp(tech_pvt, buf, SWITCH_TRUE); } void sofia_glue_set_local_sdp(private_object_t *tech_pvt, const char *ip, uint32_t port, const char *sr, int force) @@ -392,8 +391,7 @@ void sofia_glue_set_local_sdp(private_object_t *tech_pvt, const char *ip, uint32 } } } - - tech_pvt->local_sdp_str = switch_core_session_strdup(tech_pvt->session, buf); + sofia_glue_tech_set_local_sdp(tech_pvt, buf, SWITCH_TRUE); } void sofia_glue_tech_prepare_codecs(private_object_t *tech_pvt) @@ -862,16 +860,17 @@ char *sofia_overcome_sip_uri_weakness(switch_core_session_t *session, const char return new_uri; } +#define RA_PTR_LEN 512 switch_status_t sofia_glue_tech_proxy_remote_addr(private_object_t *tech_pvt) { const char *err; - char rip[128] = ""; - char rp[128] = ""; - char rvp[128] = ""; - char *p, *ip_ptr = NULL, *port_ptr = NULL, *vid_port_ptr = NULL; + char rip[RA_PTR_LEN] = ""; + char rp[RA_PTR_LEN] = ""; + char rvp[RA_PTR_LEN] = ""; + char *p, *ip_ptr = NULL, *port_ptr = NULL, *vid_port_ptr = NULL, *pe; int x; const char *val; - + if (switch_strlen_zero(tech_pvt->remote_sdp_str)) { return SWITCH_STATUS_FALSE; } @@ -898,24 +897,34 @@ switch_status_t sofia_glue_tech_proxy_remote_addr(private_object_t *tech_pvt) } p = ip_ptr; + pe = p + strlen(p); x = 0; - while (x < sizeof(rip) && p && *p && ((*p >= '0' && *p <= '9') || *p == '.' || *p == ':' || (*p >= 'a' && *p <= 'f') || (*p >= 'A' && *p <= 'F'))) { + while (x < sizeof(rip) - 1 && p && *p && ((*p >= '0' && *p <= '9') || *p == '.' || *p == ':' || (*p >= 'a' && *p <= 'f') || (*p >= 'A' && *p <= 'F'))) { rip[x++] = *p; p++; + if (p >= pe) { + return SWITCH_STATUS_FALSE; + } } p = port_ptr; x = 0; - while (x < sizeof(rp) && p && *p && (*p >= '0' && *p <= '9')) { + while (x < sizeof(rp) - 1 && p && *p && (*p >= '0' && *p <= '9')) { rp[x++] = *p; p++; + if (p >= pe) { + return SWITCH_STATUS_FALSE; + } } p = vid_port_ptr; x = 0; - while (x < sizeof(rvp) && p && *p && (*p >= '0' && *p <= '9')) { + while (x < sizeof(rvp) - 1 && p && *p && (*p >= '0' && *p <= '9')) { rvp[x++] = *p; p++; + if (p >= pe) { + return SWITCH_STATUS_FALSE; + } } if (!(*rip && *rp)) { @@ -965,12 +974,9 @@ switch_status_t sofia_glue_tech_proxy_remote_addr(private_object_t *tech_pvt) tech_pvt->remote_sdp_audio_ip, tech_pvt->remote_sdp_audio_port); return SWITCH_STATUS_SUCCESS; } - - } - - if (switch_rtp_ready(tech_pvt->rtp_session)) { - if (switch_rtp_set_remote_address(tech_pvt->rtp_session, tech_pvt->remote_sdp_audio_ip, tech_pvt->remote_sdp_audio_port, SWITCH_TRUE, &err) != - SWITCH_STATUS_SUCCESS) { + + if (switch_rtp_set_remote_address(tech_pvt->rtp_session, tech_pvt->remote_sdp_audio_ip, + tech_pvt->remote_sdp_audio_port, SWITCH_TRUE, &err) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "AUDIO RTP REPORTS ERROR: [%s]\n", err); } else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "AUDIO RTP CHANGING DEST TO: [%s:%d]\n", @@ -990,17 +996,19 @@ switch_status_t sofia_glue_tech_proxy_remote_addr(private_object_t *tech_pvt) void sofia_glue_tech_patch_sdp(private_object_t *tech_pvt) { switch_size_t len; - char *p, *q; + char *p, *q, *pe , *qe; int has_video=0,has_audio=0,has_ip=0; char port_buf[25] = ""; char vport_buf[25] = ""; + char *new_sdp; + int bad = 0; if (switch_strlen_zero(tech_pvt->local_sdp_str)) { return; } - len = strlen(tech_pvt->local_sdp_str) + 384; - + len = strlen(tech_pvt->local_sdp_str) * 2; + if (switch_stristr("sendonly", tech_pvt->local_sdp_str) || switch_stristr("0.0.0.0", tech_pvt->local_sdp_str)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Skip patch on hold SDP\n"); return; @@ -1016,14 +1024,26 @@ void sofia_glue_tech_patch_sdp(private_object_t *tech_pvt) tech_pvt->codec_ms = 20; } + new_sdp = switch_core_session_alloc(tech_pvt->session, len); switch_snprintf(port_buf, sizeof(port_buf), "%u", tech_pvt->adv_sdp_audio_port); - tech_pvt->orig_local_sdp_str = tech_pvt->local_sdp_str; - tech_pvt->local_sdp_str = switch_core_session_alloc(tech_pvt->session, len); + - p = tech_pvt->orig_local_sdp_str; - q = tech_pvt->local_sdp_str; + p = tech_pvt->local_sdp_str; + q = new_sdp; + pe = p + strlen(p); + qe = q + len - 1; while(p && *p) { + if (p >= pe) { + bad = 1; + goto end; + } + + if (q >= qe) { + bad = 2; + goto end; + } + if (tech_pvt->adv_sdp_audio_ip && !strncmp("c=IN IP", p, 7)) { strncpy(q, p, 9); p += 9; @@ -1032,19 +1052,46 @@ void sofia_glue_tech_patch_sdp(private_object_t *tech_pvt) q += strlen(tech_pvt->adv_sdp_audio_ip); while(p && *p && ((*p >= '0' && *p <= '9') || *p == '.' || *p == ':' || (*p >= 'A' && *p <= 'F') || (*p >= 'a' && *p <= 'f'))) { + if (p >= pe) { + bad = 3; + goto end; + } p++; } has_ip++; } else if (!strncmp("m=audio ", p, 8) || (!strncmp("m=image ", p, 8))) { - strncpy(q,p,8); + strncpy(q, p, 8); p += 8; + + if (p >= pe) { + bad = 4; + goto end; + } + + q += 8; + + if (q >= qe) { + bad = 5; + goto end; + } + + strncpy(q, port_buf, strlen(port_buf)); q += strlen(port_buf); + if (q >= qe) { + bad = 6; + goto end; + } + while (p && *p && (*p >= '0' && *p <= '9')) { + if (p >= pe) { + bad = 7; + goto end; + } p++; } @@ -1061,33 +1108,102 @@ void sofia_glue_tech_patch_sdp(private_object_t *tech_pvt) strncpy(q, p, 8); p += 8; + + if (p >= pe) { + bad = 8; + goto end; + } + q += 8; + + if (q >= qe) { + bad = 9; + goto end; + } + strncpy(q, vport_buf, strlen(vport_buf)); q += strlen(vport_buf); - while (p && *p && (*p >= '0' && *p <= '9')) { - p++; + if (q >= qe) { + bad = 10; + goto end; } + while (p && *p && (*p >= '0' && *p <= '9')) { + + if (p >= pe) { + bad = 11; + goto end; + } + + p++; + } + has_video++; } while (p && *p && *p != '\n') { + + if (p >= pe) { + bad = 12; + goto end; + } + + if (q >= qe) { + bad = 13; + goto end; + } + *q++ = *p++; } + + if (p >= pe) { + bad = 14; + goto end; + } + + if (q >= qe) { + bad = 15; + goto end; + } *q++ = *p++; + } + end: + + if (bad) { + return; + } + + + if (switch_channel_down(tech_pvt->channel) || sofia_test_flag(tech_pvt, TFLAG_BYE)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s too late.\n", switch_channel_get_name(tech_pvt->channel)); + return; + } + + if (!has_ip && !has_audio) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s SDP has no audio in it.\n%s\n", switch_channel_get_name(tech_pvt->channel), tech_pvt->local_sdp_str); - tech_pvt->local_sdp_str = tech_pvt->orig_local_sdp_str; return; } + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s Patched SDP\n---\n%s\n+++\n%s\n", - switch_channel_get_name(tech_pvt->channel), tech_pvt->orig_local_sdp_str, tech_pvt->local_sdp_str); + switch_channel_get_name(tech_pvt->channel), tech_pvt->local_sdp_str, new_sdp); + + sofia_glue_tech_set_local_sdp(tech_pvt, new_sdp, SWITCH_FALSE); + +} + + +void sofia_glue_tech_set_local_sdp(private_object_t *tech_pvt, const char *sdp_str, switch_bool_t dup) +{ + switch_mutex_lock(tech_pvt->sofia_mutex); + tech_pvt->local_sdp_str = dup ? switch_core_session_strdup(tech_pvt->session, sdp_str) : (char *)sdp_str; + switch_mutex_unlock(tech_pvt->sofia_mutex); } @@ -1298,7 +1414,6 @@ switch_status_t sofia_glue_do_invite(switch_core_session_t *session) SIPTAG_FROM_STR(from_str), SIPTAG_CONTACT_STR(invite_contact), TAG_END()); - if (tech_pvt->dest && (strstr(tech_pvt->dest, ";fs_nat") || strstr(tech_pvt->dest, ";received") || ((val = switch_channel_get_variable(channel, "sip_sticky_contact")) && switch_true(val)))) { @@ -1570,7 +1685,7 @@ void sofia_glue_tech_absorb_sdp(private_object_t *tech_pvt) } sdp_parser_free(parser); } - tech_pvt->local_sdp_str = switch_core_session_strdup(tech_pvt->session, sdp_str); + sofia_glue_tech_set_local_sdp(tech_pvt, sdp_str, SWITCH_TRUE); } } @@ -1883,6 +1998,11 @@ switch_status_t sofia_glue_activate_rtp(private_object_t *tech_pvt, switch_rtp_f const char *var; switch_assert(tech_pvt != NULL); + + if (switch_channel_down(tech_pvt->channel) || sofia_test_flag(tech_pvt, TFLAG_BYE)) { + return SWITCH_STATUS_FALSE; + } + switch_mutex_lock(tech_pvt->sofia_mutex); if (switch_rtp_ready(tech_pvt->rtp_session)) { @@ -1893,7 +2013,6 @@ switch_status_t sofia_glue_activate_rtp(private_object_t *tech_pvt, switch_rtp_f sofia_set_flag_locked(tech_pvt, TFLAG_SECURE); } - if (switch_channel_test_flag(tech_pvt->channel, CF_PROXY_MODE)) { status = SWITCH_STATUS_SUCCESS; goto end; @@ -1997,6 +2116,7 @@ switch_status_t sofia_glue_activate_rtp(private_object_t *tech_pvt, switch_rtp_f if ((status = sofia_glue_tech_proxy_remote_addr(tech_pvt)) != SWITCH_STATUS_SUCCESS) { goto end; } + if (!sofia_test_pflag(tech_pvt->profile, PFLAG_DISABLE_RTP_AUTOADJ) && !((val = switch_channel_get_variable(tech_pvt->channel, "disable_rtp_auto_adjust")) && switch_true(val))) { flags = (switch_rtp_flag_t) (SWITCH_RTP_FLAG_PROXY_MEDIA | SWITCH_RTP_FLAG_AUTOADJ | SWITCH_RTP_FLAG_DATAWAIT); @@ -2005,7 +2125,8 @@ switch_status_t sofia_glue_activate_rtp(private_object_t *tech_pvt, switch_rtp_f } timer_name = NULL; - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "PROXY AUDIO RTP [%s] %s:%d->%s:%d codec: %u ms: %d\n", + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, + "PROXY AUDIO RTP [%s] %s:%d->%s:%d codec: %u ms: %d\n", switch_channel_get_name(tech_pvt->channel), tech_pvt->local_sdp_audio_ip, tech_pvt->local_sdp_audio_port, @@ -2014,21 +2135,24 @@ switch_status_t sofia_glue_activate_rtp(private_object_t *tech_pvt, switch_rtp_f } else { timer_name = tech_pvt->profile->timer_name; + + if ((var = switch_channel_get_variable(tech_pvt->channel, "rtp_timer_name"))) { + timer_name = (char *) var; + } } - if ((var = switch_channel_get_variable(tech_pvt->channel, "rtp_timer_name"))) { - timer_name = (char *) var; + if (switch_channel_up(tech_pvt->channel) && !sofia_test_flag(tech_pvt, TFLAG_BYE)) { + tech_pvt->rtp_session = switch_rtp_new(tech_pvt->local_sdp_audio_ip, + tech_pvt->local_sdp_audio_port, + tech_pvt->remote_sdp_audio_ip, + tech_pvt->remote_sdp_audio_port, + tech_pvt->agreed_pt, + tech_pvt->read_impl.samples_per_packet, + tech_pvt->codec_ms * 1000, + (switch_rtp_flag_t) flags, timer_name, &err, + switch_core_session_get_pool(tech_pvt->session)); } - tech_pvt->rtp_session = switch_rtp_new(tech_pvt->local_sdp_audio_ip, - tech_pvt->local_sdp_audio_port, - tech_pvt->remote_sdp_audio_ip, - tech_pvt->remote_sdp_audio_port, - tech_pvt->agreed_pt, - tech_pvt->read_impl.samples_per_packet, - tech_pvt->codec_ms * 1000, - (switch_rtp_flag_t) flags, timer_name, &err, switch_core_session_get_pool(tech_pvt->session)); - if (switch_rtp_ready(tech_pvt->rtp_session)) { uint8_t vad_in = sofia_test_flag(tech_pvt, TFLAG_VAD_IN) ? 1 : 0; uint8_t vad_out = sofia_test_flag(tech_pvt, TFLAG_VAD_OUT) ? 1 : 0; @@ -2223,19 +2347,18 @@ switch_status_t sofia_glue_tech_media(private_object_t *tech_pvt, const char *r_ switch_assert(tech_pvt != NULL); switch_assert(r_sdp != NULL); - parser = sdp_parse(NULL, r_sdp, (int) strlen(r_sdp), 0); - if (switch_strlen_zero(r_sdp)) { return SWITCH_STATUS_FALSE; } - if (tech_pvt->num_codecs) { - if ((sdp = sdp_session(parser))) { - match = sofia_glue_negotiate_sdp(tech_pvt->session, sdp); + if ((parser = sdp_parse(NULL, r_sdp, (int) strlen(r_sdp), 0))) { + + if (tech_pvt->num_codecs) { + if ((sdp = sdp_session(parser))) { + match = sofia_glue_negotiate_sdp(tech_pvt->session, sdp); + } } - } - - if (parser) { + sdp_parser_free(parser); }