Merge "libcutils: try all addresses in socket_network_client_timeout."

am: f3d43032d2

Change-Id: I373ce6f43a7164754930c62c7fe249ed6530cfd0
This commit is contained in:
Josh Gao 2016-09-02 00:52:38 +00:00 committed by android-build-merger
commit b7011e0410
2 changed files with 77 additions and 56 deletions

View File

@ -207,6 +207,28 @@ class NonApiTest(unittest.TestCase):
# reading the response from the adb emu kill command (on Windows).
self.assertEqual(0, p.returncode)
def test_connect_ipv4_ipv6(self):
"""Ensure that `adb connect localhost:1234` will try both IPv4 and IPv6.
Bug: http://b/30313466
"""
ipv4 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
ipv4.bind(('127.0.0.1', 0))
ipv4.listen(1)
ipv6 = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
ipv6.bind(('::1', ipv4.getsockname()[1] + 1))
ipv6.listen(1)
for s in (ipv4, ipv6):
port = s.getsockname()[1]
output = subprocess.check_output(
['adb', 'connect', 'localhost:{}'.format(port)])
self.assertEqual(
output.strip(), 'connected to localhost:{}'.format(port))
s.close()
def main():
random.seed(0)

View File

@ -59,64 +59,63 @@ int socket_network_client_timeout(const char* host, int port, int type, int time
return -1;
}
// TODO: try all the addresses if there's more than one?
int family = addrs[0].ai_family;
int protocol = addrs[0].ai_protocol;
socklen_t addr_len = addrs[0].ai_addrlen;
struct sockaddr_storage addr;
memcpy(&addr, addrs[0].ai_addr, addr_len);
int result = -1;
for (struct addrinfo* addr = addrs; addr != NULL; addr = addr->ai_next) {
// The Mac doesn't have SOCK_NONBLOCK.
int s = socket(addr->ai_family, type, addr->ai_protocol);
if (s == -1 || toggle_O_NONBLOCK(s) == -1) return -1;
int rc = connect(s, addr->ai_addr, addr->ai_addrlen);
if (rc == 0) {
result = toggle_O_NONBLOCK(s);
break;
} else if (rc == -1 && errno != EINPROGRESS) {
close(s);
continue;
}
fd_set r_set;
FD_ZERO(&r_set);
FD_SET(s, &r_set);
fd_set w_set = r_set;
struct timeval ts;
ts.tv_sec = timeout;
ts.tv_usec = 0;
if ((rc = select(s + 1, &r_set, &w_set, NULL, (timeout != 0) ? &ts : NULL)) == -1) {
close(s);
break;
}
if (rc == 0) { // we had a timeout
errno = ETIMEDOUT;
close(s);
break;
}
int error = 0;
socklen_t len = sizeof(error);
if (FD_ISSET(s, &r_set) || FD_ISSET(s, &w_set)) {
if (getsockopt(s, SOL_SOCKET, SO_ERROR, &error, &len) < 0) {
close(s);
break;
}
} else {
close(s);
break;
}
if (error) { // check if we had a socket error
// TODO: Update the timeout.
errno = error;
close(s);
continue;
}
result = toggle_O_NONBLOCK(s);
}
freeaddrinfo(addrs);
// The Mac doesn't have SOCK_NONBLOCK.
int s = socket(family, type, protocol);
if (s == -1 || toggle_O_NONBLOCK(s) == -1) return -1;
int rc = connect(s, (const struct sockaddr*) &addr, addr_len);
if (rc == 0) {
return toggle_O_NONBLOCK(s);
} else if (rc == -1 && errno != EINPROGRESS) {
close(s);
return -1;
}
fd_set r_set;
FD_ZERO(&r_set);
FD_SET(s, &r_set);
fd_set w_set = r_set;
struct timeval ts;
ts.tv_sec = timeout;
ts.tv_usec = 0;
if ((rc = select(s + 1, &r_set, &w_set, NULL, (timeout != 0) ? &ts : NULL)) == -1) {
close(s);
return -1;
}
if (rc == 0) { // we had a timeout
errno = ETIMEDOUT;
close(s);
return -1;
}
int error = 0;
socklen_t len = sizeof(error);
if (FD_ISSET(s, &r_set) || FD_ISSET(s, &w_set)) {
if (getsockopt(s, SOL_SOCKET, SO_ERROR, &error, &len) < 0) {
close(s);
return -1;
}
} else {
close(s);
return -1;
}
if (error) { // check if we had a socket error
errno = error;
close(s);
return -1;
}
return toggle_O_NONBLOCK(s);
return result;
}
int socket_network_client(const char* host, int port, int type) {