Merge commit '2e5574379e355feef79279ef6b2db0efe7c581e5' into honeycomb-release-to-dalvik-dev

This commit is contained in:
Brian Carlstrom 2011-02-01 13:49:41 -08:00
commit f10a41b5a1

View File

@ -347,35 +347,55 @@ str2number(const char *p)
return -1; return -1;
} }
/* Determine whether IPv6 connectivity is available. */ /*
* Connect a UDP socket to a given unicast address. This will cause no network
* traffic, but will fail fast if the system has no or limited reachability to
* the destination (e.g., no IPv4 address, no IPv6 default route, ...).
*/
static int static int
_have_ipv6() { _test_connect(int pf, struct sockaddr *addr, size_t addrlen) {
/* int s = socket(pf, SOCK_DGRAM, IPPROTO_UDP);
* Connect a UDP socket to an global unicast IPv6 address. This will
* cause no network traffic, but will fail fast if the system has no or
* limited IPv6 connectivity (e.g., only a link-local address).
*/
static const struct sockaddr_in6 sin6_test = {
/* family, port, flow label */
AF_INET6, 0, 0,
/* 2000:: */
{{{ 0x20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }}},
/* scope ID */
0};
sockaddr_union addr_test;
addr_test.in6 = sin6_test;
int s = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
if (s < 0) if (s < 0)
return 0; return 0;
int ret; int ret;
do { do {
ret = connect(s, &addr_test.generic, sizeof(addr_test.in6)); ret = connect(s, addr, addrlen);
} while (ret < 0 && errno == EINTR); } while (ret < 0 && errno == EINTR);
int have_ipv6 = (ret == 0); int success = (ret == 0);
do { do {
ret = close(s); ret = close(s);
} while (ret < 0 && errno == EINTR); } while (ret < 0 && errno == EINTR);
return have_ipv6; return success;
}
/*
* The following functions determine whether IPv4 or IPv6 connectivity is
* available in order to implement AI_ADDRCONFIG.
*
* Strictly speaking, AI_ADDRCONFIG should not look at whether connectivity is
* available, but whether addresses of the specified family are "configured
* on the local system". However, bionic doesn't currently support getifaddrs,
* so checking for connectivity is the next best thing.
*/
static int
_have_ipv6() {
static const struct sockaddr_in6 sin6_test = {
.sin6_family = AF_INET6,
.sin6_addr.s6_addr = { // 2000::
0x20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
};
sockaddr_union addr = { .in6 = sin6_test };
return _test_connect(PF_INET6, &addr.generic, sizeof(addr.in6));
}
static int
_have_ipv4() {
static const struct sockaddr_in sin_test = {
.sin_family = AF_INET,
.sin_addr.s_addr = __constant_htonl(0x08080808L) // 8.8.8.8
};
sockaddr_union addr = { .in = sin_test };
return _test_connect(PF_INET, &addr.generic, sizeof(addr.in));
} }
// Returns 0 on success, else returns non-zero on error (in which case // Returns 0 on success, else returns non-zero on error (in which case
@ -1525,9 +1545,13 @@ _get_scope(const struct sockaddr *addr)
#define IN6_IS_ADDR_6TO4(a) \ #define IN6_IS_ADDR_6TO4(a) \
(((a)->s6_addr[0] == 0x20) && ((a)->s6_addr[1] == 0x02)) (((a)->s6_addr[0] == 0x20) && ((a)->s6_addr[1] == 0x02))
/* 6bone testing address area (3ffe::/16), deprecated in RFC 3701. */
#define IN6_IS_ADDR_6BONE(a) \
(((a)->s6_addr[0] == 0x3f) && ((a)->s6_addr[1] == 0xfe))
/* /*
* Get the label for a given IPv4/IPv6 address. * Get the label for a given IPv4/IPv6 address.
* RFC 3484, section 2.1, plus Teredo added in with label 5. * RFC 3484, section 2.1, plus changes from draft-ietf-6man-rfc3484-revise-01.
*/ */
/*ARGSUSED*/ /*ARGSUSED*/
@ -1535,19 +1559,27 @@ static int
_get_label(const struct sockaddr *addr) _get_label(const struct sockaddr *addr)
{ {
if (addr->sa_family == AF_INET) { if (addr->sa_family == AF_INET) {
return 4; return 3;
} else if (addr->sa_family == AF_INET6) { } else if (addr->sa_family == AF_INET6) {
const struct sockaddr_in6 *addr6 = (const struct sockaddr_in6 *)addr; const struct sockaddr_in6 *addr6 = (const struct sockaddr_in6 *)addr;
if (IN6_IS_ADDR_LOOPBACK(&addr6->sin6_addr)) { if (IN6_IS_ADDR_LOOPBACK(&addr6->sin6_addr)) {
return 0; return 0;
} else if (IN6_IS_ADDR_V4COMPAT(&addr6->sin6_addr)) { } else if (IN6_IS_ADDR_ULA(&addr6->sin6_addr)) {
return 1;
} else if (IN6_IS_ADDR_V4MAPPED(&addr6->sin6_addr)) {
return 3; return 3;
} else if (IN6_IS_ADDR_6TO4(&addr6->sin6_addr)) {
return 4;
} else if (IN6_IS_ADDR_TEREDO(&addr6->sin6_addr)) { } else if (IN6_IS_ADDR_TEREDO(&addr6->sin6_addr)) {
return 5; return 5;
} else if (IN6_IS_ADDR_6TO4(&addr6->sin6_addr)) { } else if (IN6_IS_ADDR_V4COMPAT(&addr6->sin6_addr)) {
return 2; return 10;
} else if (IN6_IS_ADDR_SITELOCAL(&addr6->sin6_addr)) {
return 11;
} else if (IN6_IS_ADDR_6BONE(&addr6->sin6_addr)) {
return 12;
} else { } else {
return 1; return 2;
} }
} else { } else {
/* /*
@ -1560,7 +1592,7 @@ _get_label(const struct sockaddr *addr)
/* /*
* Get the precedence for a given IPv4/IPv6 address. * Get the precedence for a given IPv4/IPv6 address.
* RFC 3484, section 2.1, plus Teredo added in with precedence 25. * RFC 3484, section 2.1, plus changes from draft-ietf-6man-rfc3484-revise-01.
*/ */
/*ARGSUSED*/ /*ARGSUSED*/
@ -1568,22 +1600,28 @@ static int
_get_precedence(const struct sockaddr *addr) _get_precedence(const struct sockaddr *addr)
{ {
if (addr->sa_family == AF_INET) { if (addr->sa_family == AF_INET) {
return 10; return 30;
} else if (addr->sa_family == AF_INET6) { } else if (addr->sa_family == AF_INET6) {
const struct sockaddr_in6 *addr6 = (const struct sockaddr_in6 *)addr; const struct sockaddr_in6 *addr6 = (const struct sockaddr_in6 *)addr;
if (IN6_IS_ADDR_LOOPBACK(&addr6->sin6_addr)) { if (IN6_IS_ADDR_LOOPBACK(&addr6->sin6_addr)) {
return 60;
} else if (IN6_IS_ADDR_ULA(&addr6->sin6_addr)) {
return 50; return 50;
} else if (IN6_IS_ADDR_V4COMPAT(&addr6->sin6_addr)) { } else if (IN6_IS_ADDR_V4MAPPED(&addr6->sin6_addr)) {
return 30;
} else if (IN6_IS_ADDR_6TO4(&addr6->sin6_addr)) {
return 20; return 20;
} else if (IN6_IS_ADDR_TEREDO(&addr6->sin6_addr)) { } else if (IN6_IS_ADDR_TEREDO(&addr6->sin6_addr)) {
return 25; return 10;
} else if (IN6_IS_ADDR_6TO4(&addr6->sin6_addr)) { } else if (IN6_IS_ADDR_V4COMPAT(&addr6->sin6_addr) ||
return 30; IN6_IS_ADDR_SITELOCAL(&addr6->sin6_addr) ||
IN6_IS_ADDR_6BONE(&addr6->sin6_addr)) {
return 1;
} else { } else {
return 40; return 40;
} }
} else { } else {
return 5; return 1;
} }
} }
@ -1867,17 +1905,27 @@ _dns_getaddrinfo(void *rv, void *cb_data, va_list ap)
q.qclass = C_IN; q.qclass = C_IN;
q.answer = buf->buf; q.answer = buf->buf;
q.anslen = sizeof(buf->buf); q.anslen = sizeof(buf->buf);
/* If AI_ADDRCONFIG, lookup IPv6 only if we have connectivity */ int query_ipv6 = 1, query_ipv4 = 1;
if (!(pai->ai_flags & AI_ADDRCONFIG) || _have_ipv6()) { if (pai->ai_flags & AI_ADDRCONFIG) {
query_ipv6 = _have_ipv6();
query_ipv4 = _have_ipv4();
}
if (query_ipv6) {
q.qtype = T_AAAA; q.qtype = T_AAAA;
q.next = &q2; if (query_ipv4) {
q2.name = name; q.next = &q2;
q2.qclass = C_IN; q2.name = name;
q2.qtype = T_A; q2.qclass = C_IN;
q2.answer = buf2->buf; q2.qtype = T_A;
q2.anslen = sizeof(buf2->buf); q2.answer = buf2->buf;
} else { q2.anslen = sizeof(buf2->buf);
}
} else if (query_ipv4) {
q.qtype = T_A; q.qtype = T_A;
} else {
free(buf);
free(buf2);
return NS_NOTFOUND;
} }
break; break;
case AF_INET: case AF_INET: