Commit 62703c01 authored by Simon Morlat's avatar Simon Morlat
Browse files

robustize IPv6 support for heterogenous cases.

Also, the RTP sockets are now always IPv6 when ipv6 is enabled in LinphoneCore,
independently of what is finally proposed in SDP, so that these sockets can always send and recv
with both versions.
This is consistent with what is already done in belle-sip for SIP sockets.
parent 5de03489
......@@ -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);
/*
......
......@@ -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;
......
......@@ -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;
......
......@@ -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),
......
......@@ -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);
......
......@@ -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);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment