Merge "adb: win32: initial IPv6 support and improved Winsock error reporting"
diff --git a/adb/adb.cpp b/adb/adb.cpp
index aa9ef55..aa0256d 100644
--- a/adb/adb.cpp
+++ b/adb/adb.cpp
@@ -801,11 +801,13 @@
             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 @@
           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/adb_client.cpp b/adb/adb_client.cpp
index 418662c..6d75966 100644
--- a/adb/adb_client.cpp
+++ b/adb/adb_client.cpp
@@ -153,8 +153,8 @@
     }
 
     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 @@
             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/adb_listeners.cpp b/adb/adb_listeners.cpp
index bb45022..1e7ce5d 100644
--- a/adb/adb_listeners.cpp
+++ b/adb/adb_listeners.cpp
@@ -110,27 +110,30 @@
     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 @@
 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 @@
         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/adb_listeners.h b/adb/adb_listeners.h
index 67deb21..fa98eed 100644
--- a/adb/adb_listeners.h
+++ b/adb/adb_listeners.h
@@ -33,7 +33,8 @@
 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/adb_utils.cpp b/adb/adb_utils.cpp
index 3ba971d..12208cd 100644
--- a/adb/adb_utils.cpp
+++ b/adb/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 @@
                << " (" << *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/adb_utils.h b/adb/adb_utils.h
index 30cd7a4..8c5208c 100644
--- a/adb/adb_utils.h
+++ b/adb/adb_utils.h
@@ -40,6 +40,4 @@
                          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/adb/client/main.cpp b/adb/client/main.cpp
index c018b8a..2b174cd 100644
--- a/adb/client/main.cpp
+++ b/adb/client/main.cpp
@@ -150,9 +150,10 @@
     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/adb/console.cpp b/adb/console.cpp
index b7f5345..ba5a72b 100644
--- a/adb/console.cpp
+++ b/adb/console.cpp
@@ -71,9 +71,11 @@
         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/adb/daemon/main.cpp b/adb/daemon/main.cpp
index 157c97b..a63d67e 100644
--- a/adb/daemon/main.cpp
+++ b/adb/daemon/main.cpp
@@ -177,10 +177,13 @@
                 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/adb/services.cpp b/adb/services.cpp
index 708ef42..63a0a76 100644
--- a/adb/services.cpp
+++ b/adb/services.cpp
@@ -432,7 +432,8 @@
         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 {
diff --git a/adb/sysdeps.h b/adb/sysdeps.h
index c033999..a57f650 100644
--- a/adb/sysdeps.h
+++ b/adb/sysdeps.h
@@ -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 @@
     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 @@
     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 @@
 #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 @@
 #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/adb/sysdeps_win32.cpp b/adb/sysdeps_win32.cpp
index a274892..9fdc24c 100644
--- a/adb/sysdeps_win32.cpp
+++ b/adb/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 @@
 
 #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 @@
     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_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 @@
 
 #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_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_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 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 @@
 
     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 @@
     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 @@
 
     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 @@
 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 @@
     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 @@
     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 @@
     hook->check   = _event_socket_check;
     hook->peek    = _event_socket_peek;
 
+    // TODO: check return value?
     _event_socket_start( hook );
 }
 
diff --git a/adb/transport_local.cpp b/adb/transport_local.cpp
index 0dc9581..db9bedb 100644
--- a/adb/transport_local.cpp
+++ b/adb/transport_local.cpp
@@ -100,7 +100,7 @@
     }
 #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 @@
     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;
             }