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

* commit 'cf4dba5ab315493531fff5a4867698a3659b0526':
  adb: win32: initial IPv6 support and improved Winsock error reporting
This commit is contained in:
Elliott Hughes 2015-07-31 18:18:32 +00:00 committed by Android Git Automerger
commit 6dca198753
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;
}
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");

View File

@ -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;
}
}

View File

@ -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);

View File

@ -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();

View File

@ -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;
}

View File

@ -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

View File

@ -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) {

View File

@ -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;

View File

@ -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;
}
}

View File

@ -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 {

View File

@ -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;

View File

@ -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)) == 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;
}
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);
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;
int network_inaddr_any_server(int port, int type, std::string* error) {
return _network_server(port, type, INADDR_ANY, error);
}
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();
hostent* hp = gethostbyname(host);
if(hp == 0) {
_fh_close(f);
struct addrinfo hints;
memset(&hints, 0, sizeof(hints));
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;
}
std::unique_ptr<struct addrinfo, decltype(freeaddrinfo)*>
addrinfo(addrinfo_ptr, freeaddrinfo);
addrinfo_ptr = nullptr;
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);
SOCKET s = socket(hp->h_addrtype, 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;
// TODO: implement timeouts for Windows.
if(connect(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;
}
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);
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);
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;
}
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 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]) {
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 );
}

View File

@ -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;
}