Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0eb8e1b7 authored by David Pursell's avatar David Pursell
Browse files

libcutils: share Windows networking code.

This CL moves Windows networking code from fastboot to libcutils so
that it can be shared with other host programs such as adb.

Not all libcutils networking functions have been implemented for
Windows, just those necessary for fastboot. In the next CL I will do
the same for adb, adding any additional required functions.

Unit tests have also been added to test the functions using a loopback
connection.

Bug: http://b/26236380.
Change-Id: Ibc51a67030fe69a04c23512eefa9d19b055c7c12
parent 047597b3
Loading
Loading
Loading
Loading
+4 −5
Original line number Diff line number Diff line
@@ -34,10 +34,10 @@ LOCAL_CFLAGS += -Wall -Wextra -Werror -Wunreachable-code
LOCAL_CFLAGS += -DFASTBOOT_REVISION='"$(fastboot_version)"'

LOCAL_SRC_FILES_linux := socket_unix.cpp usb_linux.cpp util_linux.cpp
LOCAL_STATIC_LIBRARIES_linux := libcutils libselinux
LOCAL_STATIC_LIBRARIES_linux := libselinux

LOCAL_SRC_FILES_darwin := socket_unix.cpp usb_osx.cpp util_osx.cpp
LOCAL_STATIC_LIBRARIES_darwin := libcutils libselinux
LOCAL_STATIC_LIBRARIES_darwin := libselinux
LOCAL_LDLIBS_darwin := -lpthread -framework CoreFoundation -framework IOKit -framework Carbon
LOCAL_CFLAGS_darwin := -Wno-unused-parameter

@@ -56,6 +56,7 @@ LOCAL_STATIC_LIBRARIES := \
    libz \
    libdiagnose_usb \
    libbase \
    libcutils \

# libf2fs_dlutils_host will dlopen("libf2fs_fmt_host_dyn")
LOCAL_CFLAGS_linux := -DUSE_F2FS
@@ -98,17 +99,15 @@ LOCAL_MODULE := fastboot_test
LOCAL_MODULE_HOST_OS := darwin linux windows

LOCAL_SRC_FILES := socket_test.cpp
LOCAL_STATIC_LIBRARIES := libbase
LOCAL_STATIC_LIBRARIES := libbase libcutils

LOCAL_CFLAGS += -Wall -Wextra -Werror -Wunreachable-code

LOCAL_SRC_FILES_linux := socket_unix.cpp
LOCAL_STATIC_LIBRARIES_linux := libcutils

LOCAL_SRC_FILES_darwin := socket_unix.cpp
LOCAL_LDLIBS_darwin := -lpthread -framework CoreFoundation -framework IOKit -framework Carbon
LOCAL_CFLAGS_darwin := -Wno-unused-parameter
LOCAL_STATIC_LIBRARIES_darwin := libcutils

LOCAL_SRC_FILES_windows := socket_windows.cpp
LOCAL_LDLIBS_windows := -lws2_32
+2 −114
Original line number Diff line number Diff line
@@ -34,6 +34,7 @@
#include <memory>

#include <android-base/stringprintf.h>
#include <cutils/sockets.h>

// Windows UDP socket functionality.
class WindowsUdpSocket : public UdpSocket {
@@ -108,118 +109,9 @@ int WindowsUdpSocket::Close() {
    return result;
}

static int GetProtocol(int sock_type) {
    switch (sock_type) {
        case SOCK_DGRAM:
            return IPPROTO_UDP;
        case SOCK_STREAM:
            return IPPROTO_TCP;
        default:
            // 0 lets the system decide which protocol to use.
            return 0;
    }
}

// Windows implementation of this libcutils function. This function does not make any calls to
// WSAStartup() or WSACleanup() so that must be handled by the caller.
// TODO(dpursell): share this code with adb.
static SOCKET socket_network_client(const std::string& host, int port, int type) {
    // First resolve the host and port parameters into a usable network address.
    addrinfo hints;
    memset(&hints, 0, sizeof(hints));
    hints.ai_socktype = type;
    hints.ai_protocol = GetProtocol(type);

    addrinfo* address = nullptr;
    getaddrinfo(host.c_str(), android::base::StringPrintf("%d", port).c_str(), &hints, &address);
    if (address == nullptr) {
        return INVALID_SOCKET;
    }

    // Now create and connect the socket.
    SOCKET sock = socket(address->ai_family, address->ai_socktype, address->ai_protocol);
    if (sock == INVALID_SOCKET) {
        freeaddrinfo(address);
        return INVALID_SOCKET;
    }

    if (connect(sock, address->ai_addr, address->ai_addrlen) == SOCKET_ERROR) {
        closesocket(sock);
        freeaddrinfo(address);
        return INVALID_SOCKET;
    }

    freeaddrinfo(address);
    return sock;
}

// Windows implementation of this libcutils function. This implementation creates a dual-stack
// server socket that can accept incoming IPv4 or IPv6 packets. This function does not make any
// calls to WSAStartup() or WSACleanup() so that must be handled by the caller.
// TODO(dpursell): share this code with adb.
static SOCKET socket_inaddr_any_server(int port, int type) {
    SOCKET sock = socket(AF_INET6, type, GetProtocol(type));
    if (sock == INVALID_SOCKET) {
        return INVALID_SOCKET;
    }

    // Enforce exclusive addresses (1), and enable dual-stack so both IPv4 and IPv6 work (2).
    // (1) https://msdn.microsoft.com/en-us/library/windows/desktop/ms740621(v=vs.85).aspx.
    // (2) https://msdn.microsoft.com/en-us/library/windows/desktop/bb513665(v=vs.85).aspx.
    int exclusive = 1;
    DWORD v6_only = 0;
    if (setsockopt(sock, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, reinterpret_cast<const char*>(&exclusive),
                   sizeof(exclusive)) == SOCKET_ERROR ||
        setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, reinterpret_cast<const char*>(&v6_only),
                   sizeof(v6_only)) == SOCKET_ERROR) {
        closesocket(sock);
        return INVALID_SOCKET;
    }

    // Bind the socket to our local port.
    sockaddr_in6 addr;
    memset(&addr, 0, sizeof(addr));
    addr.sin6_family = AF_INET6;
    addr.sin6_port = htons(port);
    addr.sin6_addr = in6addr_any;
    if (bind(sock, reinterpret_cast<sockaddr*>(&addr), sizeof(addr)) == SOCKET_ERROR) {
        closesocket(sock);
        return INVALID_SOCKET;
    }

    return sock;
}

// Documentation at https://msdn.microsoft.com/en-us/library/windows/desktop/ms741549(v=vs.85).aspx
// claims WSACleanup() should be called before program exit, but general consensus seems to be that
// it hasn't actually been necessary for a long time, possibly since Windows 3.1.
//
// Both adb (1) and Chrome (2) purposefully avoid WSACleanup(), and since no adverse affects have
// been found we may as well do the same here to keep this code simpler.
// (1) https://android.googlesource.com/platform/system/core.git/+/master/adb/sysdeps_win32.cpp#816
// (2) https://code.google.com/p/chromium/codesearch#chromium/src/net/base/winsock_init.cc&l=35
static bool InitWinsock() {
    static bool init_success = false;

    if (!init_success) {
        WSADATA wsaData;
        init_success = (WSAStartup(MAKEWORD(2, 2), &wsaData) == 0);
    }

    return init_success;
}

std::unique_ptr<UdpSocket> UdpSocket::NewUdpClient(const std::string& host, int port,
                                                   std::string* error) {
    if (!InitWinsock()) {
        if (error) {
            *error = android::base::StringPrintf("Failed to initialize Winsock (error %d)",
                                                 WSAGetLastError());
        }
        return nullptr;
    }

    SOCKET sock = socket_network_client(host, port, SOCK_DGRAM);
    SOCKET sock = socket_network_client(host.c_str(), port, SOCK_DGRAM);
    if (sock == INVALID_SOCKET) {
        if (error) {
            *error = android::base::StringPrintf("Failed to connect to %s:%d (error %d)",
@@ -233,10 +125,6 @@ std::unique_ptr<UdpSocket> UdpSocket::NewUdpClient(const std::string& host, int

// This functionality is currently only used by tests so we don't need any error messages.
std::unique_ptr<UdpSocket> UdpSocket::NewUdpServer(int port) {
    if (!InitWinsock()) {
        return nullptr;
    }

    SOCKET sock = socket_inaddr_any_server(port, SOCK_DGRAM);
    if (sock == INVALID_SOCKET) {
        return nullptr;
+50 −13
Original line number Diff line number Diff line
@@ -24,10 +24,20 @@
#include <stdbool.h>

#if defined(_WIN32)

#include <winsock2.h>
#include <ws2tcpip.h>

typedef int  socklen_t;
typedef SOCKET cutils_socket_t;

#else

#include <sys/socket.h>

typedef int cutils_socket_t;
#define INVALID_SOCKET (-1)

#endif

#define ANDROID_SOCKET_ENV_PREFIX	"ANDROID_SOCKET_"
@@ -74,17 +84,44 @@ static inline int android_get_control_socket(const char *name)
// Normal filesystem namespace
#define ANDROID_SOCKET_NAMESPACE_FILESYSTEM 2

extern int socket_loopback_client(int port, int type);
extern int socket_network_client(const char *host, int port, int type);
extern int socket_network_client_timeout(const char *host, int port, int type,
/*
 * Functions to create sockets for some common usages.
 *
 * All these functions are implemented for Unix, but only a few are implemented
 * for Windows. Those which are can be identified by the cutils_socket_t
 * return type. The idea is to be able to use this return value with the
 * standard Unix socket functions on any platform.
 *
 * On Unix the returned cutils_socket_t is a standard int file descriptor and
 * can always be used as normal with all file descriptor functions.
 *
 * On Windows utils_socket_t is an unsigned int pointer, and is only valid
 * with functions that specifically take a socket, e.g. send(), sendto(),
 * recv(), and recvfrom(). General file descriptor functions such as read(),
 * write(), and close() will not work with utils_socket_t and will require
 * special handling.
 *
 * These functions return INVALID_SOCKET (-1) on failure for all platforms.
 */
int socket_loopback_client(int port, int type);
cutils_socket_t socket_network_client(const char* host, int port, int type);
int socket_network_client_timeout(const char* host, int port, int type,
                                  int timeout, int* getaddrinfo_error);
extern int socket_loopback_server(int port, int type);
extern int socket_local_server(const char *name, int namespaceId, int type);
extern int socket_local_server_bind(int s, const char *name, int namespaceId);
extern int socket_local_client_connect(int fd, 
        const char *name, int namespaceId, int type);
extern int socket_local_client(const char *name, int namespaceId, int type);
extern int socket_inaddr_any_server(int port, int type);
int socket_loopback_server(int port, int type);
int socket_local_server(const char* name, int namespaceId, int type);
int socket_local_server_bind(int s, const char* name, int namespaceId);
int socket_local_client_connect(int fd, const char *name, int namespaceId,
                                int type);
int socket_local_client(const char* name, int namespaceId, int type);
cutils_socket_t socket_inaddr_any_server(int port, int type);

/*
 * Closes a cutils_socket_t. Windows doesn't allow calling close() on a socket
 * so this is a cross-platform way to close a cutils_socket_t.
 *
 * Returns 0 on success.
 */
int socket_close(cutils_socket_t sock);

/*
 * socket_peer_is_trusted - Takes a socket which is presumed to be a
+15 −8
Original line number Diff line number Diff line
@@ -39,26 +39,33 @@ libcutils_common_sources := \
libcutils_nonwindows_sources := \
        fs.c \
        multiuser.c \
        socket_inaddr_any_server.c \
        socket_local_client.c \
        socket_local_server.c \
        socket_loopback_client.c \
        socket_loopback_server.c \
        socket_network_client.c \
        sockets.c \
        socket_inaddr_any_server_unix.c \
        socket_local_client_unix.c \
        socket_local_server_unix.c \
        socket_loopback_client_unix.c \
        socket_loopback_server_unix.c \
        socket_network_client_unix.c \
        sockets_unix.c \
        str_parms.c \

libcutils_nonwindows_host_sources := \
        ashmem-host.c \
        trace-host.c
        trace-host.c \

libcutils_windows_host_sources := \
        socket_inaddr_any_server_windows.c \
        socket_network_client_windows.c \
        sockets_windows.c \

# Shared and static library for host
# Note: when linking this library on Windows, you must also link to Winsock2
# using "LOCAL_LDLIBS_windows := -lws2_32".
# ========================================================
LOCAL_MODULE := libcutils
LOCAL_SRC_FILES := $(libcutils_common_sources) dlmalloc_stubs.c
LOCAL_SRC_FILES_darwin := $(libcutils_nonwindows_sources) $(libcutils_nonwindows_host_sources)
LOCAL_SRC_FILES_linux := $(libcutils_nonwindows_sources) $(libcutils_nonwindows_host_sources)
LOCAL_SRC_FILES_windows := $(libcutils_windows_host_sources)
LOCAL_STATIC_LIBRARIES := liblog
LOCAL_CFLAGS := -Werror -Wall -Wextra
LOCAL_MULTILIB := both
+0 −2
Original line number Diff line number Diff line
@@ -20,12 +20,10 @@
#include <string.h>
#include <unistd.h>

#if !defined(_WIN32)
#include <sys/socket.h>
#include <sys/select.h>
#include <sys/types.h>
#include <netinet/in.h>
#endif

#include <cutils/sockets.h>

Loading