diff --git a/adb/Android.mk b/adb/Android.mk index a05bb551e..f19ef4d00 100644 --- a/adb/Android.mk +++ b/adb/Android.mk @@ -81,12 +81,14 @@ LIBADB_windows_CFLAGS := \ LIBADB_darwin_SRC_FILES := \ sysdeps_unix.cpp \ + sysdeps/posix/network.cpp \ client/usb_dispatch.cpp \ client/usb_libusb.cpp \ client/usb_osx.cpp \ LIBADB_linux_SRC_FILES := \ sysdeps_unix.cpp \ + sysdeps/posix/network.cpp \ client/usb_dispatch.cpp \ client/usb_libusb.cpp \ client/usb_linux.cpp \ @@ -123,6 +125,7 @@ LOCAL_SRC_FILES := \ $(LIBADB_SRC_FILES) \ adbd_auth.cpp \ jdwp_service.cpp \ + sysdeps/posix/network.cpp \ LOCAL_SANITIZE := $(adb_target_sanitize) diff --git a/adb/sysdeps.h b/adb/sysdeps.h index f95a8556f..5cd0cd1ac 100644 --- a/adb/sysdeps.h +++ b/adb/sysdeps.h @@ -35,6 +35,7 @@ #include #include "sysdeps/errno.h" +#include "sysdeps/network.h" #include "sysdeps/stat.h" /* @@ -248,8 +249,6 @@ extern int unix_open(const char* path, int options, ...); int unix_isatty(int fd); #define isatty ___xxx_isatty -int network_loopback_client(int port, int type, std::string* error); -int network_loopback_server(int port, int type, std::string* error); int network_inaddr_any_server(int port, int type, std::string* error); inline int network_local_client(const char* name, int namespace_id, int type, std::string* error) { @@ -587,17 +586,6 @@ inline int _fd_set_error_str(int fd, std::string* error) { return fd; } -inline int network_loopback_client(int port, int type, std::string* error) { - return _fd_set_error_str(socket_network_client("localhost", port, type), error); -} - -inline int network_loopback_server(int port, int type, std::string* error) { - int fd = socket_loopback_server(port, type); - if (fd < 0 && errno == EAFNOSUPPORT) - return _fd_set_error_str(socket_loopback_server6(port, type), error); - return _fd_set_error_str(fd, error); -} - inline int network_inaddr_any_server(int port, int type, std::string* error) { return _fd_set_error_str(socket_inaddr_any_server(port, type), error); } diff --git a/adb/sysdeps/network.h b/adb/sysdeps/network.h new file mode 100644 index 000000000..83ce37112 --- /dev/null +++ b/adb/sysdeps/network.h @@ -0,0 +1,22 @@ +#pragma once + +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +int network_loopback_client(int port, int type, std::string* error); +int network_loopback_server(int port, int type, std::string* error); diff --git a/adb/sysdeps/posix/network.cpp b/adb/sysdeps/posix/network.cpp new file mode 100644 index 000000000..45da5af4a --- /dev/null +++ b/adb/sysdeps/posix/network.cpp @@ -0,0 +1,127 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "sysdeps/network.h" + +#include +#include +#include + +#include + +#include "adb_unique_fd.h" + +static void set_error(std::string* error) { + if (error) { + *error = strerror(errno); + } +} + +static sockaddr* loopback_addr4(sockaddr_storage* addr, socklen_t* addrlen, int port) { + struct sockaddr_in* addr4 = reinterpret_cast(addr); + *addrlen = sizeof(*addr4); + + addr4->sin_family = AF_INET; + addr4->sin_addr.s_addr = htonl(INADDR_LOOPBACK); + addr4->sin_port = htons(port); + return reinterpret_cast(addr); +} + +static sockaddr* loopback_addr6(sockaddr_storage* addr, socklen_t* addrlen, int port) { + struct sockaddr_in6* addr6 = reinterpret_cast(addr); + *addrlen = sizeof(*addr6); + + addr6->sin6_family = AF_INET6; + addr6->sin6_addr = in6addr_loopback; + addr6->sin6_port = htons(port); + return reinterpret_cast(addr); +} + +static int _network_loopback_client(bool ipv6, int port, int type, std::string* error) { + unique_fd s(socket(ipv6 ? AF_INET6 : AF_INET, type, 0)); + if (s == -1) { + set_error(error); + return -1; + } + + struct sockaddr_storage addr_storage = {}; + socklen_t addrlen = sizeof(addr_storage); + sockaddr* addr = (ipv6 ? loopback_addr6 : loopback_addr4)(&addr_storage, &addrlen, 0); + + if (bind(s.get(), addr, addrlen) != 0) { + set_error(error); + return -1; + } + + addr = (ipv6 ? loopback_addr6 : loopback_addr4)(&addr_storage, &addrlen, port); + + if (connect(s.get(), addr, addrlen) != 0) { + set_error(error); + return -1; + } + + return s.release(); +} + +int network_loopback_client(int port, int type, std::string* error) { + // Try IPv4 first, use IPv6 as a fallback. + int rc = _network_loopback_client(false, port, type, error); + if (rc == -1) { + return _network_loopback_client(true, port, type, error); + } + return rc; +} + +static int _network_loopback_server(bool ipv6, int port, int type, std::string* error) { + unique_fd s(socket(ipv6 ? AF_INET6 : AF_INET, type, 0)); + if (s == -1) { + set_error(error); + return -1; + } + + int n = 1; + setsockopt(s.get(), SOL_SOCKET, SO_REUSEADDR, &n, sizeof(n)); + + struct sockaddr_storage addr_storage = {}; + socklen_t addrlen = sizeof(addr_storage); + sockaddr* addr = (ipv6 ? loopback_addr6 : loopback_addr4)(&addr_storage, &addrlen, port); + + if (bind(s, addr, addrlen) != 0) { + set_error(error); + return -1; + } + + if (type == SOCK_STREAM || type == SOCK_SEQPACKET) { + // Arbitrarily selected value, ported from libcutils. + if (listen(s, 4) != 0) { + set_error(error); + return -1; + } + } + + return s.release(); +} + +int network_loopback_server(int port, int type, std::string* error) { + int rc = _network_loopback_server(false, port, type, error); + + // Only attempt to listen on IPv6 if IPv4 is unavailable. + // We don't want to start an IPv6 server if there's already an IPv4 one running. + if (rc == -1 && (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT)) { + return _network_loopback_server(true, port, type, error); + } + return rc; +} diff --git a/libcutils/Android.bp b/libcutils/Android.bp index f668f18e5..bb82f4da3 100644 --- a/libcutils/Android.bp +++ b/libcutils/Android.bp @@ -24,7 +24,6 @@ libcutils_nonwindows_sources = [ "socket_inaddr_any_server_unix.c", "socket_local_client_unix.c", "socket_local_server_unix.c", - "socket_loopback_server_unix.c", "socket_network_client_unix.c", "sockets_unix.cpp", "str_parms.c", diff --git a/libcutils/include/cutils/sockets.h b/libcutils/include/cutils/sockets.h index d724dd6a5..b24468bf4 100644 --- a/libcutils/include/cutils/sockets.h +++ b/libcutils/include/cutils/sockets.h @@ -88,8 +88,6 @@ int android_get_control_socket(const char* name); cutils_socket_t socket_network_client(const char* host, int port, int type); int socket_network_client_timeout(const char* host, int port, int type, int timeout, int* getaddrinfo_error); -int socket_loopback_server(int port, int type); -int socket_loopback_server6(int port, int type); int socket_local_server(const char* name, int namespaceId, int type); int socket_local_server_bind(int s, const char* name, int namespaceId); int socket_local_client_connect(int fd, const char *name, int namespaceId, diff --git a/libcutils/socket_loopback_server_unix.c b/libcutils/socket_loopback_server_unix.c deleted file mode 100644 index 7b92fd62d..000000000 --- a/libcutils/socket_loopback_server_unix.c +++ /dev/null @@ -1,88 +0,0 @@ -/* -** Copyright 2006, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You may obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - -#include -#include -#include -#include -#include - -#define LISTEN_BACKLOG 4 - -#if !defined(_WIN32) -#include -#include -#include -#include -#endif - -#include - -static int _socket_loopback_server(int family, int type, struct sockaddr * addr, size_t size) -{ - int s, n; - - s = socket(family, type, 0); - if(s < 0) - return -1; - - n = 1; - setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (const char *) &n, sizeof(n)); - - if(bind(s, addr, size) < 0) { - close(s); - return -1; - } - - if (type == SOCK_STREAM) { - int ret; - - ret = listen(s, LISTEN_BACKLOG); - - if (ret < 0) { - close(s); - return -1; - } - } - - return s; -} - -/* open listen() port on loopback IPv6 interface */ -int socket_loopback_server6(int port, int type) -{ - struct sockaddr_in6 addr; - - memset(&addr, 0, sizeof(addr)); - addr.sin6_family = AF_INET6; - addr.sin6_port = htons(port); - addr.sin6_addr = in6addr_loopback; - - return _socket_loopback_server(AF_INET6, type, (struct sockaddr *) &addr, sizeof(addr)); -} - -/* open listen() port on loopback interface */ -int socket_loopback_server(int port, int type) -{ - struct sockaddr_in addr; - - memset(&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_port = htons(port); - addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); - - return _socket_loopback_server(AF_INET, type, (struct sockaddr *) &addr, sizeof(addr)); -}