From aa5f676dcdb70a68b3c6cb509f187e8e1622ef6a Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 21 Aug 2014 17:50:31 +0200 Subject: [PATCH] Improve fetching of the local IP to take into account the destination. --- coreapi/linphonecall.c | 59 ++++++++++++++++++++++++++++++++++++++++-- coreapi/linphonecore.c | 42 ++---------------------------- coreapi/private.h | 1 - 3 files changed, 59 insertions(+), 43 deletions(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index dc339f09d..3e584318d 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -645,6 +645,61 @@ static void linphone_call_outgoing_select_ip_version(LinphoneCall *call, Linphon }else call->af=AF_INET; } +/** + * Fill the local ip that routes to the internet according to the destination, or guess it by other special means (upnp). + */ +static void linphone_call_get_local_ip(LinphoneCall *call, const LinphoneAddress *remote_addr){ + const char *ip; + int af = call->af; + const char *dest = NULL; + if (call->dest_proxy == NULL) { + struct addrinfo hints; + struct addrinfo *res = NULL; + int err; + const char *domain = linphone_address_get_domain(remote_addr); + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_DGRAM; + hints.ai_flags = AI_NUMERICHOST; + err = getaddrinfo(domain, NULL, &hints, &res); + if (err == 0) { + dest = domain; + } + } + if (linphone_core_get_firewall_policy(call->core)==LinphonePolicyUseNatAddress + && (ip=linphone_core_get_nat_address_resolved(call->core))!=NULL){ + strncpy(call->localip,ip,LINPHONE_IPADDR_SIZE); + return; + } +#ifdef BUILD_UPNP + else if (call->core->upnp != NULL && linphone_core_get_firewall_policy(call->core)==LinphonePolicyUseUpnp && + linphone_upnp_context_get_state(call->core->upnp) == LinphoneUpnpStateOk) { + ip = linphone_upnp_context_get_external_ipaddress(call->core->upnp); + strncpy(call->localip,ip,LINPHONE_IPADDR_SIZE); + return; + } +#endif //BUILD_UPNP + if (af==AF_UNSPEC){ + if (linphone_core_ipv6_enabled(call->core)){ + bool_t has_ipv6; + has_ipv6=linphone_core_get_local_ip_for(AF_INET6,dest,call->localip)==0; + if (strcmp(call->localip,"::1")!=0) + return; /*this machine has real ipv6 connectivity*/ + if (linphone_core_get_local_ip_for(AF_INET,dest,call->localip)==0 && strcmp(call->localip,"127.0.0.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(call->localip,"::1",LINPHONE_IPADDR_SIZE); + return; + } + } + /*in all other cases use IPv4*/ + af=AF_INET; + } + if (linphone_core_get_local_ip_for(af,dest,call->localip)==0) + return; +} + static void linphone_call_destroy(LinphoneCall *obj); BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneCall); @@ -662,7 +717,7 @@ LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddr call->dir=LinphoneCallOutgoing; call->core=lc; linphone_call_outgoing_select_ip_version(call,to,cfg); - linphone_core_get_local_ip(lc,call->af,call->localip); + linphone_call_get_local_ip(call, to); linphone_call_init_common(call,from,to); _linphone_call_params_copy(&call->params,params); @@ -748,7 +803,7 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro } linphone_address_clean(from); - linphone_core_get_local_ip(lc,call->af,call->localip); + linphone_call_get_local_ip(call, from); 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); diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index eb137bdd9..a3244e59d 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -1522,44 +1522,6 @@ 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, int af, char *result){ - const char *ip; - if (linphone_core_get_firewall_policy(lc)==LinphonePolicyUseNatAddress - && (ip=linphone_core_get_nat_address_resolved(lc))!=NULL){ - strncpy(result,ip,LINPHONE_IPADDR_SIZE); - return; - } -#ifdef BUILD_UPNP - else if (lc->upnp != NULL && linphone_core_get_firewall_policy(lc)==LinphonePolicyUseUpnp && - linphone_upnp_context_get_state(lc->upnp) == LinphoneUpnpStateOk) { - ip = linphone_upnp_context_get_external_ipaddress(lc->upnp); - strncpy(result,ip,LINPHONE_IPADDR_SIZE); - return; - } -#endif //BUILD_UPNP - 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,"127.0.0.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; - } - } - /*in all other cases use IPv4*/ - af=AF_INET; - } - if (linphone_core_get_local_ip_for(af,NULL,result)==0) - return; -} - static void update_primary_contact(LinphoneCore *lc){ char *guessed=NULL; char tmp[LINPHONE_IPADDR_SIZE]; @@ -1574,7 +1536,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, AF_UNSPEC, tmp); + linphone_core_get_local_ip_for(AF_UNSPEC, NULL, 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; @@ -2170,7 +2132,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(lc,AF_UNSPEC,newip); + linphone_core_get_local_ip_for(AF_UNSPEC,NULL,newip); if (strcmp(newip,"::1")!=0 && strcmp(newip,"127.0.0.1")!=0){ new_status=TRUE; }else new_status=FALSE; /*no network*/ diff --git a/coreapi/private.h b/coreapi/private.h index be8d8667f..1ada4a618 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -292,7 +292,6 @@ void linphone_core_update_friends_subscriptions(LinphoneCore *lc, LinphoneProxyC int parse_hostname_to_addr(const char *server, struct sockaddr_storage *ss, socklen_t *socklen, int default_port); -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);