diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 403a9c7b0..516bc0150 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -625,7 +625,8 @@ static void transfer_already_assigned_payload_types(SalMediaDescription *old, Sa } static const char *linphone_call_get_bind_ip_for_stream(LinphoneCall *call, int stream_index){ - const char *bind_ip = lp_config_get_string(call->core->config,"rtp","bind_address",call->af==AF_INET6 ? "::0" : "0.0.0.0"); + const char *bind_ip = lp_config_get_string(call->core->config,"rtp","bind_address", + linphone_core_ipv6_enabled(call->core) ? "::0" : "0.0.0.0"); if (stream_index<2 && call->media_ports[stream_index].multicast_ip[0]!='\0'){ if (call->dir==LinphoneCallOutgoing){ @@ -1025,7 +1026,7 @@ void linphone_call_create_op(LinphoneCall *call){ } /* - * Choose IP version we are going to use for RTP socket. + * Choose IP version we are going to use for RTP streams IP address advertised in SDP. * The algorithm is as follows: * - if ipv6 is disabled at the core level, it is always AF_INET * - Otherwise, if the destination address for the call is an IPv6 address, use IPv6. @@ -1164,9 +1165,19 @@ LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddr return call; } -static void linphone_call_incoming_select_ip_version(LinphoneCall *call){ +/*Select IP version to use for advertising local addresses of RTP streams, for an incoming call. + *If the call is received through a know proxy that is IPv6, use IPv6. + *Otherwise check the remote contact address. + *If later the resulting media description tells that we have to send IPv4, it won't be a problem because the RTP sockets + * are dual stack. + */ +static void linphone_call_incoming_select_ip_version(LinphoneCall *call, LinphoneProxyConfig *cfg){ if (linphone_core_ipv6_enabled(call->core)){ - call->af=sal_op_is_ipv6(call->op) ? AF_INET6 : AF_INET; + if (cfg && cfg->op){ + call->af=sal_op_is_ipv6(cfg->op) ? AF_INET6 : AF_INET; + }else{ + call->af=sal_op_is_ipv6(call->op) ? AF_INET6 : AF_INET; + } }else call->af=AF_INET; } @@ -1192,6 +1203,10 @@ void linphone_call_set_compatible_incoming_call_parameters(LinphoneCall *call, S }else if (call->params->media_encryption != LinphoneMediaEncryptionZRTP){ call->params->media_encryption = LinphoneMediaEncryptionNone; } + if (!sal_media_description_has_ipv6(md)){ + ms_message("The remote SDP doesn't seem to offer any IPv6 connectivity, so disabling IPv6 for this call."); + call->af = AF_INET; + } linphone_call_fix_call_parameters(call, md); } @@ -1305,7 +1320,11 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro call->op=op; call->core=lc; - linphone_call_incoming_select_ip_version(call); + call->dest_proxy = linphone_core_lookup_known_proxy(call->core, to); + linphone_call_incoming_select_ip_version(call, call->dest_proxy); + /*note that the choice of IP version for streams is later refined by + * linphone_call_set_compatible_incoming_call_parameters() when examining the remote offer, if any. + * If the remote offer contains IPv4 addresses, we should propose IPv4 as well*/ sal_op_cnx_ip_to_0000_if_sendonly_enable(op,lp_config_get_default_int(lc->config,"sip","cnx_ip_to_0000_if_sendonly_enabled",0)); @@ -1336,7 +1355,6 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro call->params = linphone_call_params_new(); linphone_call_init_common(call, from, to); call->log->call_id=ms_strdup(sal_op_get_call_id(op)); /*must be known at that time*/ - call->dest_proxy = linphone_core_lookup_known_proxy(call->core, to); linphone_core_init_default_params(lc, call->params); /* diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index 084869204..e0b8ef53f 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -1790,7 +1790,7 @@ extern "C" void Java_org_linphone_core_LinphoneCoreImpl_muteMic( JNIEnv* env ,jobject thiz ,jlong lc ,jboolean isMuted) { - linphone_core_enable_mic((LinphoneCore*)lc,isMuted); + linphone_core_enable_mic((LinphoneCore*)lc, !isMuted); } extern "C" jlong Java_org_linphone_core_LinphoneCoreImpl_interpretUrl( JNIEnv* env diff --git a/coreapi/misc.c b/coreapi/misc.c index 0ab5a04fa..835acb6e9 100644 --- a/coreapi/misc.c +++ b/coreapi/misc.c @@ -572,7 +572,7 @@ void linphone_core_adapt_to_network(LinphoneCore *lc, int ping_time_ms, Linphone static void stun_server_resolved(LinphoneCore *lc, const char *name, struct addrinfo *addrinfo){ if (lc->net_conf.stun_addrinfo){ - belle_sip_freeaddrinfo(lc->net_conf.stun_addrinfo); + bctbx_freeaddrinfo(lc->net_conf.stun_addrinfo); lc->net_conf.stun_addrinfo=NULL; } if (addrinfo){ diff --git a/coreapi/private.h b/coreapi/private.h index 412e39ed7..935066238 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -37,6 +37,7 @@ #include "ringtoneplayer.h" #include "vcard.h" +#include #include #include diff --git a/coreapi/sal.c b/coreapi/sal.c index 6a53b61d7..0f43d1a1d 100644 --- a/coreapi/sal.c +++ b/coreapi/sal.c @@ -220,6 +220,10 @@ bool_t sal_stream_description_has_avpf(const SalStreamDescription *sd) { return FALSE; } +bool_t sal_stream_description_has_ipv6(const SalStreamDescription *sd){ + return strchr(sd->rtp_addr,':') != NULL; +} + bool_t sal_stream_description_has_implicit_avpf(const SalStreamDescription *sd){ return sd->implicit_rtcp_fb; } @@ -309,6 +313,20 @@ bool_t sal_media_description_has_zrtp(const SalMediaDescription *md) { return TRUE; } +bool_t sal_media_description_has_ipv6(const SalMediaDescription *md){ + int i; + if (md->nb_streams == 0) return FALSE; + for (i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; i++) { + if (!sal_stream_description_active(&md->streams[i])) continue; + if (md->streams[i].rtp_addr[0] != '\0'){ + if (!sal_stream_description_has_ipv6(&md->streams[i])) return FALSE; + }else{ + if (strchr(md->addr,':') == NULL) return FALSE; + } + } + return TRUE; +} + /* static bool_t fmtp_equals(const char *p1, const char *p2){ if (p1 && p2 && strcmp(p1,p2)==0) return TRUE; diff --git a/daemon/commands/call-mute.cc b/daemon/commands/call-mute.cc index c5f79b2b6..918552159 100644 --- a/daemon/commands/call-mute.cc +++ b/daemon/commands/call-mute.cc @@ -29,9 +29,9 @@ void CallMute::exec(Daemon* app, const char* args) } if (sscanf(args, "%i", &muted) == 1) { - linphone_core_enable_mic(lc, (muted != 0)); + linphone_core_enable_mic(lc, !muted); } else { - linphone_core_enable_mic(lc, (muted != 0)); + linphone_core_enable_mic(lc, !muted); } app->sendResponse(Response(muted?"Microphone Muted" diff --git a/include/sal/sal.h b/include/sal/sal.h index 9b3b979cf..057c9d1b5 100644 --- a/include/sal/sal.h +++ b/include/sal/sal.h @@ -326,11 +326,13 @@ bool_t sal_stream_description_has_avpf(const SalStreamDescription *sd); bool_t sal_stream_description_has_implicit_avpf(const SalStreamDescription *sd); bool_t sal_stream_description_has_srtp(const SalStreamDescription *sd); bool_t sal_stream_description_has_dtls(const SalStreamDescription *sd); +bool_t sal_stream_description_has_ipv6(const SalStreamDescription *md); bool_t sal_media_description_has_avpf(const SalMediaDescription *md); bool_t sal_media_description_has_implicit_avpf(const SalMediaDescription *md); bool_t sal_media_description_has_srtp(const SalMediaDescription *md); bool_t sal_media_description_has_dtls(const SalMediaDescription *md); bool_t sal_media_description_has_zrtp(const SalMediaDescription *md); +bool_t sal_media_description_has_ipv6(const SalMediaDescription *md); int sal_media_description_get_nb_active_streams(const SalMediaDescription *md); struct SalOpBase; diff --git a/mediastreamer2 b/mediastreamer2 index 2076bcda9..57f7b9526 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 2076bcda91d98388f475727ea3234505679caa38 +Subproject commit 57f7b95267f1b943f15b7dd00b3ccaeb43fb373f diff --git a/tester/flexisip_tester.c b/tester/flexisip_tester.c index 944cec912..2a9dea118 100644 --- a/tester/flexisip_tester.c +++ b/tester/flexisip_tester.c @@ -683,10 +683,34 @@ static void call_with_sips_not_achievable(void){ } } -static void call_with_ipv6(void) { + + +static bool_t is_sending_ipv6(RtpSession *session, bool_t rtcp){ + const struct sockaddr *dest = rtcp ? (struct sockaddr*)&session->rtcp.gs.rem_addr : (struct sockaddr*)&session->rtp.gs.rem_addr; + struct sockaddr_in6 *in6=(struct sockaddr_in6*)dest; + return dest->sa_family == AF_INET6 && !IN6_IS_ADDR_V4MAPPED(&in6->sin6_addr); +} +static bool_t is_remote_contact_ipv6(LinphoneCall *call){ + const char *contact=linphone_call_get_remote_contact(call); + LinphoneAddress *ct_addr; + bool_t ret = FALSE; + + BC_ASSERT_PTR_NOT_NULL(contact); + if (contact){ + ct_addr=linphone_address_new(contact); + BC_ASSERT_PTR_NOT_NULL(ct_addr); + if (ct_addr){ + ret = strchr(linphone_address_get_domain(ct_addr),':') != NULL; + } + linphone_address_destroy(ct_addr); + } + return ret; +} + +static void _call_with_ipv6(bool_t caller_with_ipv6, bool_t callee_with_ipv6) { LinphoneCoreManager* marie; LinphoneCoreManager* pauline; - LinphoneCall *pauline_call; + LinphoneCall *pauline_call, *marie_call; /*calling ortp_init() here is done to have WSAStartup() done, otherwise liblinphone_tester_ipv6_available() will not work.*/ ortp_init(); @@ -696,41 +720,54 @@ static void call_with_ipv6(void) { return; } - liblinphone_tester_enable_ipv6(TRUE); - marie = linphone_core_manager_new( "marie_rc"); - pauline = linphone_core_manager_new( transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); + marie = linphone_core_manager_new2( "marie_rc", FALSE); + linphone_core_enable_ipv6(marie->lc, caller_with_ipv6); + linphone_core_manager_start(marie, TRUE); + + pauline = linphone_core_manager_new2( transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc", FALSE); + linphone_core_enable_ipv6(pauline->lc, callee_with_ipv6); + linphone_core_manager_start(pauline, TRUE); linphone_core_set_user_agent(marie->lc,"Natted Linphone",NULL); linphone_core_set_user_agent(pauline->lc,"Natted Linphone",NULL); BC_ASSERT_TRUE(call(marie,pauline)); - pauline_call=linphone_core_get_current_call(pauline->lc); + pauline_call = linphone_core_get_current_call(pauline->lc); + marie_call = linphone_core_get_current_call(marie->lc); BC_ASSERT_PTR_NOT_NULL(pauline_call); - if (pauline_call){ + BC_ASSERT_PTR_NOT_NULL(marie_call); + if (pauline_call && marie_call){ /*check that the remote contact is IPv6*/ - const char *contact=linphone_call_get_remote_contact(pauline_call); - LinphoneAddress *ct_addr; - - BC_ASSERT_PTR_NOT_NULL(contact); - if (contact){ - ct_addr=linphone_address_new(contact); - BC_ASSERT_PTR_NOT_NULL(ct_addr); - if (ct_addr){ - BC_ASSERT_PTR_NOT_NULL(strchr(linphone_address_get_domain(ct_addr),':')); - } - linphone_address_destroy(ct_addr); - } - + BC_ASSERT_EQUAL(is_remote_contact_ipv6(pauline_call), caller_with_ipv6, int, "%i"); + BC_ASSERT_EQUAL(is_remote_contact_ipv6(marie_call), callee_with_ipv6, int, "%i"); + + /*check that the RTP destinations are IPv6 (flexisip should propose an IPv6 relay for parties with IPv6)*/ + BC_ASSERT_EQUAL(is_sending_ipv6(marie_call->sessions[0].rtp_session, FALSE), caller_with_ipv6, int, "%i"); + BC_ASSERT_EQUAL(is_sending_ipv6(marie_call->sessions[0].rtp_session, TRUE), caller_with_ipv6, int, "%i"); + BC_ASSERT_EQUAL(is_sending_ipv6(pauline_call->sessions[0].rtp_session, FALSE), callee_with_ipv6, int, "%i"); + BC_ASSERT_EQUAL(is_sending_ipv6(pauline_call->sessions[0].rtp_session, TRUE), callee_with_ipv6, int, "%i"); + } liblinphone_tester_check_rtcp(marie,pauline); end_call(marie,pauline); linphone_core_manager_destroy(marie); linphone_core_manager_destroy(pauline); - liblinphone_tester_enable_ipv6(FALSE); ortp_exit(); } +static void call_with_ipv6(void){ + _call_with_ipv6(TRUE, TRUE); +} + +static void call_ipv4_to_ipv6(void){ + _call_with_ipv6(FALSE, TRUE); +} + +static void call_ipv6_to_ipv4(void){ + _call_with_ipv6(TRUE, FALSE); +} + static void file_transfer_message_rcs_to_external_body_client(void) { if (transport_supported(LinphoneTransportTls)) { LinphoneChatRoom* chat_room; @@ -1143,7 +1180,9 @@ test_t flexisip_tests[] = { TEST_NO_TAG("Early-media call forking", early_media_call_forking), TEST_NO_TAG("Call with sips", call_with_sips), TEST_ONE_TAG("Call with sips not achievable", call_with_sips_not_achievable, "LeaksMemory"), - TEST_NO_TAG("Call with ipv6", call_with_ipv6), + TEST_NO_TAG("Call ipv6 to ipv6", call_with_ipv6), + TEST_NO_TAG("Call ipv6 to ipv4", call_ipv6_to_ipv4), + TEST_NO_TAG("Call ipv4 to ipv6", call_ipv4_to_ipv6), TEST_ONE_TAG("Subscribe Notify with sipp publisher", test_subscribe_notify_with_sipp_publisher, "LeaksMemory"), /*TEST_ONE_TAG("Subscribe Notify with sipp double publish", test_subscribe_notify_with_sipp_publisher_double_publish, "LeaksMemory"),*/ TEST_NO_TAG("Publish/unpublish", test_publish_unpublish), diff --git a/tester/liblinphone_tester.h b/tester/liblinphone_tester.h index eb1d21561..9718e3b1b 100644 --- a/tester/liblinphone_tester.h +++ b/tester/liblinphone_tester.h @@ -339,7 +339,7 @@ bool_t liblinphone_tester_clock_elapsed(const MSTimeSpec *start, int value_ms); void linphone_core_manager_check_accounts(LinphoneCoreManager *m); void account_manager_destroy(void); LinphoneCore* configure_lc_from(LinphoneCoreVTable* v_table, const char* path, const char* file, void* user_data); -void liblinphone_tester_enable_ipv6(bool_t enabled); + void linphone_call_iframe_decoded_cb(LinphoneCall *call,void * user_data); void call_paused_resumed_base(bool_t multicast,bool_t with_losses); void simple_call_base(bool_t enable_multicast_recv_side); diff --git a/tester/tester.c b/tester/tester.c index ec253ba2e..4ddd07cd6 100644 --- a/tester/tester.c +++ b/tester/tester.c @@ -39,7 +39,7 @@ #define unlink _unlink #endif -static bool_t liblinphone_tester_ipv6_enabled=FALSE; + static int liblinphone_tester_keep_accounts_flag = 0; static int liblinphone_tester_keep_record_files = FALSE; static int liblinphone_tester_leak_detector_disabled = FALSE; @@ -77,9 +77,6 @@ bool_t liblinphone_tester_clock_elapsed(const MSTimeSpec *start, int value_ms){ return FALSE; } -void liblinphone_tester_enable_ipv6(bool_t enabled){ - liblinphone_tester_ipv6_enabled=enabled; -} LinphoneAddress * create_linphone_address(const char * domain) { LinphoneAddress *addr = linphone_address_new(NULL); @@ -156,8 +153,6 @@ LinphoneCore* configure_lc_from(LinphoneCoreVTable* v_table, const char* path, c sal_set_dns_user_hosts_file(lc->sal, dnsuserhostspath); linphone_core_set_static_picture(lc,nowebcampath); - linphone_core_enable_ipv6(lc, liblinphone_tester_ipv6_enabled); - ms_free(ringpath); ms_free(ringbackpath); ms_free(nowebcampath); @@ -436,7 +431,7 @@ void linphone_core_manager_destroy(LinphoneCoreManager* mgr) { } int liblinphone_tester_ipv6_available(void){ - struct addrinfo *ai=belle_sip_ip_address_to_addrinfo(AF_INET6,"2a01:e00::2",53); + struct addrinfo *ai=bctbx_ip_address_to_addrinfo(AF_INET6,"2a01:e00::2",53); if (ai){ struct sockaddr_storage ss; struct addrinfo src; @@ -446,7 +441,7 @@ int liblinphone_tester_ipv6_available(void){ belle_sip_get_src_addr_for(ai->ai_addr,(socklen_t)ai->ai_addrlen,(struct sockaddr*) &ss,&slen,4444); src.ai_addr=(struct sockaddr*) &ss; src.ai_addrlen=slen; - belle_sip_addrinfo_to_ip(&src,localip, sizeof(localip),&port); + bctbx_addrinfo_to_ip_address(&src,localip, sizeof(localip),&port); freeaddrinfo(ai); return strcmp(localip,"::1")!=0; }