diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 5dcb7b4c4..a927500c0 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -336,7 +336,7 @@ static void call_received(SalOp *h){ call->bg_task_id=sal_begin_background_task("liblinphone call notification", NULL, NULL); - if ((linphone_core_get_firewall_policy(lc) == LinphonePolicyUseIce) && (call->ice_session != NULL)) { + if (call->defer_notify_incoming) { /* Defer ringing until the end of the ICE candidates gathering process. */ ms_message("Defer ringing to gather ICE candidates"); return; diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 305913b6d..e01da00a5 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -585,7 +585,7 @@ void linphone_call_increment_local_media_description(LinphoneCall *call){ void linphone_call_update_local_media_description_from_ice_or_upnp(LinphoneCall *call){ LinphoneCore *lc = call->core; if (call->ice_session != NULL) { - /*set this to FALSE once flexisip are updated*/ + /*set this to FALSE once flexisip are updated everywhere, let's say in December 2016.*/ bool_t use_nortpproxy = lp_config_get_int(lc->config, "sip", "ice_uses_nortpproxy", TRUE); _update_local_media_description_from_ice(call->localdesc, call->ice_session, use_nortpproxy); linphone_core_update_ice_state_in_call_stats(call); @@ -1091,6 +1091,21 @@ void linphone_call_fill_media_multicast_addr(LinphoneCall *call) { call->media_ports[call->main_video_stream_index].multicast_ip[0]='\0'; } +static void linphone_call_create_ice_session(LinphoneCall *call, IceRole role){ + call->ice_session = ice_session_new(); + /*for backward compatibility purposes, shall be enabled by default in futur*/ + ice_session_enable_message_integrity_check(call->ice_session,lp_config_get_int(call->core->config,"net","ice_session_enable_message_integrity_check",1)); + if (lp_config_get_int(call->core->config, "net", "dont_default_to_stun_candidates", 0)){ + IceCandidateType types[ICT_CandidateTypeMax]; + types[0] = ICT_RelayedCandidate; + types[1] = ICT_HostCandidate; + types[2] = ICT_CandidateInvalid; + ice_session_set_default_candidates_types(call->ice_session, types); + } + + ice_session_set_role(call->ice_session, role); +} + LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to, const LinphoneCallParams *params, LinphoneProxyConfig *cfg){ LinphoneCall *call = belle_sip_object_new(LinphoneCall); @@ -1106,10 +1121,7 @@ LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddr linphone_call_fill_media_multicast_addr(call); if (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseIce) { - call->ice_session = ice_session_new(); - /*for backward compatibility purposes, shall be enabled by default in futur*/ - ice_session_enable_message_integrity_check(call->ice_session,lp_config_get_int(lc->config,"net","ice_session_enable_message_integrity_check",1)); - ice_session_set_role(call->ice_session, IR_Controlling); + linphone_call_create_ice_session(call, IR_Controlling); } if (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseStun) { call->ping_time=linphone_core_run_stun_tests(call->core,call); @@ -1338,10 +1350,7 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro /*create the ice session now if ICE is required*/ if (fpol==LinphonePolicyUseIce){ if (md){ - call->ice_session = ice_session_new(); - /*for backward compatibility purposes, shall be enabled by default in futur*/ - ice_session_enable_message_integrity_check(call->ice_session,lp_config_get_int(lc->config,"net","ice_session_enable_message_integrity_check",1)); - ice_session_set_role(call->ice_session, IR_Controlled); + linphone_call_create_ice_session(call, IR_Controlled); }else{ fpol=LinphonePolicyNoFirewall; ms_warning("ICE not supported for incoming INVITE without SDP."); @@ -1352,7 +1361,7 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro linphone_call_init_media_streams(call); switch (fpol) { case LinphonePolicyUseIce: - linphone_call_prepare_ice(call,TRUE); + call->defer_notify_incoming = linphone_call_prepare_ice(call,TRUE) == 1; break; case LinphonePolicyUseStun: call->ping_time=linphone_core_run_stun_tests(call->core,call); @@ -2225,6 +2234,7 @@ static void _linphone_call_prepare_ice_for_stream(LinphoneCall *call, int stream int linphone_call_prepare_ice(LinphoneCall *call, bool_t incoming_offer){ SalMediaDescription *remote = NULL; + int err; bool_t has_video=FALSE; if ((linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseIce) && (call->ice_session != NULL)){ @@ -2251,13 +2261,12 @@ int linphone_call_prepare_ice(LinphoneCall *call, bool_t incoming_offer){ text_stream_prepare_text(call->textstream); } - if (linphone_core_gather_ice_candidates(call->core,call)<0) { + if ((err=linphone_core_gather_ice_candidates(call->core,call))<0) { /* Ice candidates gathering failed, proceed with the call anyway. */ linphone_call_delete_ice_session(call); linphone_call_stop_media_streams_for_ice_gathering(call); - return -1; } - return 1;/*gathering in progress, wait*/ + return err;/* 1= gathering in progress, wait; 0=proceed*/ } } return 0; @@ -4282,12 +4291,10 @@ static void handle_ice_events(LinphoneCall *call, OrtpEvent *ev){ linphone_call_params_unref(params); } else if (evt == ORTP_EVENT_ICE_GATHERING_FINISHED) { - if (evd->info.ice_processing_successful==TRUE) { - linphone_call_on_ice_gathering_finished(call); - } else { - ms_warning("No STUN answer from [%s], disabling ICE",linphone_core_get_stun_server(call->core)); - linphone_call_delete_ice_session(call); + if (! evd->info.ice_processing_successful==TRUE) { + ms_warning("No STUN answer from [%s], continuing without STUN",linphone_core_get_stun_server(call->core)); } + linphone_call_on_ice_gathering_finished(call); switch (call->state) { case LinphoneCallUpdating: linphone_core_start_update_call(call->core, call); diff --git a/coreapi/misc.c b/coreapi/misc.c index d2fd020f7..7db9518e1 100644 --- a/coreapi/misc.c +++ b/coreapi/misc.c @@ -628,16 +628,15 @@ void linphone_core_enable_forced_ice_relay(LinphoneCore *lc, bool_t enable) { lc->forced_ice_relay = enable; } -int linphone_core_gather_ice_candidates(LinphoneCore *lc, LinphoneCall *call) -{ +int linphone_core_gather_ice_candidates(LinphoneCore *lc, LinphoneCall *call){ char local_addr[64]; - const struct addrinfo *ai; + const struct addrinfo *ai = NULL; IceCheckList *audio_check_list; IceCheckList *video_check_list; IceCheckList *text_check_list; const char *server = linphone_core_get_stun_server(lc); - if ((server == NULL) || (call->ice_session == NULL)) return -1; + if (call->ice_session == NULL) return -1; audio_check_list = ice_session_check_list(call->ice_session, call->main_audio_stream_index); video_check_list = ice_session_check_list(call->ice_session, call->main_video_stream_index); text_check_list = ice_session_check_list(call->ice_session, call->main_text_stream_index); @@ -647,10 +646,13 @@ int linphone_core_gather_ice_candidates(LinphoneCore *lc, LinphoneCall *call) ms_warning("Ice gathering is not implemented for ipv6"); return -1; } - ai=linphone_core_get_stun_server_addrinfo(lc); - if (ai==NULL){ - ms_warning("Fail to resolve STUN server for ICE gathering."); - return -1; + if (server){ + ai=linphone_core_get_stun_server_addrinfo(lc); + if (ai==NULL){ + ms_warning("Fail to resolve STUN server for ICE gathering, continuing without stun."); + } + }else{ + ms_warning("Ice is used without stun server."); } linphone_core_notify_display_status(lc, _("ICE local candidates gathering in progress...")); @@ -678,10 +680,12 @@ int linphone_core_gather_ice_candidates(LinphoneCore *lc, LinphoneCall *call) ice_add_local_candidate(text_check_list, "host", local_addr, call->media_ports[call->main_text_stream_index].rtcp_port, 2, NULL); call->stats[LINPHONE_CALL_STATS_TEXT].ice_state = LinphoneIceStateInProgress; } - - ms_message("ICE: gathering candidate from [%s]",server); - /* Gather local srflx candidates. */ - ice_session_gather_candidates(call->ice_session, ai->ai_addr, (socklen_t)ai->ai_addrlen); + if (ai){ + ms_message("ICE: gathering candidate from [%s]",server); + /* Gather local srflx candidates. */ + ice_session_gather_candidates(call->ice_session, ai->ai_addr, (socklen_t)ai->ai_addrlen); + return 1; + } return 0; } @@ -731,6 +735,10 @@ void linphone_core_update_ice_state_in_call_stats(LinphoneCall *call) case ICT_RelayedCandidate: call->stats[LINPHONE_CALL_STATS_AUDIO].ice_state = LinphoneIceStateRelayConnection; break; + case ICT_CandidateInvalid: + case ICT_CandidateTypeMax: + /*shall not happen*/ + break; } } else { call->stats[LINPHONE_CALL_STATS_AUDIO].ice_state = LinphoneIceStateFailed; @@ -750,6 +758,10 @@ void linphone_core_update_ice_state_in_call_stats(LinphoneCall *call) case ICT_RelayedCandidate: call->stats[LINPHONE_CALL_STATS_VIDEO].ice_state = LinphoneIceStateRelayConnection; break; + case ICT_CandidateInvalid: + case ICT_CandidateTypeMax: + /*shall not happen*/ + break; } } else { call->stats[LINPHONE_CALL_STATS_VIDEO].ice_state = LinphoneIceStateFailed; @@ -769,6 +781,10 @@ void linphone_core_update_ice_state_in_call_stats(LinphoneCall *call) case ICT_RelayedCandidate: call->stats[LINPHONE_CALL_STATS_TEXT].ice_state = LinphoneIceStateRelayConnection; break; + case ICT_CandidateInvalid: + case ICT_CandidateTypeMax: + /*shall not happen*/ + break; } } else { call->stats[LINPHONE_CALL_STATS_TEXT].ice_state = LinphoneIceStateFailed; diff --git a/coreapi/private.h b/coreapi/private.h index 23abcd068..ae57efc0c 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -340,6 +340,7 @@ struct _LinphoneCall{ char *dtls_certificate_fingerprint; /**> This fingerprint is computed during stream init and is stored in call to be used when making local media description */ char *onhold_file; /*set if a on-hold file is to be played*/ LinphoneChatRoom *chat_room; + LinphoneConference *conf_ref; /**> Point on the associated conference if this call is part of a conference. NULL instead. */ bool_t refer_pending; bool_t expect_media_in_ack; bool_t audio_muted; @@ -357,8 +358,7 @@ struct _LinphoneCall{ bool_t paused_by_app; bool_t broken; /*set to TRUE when the call is in broken state due to network disconnection or transport */ - - LinphoneConference *conf_ref; /**> Point on the associated conference if this call is part of a conference. NULL instead. */ + bool_t defer_notify_incoming; }; BELLE_SIP_DECLARE_VPTR(LinphoneCall); diff --git a/tester/call_tester.c b/tester/call_tester.c index 5c4d6fa96..b9d4a39f6 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -6003,6 +6003,47 @@ static void call_with_zrtp_configured_calling_base(LinphoneCoreManager *marie, L end_call(pauline, marie); } + +/* + * this test checks the 'dont_default_to_stun_candidates' mode, where the c= line is left to host + * ip instead of stun candidate when ice is enabled*/ +static void call_with_ice_with_default_candidate_not_stun(void){ + LinphoneCoreManager * marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager *pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); + char localip[LINPHONE_IPADDR_SIZE]; + bool_t call_ok; + + lp_config_set_int(marie->lc->config, "net", "dont_default_to_stun_candidates", 1); + linphone_core_set_firewall_policy(marie->lc, LinphonePolicyUseIce); + linphone_core_set_firewall_policy(pauline->lc, LinphonePolicyUseIce); + linphone_core_get_local_ip(marie->lc, AF_INET, NULL, localip); + call_ok = call(marie, pauline); + if (call_ok){ + check_ice(marie, pauline, LinphoneIceStateHostConnection); + BC_ASSERT_STRING_EQUAL(marie->lc->current_call->localdesc->addr, localip); + BC_ASSERT_STRING_EQUAL(pauline->lc->current_call->resultdesc->addr, localip); + BC_ASSERT_STRING_EQUAL(marie->lc->current_call->localdesc->streams[0].rtp_addr, localip); + BC_ASSERT_STRING_EQUAL(pauline->lc->current_call->resultdesc->streams[0].rtp_addr, ""); + } + end_call(marie, pauline); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +static void call_with_ice_without_stun(void){ +#if GHISLAIN_CAN_MAKE_THIS_TEST_TO_WORK + LinphoneCoreManager * marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager *pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); + + linphone_core_set_stun_server(marie->lc, NULL); + linphone_core_set_stun_server(pauline->lc, NULL); + _call_with_ice_base(marie, pauline, TRUE, TRUE, TRUE, FALSE); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +#endif +} + static void call_with_zrtp_configured_calling_side(void) { LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); @@ -6198,6 +6239,8 @@ test_t call_tests[] = { TEST_NO_TAG("Call with rtcp-mux not accepted", call_with_rtcp_mux_not_accepted), TEST_ONE_TAG("Call with ICE and rtcp-mux", call_with_ice_and_rtcp_mux, "ICE"), TEST_ONE_TAG("Call with ICE and rtcp-mux without ICE re-invite", call_with_ice_and_rtcp_mux_without_reinvite, "ICE"), + TEST_ONE_TAG("Call with ICE with default candidate not stun", call_with_ice_with_default_candidate_not_stun, "ICE"), + TEST_ONE_TAG("Call with ICE without stun server", call_with_ice_without_stun, "ICE"), TEST_NO_TAG("call with ZRTP configured calling side only", call_with_zrtp_configured_calling_side) };