Merge "libcutils: try all addresses in socket_network_client_timeout."
This commit is contained in:
commit
f3d43032d2
2 changed files with 77 additions and 56 deletions
|
|
@ -207,6 +207,28 @@ class NonApiTest(unittest.TestCase):
|
||||||
# reading the response from the adb emu kill command (on Windows).
|
# reading the response from the adb emu kill command (on Windows).
|
||||||
self.assertEqual(0, p.returncode)
|
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():
|
def main():
|
||||||
random.seed(0)
|
random.seed(0)
|
||||||
|
|
|
||||||
|
|
@ -59,64 +59,63 @@ int socket_network_client_timeout(const char* host, int port, int type, int time
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: try all the addresses if there's more than one?
|
int result = -1;
|
||||||
int family = addrs[0].ai_family;
|
for (struct addrinfo* addr = addrs; addr != NULL; addr = addr->ai_next) {
|
||||||
int protocol = addrs[0].ai_protocol;
|
// The Mac doesn't have SOCK_NONBLOCK.
|
||||||
socklen_t addr_len = addrs[0].ai_addrlen;
|
int s = socket(addr->ai_family, type, addr->ai_protocol);
|
||||||
struct sockaddr_storage addr;
|
if (s == -1 || toggle_O_NONBLOCK(s) == -1) return -1;
|
||||||
memcpy(&addr, addrs[0].ai_addr, addr_len);
|
|
||||||
|
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);
|
freeaddrinfo(addrs);
|
||||||
|
return result;
|
||||||
// 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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int socket_network_client(const char* host, int port, int type) {
|
int socket_network_client(const char* host, int port, int type) {
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue