diff --git a/coreapi/misc.c b/coreapi/misc.c index 555d5b06c..47ca5b83b 100644 --- a/coreapi/misc.c +++ b/coreapi/misc.c @@ -587,16 +587,17 @@ void linphone_core_resolve_stun_server(LinphoneCore *lc){ if (lc->nat_policy != NULL) { linphone_nat_policy_resolve_stun_server(lc->nat_policy); } else { - /* - * WARNING: stun server resolution only done in IPv4. - * TODO: use IPv6 resolution if linphone_core_ipv6_enabled()==TRUE and use V4Mapped addresses for ICE gathering. - */ const char *server=linphone_core_get_stun_server(lc); - if (lc->sal && server && !lc->net_conf.stun_res){ + LinphoneFirewallPolicy firewall_policy = linphone_core_get_firewall_policy(lc); + if (lc->sal && server && !lc->net_conf.stun_res + && ((firewall_policy == LinphonePolicyUseStun) || (firewall_policy == LinphonePolicyUseIce))) { char host[NI_MAXHOST]; + const char *service = "stun"; int port=3478; + int family = AF_INET; linphone_parse_host_port(server,host,sizeof(host),&port); - lc->net_conf.stun_res=sal_resolve_a(lc->sal,host,port,AF_INET,(SalResolverCallback)stun_server_resolved,lc); + if (linphone_core_ipv6_enabled(lc) == TRUE) family = AF_INET6; + lc->net_conf.stun_res = sal_resolve(lc->sal, service, "udp", host, port, family, (SalResolverCallback)stun_server_resolved, lc); } } } @@ -682,12 +683,55 @@ static void stun_auth_requested_cb(LinphoneCall *call, const char *realm, const } } +static void linphone_core_add_local_ice_candidates(LinphoneCall *call, int family, const char *addr, IceCheckList *audio_cl, IceCheckList *video_cl, IceCheckList *text_cl) { + if ((ice_check_list_state(audio_cl) != ICL_Completed) && (ice_check_list_candidates_gathered(audio_cl) == FALSE)) { + ice_add_local_candidate(audio_cl, "host", family, addr, call->media_ports[call->main_audio_stream_index].rtp_port, 1, NULL); + ice_add_local_candidate(audio_cl, "host", family, addr, call->media_ports[call->main_audio_stream_index].rtcp_port, 2, NULL); + call->stats[LINPHONE_CALL_STATS_AUDIO].ice_state = LinphoneIceStateInProgress; + } + if (linphone_core_video_enabled(call->core) && (video_cl != NULL) + && (ice_check_list_state(video_cl) != ICL_Completed) && (ice_check_list_candidates_gathered(video_cl) == FALSE)) { + ice_add_local_candidate(video_cl, "host", family, addr, call->media_ports[call->main_video_stream_index].rtp_port, 1, NULL); + ice_add_local_candidate(video_cl, "host", family, addr, call->media_ports[call->main_video_stream_index].rtcp_port, 2, NULL); + call->stats[LINPHONE_CALL_STATS_VIDEO].ice_state = LinphoneIceStateInProgress; + } + if (call->params->realtimetext_enabled && (text_cl != NULL) + && (ice_check_list_state(text_cl) != ICL_Completed) && (ice_check_list_candidates_gathered(text_cl) == FALSE)) { + ice_add_local_candidate(text_cl, "host", family, addr, call->media_ports[call->main_text_stream_index].rtp_port, 1, NULL); + ice_add_local_candidate(text_cl, "host", family, addr, call->media_ports[call->main_text_stream_index].rtcp_port, 2, NULL); + call->stats[LINPHONE_CALL_STATS_TEXT].ice_state = LinphoneIceStateInProgress; + } +} + +static const struct addrinfo * get_preferred_stun_server_addrinfo(const struct addrinfo *ai) { + char ip[NI_MAXHOST]; + const struct addrinfo *preferred_ai = NULL; + + while (ai != NULL) { + bctbx_addrinfo_to_printable_ip_address(ai, ip, sizeof(ip)); + if (ai->ai_family == AF_INET) { + preferred_ai = ai; + break; + } + else if (ai->ai_family == AF_INET6) { + struct sockaddr_storage ss; + socklen_t sslen = sizeof(ss); + bctbx_sockaddr_ipv6_to_ipv4(ai->ai_addr, (struct sockaddr *)&ss, &sslen); + if ((ss.ss_family == AF_INET) && (preferred_ai == NULL)) preferred_ai = ai; + } + ai = ai->ai_next; + } + + bctbx_addrinfo_to_printable_ip_address(preferred_ai, ip, sizeof(ip)); + return preferred_ai; +} + int linphone_core_gather_ice_candidates(LinphoneCore *lc, LinphoneCall *call){ char local_addr[64]; const struct addrinfo *ai = NULL; - IceCheckList *audio_check_list; - IceCheckList *video_check_list; - IceCheckList *text_check_list; + IceCheckList *audio_cl; + IceCheckList *video_cl; + IceCheckList *text_cl; LinphoneNatPolicy *nat_policy = NULL; const char *server = NULL; @@ -696,19 +740,17 @@ int linphone_core_gather_ice_candidates(LinphoneCore *lc, LinphoneCall *call){ if (nat_policy != NULL) server = linphone_nat_policy_get_stun_server(nat_policy); 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); - if (audio_check_list == NULL) return -1; + audio_cl = ice_session_check_list(call->ice_session, call->main_audio_stream_index); + video_cl = ice_session_check_list(call->ice_session, call->main_video_stream_index); + text_cl = ice_session_check_list(call->ice_session, call->main_text_stream_index); + if (audio_cl == NULL) return -1; - if (call->af==AF_INET6){ - ms_warning("Ice gathering is not implemented for ipv6"); - return -1; - } if ((nat_policy != NULL) && (server != NULL) && (server[0] != '\0')) { ai=linphone_nat_policy_get_stun_server_addrinfo(nat_policy); if (ai==NULL){ ms_warning("Fail to resolve STUN server for ICE gathering, continuing without stun."); + } else { + ai = get_preferred_stun_server_addrinfo(ai); } }else{ ms_warning("Ice is used without stun server."); @@ -718,28 +760,22 @@ int linphone_core_gather_ice_candidates(LinphoneCore *lc, LinphoneCall *call){ ice_session_enable_forced_relay(call->ice_session, lc->forced_ice_relay); ice_session_enable_short_turn_refresh(call->ice_session, lc->short_turn_refresh); - // TODO: Handle IPv6 /* Gather local host candidates. */ + if (call->af == AF_INET6) { + if (linphone_core_get_local_ip_for(AF_INET6, NULL, local_addr) < 0) { + ms_error("Fail to get local IPv6"); + return -1; + } else { + linphone_core_add_local_ice_candidates(call, AF_INET6, local_addr, audio_cl, video_cl, text_cl); + } + } if (linphone_core_get_local_ip_for(AF_INET, NULL, local_addr) < 0) { - ms_error("Fail to get local ip"); - return -1; - } - if ((ice_check_list_state(audio_check_list) != ICL_Completed) && (ice_check_list_candidates_gathered(audio_check_list) == FALSE)) { - ice_add_local_candidate(audio_check_list, "host", AF_INET, local_addr, call->media_ports[call->main_audio_stream_index].rtp_port, 1, NULL); - ice_add_local_candidate(audio_check_list, "host", AF_INET, local_addr, call->media_ports[call->main_audio_stream_index].rtcp_port, 2, NULL); - call->stats[LINPHONE_CALL_STATS_AUDIO].ice_state = LinphoneIceStateInProgress; - } - if (linphone_core_video_enabled(lc) && (video_check_list != NULL) - && (ice_check_list_state(video_check_list) != ICL_Completed) && (ice_check_list_candidates_gathered(video_check_list) == FALSE)) { - ice_add_local_candidate(video_check_list, "host", AF_INET, local_addr, call->media_ports[call->main_video_stream_index].rtp_port, 1, NULL); - ice_add_local_candidate(video_check_list, "host", AF_INET, local_addr, call->media_ports[call->main_video_stream_index].rtcp_port, 2, NULL); - call->stats[LINPHONE_CALL_STATS_VIDEO].ice_state = LinphoneIceStateInProgress; - } - if (call->params->realtimetext_enabled && (text_check_list != NULL) - && (ice_check_list_state(text_check_list) != ICL_Completed) && (ice_check_list_candidates_gathered(text_check_list) == FALSE)) { - ice_add_local_candidate(text_check_list, "host", AF_INET, local_addr, call->media_ports[call->main_text_stream_index].rtp_port, 1, NULL); - ice_add_local_candidate(text_check_list, "host", AF_INET, local_addr, call->media_ports[call->main_text_stream_index].rtcp_port, 2, NULL); - call->stats[LINPHONE_CALL_STATS_TEXT].ice_state = LinphoneIceStateInProgress; + if (call->af != AF_INET6) { + ms_error("Fail to get local IPv4"); + return -1; + } + } else { + linphone_core_add_local_ice_candidates(call, AF_INET, local_addr, audio_cl, video_cl, text_cl); } if ((ai != NULL) && (nat_policy != NULL) && (linphone_nat_policy_stun_enabled(nat_policy) || linphone_nat_policy_turn_enabled(nat_policy))) { @@ -1123,6 +1159,7 @@ void linphone_call_update_ice_from_remote_media_description(LinphoneCall *call, ice_session_remove_check_list(call->ice_session, cl); clear_ice_check_list(call,cl); } else { + int family; if ((stream->ice_pwd[0] != '\0') && (stream->ice_ufrag[0] != '\0')) ice_check_list_set_remote_credentials(cl, stream->ice_ufrag, stream->ice_pwd); for (j = 0; j < SAL_MEDIA_DESCRIPTION_MAX_ICE_CANDIDATES; j++) { @@ -1135,8 +1172,9 @@ void linphone_call_update_ice_from_remote_media_description(LinphoneCall *call, get_default_addr_and_port(candidate->componentID, md, stream, &addr, &port); if (addr && (candidate->port == port) && (strlen(candidate->addr) == strlen(addr)) && (strcmp(candidate->addr, addr) == 0)) default_candidate = TRUE; - // TODO: Handle IPv6 - ice_add_remote_candidate(cl, candidate->type, AF_INET, candidate->addr, candidate->port, candidate->componentID, + if (strchr(candidate->addr, ':') != NULL) family = AF_INET6; + else family = AF_INET; + ice_add_remote_candidate(cl, candidate->type, family, candidate->addr, candidate->port, candidate->componentID, candidate->priority, candidate->foundation, default_candidate); } if (ice_restarted == FALSE) { @@ -1152,8 +1190,9 @@ void linphone_call_update_ice_from_remote_media_description(LinphoneCall *call, /* If we receive a re-invite and we finished ICE processing on our side, use the candidates given by the remote. */ ice_check_list_unselect_valid_pairs(cl); } - // TODO: Handle IPv6 - ice_add_losing_pair(cl, j + 1, AF_INET, remote_candidate->addr, remote_candidate->port, addr, port); + if (strchr(remote_candidate->addr, ':') != NULL) family = AF_INET6; + else family = AF_INET; + ice_add_losing_pair(cl, j + 1, family, remote_candidate->addr, remote_candidate->port, addr, port); losing_pairs_added = TRUE; } if (losing_pairs_added == TRUE) ice_check_list_check_completed(cl); diff --git a/coreapi/nat_policy.c b/coreapi/nat_policy.c index cf3e11b9d..801a993b8 100644 --- a/coreapi/nat_policy.c +++ b/coreapi/nat_policy.c @@ -220,20 +220,16 @@ static void stun_server_resolved(LinphoneNatPolicy *policy, const char *name, st void linphone_nat_policy_resolve_stun_server(LinphoneNatPolicy *policy) { const char *service = NULL; - /* - * WARNING: stun server resolution only done in IPv4. - * TODO: use IPv6 resolution if linphone_core_ipv6_enabled()==TRUE and use V4Mapped addresses for ICE gathering. - */ - if (linphone_nat_policy_stun_server_activated(policy) - && (policy->lc->sal != NULL) - && !policy->stun_resolver_context) { + if (linphone_nat_policy_stun_server_activated(policy) && (policy->lc->sal != NULL) && !policy->stun_resolver_context) { char host[NI_MAXHOST]; int port = 3478; linphone_parse_host_port(policy->stun_server, host, sizeof(host), &port); if (linphone_nat_policy_turn_enabled(policy)) service = "turn"; else if (linphone_nat_policy_stun_enabled(policy)) service = "stun"; if (service != NULL) { - policy->stun_resolver_context = sal_resolve(policy->lc->sal, service, "udp", host, port, AF_INET, (SalResolverCallback)stun_server_resolved, policy); + int family = AF_INET; + if (linphone_core_ipv6_enabled(policy->lc) == TRUE) family = AF_INET6; + policy->stun_resolver_context = sal_resolve(policy->lc->sal, service, "udp", host, port, family, (SalResolverCallback)stun_server_resolved, policy); } } } diff --git a/tester/call_single_tester.c b/tester/call_single_tester.c index 5bd6a7821..5e34dbc85 100644 --- a/tester/call_single_tester.c +++ b/tester/call_single_tester.c @@ -1232,15 +1232,30 @@ void _call_with_ice_base(LinphoneCoreManager* pauline,LinphoneCoreManager* marie end_call(pauline, marie); } -static void _call_with_ice(bool_t caller_with_ice, bool_t callee_with_ice, bool_t random_ports, bool_t forced_relay) { - LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); - LinphoneCoreManager* pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); +static void _call_with_ice(bool_t caller_with_ice, bool_t callee_with_ice, bool_t random_ports, bool_t forced_relay, bool_t ipv6) { + LinphoneCoreManager* marie = linphone_core_manager_new2("marie_rc", FALSE); + LinphoneCoreManager* pauline = linphone_core_manager_new2(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc", FALSE); + if (ipv6) { + linphone_core_enable_ipv6(marie->lc, TRUE); + linphone_core_enable_ipv6(pauline->lc, TRUE); + } + linphone_core_manager_start(marie, TRUE); + linphone_core_manager_start(pauline, TRUE); _call_with_ice_base(pauline,marie,caller_with_ice,callee_with_ice,random_ports,forced_relay); linphone_core_manager_destroy(marie); linphone_core_manager_destroy(pauline); } + static void call_with_ice(void){ - _call_with_ice(TRUE,TRUE,FALSE,FALSE); + _call_with_ice(TRUE,TRUE,FALSE,FALSE,FALSE); +} + +static void call_with_ice_ipv6(void) { + if (liblinphone_tester_ipv6_available()) { + _call_with_ice(TRUE, TRUE, FALSE, FALSE, TRUE); + } else { + ms_warning("Test skipped, no ipv6 available"); + } } /*ICE is not expected to work in this case, however this should not crash*/ @@ -1264,19 +1279,19 @@ static void call_with_ice_no_sdp(void){ } static void call_with_ice_random_ports(void){ - _call_with_ice(TRUE,TRUE,TRUE,FALSE); + _call_with_ice(TRUE,TRUE,TRUE,FALSE,FALSE); } static void call_with_ice_forced_relay(void) { - _call_with_ice(TRUE, TRUE, TRUE, TRUE); + _call_with_ice(TRUE, TRUE, TRUE, TRUE, FALSE); } static void ice_to_not_ice(void){ - _call_with_ice(TRUE,FALSE,FALSE,FALSE); + _call_with_ice(TRUE,FALSE,FALSE,FALSE,FALSE); } static void not_ice_to_ice(void){ - _call_with_ice(FALSE,TRUE,FALSE,FALSE); + _call_with_ice(FALSE,TRUE,FALSE,FALSE,FALSE); } static void ice_added_by_reinvite(void){ @@ -1311,15 +1326,11 @@ static void ice_added_by_reinvite(void){ linphone_call_params_destroy(params); BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallUpdatedByRemote,1)); - BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallStreamsRunning,2)); - BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallStreamsRunning,2)); - - BC_ASSERT_TRUE(check_ice(marie, pauline, LinphoneIceStateHostConnection)); - + /*wait for the ICE reINVITE*/ BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallStreamsRunning,3)); BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallStreamsRunning,3)); - + BC_ASSERT_TRUE(check_ice(marie, pauline, LinphoneIceStateHostConnection)); end_call(pauline, marie); @@ -4189,10 +4200,10 @@ static void _call_with_network_switch(bool_t use_ice, bool_t with_socket_refresh wait_for_until(marie->lc, pauline->lc, NULL, 0, 2000); if (use_ice) { - BC_ASSERT_TRUE(check_ice(pauline,marie,LinphoneIceStateHostConnection)); /*wait for ICE reINVITE to complete*/ BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneCallStreamsRunning, 2)); BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneCallStreamsRunning, 2)); + BC_ASSERT_TRUE(check_ice(pauline,marie,LinphoneIceStateHostConnection)); } /*marie looses the network and reconnects*/ @@ -4279,10 +4290,10 @@ static void call_with_sip_and_rtp_independant_switches(void){ wait_for_until(marie->lc, pauline->lc, NULL, 0, 2000); if (use_ice) { - BC_ASSERT_TRUE(check_ice(pauline,marie,LinphoneIceStateHostConnection)); /*wait for ICE reINVITE to complete*/ BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneCallStreamsRunning, 2)); BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneCallStreamsRunning, 2)); + BC_ASSERT_TRUE(check_ice(pauline,marie,LinphoneIceStateHostConnection)); } /*marie looses the SIP network and reconnects*/ linphone_core_set_sip_network_reachable(marie->lc, FALSE); @@ -4799,17 +4810,19 @@ static void v6_call_over_nat_64(void){ } static void call_with_ice_in_ipv4_with_v6_enabled(void) { - if (liblinphone_tester_ipv4_available() && liblinphone_tester_ipv6_available()){ - bool_t liblinphonetester_ipv6_save=liblinphonetester_ipv6; /*this test nee v6*/ - LinphoneCoreManager* marie = linphone_core_manager_new("marie_v4proxy_rc"); - LinphoneCoreManager* pauline = linphone_core_manager_new("pauline_v4proxy_rc"); + LinphoneCoreManager* marie; + LinphoneCoreManager* pauline; - liblinphonetester_ipv6=TRUE; - _call_with_ice_base(pauline,marie,TRUE,TRUE,TRUE,FALSE); - linphone_core_manager_destroy(marie); - linphone_core_manager_destroy(pauline); - liblinphonetester_ipv6=liblinphonetester_ipv6_save; /*this test nee v6*/ + if (liblinphone_tester_ipv4_available() && liblinphone_tester_ipv6_available()){ + bool_t liblinphonetester_ipv6_save=liblinphonetester_ipv6; /*this test nee v6*/ + liblinphonetester_ipv6=TRUE; + marie = linphone_core_manager_new("marie_v4proxy_rc"); + pauline = linphone_core_manager_new("pauline_v4proxy_rc"); + _call_with_ice_base(pauline,marie,TRUE,TRUE,TRUE,FALSE); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); + liblinphonetester_ipv6=liblinphonetester_ipv6_save; /*this test nee v6*/ } else ms_warning("Test skipped, need both ipv6 and v4 available"); } @@ -4873,6 +4886,7 @@ test_t call_tests[] = { TEST_NO_TAG("Call rejected without 403 because of wrong credential", call_rejected_without_403_because_wrong_credentials), TEST_NO_TAG("Call rejected without 403 because of wrong credential and no auth req cb", call_rejected_without_403_because_wrong_credentials_no_auth_req_cb), TEST_ONE_TAG("Call with ICE", call_with_ice, "ICE"), + TEST_ONE_TAG("Call with ICE IPv6", call_with_ice_ipv6, "ICE"), TEST_ONE_TAG("Call with ICE without SDP", call_with_ice_no_sdp, "ICE"), TEST_ONE_TAG("Call with ICE (random ports)", call_with_ice_random_ports, "ICE"), TEST_ONE_TAG("Call with ICE (forced relay)", call_with_ice_forced_relay, "ICE"), diff --git a/tester/call_video_tester.c b/tester/call_video_tester.c index 2f8abfaaf..2c5e7bc06 100644 --- a/tester/call_video_tester.c +++ b/tester/call_video_tester.c @@ -886,11 +886,11 @@ static void _call_with_ice_video(LinphoneVideoPolicy caller_policy, LinphoneVide BC_ASSERT_TRUE(call_ok = call(pauline, marie)); if (!call_ok) goto end; - BC_ASSERT_TRUE(check_ice(pauline, marie, LinphoneIceStateHostConnection)); /* Wait for ICE reINVITEs to complete. */ BC_ASSERT_TRUE(wait_for(pauline->lc, marie->lc, &pauline->stat.number_of_LinphoneCallStreamsRunning, 2) && wait_for(pauline->lc, pauline->lc, &marie->stat.number_of_LinphoneCallStreamsRunning, 2)); + BC_ASSERT_TRUE(check_ice(pauline, marie, LinphoneIceStateHostConnection)); check_nb_media_starts(pauline, marie, nb_media_starts, nb_media_starts); nb_media_starts++; diff --git a/tester/stun_tester.c b/tester/stun_tester.c index 3967ebb44..69003fd2c 100644 --- a/tester/stun_tester.c +++ b/tester/stun_tester.c @@ -121,7 +121,7 @@ static void check_turn_context_statistics(MSTurnContext *turn_context, bool_t fo } } -static void ice_turn_call_base(bool_t video_enabled, bool_t forced_relay, bool_t caller_turn_enabled, bool_t callee_turn_enabled, bool_t rtcp_mux_enabled) { +static void ice_turn_call_base(bool_t video_enabled, bool_t forced_relay, bool_t caller_turn_enabled, bool_t callee_turn_enabled, bool_t rtcp_mux_enabled, bool_t ipv6) { LinphoneCoreManager *marie; LinphoneCoreManager *pauline; LinphoneCall *lcall; @@ -129,11 +129,16 @@ static void ice_turn_call_base(bool_t video_enabled, bool_t forced_relay, bool_t LinphoneMediaDirection expected_video_dir = LinphoneMediaDirectionInactive; bctbx_list_t *lcs = NULL; - marie = linphone_core_manager_new("marie_rc"); + marie = linphone_core_manager_new2("marie_rc", FALSE); lcs = bctbx_list_append(lcs, marie->lc); - pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); + pauline = linphone_core_manager_new2(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc", FALSE); lcs = bctbx_list_append(lcs, pauline->lc); + if (ipv6) { + linphone_core_enable_ipv6(marie->lc, TRUE); + linphone_core_enable_ipv6(pauline->lc, TRUE); + } + configure_nat_policy(marie->lc, caller_turn_enabled); configure_nat_policy(pauline->lc, callee_turn_enabled); if (forced_relay == TRUE) { @@ -148,6 +153,9 @@ static void ice_turn_call_base(bool_t video_enabled, bool_t forced_relay, bool_t lp_config_set_int(linphone_core_get_config(pauline->lc), "rtp", "rtcp_mux", 1); } + linphone_core_manager_start(marie, TRUE); + linphone_core_manager_start(pauline, TRUE); + if (video_enabled) { #ifdef VIDEO_ENABLED video_call_base_2(marie, pauline, FALSE, LinphoneMediaEncryptionNone, TRUE, TRUE); @@ -184,31 +192,39 @@ static void ice_turn_call_base(bool_t video_enabled, bool_t forced_relay, bool_t } static void basic_ice_turn_call(void) { - ice_turn_call_base(FALSE, FALSE, TRUE, TRUE, FALSE); + ice_turn_call_base(FALSE, FALSE, TRUE, TRUE, FALSE, FALSE); +} + +static void basic_ipv6_ice_turn_call(void) { + if (liblinphone_tester_ipv6_available()) { + ice_turn_call_base(FALSE, FALSE, TRUE, TRUE, FALSE, TRUE); + } else { + ms_warning("Test skipped, no ipv6 available"); + } } #ifdef VIDEO_ENABLED static void video_ice_turn_call(void) { - ice_turn_call_base(TRUE, FALSE, TRUE, TRUE, FALSE); + ice_turn_call_base(TRUE, FALSE, TRUE, TRUE, FALSE, FALSE); } #endif static void relayed_ice_turn_call(void) { - ice_turn_call_base(FALSE, TRUE, TRUE, TRUE, FALSE); + ice_turn_call_base(FALSE, TRUE, TRUE, TRUE, FALSE, FALSE); } #ifdef VIDEO_ENABLED static void relayed_video_ice_turn_call(void) { - ice_turn_call_base(TRUE, TRUE, TRUE, TRUE, FALSE); + ice_turn_call_base(TRUE, TRUE, TRUE, TRUE, FALSE, FALSE); } #endif static void relayed_ice_turn_call_with_rtcp_mux(void) { - ice_turn_call_base(FALSE, TRUE, TRUE, TRUE, TRUE); + ice_turn_call_base(FALSE, TRUE, TRUE, TRUE, TRUE, FALSE); } static void relayed_ice_turn_to_ice_stun_call(void) { - ice_turn_call_base(FALSE, TRUE, TRUE, FALSE, FALSE); + ice_turn_call_base(FALSE, TRUE, TRUE, FALSE, FALSE, FALSE); } @@ -216,6 +232,7 @@ test_t stun_tests[] = { TEST_ONE_TAG("Basic Stun test (Ping/public IP)", linphone_stun_test_grab_ip, "STUN"), TEST_ONE_TAG("STUN encode", linphone_stun_test_encode, "STUN"), TEST_TWO_TAGS("Basic ICE+TURN call", basic_ice_turn_call, "ICE", "TURN"), + TEST_TWO_TAGS("Basic IPv6 ICE+TURN call", basic_ipv6_ice_turn_call, "ICE", "TURN"), #ifdef VIDEO_ENABLED TEST_TWO_TAGS("Video ICE+TURN call", video_ice_turn_call, "ICE", "TURN"), TEST_TWO_TAGS("Relayed video ICE+TURN call", relayed_video_ice_turn_call, "ICE", "TURN"), diff --git a/tester/tester.c b/tester/tester.c index 72d5d4604..9d8c768f5 100644 --- a/tester/tester.c +++ b/tester/tester.c @@ -666,20 +666,33 @@ static void check_ice_from_rtp(LinphoneCall *c1, LinphoneCall *c2, LinphoneStrea return; } - if (linphone_call_get_audio_stats(c1)->ice_state == LinphoneIceStateHostConnection && media_stream_started(ms)) { - char ip[16]; - char port[8]; - getnameinfo((const struct sockaddr *)&c1->audiostream->ms.sessions.rtp_session->rtp.gs.rem_addr - , c1->audiostream->ms.sessions.rtp_session->rtp.gs.rem_addrlen - , ip - , sizeof(ip) - , port - , sizeof(port) - , NI_NUMERICHOST|NI_NUMERICSERV); - BC_ASSERT_STRING_EQUAL(ip, c2->media_localip); + struct sockaddr_storage remaddr; + socklen_t remaddrlen = sizeof(remaddr); + char ip[NI_MAXHOST] = { 0 }; + int port = 0; + SalMediaDescription *result_desc; + char *expected_addr = NULL; + + const LinphoneCallParams *cp1 = linphone_call_get_current_params(c1); + const LinphoneCallParams *cp2 = linphone_call_get_current_params(c2); + if (cp1->update_call_when_ice_completed && cp2->update_call_when_ice_completed) { + memset(&remaddr, 0, remaddrlen); + result_desc = sal_call_get_final_media_description(c2->op); + expected_addr = result_desc->streams[0].rtp_addr; + if (expected_addr[0] == '\0') expected_addr = result_desc->addr; + if ((strchr(expected_addr, ':') == NULL) && (c1->audiostream->ms.sessions.rtp_session->rtp.gs.rem_addr.ss_family == AF_INET6)) { + bctbx_sockaddr_ipv6_to_ipv4((struct sockaddr *)&c1->audiostream->ms.sessions.rtp_session->rtp.gs.rem_addr, (struct sockaddr *)&remaddr, &remaddrlen); + } else { + memcpy(&remaddr, &c1->audiostream->ms.sessions.rtp_session->rtp.gs.rem_addr, c1->audiostream->ms.sessions.rtp_session->rtp.gs.rem_addrlen); + } + bctbx_sockaddr_to_ip_address((struct sockaddr *)&remaddr, remaddrlen, ip, sizeof(ip), &port); + + BC_ASSERT_STRING_EQUAL(ip, expected_addr); + } } } + bool_t check_ice(LinphoneCoreManager* caller, LinphoneCoreManager* callee, LinphoneIceState state) { LinphoneCall *c1,*c2; bool_t audio_success=FALSE;