Merge "adb: win32: initial IPv6 support and improved Winsock error reporting"

This commit is contained in:
Elliott Hughes 2015-07-31 18:11:45 +00:00 committed by Gerrit Code Review
commit cf4dba5ab3
13 changed files with 372 additions and 201 deletions

View file

@ -801,11 +801,13 @@ int handle_forward_request(const char* service, TransportType type, const char*
return 1; return 1;
} }
std::string error;
InstallStatus r; InstallStatus r;
if (kill_forward) { if (kill_forward) {
r = remove_listener(pieces[0].c_str(), transport); r = remove_listener(pieces[0].c_str(), transport);
} else { } 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 (r == INSTALL_STATUS_OK) {
#if ADB_HOST #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_OK: message = "success (!)"; break;
case INSTALL_STATUS_INTERNAL_ERROR: message = "internal error"; break; case INSTALL_STATUS_INTERNAL_ERROR: message = "internal error"; break;
case INSTALL_STATUS_CANNOT_BIND: 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; break;
case INSTALL_STATUS_CANNOT_REBIND: case INSTALL_STATUS_CANNOT_REBIND:
message = android::base::StringPrintf("cannot rebind existing socket"); message = android::base::StringPrintf("cannot rebind existing socket");

View file

@ -153,8 +153,8 @@ int _adb_connect(const std::string& service, std::string* error) {
} }
int fd; int fd;
std::string reason;
if (__adb_server_name) { if (__adb_server_name) {
std::string reason;
fd = network_connect(__adb_server_name, __adb_server_port, SOCK_STREAM, 0, &reason); fd = network_connect(__adb_server_name, __adb_server_port, SOCK_STREAM, 0, &reason);
if (fd == -1) { if (fd == -1) {
*error = android::base::StringPrintf("can't connect to %s:%d: %s", *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; return -2;
} }
} else { } else {
fd = socket_loopback_client(__adb_server_port, SOCK_STREAM); fd = network_loopback_client(__adb_server_port, SOCK_STREAM, &reason);
if (fd == -1) { if (fd == -1) {
*error = perror_str("cannot connect to daemon"); *error = android::base::StringPrintf("cannot connect to daemon: %s",
reason.c_str());
return -2; return -2;
} }
} }

View file

@ -110,27 +110,30 @@ static void listener_disconnect(void* listener, atransport* t) {
free_listener(reinterpret_cast<alistener*>(listener)); 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)) { if (!strncmp("tcp:", name, 4)) {
int port = atoi(name + 4); int port = atoi(name + 4);
if (gListenAll > 0) { if (gListenAll > 0) {
return socket_inaddr_any_server(port, SOCK_STREAM); return network_inaddr_any_server(port, SOCK_STREAM, error);
} else { } 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. #if !defined(_WIN32) // No Unix-domain sockets on Windows.
// It's nonsensical to support the "reserved" space on the adb host side // It's nonsensical to support the "reserved" space on the adb host side
if (!strncmp(name, "local:", 6)) { 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)) { } 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)) { } 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 #endif
printf("unknown local portname '%s'\n", name); *error = android::base::StringPrintf("unknown local portname '%s'", name);
return -1; return -1;
} }
@ -178,7 +181,8 @@ void remove_all_listeners(void)
InstallStatus install_listener(const std::string& local_name, InstallStatus install_listener(const std::string& local_name,
const char *connect_to, const char *connect_to,
atransport* transport, atransport* transport,
int no_rebind) int no_rebind,
std::string* error)
{ {
for (alistener* l = listener_list.next; l != &listener_list; l = l->next) { for (alistener* l = listener_list.next; l != &listener_list; l = l->next) {
if (local_name == l->local_name) { if (local_name == l->local_name) {
@ -226,9 +230,9 @@ InstallStatus install_listener(const std::string& local_name,
goto nomem; 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) { 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->local_name);
free(listener->connect_to); free(listener->connect_to);
free(listener); free(listener);

View file

@ -33,7 +33,8 @@ enum InstallStatus {
InstallStatus install_listener(const std::string& local_name, InstallStatus install_listener(const std::string& local_name,
const char* connect_to, const char* connect_to,
atransport* transport, atransport* transport,
int no_rebind); int no_rebind,
std::string* error);
std::string format_listeners(); std::string format_listeners();

View file

@ -28,17 +28,10 @@
#include <base/logging.h> #include <base/logging.h>
#include <base/stringprintf.h> #include <base/stringprintf.h>
#include <base/strings.h> #include <base/strings.h>
#include <cutils/sockets.h>
#include "adb_trace.h" #include "adb_trace.h"
#include "sysdeps.h" #include "sysdeps.h"
#if defined(_WIN32)
#include <ws2tcpip.h>
#else
#include <netdb.h>
#endif
bool getcwd(std::string* s) { bool getcwd(std::string* s) {
char* cwd = getcwd(nullptr, 0); char* cwd = getcwd(nullptr, 0);
if (cwd != nullptr) *s = cwd; if (cwd != nullptr) *s = cwd;
@ -178,18 +171,3 @@ bool parse_host_and_port(const std::string& address,
<< " (" << *canonical_address << ")"; << " (" << *canonical_address << ")";
return true; 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;
}

View file

@ -40,6 +40,4 @@ bool parse_host_and_port(const std::string& address,
std::string* host, int* port, std::string* host, int* port,
std::string* error); std::string* error);
int network_connect(const std::string& host, int port, int type, int timeout, std::string* error);
#endif #endif

View file

@ -150,9 +150,10 @@ int adb_main(int is_daemon, int server_port) {
local_init(DEFAULT_ADB_LOCAL_TRANSPORT_PORT); local_init(DEFAULT_ADB_LOCAL_TRANSPORT_PORT);
adb_auth_init(); adb_auth_init();
std::string error;
std::string local_name = android::base::StringPrintf("tcp:%d", server_port); std::string local_name = android::base::StringPrintf("tcp:%d", server_port);
if (install_listener(local_name, "*smartsocket*", nullptr, 0)) { if (install_listener(local_name, "*smartsocket*", nullptr, 0, &error)) {
LOG(FATAL) << "Could not install *smartsocket* listener"; LOG(FATAL) << "Could not install *smartsocket* listener: " << error;
} }
if (is_daemon) { if (is_daemon) {

View file

@ -71,9 +71,11 @@ static int connect_to_console(const char* serial) {
return -1; 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) { 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 -1;
} }
return fd; return fd;

View file

@ -177,10 +177,13 @@ int adbd_main(int server_port) {
LOG(FATAL) << "Could not set selinux context"; LOG(FATAL) << "Could not set selinux context";
} }
} }
std::string error;
std::string local_name = std::string local_name =
android::base::StringPrintf("tcp:%d", server_port); android::base::StringPrintf("tcp:%d", server_port);
if (install_listener(local_name, "*smartsocket*", nullptr, 0)) { if (install_listener(local_name, "*smartsocket*", nullptr, 0,
LOG(FATAL) << "Could not install *smartsocket* listener"; &error)) {
LOG(FATAL) << "Could not install *smartsocket* listener: "
<< error;
} }
} }

View file

@ -432,7 +432,8 @@ int service_to_fd(const char *name)
int port = atoi(name + 4); int port = atoi(name + 4);
name = strchr(name + 4, ':'); name = strchr(name + 4, ':');
if(name == 0) { if(name == 0) {
ret = socket_loopback_client(port, SOCK_STREAM); std::string error;
ret = network_loopback_client(port, SOCK_STREAM, &error);
if (ret >= 0) if (ret >= 0)
disable_tcp_nagle(ret); disable_tcp_nagle(ret);
} else { } else {

View file

@ -26,6 +26,8 @@
#include <errno.h> #include <errno.h>
#include <string>
/* /*
* TEMP_FAILURE_RETRY is defined by some, but not all, versions of * 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 * <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 ); 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); extern int adb_socket_accept(int serverfd, struct sockaddr* addr, socklen_t *addrlen);
#undef accept #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] == '\\'; 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 */ #else /* !_WIN32 a.k.a. Unix */
#include "fdevent.h" #include "fdevent.h"
#include <cutils/misc.h> #include <cutils/misc.h>
#include <cutils/sockets.h>
#include <cutils/threads.h> #include <cutils/threads.h>
#include <signal.h> #include <signal.h>
#include <sys/wait.h> #include <sys/wait.h>
@ -254,6 +266,7 @@ static __inline__ int adb_is_absolute_host_path(const char* path) {
#include <unistd.h> #include <unistd.h>
#include <fcntl.h> #include <fcntl.h>
#include <stdarg.h> #include <stdarg.h>
#include <netdb.h>
#include <netinet/in.h> #include <netinet/in.h>
#include <netinet/tcp.h> #include <netinet/tcp.h>
#include <string.h> #include <string.h>
@ -404,6 +417,48 @@ static __inline__ int adb_creat(const char* path, int mode)
#undef creat #undef creat
#define creat ___xxx_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) static __inline__ int adb_socket_accept(int serverfd, struct sockaddr* addr, socklen_t *addrlen)
{ {
int fd; int fd;

View file

@ -25,8 +25,15 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <memory>
#include <string>
#include <cutils/sockets.h> #include <cutils/sockets.h>
#include <base/logging.h>
#include <base/stringprintf.h>
#include <base/strings.h>
#include "adb.h" #include "adb.h"
extern void fatal(const char *fmt, ...); 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) #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; 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) int adb_close(int fd)
{ {
FH f = _fh_from_int(fd, __func__); FH f = _fh_from_int(fd, __func__);
@ -505,29 +537,63 @@ int adb_close(int fd)
#undef setsockopt #undef setsockopt
static void _socket_set_errno( void ) { static void _socket_set_errno( const DWORD err ) {
switch (WSAGetLastError()) { // 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 0: errno = 0; break;
case WSAEWOULDBLOCK: errno = EAGAIN; break; case WSAEWOULDBLOCK: errno = EAGAIN; break;
case WSAEINTR: errno = EINTR; break; case WSAEINTR: errno = EINTR; break;
case WSAEFAULT: errno = EFAULT; break;
case WSAEINVAL: errno = EINVAL; break;
case WSAEMFILE: errno = EMFILE; break;
default: default:
D( "_socket_set_errno: unhandled value %d\n", WSAGetLastError() );
errno = EINVAL; errno = EINVAL;
D( "_socket_set_errno: mapping Windows error code %lu to errno %d\n",
err, errno );
} }
} }
static void _fh_socket_init( FH f ) { static void _fh_socket_init( FH f ) {
f->fh_socket = INVALID_SOCKET; f->fh_socket = INVALID_SOCKET;
f->event = WSACreateEvent(); 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; f->mask = 0;
} }
static int _fh_socket_close( FH f ) { static int _fh_socket_close( FH f ) {
/* gently tell any peer that we're closing the socket */ if (f->fh_socket != INVALID_SOCKET) {
shutdown( f->fh_socket, SD_BOTH ); /* gently tell any peer that we're closing the socket */
closesocket( f->fh_socket ); if (shutdown(f->fh_socket, SD_BOTH) == SOCKET_ERROR) {
f->fh_socket = INVALID_SOCKET; // If the socket is not connected, this returns an error. We want to
CloseHandle( f->event ); // 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; f->mask = 0;
return 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) { static int _fh_socket_read(FH f, void* buf, int len) {
int result = recv(f->fh_socket, reinterpret_cast<char*>(buf), len, 0); int result = recv(f->fh_socket, reinterpret_cast<char*>(buf), len, 0);
if (result == SOCKET_ERROR) { 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; result = -1;
} }
return result; 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) { 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); int result = send(f->fh_socket, reinterpret_cast<const char*>(buf), len, 0);
if (result == SOCKET_ERROR) { 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; result = -1;
} }
return result; return result;
@ -570,31 +642,39 @@ static int _winsock_init;
static void static void
_cleanup_winsock( 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(); WSACleanup();
} }
static void static void
_init_winsock( void ) _init_winsock( void )
{ {
// TODO: Multiple threads calling this may potentially cause multiple calls
// to WSAStartup() and multiple atexit() calls.
if (!_winsock_init) { if (!_winsock_init) {
WSADATA wsaData; WSADATA wsaData;
int rc = WSAStartup( MAKEWORD(2,2), &wsaData); int rc = WSAStartup( MAKEWORD(2,2), &wsaData);
if (rc != 0) { if (rc != 0) {
fatal( "adb: could not initialize Winsock\n" ); fatal( "adb: could not initialize Winsock: %s",
SystemErrorCodeToString( rc ).c_str());
} }
atexit( _cleanup_winsock ); atexit( _cleanup_winsock );
_winsock_init = 1; _winsock_init = 1;
} }
} }
int socket_loopback_client(int port, int type) int network_loopback_client(int port, int type, std::string* error) {
{
FH f = _fh_alloc( &_fh_socket_class );
struct sockaddr_in addr; struct sockaddr_in addr;
SOCKET s; SOCKET s;
if (!f) unique_fh f(_fh_alloc(&_fh_socket_class));
if (!f) {
*error = strerror(errno);
return -1; return -1;
}
if (!_winsock_init) if (!_winsock_init)
_init_winsock(); _init_winsock();
@ -606,32 +686,40 @@ int socket_loopback_client(int port, int type)
s = socket(AF_INET, type, 0); s = socket(AF_INET, type, 0);
if(s == INVALID_SOCKET) { if(s == INVALID_SOCKET) {
D("socket_loopback_client: could not create socket\n" ); *error = SystemErrorCodeToString(WSAGetLastError());
_fh_close(f); D("could not create socket: %s\n", error->c_str());
return -1;
}
f->fh_socket = s;
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; return -1;
} }
f->fh_socket = s; const int fd = _fh_to_int(f.get());
if(connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { snprintf( f->name, sizeof(f->name), "%d(lo-client:%s%d)", fd,
D("socket_loopback_client: could not connect to %s:%d\n", type != SOCK_STREAM ? "udp" : "tcp", port ); type != SOCK_STREAM ? "udp:" : "", port );
_fh_close(f); D( "port %d type %s => fd %d\n", port, type != SOCK_STREAM ? "udp" : "tcp",
return -1; fd );
} f.release();
snprintf( f->name, sizeof(f->name), "%d(lo-client:%s%d)", _fh_to_int(f), type != SOCK_STREAM ? "udp:" : "", port ); return fd;
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);
} }
#define LISTEN_BACKLOG 4 #define LISTEN_BACKLOG 4
int socket_loopback_server(int port, int type) // interface_address is INADDR_LOOPBACK or INADDR_ANY.
{ static int _network_server(int port, int type, u_long interface_address,
FH f = _fh_alloc( &_fh_socket_class ); std::string* error) {
struct sockaddr_in addr; struct sockaddr_in addr;
SOCKET s; SOCKET s;
int n; int n;
unique_fh f(_fh_alloc(&_fh_socket_class));
if (!f) { if (!f) {
*error = strerror(errno);
return -1; return -1;
} }
@ -641,149 +729,151 @@ int socket_loopback_server(int port, int type)
memset(&addr, 0, sizeof(addr)); memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET; addr.sin_family = AF_INET;
addr.sin_port = htons(port); 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); 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; f->fh_socket = s;
n = 1; 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) { if(bind(s, (struct sockaddr *) &addr, sizeof(addr)) == SOCKET_ERROR) {
_fh_close(f); *error = SystemErrorCodeToString(WSAGetLastError());
D("could not bind to %s:%d: %s\n",
type != SOCK_STREAM ? "udp" : "tcp", port, error->c_str());
return -1; return -1;
} }
if (type == SOCK_STREAM) { if (type == SOCK_STREAM) {
int ret; if (listen(s, LISTEN_BACKLOG) == SOCKET_ERROR) {
*error = SystemErrorCodeToString(WSAGetLastError());
ret = listen(s, LISTEN_BACKLOG); D("could not listen on %s:%d: %s\n",
if (ret < 0) { type != SOCK_STREAM ? "udp" : "tcp", port, error->c_str());
_fh_close(f);
return -1; return -1;
} }
} }
snprintf( f->name, sizeof(f->name), "%d(lo-server:%s%d)", _fh_to_int(f), type != SOCK_STREAM ? "udp:" : "", port ); const int fd = _fh_to_int(f.get());
D( "socket_loopback_server: port %d type %s => fd %d\n", port, type != SOCK_STREAM ? "udp" : "tcp", _fh_to_int(f) ); snprintf( f->name, sizeof(f->name), "%d(%s-server:%s%d)", fd,
return _fh_to_int(f); 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 network_inaddr_any_server(int port, int type, std::string* error) {
int* getaddrinfo_error) { return _network_server(port, type, INADDR_ANY, error);
FH f = _fh_alloc( &_fh_socket_class ); }
if (!f) return -1;
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;
}
if (!_winsock_init) _init_winsock(); if (!_winsock_init) _init_winsock();
hostent* hp = gethostbyname(host); struct addrinfo hints;
if(hp == 0) { memset(&hints, 0, sizeof(hints));
_fh_close(f); hints.ai_family = AF_UNSPEC;
hints.ai_socktype = type;
char port_str[16];
snprintf(port_str, sizeof(port_str), "%d", port);
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; return -1;
} }
std::unique_ptr<struct addrinfo, decltype(freeaddrinfo)*>
addrinfo(addrinfo_ptr, freeaddrinfo);
addrinfo_ptr = nullptr;
sockaddr_in addr; // TODO: Try all the addresses if there's more than one? This just uses
memset(&addr, 0, sizeof(addr)); // the first. Or, could call WSAConnectByName() (Windows Vista and newer)
addr.sin_family = hp->h_addrtype; // which tries all addresses, takes a timeout and more.
addr.sin_port = htons(port); SOCKET s = socket(addrinfo->ai_family, addrinfo->ai_socktype,
memcpy(&addr.sin_addr, hp->h_addr, hp->h_length); addrinfo->ai_protocol);
SOCKET s = socket(hp->h_addrtype, type, 0);
if(s == INVALID_SOCKET) { if(s == INVALID_SOCKET) {
_fh_close(f); *error = SystemErrorCodeToString(WSAGetLastError());
D("could not create socket: %s\n", error->c_str());
return -1; return -1;
} }
f->fh_socket = s; f->fh_socket = s;
// TODO: implement timeouts for Windows. // 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, (struct sockaddr *) &addr, sizeof(addr)) < 0) { if(connect(s, addrinfo->ai_addr, addrinfo->ai_addrlen) == SOCKET_ERROR) {
_fh_close(f); *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; return -1;
} }
snprintf( f->name, sizeof(f->name), "%d(net-client:%s%d)", _fh_to_int(f), type != SOCK_STREAM ? "udp:" : "", port ); const int fd = _fh_to_int(f.get());
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) ); snprintf( f->name, sizeof(f->name), "%d(net-client:%s%d)", fd,
return _fh_to_int(f); 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();
int socket_inaddr_any_server(int port, int type) return fd;
{
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);
if(s == INVALID_SOCKET) {
_fh_close(f);
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);
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);
} }
#undef accept #undef accept
int adb_socket_accept(int serverfd, struct sockaddr* addr, socklen_t *addrlen) int adb_socket_accept(int serverfd, struct sockaddr* addr, socklen_t *addrlen)
{ {
FH serverfh = _fh_from_int(serverfd, __func__); FH serverfh = _fh_from_int(serverfd, __func__);
FH fh;
if ( !serverfh || serverfh->clazz != &_fh_socket_class ) { 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; return -1;
} }
fh = _fh_alloc( &_fh_socket_class ); unique_fh fh(_fh_alloc( &_fh_socket_class ));
if (!fh) { 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; return -1;
} }
fh->fh_socket = accept( serverfh->fh_socket, addr, addrlen ); fh->fh_socket = accept( serverfh->fh_socket, addr, addrlen );
if (fh->fh_socket == INVALID_SOCKET) { if (fh->fh_socket == INVALID_SOCKET) {
const DWORD err = WSAGetLastError(); const DWORD err = WSAGetLastError();
_fh_close( fh ); LOG(ERROR) << "adb_socket_accept: accept on fd " << serverfd <<
D( "adb_socket_accept: accept on fd %d return error %ld\n", serverfd, err ); " failed: " + SystemErrorCodeToString(err);
_socket_set_errno( err );
return -1; return -1;
} }
snprintf( fh->name, sizeof(fh->name), "%d(accept:%s)", _fh_to_int(fh), serverfh->name ); const int fd = _fh_to_int(fh.get());
D( "adb_socket_accept on fd %d returns fd %d\n", serverfd, _fh_to_int(fh) ); snprintf( fh->name, sizeof(fh->name), "%d(accept:%s)", fd, serverfh->name );
return _fh_to_int(fh); 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 ) { if ( !fh || fh->clazz != &_fh_socket_class ) {
D("adb_setsockopt: invalid fd %d\n", fd); 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;
}
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; return -1;
} }
return setsockopt( fh->fh_socket, level, optname, reinterpret_cast<const char*>(optval), optlen ); 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]) { int adb_socketpair(int sv[2]) {
SocketPair pair; SocketPair pair;
FH fa = _fh_alloc(&_fh_socketpair_class); unique_fh fa(_fh_alloc(&_fh_socketpair_class));
FH fb = _fh_alloc(&_fh_socketpair_class); if (!fa) {
return -1;
if (!fa || !fb) }
goto Fail; unique_fh fb(_fh_alloc(&_fh_socketpair_class));
if (!fb) {
return -1;
}
pair = reinterpret_cast<SocketPair>(malloc(sizeof(*pair))); pair = reinterpret_cast<SocketPair>(malloc(sizeof(*pair)));
if (pair == NULL) { if (pair == NULL) {
D("adb_socketpair: not enough memory to allocate pipes\n" ); D("adb_socketpair: not enough memory to allocate pipes\n" );
goto Fail; return -1;
} }
bip_buffer_init( &pair->a2b_bip ); bip_buffer_init( &pair->a2b_bip );
@ -1217,10 +1342,10 @@ int adb_socketpair(int sv[2]) {
fa->fh_pair = pair; fa->fh_pair = pair;
fb->fh_pair = pair; fb->fh_pair = pair;
pair->used = 2; pair->used = 2;
pair->a_fd = fa; pair->a_fd = fa.get();
sv[0] = _fh_to_int(fa); sv[0] = _fh_to_int(fa.get());
sv[1] = _fh_to_int(fb); sv[1] = _fh_to_int(fb.get());
pair->a2b_bip.fdin = sv[0]; pair->a2b_bip.fdin = sv[0];
pair->a2b_bip.fdout = sv[1]; 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( 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] ); snprintf( fb->name, sizeof(fb->name), "%d(pair:%d)", sv[1], sv[0] );
D( "adb_socketpair: returns (%d, %d)\n", sv[0], sv[1] ); D( "adb_socketpair: returns (%d, %d)\n", sv[0], sv[1] );
fa.release();
fb.release();
return 0; 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->check = _event_socket_check;
hook->peek = _event_socket_peek; hook->peek = _event_socket_peek;
// TODO: check return value?
_event_socket_start( hook ); _event_socket_start( hook );
} }

View file

@ -100,7 +100,7 @@ int local_connect_arbitrary_ports(int console_port, int adb_port, std::string* e
} }
#endif #endif
if (fd < 0) { if (fd < 0) {
fd = socket_loopback_client(adb_port, SOCK_STREAM); fd = network_loopback_client(adb_port, SOCK_STREAM, error);
} }
if (fd >= 0) { if (fd >= 0) {
@ -144,9 +144,10 @@ static void *server_socket_thread(void * arg)
serverfd = -1; serverfd = -1;
for(;;) { for(;;) {
if(serverfd == -1) { 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) { 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); adb_sleep_ms(1000);
continue; continue;
} }