diff options
-rw-r--r-- | adb.cpp | 7 | ||||
-rw-r--r-- | adb_client.cpp | 7 | ||||
-rw-r--r-- | adb_listeners.cpp | 24 | ||||
-rw-r--r-- | adb_listeners.h | 3 | ||||
-rw-r--r-- | adb_utils.cpp | 22 | ||||
-rw-r--r-- | adb_utils.h | 2 | ||||
-rw-r--r-- | client/main.cpp | 5 | ||||
-rw-r--r-- | console.cpp | 6 | ||||
-rw-r--r-- | daemon/main.cpp | 7 | ||||
-rw-r--r-- | services.cpp | 3 | ||||
-rw-r--r-- | sysdeps.h | 55 | ||||
-rw-r--r-- | sysdeps_win32.cpp | 413 | ||||
-rw-r--r-- | transport_local.cpp | 7 |
13 files changed, 366 insertions, 195 deletions
@@ -801,11 +801,13 @@ int handle_forward_request(const char* service, TransportType type, const char* return 1; } + std::string error; InstallStatus r; if (kill_forward) { r = remove_listener(pieces[0].c_str(), transport); } else { - r = install_listener(pieces[0], pieces[1].c_str(), transport, no_rebind); + r = install_listener(pieces[0], pieces[1].c_str(), transport, + no_rebind, &error); } if (r == INSTALL_STATUS_OK) { #if ADB_HOST @@ -821,7 +823,8 @@ int handle_forward_request(const char* service, TransportType type, const char* case INSTALL_STATUS_OK: message = "success (!)"; break; case INSTALL_STATUS_INTERNAL_ERROR: message = "internal error"; break; case INSTALL_STATUS_CANNOT_BIND: - message = android::base::StringPrintf("cannot bind to socket: %s", strerror(errno)); + message = android::base::StringPrintf("cannot bind to socket: %s", + error.c_str()); break; case INSTALL_STATUS_CANNOT_REBIND: message = android::base::StringPrintf("cannot rebind existing socket"); diff --git a/adb_client.cpp b/adb_client.cpp index 418662c..6d75966 100644 --- a/adb_client.cpp +++ b/adb_client.cpp @@ -153,8 +153,8 @@ int _adb_connect(const std::string& service, std::string* error) { } int fd; + std::string reason; if (__adb_server_name) { - std::string reason; fd = network_connect(__adb_server_name, __adb_server_port, SOCK_STREAM, 0, &reason); if (fd == -1) { *error = android::base::StringPrintf("can't connect to %s:%d: %s", @@ -163,9 +163,10 @@ int _adb_connect(const std::string& service, std::string* error) { return -2; } } else { - fd = socket_loopback_client(__adb_server_port, SOCK_STREAM); + fd = network_loopback_client(__adb_server_port, SOCK_STREAM, &reason); if (fd == -1) { - *error = perror_str("cannot connect to daemon"); + *error = android::base::StringPrintf("cannot connect to daemon: %s", + reason.c_str()); return -2; } } diff --git a/adb_listeners.cpp b/adb_listeners.cpp index bb45022..1e7ce5d 100644 --- a/adb_listeners.cpp +++ b/adb_listeners.cpp @@ -110,27 +110,30 @@ static void listener_disconnect(void* listener, atransport* t) { free_listener(reinterpret_cast<alistener*>(listener)); } -static int local_name_to_fd(const char* name) { +static int local_name_to_fd(const char* name, std::string* error) { if (!strncmp("tcp:", name, 4)) { int port = atoi(name + 4); if (gListenAll > 0) { - return socket_inaddr_any_server(port, SOCK_STREAM); + return network_inaddr_any_server(port, SOCK_STREAM, error); } else { - return socket_loopback_server(port, SOCK_STREAM); + return network_loopback_server(port, SOCK_STREAM, error); } } #if !defined(_WIN32) // No Unix-domain sockets on Windows. // It's nonsensical to support the "reserved" space on the adb host side if (!strncmp(name, "local:", 6)) { - return socket_local_server(name + 6, ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM); + return network_local_server(name + 6, + ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM, error); } else if (!strncmp(name, "localabstract:", 14)) { - return socket_local_server(name + 14, ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM); + return network_local_server(name + 14, + ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM, error); } else if (!strncmp(name, "localfilesystem:", 16)) { - return socket_local_server(name + 16, ANDROID_SOCKET_NAMESPACE_FILESYSTEM, SOCK_STREAM); + return network_local_server(name + 16, + ANDROID_SOCKET_NAMESPACE_FILESYSTEM, SOCK_STREAM, error); } #endif - printf("unknown local portname '%s'\n", name); + *error = android::base::StringPrintf("unknown local portname '%s'", name); return -1; } @@ -178,7 +181,8 @@ void remove_all_listeners(void) InstallStatus install_listener(const std::string& local_name, const char *connect_to, atransport* transport, - int no_rebind) + int no_rebind, + std::string* error) { for (alistener* l = listener_list.next; l != &listener_list; l = l->next) { if (local_name == l->local_name) { @@ -226,9 +230,9 @@ InstallStatus install_listener(const std::string& local_name, goto nomem; } - listener->fd = local_name_to_fd(listener->local_name); + listener->fd = local_name_to_fd(listener->local_name, error); if (listener->fd < 0) { - printf("cannot bind '%s': %s\n", listener->local_name, strerror(errno)); + printf("cannot bind '%s': %s\n", listener->local_name, error->c_str()); free(listener->local_name); free(listener->connect_to); free(listener); diff --git a/adb_listeners.h b/adb_listeners.h index 67deb21..fa98eed 100644 --- a/adb_listeners.h +++ b/adb_listeners.h @@ -33,7 +33,8 @@ enum InstallStatus { InstallStatus install_listener(const std::string& local_name, const char* connect_to, atransport* transport, - int no_rebind); + int no_rebind, + std::string* error); std::string format_listeners(); diff --git a/adb_utils.cpp b/adb_utils.cpp index 3ba971d..12208cd 100644 --- a/adb_utils.cpp +++ b/adb_utils.cpp @@ -28,17 +28,10 @@ #include <base/logging.h> #include <base/stringprintf.h> #include <base/strings.h> -#include <cutils/sockets.h> #include "adb_trace.h" #include "sysdeps.h" -#if defined(_WIN32) -#include <ws2tcpip.h> -#else -#include <netdb.h> -#endif - bool getcwd(std::string* s) { char* cwd = getcwd(nullptr, 0); if (cwd != nullptr) *s = cwd; @@ -178,18 +171,3 @@ bool parse_host_and_port(const std::string& address, << " (" << *canonical_address << ")"; return true; } - -int network_connect(const std::string& host, int port, int type, int timeout, std::string* error) { - int getaddrinfo_error = 0; - int fd = socket_network_client_timeout(host.c_str(), port, type, timeout, &getaddrinfo_error); - if (fd != -1) { - return fd; - } - if (getaddrinfo_error != 0) { - // TODO: gai_strerror is not thread safe on Win32. - *error = gai_strerror(getaddrinfo_error); - } else { - *error = strerror(errno); - } - return -1; -} diff --git a/adb_utils.h b/adb_utils.h index 30cd7a4..8c5208c 100644 --- a/adb_utils.h +++ b/adb_utils.h @@ -40,6 +40,4 @@ bool parse_host_and_port(const std::string& address, std::string* host, int* port, std::string* error); -int network_connect(const std::string& host, int port, int type, int timeout, std::string* error); - #endif diff --git a/client/main.cpp b/client/main.cpp index c018b8a..2b174cd 100644 --- a/client/main.cpp +++ b/client/main.cpp @@ -150,9 +150,10 @@ int adb_main(int is_daemon, int server_port) { local_init(DEFAULT_ADB_LOCAL_TRANSPORT_PORT); adb_auth_init(); + std::string error; std::string local_name = android::base::StringPrintf("tcp:%d", server_port); - if (install_listener(local_name, "*smartsocket*", nullptr, 0)) { - LOG(FATAL) << "Could not install *smartsocket* listener"; + if (install_listener(local_name, "*smartsocket*", nullptr, 0, &error)) { + LOG(FATAL) << "Could not install *smartsocket* listener: " << error; } if (is_daemon) { diff --git a/console.cpp b/console.cpp index b7f5345..ba5a72b 100644 --- a/console.cpp +++ b/console.cpp @@ -71,9 +71,11 @@ static int connect_to_console(const char* serial) { return -1; } - int fd = socket_loopback_client(port, SOCK_STREAM); + std::string error; + int fd = network_loopback_client(port, SOCK_STREAM, &error); if (fd == -1) { - fprintf(stderr, "error: could not connect to TCP port %d\n", port); + fprintf(stderr, "error: could not connect to TCP port %d: %s\n", port, + error.c_str()); return -1; } return fd; diff --git a/daemon/main.cpp b/daemon/main.cpp index 157c97b..a63d67e 100644 --- a/daemon/main.cpp +++ b/daemon/main.cpp @@ -177,10 +177,13 @@ int adbd_main(int server_port) { LOG(FATAL) << "Could not set selinux context"; } } + std::string error; std::string local_name = android::base::StringPrintf("tcp:%d", server_port); - if (install_listener(local_name, "*smartsocket*", nullptr, 0)) { - LOG(FATAL) << "Could not install *smartsocket* listener"; + if (install_listener(local_name, "*smartsocket*", nullptr, 0, + &error)) { + LOG(FATAL) << "Could not install *smartsocket* listener: " + << error; } } diff --git a/services.cpp b/services.cpp index 708ef42..63a0a76 100644 --- a/services.cpp +++ b/services.cpp @@ -432,7 +432,8 @@ int service_to_fd(const char *name) int port = atoi(name + 4); name = strchr(name + 4, ':'); if(name == 0) { - ret = socket_loopback_client(port, SOCK_STREAM); + std::string error; + ret = network_loopback_client(port, SOCK_STREAM, &error); if (ret >= 0) disable_tcp_nagle(ret); } else { @@ -26,6 +26,8 @@ #include <errno.h> +#include <string> + /* * TEMP_FAILURE_RETRY is defined by some, but not all, versions of * <unistd.h>. (Alas, it is not as standard as we'd hoped!) So, if it's @@ -212,6 +214,12 @@ static __inline__ void adb_sleep_ms( int mseconds ) Sleep( mseconds ); } +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); +int network_connect(const std::string& host, int port, int type, int timeout, + std::string* error); + extern int adb_socket_accept(int serverfd, struct sockaddr* addr, socklen_t *addrlen); #undef accept @@ -240,10 +248,14 @@ static __inline__ int adb_is_absolute_host_path(const char* path) { return isalpha(path[0]) && path[1] == ':' && path[2] == '\\'; } +// Like strerror(), but for Win32 error codes. +std::string SystemErrorCodeToString(DWORD error_code); + #else /* !_WIN32 a.k.a. Unix */ #include "fdevent.h" #include <cutils/misc.h> +#include <cutils/sockets.h> #include <cutils/threads.h> #include <signal.h> #include <sys/wait.h> @@ -254,6 +266,7 @@ static __inline__ int adb_is_absolute_host_path(const char* path) { #include <unistd.h> #include <fcntl.h> #include <stdarg.h> +#include <netdb.h> #include <netinet/in.h> #include <netinet/tcp.h> #include <string.h> @@ -404,6 +417,48 @@ static __inline__ int adb_creat(const char* path, int mode) #undef creat #define creat ___xxx_creat +// Helper for network_* functions. +inline int _fd_set_error_str(int fd, std::string* error) { + if (fd == -1) { + *error = strerror(errno); + } + return fd; +} + +inline int network_loopback_client(int port, int type, std::string* error) { + return _fd_set_error_str(socket_loopback_client(port, type), error); +} + +inline int network_loopback_server(int port, int type, std::string* error) { + return _fd_set_error_str(socket_loopback_server(port, type), 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); +} + +inline int network_local_server(const char *name, int namespace_id, int type, + std::string* error) { + return _fd_set_error_str(socket_local_server(name, namespace_id, type), + error); +} + +inline int network_connect(const std::string& host, int port, int type, + int timeout, std::string* error) { + int getaddrinfo_error = 0; + int fd = socket_network_client_timeout(host.c_str(), port, type, timeout, + &getaddrinfo_error); + if (fd != -1) { + return fd; + } + if (getaddrinfo_error != 0) { + *error = gai_strerror(getaddrinfo_error); + } else { + *error = strerror(errno); + } + return -1; +} + static __inline__ int adb_socket_accept(int serverfd, struct sockaddr* addr, socklen_t *addrlen) { int fd; diff --git a/sysdeps_win32.cpp b/sysdeps_win32.cpp index a274892..9fdc24c 100644 --- a/sysdeps_win32.cpp +++ b/sysdeps_win32.cpp @@ -25,8 +25,15 @@ #include <stdio.h> #include <stdlib.h> +#include <memory> +#include <string> + #include <cutils/sockets.h> +#include <base/logging.h> +#include <base/stringprintf.h> +#include <base/strings.h> + #include "adb.h" extern void fatal(const char *fmt, ...); @@ -80,6 +87,29 @@ static const FHClassRec _fh_socket_class = { #define assert(cond) do { if (!(cond)) fatal( "assertion failed '%s' on %s:%ld\n", #cond, __FILE__, __LINE__ ); } while (0) +std::string SystemErrorCodeToString(const DWORD error_code) { + const int kErrorMessageBufferSize = 256; + char msgbuf[kErrorMessageBufferSize]; + DWORD flags = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS; + DWORD len = FormatMessageA(flags, nullptr, error_code, 0, msgbuf, + arraysize(msgbuf), nullptr); + if (len == 0) { + return android::base::StringPrintf( + "Error (%lu) while retrieving error. (%lu)", GetLastError(), + error_code); + } + + std::string msg(msgbuf); + // Messages returned by the system end with line breaks. + msg = android::base::Trim(msg); + // There are many Windows error messages compared to POSIX, so include the + // numeric error code for easier, quicker, accurate identification. Use + // decimal instead of hex because there are decimal ranges like 10000-11999 + // for Winsock. + android::base::StringAppendF(&msg, " (%lu)", error_code); + return msg; +} + /**************************************************************************/ /**************************************************************************/ /***** *****/ @@ -253,6 +283,23 @@ _fh_close( FH f ) return 0; } +// Deleter for unique_fh. +class fh_deleter { + public: + void operator()(struct FHRec_* fh) { + // We're called from a destructor and destructors should not overwrite + // errno because callers may do: + // errno = EBLAH; + // return -1; // calls destructor, which should not overwrite errno + const int saved_errno = errno; + _fh_close(fh); + errno = saved_errno; + } +}; + +// Like std::unique_ptr, but calls _fh_close() instead of operator delete(). +typedef std::unique_ptr<struct FHRec_, fh_deleter> unique_fh; + /**************************************************************************/ /**************************************************************************/ /***** *****/ @@ -467,21 +514,6 @@ int adb_lseek(int fd, int pos, int where) } -int adb_shutdown(int fd) -{ - FH f = _fh_from_int(fd, __func__); - - if (!f || f->clazz != &_fh_socket_class) { - D("adb_shutdown: invalid fd %d\n", fd); - return -1; - } - - D( "adb_shutdown: %s\n", f->name); - shutdown( f->fh_socket, SD_BOTH ); - return 0; -} - - int adb_close(int fd) { FH f = _fh_from_int(fd, __func__); @@ -505,29 +537,63 @@ int adb_close(int fd) #undef setsockopt -static void _socket_set_errno( void ) { - switch (WSAGetLastError()) { +static void _socket_set_errno( const DWORD err ) { + // The Windows C Runtime (MSVCRT.DLL) strerror() does not support a lot of + // POSIX and socket error codes, so this can only meaningfully map so much. + switch ( err ) { case 0: errno = 0; break; case WSAEWOULDBLOCK: errno = EAGAIN; break; case WSAEINTR: errno = EINTR; break; + case WSAEFAULT: errno = EFAULT; break; + case WSAEINVAL: errno = EINVAL; break; + case WSAEMFILE: errno = EMFILE; break; default: - D( "_socket_set_errno: unhandled value %d\n", WSAGetLastError() ); errno = EINVAL; + D( "_socket_set_errno: mapping Windows error code %lu to errno %d\n", + err, errno ); } } static void _fh_socket_init( FH f ) { f->fh_socket = INVALID_SOCKET; f->event = WSACreateEvent(); + if (f->event == WSA_INVALID_EVENT) { + D("WSACreateEvent failed: %s\n", + SystemErrorCodeToString(WSAGetLastError()).c_str()); + + // _event_socket_start assumes that this field is INVALID_HANDLE_VALUE + // on failure, instead of NULL which is what Windows really returns on + // error. It might be better to change all the other code to look for + // NULL, but that is a much riskier change. + f->event = INVALID_HANDLE_VALUE; + } f->mask = 0; } static int _fh_socket_close( FH f ) { - /* gently tell any peer that we're closing the socket */ - shutdown( f->fh_socket, SD_BOTH ); - closesocket( f->fh_socket ); - f->fh_socket = INVALID_SOCKET; - CloseHandle( f->event ); + if (f->fh_socket != INVALID_SOCKET) { + /* gently tell any peer that we're closing the socket */ + if (shutdown(f->fh_socket, SD_BOTH) == SOCKET_ERROR) { + // If the socket is not connected, this returns an error. We want to + // minimize logging spam, so don't log these errors for now. +#if 0 + D("socket shutdown failed: %s\n", + SystemErrorCodeToString(WSAGetLastError()).c_str()); +#endif + } + if (closesocket(f->fh_socket) == SOCKET_ERROR) { + D("closesocket failed: %s\n", + SystemErrorCodeToString(WSAGetLastError()).c_str()); + } + f->fh_socket = INVALID_SOCKET; + } + if (f->event != NULL) { + if (!CloseHandle(f->event)) { + D("CloseHandle failed: %s\n", + SystemErrorCodeToString(GetLastError()).c_str()); + } + f->event = NULL; + } f->mask = 0; return 0; } @@ -540,7 +606,10 @@ static int _fh_socket_lseek( FH f, int pos, int origin ) { static int _fh_socket_read(FH f, void* buf, int len) { int result = recv(f->fh_socket, reinterpret_cast<char*>(buf), len, 0); if (result == SOCKET_ERROR) { - _socket_set_errno(); + const DWORD err = WSAGetLastError(); + D("recv fd %d failed: %s\n", _fh_to_int(f), + SystemErrorCodeToString(err).c_str()); + _socket_set_errno(err); result = -1; } return result; @@ -549,7 +618,10 @@ static int _fh_socket_read(FH f, void* buf, int len) { static int _fh_socket_write(FH f, const void* buf, int len) { int result = send(f->fh_socket, reinterpret_cast<const char*>(buf), len, 0); if (result == SOCKET_ERROR) { - _socket_set_errno(); + const DWORD err = WSAGetLastError(); + D("send fd %d failed: %s\n", _fh_to_int(f), + SystemErrorCodeToString(err).c_str()); + _socket_set_errno(err); result = -1; } return result; @@ -570,31 +642,39 @@ static int _winsock_init; static void _cleanup_winsock( void ) { + // TODO: WSAStartup() might be called multiple times and this won't properly + // cleanup the right number of times. Plus, WSACleanup() probably doesn't + // make sense since it might interrupt other threads using Winsock (since + // our various threads are not explicitly cleanly shutdown at process exit). WSACleanup(); } static void _init_winsock( void ) { + // TODO: Multiple threads calling this may potentially cause multiple calls + // to WSAStartup() and multiple atexit() calls. if (!_winsock_init) { WSADATA wsaData; int rc = WSAStartup( MAKEWORD(2,2), &wsaData); if (rc != 0) { - fatal( "adb: could not initialize Winsock\n" ); + fatal( "adb: could not initialize Winsock: %s", + SystemErrorCodeToString( rc ).c_str()); } atexit( _cleanup_winsock ); _winsock_init = 1; } } -int socket_loopback_client(int port, int type) -{ - FH f = _fh_alloc( &_fh_socket_class ); +int network_loopback_client(int port, int type, std::string* error) { struct sockaddr_in addr; SOCKET s; - if (!f) + unique_fh f(_fh_alloc(&_fh_socket_class)); + if (!f) { + *error = strerror(errno); return -1; + } if (!_winsock_init) _init_winsock(); @@ -606,32 +686,40 @@ int socket_loopback_client(int port, int type) s = socket(AF_INET, type, 0); if(s == INVALID_SOCKET) { - D("socket_loopback_client: could not create socket\n" ); - _fh_close(f); + *error = SystemErrorCodeToString(WSAGetLastError()); + D("could not create socket: %s\n", error->c_str()); return -1; } - f->fh_socket = s; - if(connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { - D("socket_loopback_client: could not connect to %s:%d\n", type != SOCK_STREAM ? "udp" : "tcp", port ); - _fh_close(f); + + if(connect(s, (struct sockaddr *) &addr, sizeof(addr)) == SOCKET_ERROR) { + *error = SystemErrorCodeToString(WSAGetLastError()); + D("could not connect to %s:%d: %s\n", + type != SOCK_STREAM ? "udp" : "tcp", port, error->c_str()); return -1; } - snprintf( f->name, sizeof(f->name), "%d(lo-client:%s%d)", _fh_to_int(f), type != SOCK_STREAM ? "udp:" : "", port ); - D( "socket_loopback_client: port %d type %s => fd %d\n", port, type != SOCK_STREAM ? "udp" : "tcp", _fh_to_int(f) ); - return _fh_to_int(f); + + const int fd = _fh_to_int(f.get()); + snprintf( f->name, sizeof(f->name), "%d(lo-client:%s%d)", fd, + type != SOCK_STREAM ? "udp:" : "", port ); + D( "port %d type %s => fd %d\n", port, type != SOCK_STREAM ? "udp" : "tcp", + fd ); + f.release(); + return fd; } #define LISTEN_BACKLOG 4 -int socket_loopback_server(int port, int type) -{ - FH f = _fh_alloc( &_fh_socket_class ); +// interface_address is INADDR_LOOPBACK or INADDR_ANY. +static int _network_server(int port, int type, u_long interface_address, + std::string* error) { struct sockaddr_in addr; SOCKET s; int n; + unique_fh f(_fh_alloc(&_fh_socket_class)); if (!f) { + *error = strerror(errno); return -1; } @@ -641,149 +729,151 @@ int socket_loopback_server(int port, int type) memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_port = htons(port); - addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + addr.sin_addr.s_addr = htonl(interface_address); + // TODO: Consider using dual-stack socket that can simultaneously listen on + // IPv4 and IPv6. s = socket(AF_INET, type, 0); - if(s == INVALID_SOCKET) return -1; + if (s == INVALID_SOCKET) { + *error = SystemErrorCodeToString(WSAGetLastError()); + D("could not create socket: %s\n", error->c_str()); + return -1; + } f->fh_socket = s; n = 1; - setsockopt(s, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (const char*)&n, sizeof(n)); + if (setsockopt(s, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (const char*)&n, + sizeof(n)) == SOCKET_ERROR) { + *error = SystemErrorCodeToString(WSAGetLastError()); + D("setsockopt level %d optname %d failed: %s\n", + SOL_SOCKET, SO_EXCLUSIVEADDRUSE, error->c_str()); + return -1; + } - if(bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { - _fh_close(f); + if(bind(s, (struct sockaddr *) &addr, sizeof(addr)) == SOCKET_ERROR) { + *error = SystemErrorCodeToString(WSAGetLastError()); + D("could not bind to %s:%d: %s\n", + type != SOCK_STREAM ? "udp" : "tcp", port, error->c_str()); return -1; } if (type == SOCK_STREAM) { - int ret; - - ret = listen(s, LISTEN_BACKLOG); - if (ret < 0) { - _fh_close(f); + if (listen(s, LISTEN_BACKLOG) == SOCKET_ERROR) { + *error = SystemErrorCodeToString(WSAGetLastError()); + D("could not listen on %s:%d: %s\n", + type != SOCK_STREAM ? "udp" : "tcp", port, error->c_str()); return -1; } } - snprintf( f->name, sizeof(f->name), "%d(lo-server:%s%d)", _fh_to_int(f), type != SOCK_STREAM ? "udp:" : "", port ); - D( "socket_loopback_server: port %d type %s => fd %d\n", port, type != SOCK_STREAM ? "udp" : "tcp", _fh_to_int(f) ); - return _fh_to_int(f); + const int fd = _fh_to_int(f.get()); + snprintf( f->name, sizeof(f->name), "%d(%s-server:%s%d)", fd, + interface_address == INADDR_LOOPBACK ? "lo" : "any", + type != SOCK_STREAM ? "udp:" : "", port ); + D( "port %d type %s => fd %d\n", port, type != SOCK_STREAM ? "udp" : "tcp", + fd ); + f.release(); + return fd; } +int network_loopback_server(int port, int type, std::string* error) { + return _network_server(port, type, INADDR_LOOPBACK, error); +} -int socket_network_client_timeout(const char *host, int port, int type, int timeout, - int* getaddrinfo_error) { - FH f = _fh_alloc( &_fh_socket_class ); - if (!f) return -1; - - if (!_winsock_init) _init_winsock(); +int network_inaddr_any_server(int port, int type, std::string* error) { + return _network_server(port, type, INADDR_ANY, error); +} - hostent* hp = gethostbyname(host); - if(hp == 0) { - _fh_close(f); +int network_connect(const std::string& host, int port, int type, int timeout, std::string* error) { + unique_fh f(_fh_alloc(&_fh_socket_class)); + if (!f) { + *error = strerror(errno); return -1; } - sockaddr_in addr; - memset(&addr, 0, sizeof(addr)); - addr.sin_family = hp->h_addrtype; - addr.sin_port = htons(port); - memcpy(&addr.sin_addr, hp->h_addr, hp->h_length); + if (!_winsock_init) _init_winsock(); - SOCKET s = socket(hp->h_addrtype, type, 0); - if(s == INVALID_SOCKET) { - _fh_close(f); - return -1; - } - f->fh_socket = s; + struct addrinfo hints; + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = type; - // TODO: implement timeouts for Windows. + char port_str[16]; + snprintf(port_str, sizeof(port_str), "%d", port); - if(connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { - _fh_close(f); + struct addrinfo* addrinfo_ptr = nullptr; + if (getaddrinfo(host.c_str(), port_str, &hints, &addrinfo_ptr) != 0) { + *error = SystemErrorCodeToString(WSAGetLastError()); + D("could not resolve host '%s' and port %s: %s\n", host.c_str(), + port_str, error->c_str()); return -1; } + std::unique_ptr<struct addrinfo, decltype(freeaddrinfo)*> + addrinfo(addrinfo_ptr, freeaddrinfo); + addrinfo_ptr = nullptr; - snprintf( f->name, sizeof(f->name), "%d(net-client:%s%d)", _fh_to_int(f), type != SOCK_STREAM ? "udp:" : "", port ); - D( "socket_network_client_timeout: host '%s' port %d type %s => fd %d\n", host, port, type != SOCK_STREAM ? "udp" : "tcp", _fh_to_int(f) ); - return _fh_to_int(f); -} - - -int socket_inaddr_any_server(int port, int type) -{ - FH f = _fh_alloc( &_fh_socket_class ); - struct sockaddr_in addr; - SOCKET s; - int n; - - if (!f) - return -1; - - if (!_winsock_init) - _init_winsock(); - - memset(&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_port = htons(port); - addr.sin_addr.s_addr = htonl(INADDR_ANY); - - s = socket(AF_INET, type, 0); + // TODO: Try all the addresses if there's more than one? This just uses + // the first. Or, could call WSAConnectByName() (Windows Vista and newer) + // which tries all addresses, takes a timeout and more. + SOCKET s = socket(addrinfo->ai_family, addrinfo->ai_socktype, + addrinfo->ai_protocol); if(s == INVALID_SOCKET) { - _fh_close(f); + *error = SystemErrorCodeToString(WSAGetLastError()); + D("could not create socket: %s\n", error->c_str()); return -1; } - f->fh_socket = s; - n = 1; - setsockopt(s, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (const char*)&n, sizeof(n)); - if(bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { - _fh_close(f); + // TODO: Implement timeouts for Windows. Seems like the default in theory + // (according to http://serverfault.com/a/671453) and in practice is 21 sec. + if(connect(s, addrinfo->ai_addr, addrinfo->ai_addrlen) == SOCKET_ERROR) { + *error = SystemErrorCodeToString(WSAGetLastError()); + D("could not connect to %s:%s:%s: %s\n", + type != SOCK_STREAM ? "udp" : "tcp", host.c_str(), port_str, + error->c_str()); return -1; } - if (type == SOCK_STREAM) { - int ret; - - ret = listen(s, LISTEN_BACKLOG); - if (ret < 0) { - _fh_close(f); - return -1; - } - } - snprintf( f->name, sizeof(f->name), "%d(any-server:%s%d)", _fh_to_int(f), type != SOCK_STREAM ? "udp:" : "", port ); - D( "socket_inaddr_server: port %d type %s => fd %d\n", port, type != SOCK_STREAM ? "udp" : "tcp", _fh_to_int(f) ); - return _fh_to_int(f); + const int fd = _fh_to_int(f.get()); + snprintf( f->name, sizeof(f->name), "%d(net-client:%s%d)", fd, + type != SOCK_STREAM ? "udp:" : "", port ); + D( "host '%s' port %d type %s => fd %d\n", host.c_str(), port, + type != SOCK_STREAM ? "udp" : "tcp", fd ); + f.release(); + return fd; } #undef accept int adb_socket_accept(int serverfd, struct sockaddr* addr, socklen_t *addrlen) { FH serverfh = _fh_from_int(serverfd, __func__); - FH fh; if ( !serverfh || serverfh->clazz != &_fh_socket_class ) { - D( "adb_socket_accept: invalid fd %d\n", serverfd ); + D("adb_socket_accept: invalid fd %d\n", serverfd); + errno = EBADF; return -1; } - fh = _fh_alloc( &_fh_socket_class ); + unique_fh fh(_fh_alloc( &_fh_socket_class )); if (!fh) { - D( "adb_socket_accept: not enough memory to allocate accepted socket descriptor\n" ); + PLOG(ERROR) << "adb_socket_accept: failed to allocate accepted socket " + "descriptor"; return -1; } fh->fh_socket = accept( serverfh->fh_socket, addr, addrlen ); if (fh->fh_socket == INVALID_SOCKET) { const DWORD err = WSAGetLastError(); - _fh_close( fh ); - D( "adb_socket_accept: accept on fd %d return error %ld\n", serverfd, err ); + LOG(ERROR) << "adb_socket_accept: accept on fd " << serverfd << + " failed: " + SystemErrorCodeToString(err); + _socket_set_errno( err ); return -1; } - snprintf( fh->name, sizeof(fh->name), "%d(accept:%s)", _fh_to_int(fh), serverfh->name ); - D( "adb_socket_accept on fd %d returns fd %d\n", serverfd, _fh_to_int(fh) ); - return _fh_to_int(fh); + const int fd = _fh_to_int(fh.get()); + snprintf( fh->name, sizeof(fh->name), "%d(accept:%s)", fd, serverfh->name ); + D( "adb_socket_accept on fd %d returns fd %d\n", serverfd, fd ); + fh.release(); + return fd; } @@ -793,10 +883,42 @@ int adb_setsockopt( int fd, int level, int optname, const void* optval, soc if ( !fh || fh->clazz != &_fh_socket_class ) { D("adb_setsockopt: invalid fd %d\n", fd); + errno = EBADF; return -1; } + int result = setsockopt( fh->fh_socket, level, optname, + reinterpret_cast<const char*>(optval), optlen ); + if ( result == SOCKET_ERROR ) { + const DWORD err = WSAGetLastError(); + D( "adb_setsockopt: setsockopt on fd %d level %d optname %d " + "failed: %s\n", fd, level, optname, + SystemErrorCodeToString(err).c_str() ); + _socket_set_errno( err ); + result = -1; + } + return result; +} + - return setsockopt( fh->fh_socket, level, optname, reinterpret_cast<const char*>(optval), optlen ); +int adb_shutdown(int fd) +{ + FH f = _fh_from_int(fd, __func__); + + if (!f || f->clazz != &_fh_socket_class) { + D("adb_shutdown: invalid fd %d\n", fd); + errno = EBADF; + return -1; + } + + D( "adb_shutdown: %s\n", f->name); + if (shutdown(f->fh_socket, SD_BOTH) == SOCKET_ERROR) { + const DWORD err = WSAGetLastError(); + D("socket shutdown fd %d failed: %s\n", fd, + SystemErrorCodeToString(err).c_str()); + _socket_set_errno(err); + return -1; + } + return 0; } /**************************************************************************/ @@ -1199,16 +1321,19 @@ static const FHClassRec _fh_socketpair_class = int adb_socketpair(int sv[2]) { SocketPair pair; - FH fa = _fh_alloc(&_fh_socketpair_class); - FH fb = _fh_alloc(&_fh_socketpair_class); - - if (!fa || !fb) - goto Fail; + unique_fh fa(_fh_alloc(&_fh_socketpair_class)); + if (!fa) { + return -1; + } + unique_fh fb(_fh_alloc(&_fh_socketpair_class)); + if (!fb) { + return -1; + } pair = reinterpret_cast<SocketPair>(malloc(sizeof(*pair))); if (pair == NULL) { D("adb_socketpair: not enough memory to allocate pipes\n" ); - goto Fail; + return -1; } bip_buffer_init( &pair->a2b_bip ); @@ -1217,10 +1342,10 @@ int adb_socketpair(int sv[2]) { fa->fh_pair = pair; fb->fh_pair = pair; pair->used = 2; - pair->a_fd = fa; + pair->a_fd = fa.get(); - sv[0] = _fh_to_int(fa); - sv[1] = _fh_to_int(fb); + sv[0] = _fh_to_int(fa.get()); + sv[1] = _fh_to_int(fb.get()); pair->a2b_bip.fdin = sv[0]; pair->a2b_bip.fdout = sv[1]; @@ -1230,12 +1355,9 @@ int adb_socketpair(int sv[2]) { snprintf( fa->name, sizeof(fa->name), "%d(pair:%d)", sv[0], sv[1] ); snprintf( fb->name, sizeof(fb->name), "%d(pair:%d)", sv[1], sv[0] ); D( "adb_socketpair: returns (%d, %d)\n", sv[0], sv[1] ); + fa.release(); + fb.release(); return 0; - -Fail: - _fh_close(fb); - _fh_close(fa); - return -1; } /**************************************************************************/ @@ -2083,6 +2205,7 @@ static void _fh_socket_hook( FH f, int events, EventHook hook ) hook->check = _event_socket_check; hook->peek = _event_socket_peek; + // TODO: check return value? _event_socket_start( hook ); } diff --git a/transport_local.cpp b/transport_local.cpp index 0dc9581..db9bedb 100644 --- a/transport_local.cpp +++ b/transport_local.cpp @@ -100,7 +100,7 @@ int local_connect_arbitrary_ports(int console_port, int adb_port, std::string* e } #endif if (fd < 0) { - fd = socket_loopback_client(adb_port, SOCK_STREAM); + fd = network_loopback_client(adb_port, SOCK_STREAM, error); } if (fd >= 0) { @@ -144,9 +144,10 @@ static void *server_socket_thread(void * arg) serverfd = -1; for(;;) { if(serverfd == -1) { - serverfd = socket_inaddr_any_server(port, SOCK_STREAM); + std::string error; + serverfd = network_inaddr_any_server(port, SOCK_STREAM, &error); if(serverfd < 0) { - D("server: cannot bind socket yet: %s\n", strerror(errno)); + D("server: cannot bind socket yet: %s\n", error.c_str()); adb_sleep_ms(1000); continue; } |