Commit ffaf9682 authored by Simon Morlat's avatar Simon Morlat

Implement fully compatible IPv4/IPv6 mode.

Requires belle-sip upgrade.
parent fda6a31d
......@@ -179,6 +179,17 @@ void sal_address_unref(SalAddress *addr){
belle_sip_object_unref(BELLE_SIP_HEADER_ADDRESS(addr));
}
bool_t sal_address_is_ipv6(SalAddress *addr){
belle_sip_header_address_t* header_addr = BELLE_SIP_HEADER_ADDRESS(addr);
belle_sip_uri_t* uri = belle_sip_header_address_get_uri(header_addr);
if (uri){
const char *host=belle_sip_uri_get_host(uri);
if (host && strchr(host,':')!=NULL)
return TRUE;
}
return FALSE;
}
void sal_address_destroy(SalAddress *addr){
sal_address_unref(addr);
}
......
......@@ -612,3 +612,29 @@ bool_t sal_op_is_secure(const SalOp* op) {
void sal_op_set_manual_refresher_mode(SalOp *op, bool_t enabled){
op->manual_refresher=enabled;
}
bool_t sal_op_is_ipv6(SalOp *op){
belle_sip_transaction_t *tr=NULL;
belle_sip_header_address_t *contact;
belle_sip_request_t *req;
if (op->refresher)
tr=(belle_sip_transaction_t *)belle_sip_refresher_get_transaction(op->refresher);
if (tr==NULL)
tr=(belle_sip_transaction_t *)op->pending_client_trans;
if (tr==NULL)
tr=(belle_sip_transaction_t *)op->pending_server_trans;
if (tr==NULL){
ms_error("Unable to determine IP version from signaling operation.");
return FALSE;
}
req=belle_sip_transaction_get_request(tr);
contact=(belle_sip_header_address_t*)belle_sip_message_get_header_by_type(req,belle_sip_header_contact_t);
if (!contact){
ms_error("Unable to determine IP version from signaling operation, no contact header found.");
}
return sal_address_is_ipv6((SalAddress*)contact);
}
......@@ -501,12 +501,32 @@ void linphone_call_create_op(LinphoneCall *call){
/*else privacy might be set by proxy */
}
/*
* Choose IP version we are going to use for RTP socket.
* 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.
* - Otherwise, if the call is done through a known proxy config, then use the information obtained during REGISTER
* to know if IPv6 is supported by the server.
**/
static void linphone_call_outgoing_select_ip_version(LinphoneCall *call, LinphoneAddress *to, LinphoneProxyConfig *cfg){
if (linphone_core_ipv6_enabled(call->core)){
call->af=AF_INET;
if (sal_address_is_ipv6((SalAddress*)to)){
call->af=AF_INET6;
}else if (cfg && cfg->op){
call->af=sal_op_is_ipv6(cfg->op) ? AF_INET6 : AF_INET;
}
}else call->af=AF_INET;
}
LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to, const LinphoneCallParams *params, LinphoneProxyConfig *cfg){
LinphoneCall *call=ms_new0(LinphoneCall,1);
call->dir=LinphoneCallOutgoing;
call->core=lc;
linphone_core_get_local_ip(lc,NULL,call->localip);
linphone_call_outgoing_select_ip_version(call,to,cfg);
linphone_core_get_local_ip(lc,call->af,call->localip);
linphone_call_init_common(call,from,to);
_linphone_call_params_copy(&call->params,params);
......@@ -535,6 +555,12 @@ LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddr
return call;
}
static void linphone_call_incoming_select_ip_version(LinphoneCall *call){
if (linphone_core_ipv6_enabled(call->core)){
call->af=sal_op_is_ipv6(call->op) ? AF_INET6 : AF_INET;
}else call->af=AF_INET;
}
LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to, SalOp *op){
LinphoneCall *call=ms_new0(LinphoneCall,1);
char *from_str;
......@@ -544,7 +570,7 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro
sal_op_set_user_pointer(op,call);
call->op=op;
call->core=lc;
linphone_call_incoming_select_ip_version(call);
if (lc->sip_conf.ping_with_options){
#ifdef BUILD_UPNP
......@@ -565,7 +591,7 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro
}
linphone_address_clean(from);
linphone_core_get_local_ip(lc,NULL,call->localip);
linphone_core_get_local_ip(lc,call->af,call->localip);
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*/
linphone_core_init_default_params(lc, &call->params);
......@@ -1331,7 +1357,7 @@ void linphone_call_init_audio_stream(LinphoneCall *call){
int dscp;
if (call->audiostream != NULL) return;
call->audiostream=audiostream=audio_stream_new(call->audio_port,call->audio_port+1,linphone_core_ipv6_enabled(lc));
call->audiostream=audiostream=audio_stream_new(call->audio_port,call->audio_port+1,call->af==AF_INET6);
dscp=linphone_core_get_audio_dscp(lc);
if (dscp!=-1)
audio_stream_set_dscp(audiostream,dscp);
......@@ -1395,7 +1421,7 @@ void linphone_call_init_video_stream(LinphoneCall *call){
int dscp=linphone_core_get_video_dscp(lc);
const char *display_filter=linphone_core_get_video_display_filter(lc);
call->videostream=video_stream_new(call->video_port,call->video_port+1,linphone_core_ipv6_enabled(lc));
call->videostream=video_stream_new(call->video_port,call->video_port+1,call->af==AF_INET6);
if (dscp!=-1)
video_stream_set_dscp(call->videostream,dscp);
video_stream_enable_display_filter_auto_rotate(call->videostream, lp_config_get_int(lc->config,"video","display_filter_auto_rotate",0));
......
......@@ -1443,8 +1443,9 @@ int linphone_core_set_primary_contact(LinphoneCore *lc, const char *contact)
}
/*Returns the local ip that routes to the internet, or guessed by other special means (upnp)*/
/*result must be an array of chars at least LINPHONE_IPADDR_SIZE */
void linphone_core_get_local_ip(LinphoneCore *lc, const char *dest, char *result){
void linphone_core_get_local_ip(LinphoneCore *lc, int af, char *result){
const char *ip;
if (linphone_core_get_firewall_policy(lc)==LinphonePolicyUseNatAddress
&& (ip=linphone_core_get_nat_address_resolved(lc))!=NULL){
......@@ -1459,10 +1460,23 @@ void linphone_core_get_local_ip(LinphoneCore *lc, const char *dest, char *result
return;
}
#endif //BUILD_UPNP
if (linphone_core_get_local_ip_for(lc->sip_conf.ipv6_enabled ? AF_INET6 : AF_INET,dest,result)==0)
if (af==AF_UNSPEC){
if (linphone_core_ipv6_enabled(lc)){
bool_t has_ipv6;
has_ipv6=linphone_core_get_local_ip_for(AF_INET6,NULL,result)==0;
if (strcmp(result,"::1")!=0)
return; /*this machine has real ipv6 connectivity*/
if (linphone_core_get_local_ip_for(AF_INET,NULL,result)==0 && strcmp(result,"::1")!=0)
return; /*this machine has only ipv4 connectivity*/
if (has_ipv6){
/*this machine has only local loopback for both ipv4 and ipv6, so prefer ipv6*/
strncpy(result,"::1",LINPHONE_IPADDR_SIZE);
return;
}
}else af=AF_INET;
}
if (linphone_core_get_local_ip_for(af,NULL,result)==0)
return;
/*else fallback to SAL routine that will attempt to find the most realistic interface */
sal_get_default_local_ip(lc->sal,lc->sip_conf.ipv6_enabled ? AF_INET6 : AF_INET,result,LINPHONE_IPADDR_SIZE);
}
static void update_primary_contact(LinphoneCore *lc){
......@@ -1479,7 +1493,7 @@ static void update_primary_contact(LinphoneCore *lc){
ms_error("Could not parse identity contact !");
url=linphone_address_new("sip:unknown@unkwownhost");
}
linphone_core_get_local_ip(lc, NULL, tmp);
linphone_core_get_local_ip(lc, AF_UNSPEC, tmp);
if (strcmp(tmp,"127.0.0.1")==0 || strcmp(tmp,"::1")==0 ){
ms_warning("Local loopback network only !");
lc->sip_conf.loopback_only=TRUE;
......@@ -2027,7 +2041,7 @@ static void monitor_network_state(LinphoneCore *lc, time_t curtime){
/* only do the network up checking every five seconds */
if (lc->network_last_check==0 || (curtime-lc->network_last_check)>=5){
linphone_core_get_local_ip_for(lc->sip_conf.ipv6_enabled ? AF_INET6 : AF_INET,NULL,result);
linphone_core_get_local_ip(lc,AF_UNSPEC,result);
if (strcmp(result,"::1")!=0 && strcmp(result,"127.0.0.1")!=0){
new_status=TRUE;
}else new_status=FALSE;
......
......@@ -637,12 +637,16 @@ static void stun_server_resolved(LinphoneCore *lc, const char *name, struct addr
}
void linphone_core_resolve_stun_server(LinphoneCore *lc){
/*
* 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=lc->net_conf.stun_server;
if (lc->sal && server){
char host[NI_MAXHOST];
int port=3478;
linphone_parse_host_port(server,host,sizeof(host),&port);
lc->net_conf.stun_res=sal_resolve_a(lc->sal,host,port,AF_UNSPEC,(SalResolverCallback)stun_server_resolved,lc);
lc->net_conf.stun_res=sal_resolve_a(lc->sal,host,port,AF_INET,(SalResolverCallback)stun_server_resolved,lc);
}
}
......@@ -685,8 +689,8 @@ int linphone_core_gather_ice_candidates(LinphoneCore *lc, LinphoneCall *call)
video_check_list = ice_session_check_list(call->ice_session, 1);
if (audio_check_list == NULL) return -1;
if (lc->sip_conf.ipv6_enabled){
ms_warning("stun support is not implemented for ipv6");
if (call->af==AF_INET6){
ms_warning("Ice gathering is not implemented for ipv6");
return -1;
}
ai=linphone_core_get_stun_server_addrinfo(lc);
......@@ -1133,12 +1137,12 @@ static int get_local_ip_for_with_connect(int type, const char *dest, char *resul
socklen_t s;
memset(&hints,0,sizeof(hints));
hints.ai_family=(type==AF_INET6) ? PF_INET6 : PF_INET;
hints.ai_family=type;
hints.ai_socktype=SOCK_DGRAM;
/*hints.ai_flags=AI_NUMERICHOST|AI_CANONNAME;*/
err=getaddrinfo(dest,"5060",&hints,&res);
if (err!=0){
ms_error("getaddrinfo() error: %s",gai_strerror(err));
ms_error("getaddrinfo() error for %s : %s",dest, gai_strerror(err));
return -1;
}
if (res==NULL){
......@@ -1153,7 +1157,8 @@ static int get_local_ip_for_with_connect(int type, const char *dest, char *resul
}
err=connect(sock,res->ai_addr,res->ai_addrlen);
if (err<0) {
ms_error("Error in connect: %s",strerror(errno));
/*the network isn't reachable*/
if (getSocketErrorCode()!=ENETUNREACH) ms_error("Error in connect: %s",strerror(errno));
freeaddrinfo(res);
close_socket(sock);
return -1;
......
......@@ -154,6 +154,7 @@ struct _LinphoneCall
{
int magic; /*used to distinguish from proxy config*/
struct _LinphoneCore *core;
int af; /*the address family to prefer for RTP path, guessed from signaling path*/
SalMediaDescription *localdesc;
SalMediaDescription *resultdesc;
LinphoneCallDir dir;
......@@ -263,7 +264,7 @@ int set_lock_file();
int get_lock_file();
int remove_lock_file();
void check_sound_device(LinphoneCore *lc);
void linphone_core_get_local_ip(LinphoneCore *lc, const char *to, char *result);
void linphone_core_get_local_ip(LinphoneCore *lc, int af, char *result);
bool_t host_has_ipv6_network();
bool_t lp_spawn_command_line_sync(const char *command, char **result,int *command_ret);
......
......@@ -104,6 +104,7 @@ void sal_address_set_transport(SalAddress* addr,SalTransport transport);
void sal_address_set_transport_name(SalAddress* addr,const char* transport);
void sal_address_set_params(SalAddress *addr, const char *params);
void sal_address_set_uri_params(SalAddress *addr, const char *params);
bool_t sal_address_is_ipv6(SalAddress *addr);
Sal * sal_init();
void sal_uninit(Sal* sal);
......@@ -556,6 +557,7 @@ const SalAddress* sal_op_get_service_route(const SalOp *op);
void sal_op_set_service_route(SalOp *op,const SalAddress* service_route);
void sal_op_set_manual_refresher_mode(SalOp *op, bool_t enabled);
bool_t sal_op_is_ipv6(SalOp *op);
/*Call API*/
int sal_call_set_local_media_description(SalOp *h, SalMediaDescription *desc);
......
oRTP @ 123ef1a5
Subproject commit fcc51caa15def815189a388e878877a5354850e6
Subproject commit 123ef1a55c321826966a3a375bee09b558ae170d
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