* ecore_con: with AF_UNSPEC, c-ares will prefer IPv4 address

when IPv4 and IPv6 exist, if you ask AF_INET6, it will first
	try IPv6 before falling back to IPv4 address.

	So now ecore_con_ares will prefer IPv6 if available.


SVN revision: 49552
This commit is contained in:
Cedric BAIL 2010-06-07 13:08:19 +00:00
parent d76f881898
commit 6aac60a150
1 changed files with 109 additions and 48 deletions

View File

@ -40,7 +40,8 @@ struct _Ecore_Con_CAres
struct in6_addr v6;
} addr;
Eina_Bool byaddr;
Eina_Bool byaddr : 1;
Eina_Bool isv6 : 1;
};
static ares_channel info_channel;
@ -99,7 +100,7 @@ ecore_con_info_tcp_connect(Ecore_Con_Server *svr,
struct addrinfo hints;
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_UNSPEC;
hints.ai_family = AF_INET6;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_CANONNAME;
hints.ai_protocol = IPPROTO_TCP;
@ -118,7 +119,7 @@ ecore_con_info_tcp_listen(Ecore_Con_Server *svr,
struct addrinfo hints;
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_UNSPEC;
hints.ai_family = AF_INET6;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
hints.ai_protocol = IPPROTO_TCP;
@ -137,7 +138,7 @@ ecore_con_info_udp_connect(Ecore_Con_Server *svr,
struct addrinfo hints;
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_UNSPEC;
hints.ai_family = AF_INET6;
hints.ai_socktype = SOCK_DGRAM;
hints.ai_flags = AI_CANONNAME;
hints.ai_protocol = IPPROTO_UDP;
@ -156,7 +157,7 @@ ecore_con_info_udp_listen(Ecore_Con_Server *svr,
struct addrinfo hints;
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_UNSPEC;
hints.ai_family = AF_INET6;
hints.ai_socktype = SOCK_DGRAM;
hints.ai_flags = AI_PASSIVE;
hints.ai_protocol = IPPROTO_UDP;
@ -175,7 +176,7 @@ ecore_con_info_mcast_listen(Ecore_Con_Server *svr,
struct addrinfo hints;
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_UNSPEC;
hints.ai_family = AF_INET6;
hints.ai_socktype = SOCK_DGRAM;
hints.ai_flags = 0;
hints.ai_protocol = IPPROTO_UDP;
@ -186,6 +187,47 @@ ecore_con_info_mcast_listen(Ecore_Con_Server *svr,
return ecore_con_info_get(svr, done_cb, data, &hints);
}
static Eina_Bool
_ecore_con_info_ares_getnameinfo(Ecore_Con_CAres *arg,
int addrtype, const char *name,
struct sockaddr *addr, int addrlen)
{
int length = 0;
if (name)
length = strlen(name) + 1;
else
length = 1;
arg->result = malloc(sizeof (Ecore_Con_Info) + length);
if (!arg->result)
return EINA_FALSE;
/* FIXME: What to do when hint is not set ? */
arg->result->info.ai_flags = arg->hints.ai_flags;
arg->result->info.ai_socktype = arg->hints.ai_socktype;
arg->result->info.ai_protocol = arg->hints.ai_protocol;
arg->result->info.ai_family = addrtype;
arg->result->info.ai_addrlen = addrlen;
arg->result->info.ai_addr = addr;
arg->result->info.ai_canonname = (char*) (arg->result + 1);
if (!name)
*arg->result->info.ai_canonname = '\0';
else
strcpy(arg->result->info.ai_canonname, name);
arg->result->info.ai_next = NULL;
ares_getnameinfo(info_channel, addr, addrlen,
ARES_NI_NUMERICSERV | ARES_NI_NUMERICHOST | ARES_NI_LOOKUPSERVICE | ARES_NI_LOOKUPHOST,
(ares_nameinfo_callback) _ecore_con_info_ares_nameinfo, arg);
return EINA_TRUE;
}
EAPI int
ecore_con_info_get(Ecore_Con_Server *svr,
Ecore_Con_Info_Cb done_cb,
@ -193,7 +235,7 @@ ecore_con_info_get(Ecore_Con_Server *svr,
struct addrinfo *hints)
{
Ecore_Con_CAres *cares;
int ai_family = AF_UNSPEC;
int ai_family = AF_INET6;
cares = calloc(1, sizeof (Ecore_Con_CAres));
if (!cares) return 0;
@ -211,11 +253,13 @@ ecore_con_info_get(Ecore_Con_Server *svr,
if (inet_pton(AF_INET, svr->name, &cares->addr.v4) == 1)
{
cares->byaddr = EINA_TRUE;
cares->isv6 = EINA_FALSE;
ares_gethostbyaddr(info_channel, &cares->addr.v4, sizeof (cares->addr.v4), AF_INET, (ares_host_callback) _ecore_con_info_ares_host_cb, cares);
}
else if (inet_pton(AF_INET6, svr->name, &cares->addr.v6) == 1)
{
cares->byaddr = EINA_TRUE;
cares->isv6 = EINA_TRUE;
ares_gethostbyaddr(info_channel, &cares->addr.v6, sizeof (cares->addr.v6), AF_INET6, (ares_host_callback) _ecore_con_info_ares_host_cb, cares);
}
else
@ -367,16 +411,13 @@ _ecore_con_info_ares_host_cb(Ecore_Con_CAres *arg, int status, int timeouts, str
addrlen = sizeof (struct sockaddr_in);
addri = malloc(addrlen);
if (!addri)
{
fprintf(stderr, "Not enough memory\n");
goto on_error;
}
if (!addri) goto on_mem_error;
addri->sin_family = AF_INET;
addri->sin_port = htons(arg->svr->port);
memcpy(&addri->sin_addr.s_addr, arg->byaddr ? &arg->addr.v4 : (struct in_addr*)hostent->h_addr_list[0], sizeof (struct in_addr));
memcpy(&addri->sin_addr.s_addr,
hostent->h_addr_list[0], sizeof (struct in_addr));
addr = (struct sockaddr*) addri;
break;
@ -388,18 +429,15 @@ _ecore_con_info_ares_host_cb(Ecore_Con_CAres *arg, int status, int timeouts, str
addrlen = sizeof (struct sockaddr_in6);
addri6 = malloc(addrlen);
if (!addri6)
{
fprintf(stderr, "Not enough memory\n");
goto on_error;
}
if (!addri6) goto on_mem_error;
addri6->sin6_family = AF_INET6;
addri6->sin6_port = htons(arg->svr->port);
addri6->sin6_flowinfo = 0;
addri6->sin6_scope_id = 0;
memcpy(&addri6->sin6_addr.s6_addr, arg->byaddr ? &arg->addr.v6 : (struct in6_addr*)hostent->h_addr_list[0], sizeof (struct in6_addr));
memcpy(&addri6->sin6_addr.s6_addr,
hostent->h_addr_list[0], sizeof (struct in6_addr));
addr = (struct sockaddr*) addri6;
break;
@ -409,38 +447,58 @@ _ecore_con_info_ares_host_cb(Ecore_Con_CAres *arg, int status, int timeouts, str
goto on_error;
}
if (hostent->h_name)
length = strlen(hostent->h_name) + 1;
arg->result = malloc(sizeof (Ecore_Con_Info) + length);
if (!arg->result)
{
fprintf(stderr, "Not enough memory\n");
free(addr);
goto on_error;
}
/* FIXME: What to do when hint is not set ? */
arg->result->info.ai_flags = arg->hints.ai_flags;
arg->result->info.ai_socktype = arg->hints.ai_socktype;
arg->result->info.ai_protocol = arg->hints.ai_protocol;
arg->result->info.ai_family = hostent->h_addrtype;
arg->result->info.ai_addrlen = addrlen;
arg->result->info.ai_addr = addr;
arg->result->info.ai_canonname = (char*) (arg->result + 1);
strcpy(arg->result->info.ai_canonname, hostent->h_name);
arg->result->info.ai_next = NULL;
ares_getnameinfo(info_channel, addr, addrlen,
ARES_NI_NUMERICSERV | ARES_NI_NUMERICHOST | ARES_NI_LOOKUPSERVICE | ARES_NI_LOOKUPHOST,
(ares_nameinfo_callback) _ecore_con_info_ares_nameinfo, arg);
if (!_ecore_con_info_ares_getnameinfo(arg, hostent->h_addrtype, hostent->h_name,
addr, addrlen))
goto on_error;
break;
case ARES_ENOTFOUND: /* address notfound */
if (arg->byaddr)
{
/* This happen when host doesn't have a reverse. */
if (arg->isv6)
{
struct sockaddr_in6 *addri6;
addrlen = sizeof (struct sockaddr_in6);
addri6 = malloc(addrlen);
if (!addri6) goto on_mem_error;
addri6->sin6_family = AF_INET6;
addri6->sin6_port = htons(arg->svr->port);
addri6->sin6_flowinfo = 0;
addri6->sin6_scope_id = 0;
memcpy(&addri6->sin6_addr.s6_addr,
&arg->addr.v6, sizeof (struct in6_addr));
addr = (struct sockaddr*) addri6;
}
else
{
struct sockaddr_in *addri;
addrlen = sizeof (struct sockaddr_in);
addri = malloc(addrlen);
if (!addri) goto on_mem_error;
addri->sin_family = AF_INET;
addri->sin_port = htons(arg->svr->port);
memcpy(&addri->sin_addr.s_addr,
&arg->addr.v4, sizeof (struct in_addr));
addr = (struct sockaddr*) addri;
}
if (!_ecore_con_info_ares_getnameinfo(arg, arg->isv6 ? AF_INET6 : AF_INET,
NULL, addr, addrlen))
goto on_error;
break;
}
case ARES_ENOTIMP: /* unknown family */
case ARES_EBADNAME: /* not a valid internet address */
case ARES_ENOTFOUND: /* address notfound */
case ARES_ENOMEM: /* not enough memory */
case ARES_EDESTRUCTION: /* request canceled, shuting down */
goto on_error;
@ -451,6 +509,9 @@ _ecore_con_info_ares_host_cb(Ecore_Con_CAres *arg, int status, int timeouts, str
return ;
on_mem_error:
fprintf(stderr, "Not enough memory\n");
on_error:
arg->done_cb(arg->data, NULL);
free(arg);