Merge "libcutils: share Windows networking code."
am: 1906de1e0f
* commit '1906de1e0fb70dbae4a713620072113a76d0a22a':
libcutils: share Windows networking code.
This commit is contained in:
commit
7a568dbdd6
17 changed files with 399 additions and 145 deletions
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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_"
|
||||
|
@ -45,7 +55,7 @@ extern "C" {
|
|||
* This is inline and not in libcutils proper because we want to use this in
|
||||
* third-party daemons with minimal modification.
|
||||
*/
|
||||
static inline int android_get_control_socket(const char *name)
|
||||
static inline int android_get_control_socket(const char* name)
|
||||
{
|
||||
char key[64];
|
||||
snprintf(key, sizeof(key), ANDROID_SOCKET_ENV_PREFIX "%s", name);
|
||||
|
@ -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,
|
||||
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);
|
||||
/*
|
||||
* 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);
|
||||
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
|
||||
|
@ -101,4 +138,4 @@ extern bool socket_peer_is_trusted(int fd);
|
|||
}
|
||||
#endif
|
||||
|
||||
#endif /* __CUTILS_SOCKETS_H */
|
||||
#endif /* __CUTILS_SOCKETS_H */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>
|
||||
|
79
libcutils/socket_inaddr_any_server_windows.c
Normal file
79
libcutils/socket_inaddr_any_server_windows.c
Normal file
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
* Copyright (C) 2015 The Android Open Source Project
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#include <cutils/sockets.h>
|
||||
|
||||
#define LISTEN_BACKLOG 4
|
||||
|
||||
extern bool initialize_windows_sockets();
|
||||
|
||||
SOCKET socket_inaddr_any_server(int port, int type) {
|
||||
if (!initialize_windows_sockets()) {
|
||||
return INVALID_SOCKET;
|
||||
}
|
||||
|
||||
SOCKET sock = socket(AF_INET6, type, 0);
|
||||
if (sock == INVALID_SOCKET) {
|
||||
return INVALID_SOCKET;
|
||||
}
|
||||
|
||||
// Enforce exclusive addresses so nobody can steal the port from us (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, (char*)&exclusive,
|
||||
sizeof(exclusive)) == SOCKET_ERROR ||
|
||||
setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&v6_only,
|
||||
sizeof(v6_only)) == SOCKET_ERROR) {
|
||||
closesocket(sock);
|
||||
return INVALID_SOCKET;
|
||||
}
|
||||
|
||||
// Bind the socket to our local port.
|
||||
struct 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, (struct sockaddr*)&addr, sizeof(addr)) == SOCKET_ERROR) {
|
||||
closesocket(sock);
|
||||
return INVALID_SOCKET;
|
||||
}
|
||||
|
||||
// Start listening for connections if this is a TCP socket.
|
||||
if (type == SOCK_STREAM && listen(sock, LISTEN_BACKLOG) == SOCKET_ERROR) {
|
||||
closesocket(sock);
|
||||
return INVALID_SOCKET;
|
||||
}
|
||||
|
||||
return sock;
|
||||
}
|
|
@ -37,7 +37,7 @@ int socket_local_client(const char *name, int namespaceId, int type)
|
|||
#include <sys/select.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "socket_local.h"
|
||||
#include "socket_local_unix.h"
|
||||
|
||||
#define UNUSED __attribute__((unused))
|
||||
|
|
@ -39,7 +39,7 @@ int socket_local_server(const char *name, int namespaceId, int type)
|
|||
#include <sys/types.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include "socket_local.h"
|
||||
#include "socket_local_unix.h"
|
||||
|
||||
#define LISTEN_BACKLOG 4
|
||||
|
69
libcutils/socket_network_client_windows.c
Normal file
69
libcutils/socket_network_client_windows.c
Normal file
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* Copyright (C) 2015 The Android Open Source Project
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <cutils/sockets.h>
|
||||
|
||||
extern bool initialize_windows_sockets();
|
||||
|
||||
SOCKET socket_network_client(const char* host, int port, int type) {
|
||||
if (!initialize_windows_sockets()) {
|
||||
return INVALID_SOCKET;
|
||||
}
|
||||
|
||||
// First resolve the host and port parameters into a usable network address.
|
||||
struct addrinfo hints;
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_socktype = type;
|
||||
|
||||
struct addrinfo* address = NULL;
|
||||
char port_str[16];
|
||||
snprintf(port_str, sizeof(port_str), "%d", port);
|
||||
if (getaddrinfo(host, port_str, &hints, &address) != 0 || address == NULL) {
|
||||
if (address != NULL) {
|
||||
freeaddrinfo(address);
|
||||
}
|
||||
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;
|
||||
}
|
|
@ -45,3 +45,7 @@ bool socket_peer_is_trusted(int fd __android_unused)
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
int socket_close(int sock) {
|
||||
return close(sock);
|
||||
}
|
55
libcutils/sockets_windows.c
Normal file
55
libcutils/sockets_windows.c
Normal file
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* Copyright (C) 2015 The Android Open Source Project
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <cutils/sockets.h>
|
||||
|
||||
// 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,
|
||||
// likely since Windows 3.1. Additionally, trying to properly use WSACleanup()
|
||||
// can be extremely tricky and cause deadlock when using threads or atexit().
|
||||
//
|
||||
// Both adb (1) and Chrome (2) purposefully avoid WSACleanup() with no issues.
|
||||
// (1) https://android.googlesource.com/platform/system/core.git/+/master/adb/sysdeps_win32.cpp
|
||||
// (2) https://code.google.com/p/chromium/codesearch#chromium/src/net/base/winsock_init.cc
|
||||
bool initialize_windows_sockets() {
|
||||
// There's no harm in calling WSAStartup() multiple times but no benefit
|
||||
// either, we may as well skip it after the first.
|
||||
static bool init_success = false;
|
||||
|
||||
if (!init_success) {
|
||||
WSADATA wsaData;
|
||||
init_success = (WSAStartup(MAKEWORD(2, 2), &wsaData) == 0);
|
||||
}
|
||||
|
||||
return init_success;
|
||||
}
|
||||
|
||||
int socket_close(cutils_socket_t sock) {
|
||||
return closesocket(sock);
|
||||
}
|
|
@ -15,6 +15,9 @@
|
|||
LOCAL_PATH := $(call my-dir)
|
||||
|
||||
test_src_files := \
|
||||
sockets_test.cpp \
|
||||
|
||||
test_src_files_nonwindows := \
|
||||
test_str_parms.cpp \
|
||||
|
||||
test_target_only_src_files := \
|
||||
|
@ -55,7 +58,7 @@ include $(BUILD_NATIVE_TEST)
|
|||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := libcutils_test
|
||||
LOCAL_SRC_FILES := $(test_src_files)
|
||||
LOCAL_SRC_FILES := $(test_src_files) $(test_src_files_nonwindows)
|
||||
LOCAL_SHARED_LIBRARIES := $(test_libraries)
|
||||
LOCAL_MULTILIB := both
|
||||
LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
|
||||
|
@ -65,9 +68,13 @@ include $(BUILD_HOST_NATIVE_TEST)
|
|||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := libcutils_test_static
|
||||
LOCAL_SRC_FILES := $(test_src_files)
|
||||
LOCAL_SRC_FILES_darwin := $(test_src_files_nonwindows)
|
||||
LOCAL_SRC_FILES_linux := $(test_src_files_nonwindows)
|
||||
LOCAL_STATIC_LIBRARIES := $(test_libraries)
|
||||
LOCAL_LDLIBS_windows := -lws2_32
|
||||
LOCAL_CXX_STL := libc++_static
|
||||
LOCAL_MULTILIB := both
|
||||
LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
|
||||
LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
|
||||
LOCAL_MODULE_HOST_OS := darwin linux windows
|
||||
include $(BUILD_HOST_NATIVE_TEST)
|
||||
|
|
111
libcutils/tests/sockets_test.cpp
Normal file
111
libcutils/tests/sockets_test.cpp
Normal file
|
@ -0,0 +1,111 @@
|
|||
/*
|
||||
* Copyright (C) 2015 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
// Tests socket functionality using loopback connections. Requires IPv4 and
|
||||
// IPv6 capabilities, and that kTestPort is available for loopback
|
||||
// communication. These tests also assume that no UDP packets are lost,
|
||||
// which should be the case for loopback communication, but is not guaranteed.
|
||||
|
||||
#include <cutils/sockets.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
enum {
|
||||
// This port must be available for loopback communication.
|
||||
kTestPort = 54321
|
||||
};
|
||||
|
||||
// Makes sure the passed sockets are valid, sends data between them, and closes
|
||||
// them. Any failures are logged with gtest.
|
||||
//
|
||||
// On Mac recvfrom() will not fill in the address for TCP sockets, so we need
|
||||
// separate logic paths depending on socket type.
|
||||
static void TestConnectedSockets(cutils_socket_t server, cutils_socket_t client,
|
||||
int type) {
|
||||
ASSERT_NE(INVALID_SOCKET, server);
|
||||
ASSERT_NE(INVALID_SOCKET, client);
|
||||
|
||||
char buffer[3];
|
||||
sockaddr_storage addr;
|
||||
socklen_t addr_size = sizeof(addr);
|
||||
|
||||
// Send client -> server first to get the UDP client's address.
|
||||
ASSERT_EQ(3, send(client, "foo", 3, 0));
|
||||
if (type == SOCK_DGRAM) {
|
||||
EXPECT_EQ(3, recvfrom(server, buffer, 3, 0,
|
||||
reinterpret_cast<sockaddr*>(&addr), &addr_size));
|
||||
} else {
|
||||
EXPECT_EQ(3, recv(server, buffer, 3, 0));
|
||||
}
|
||||
EXPECT_EQ(0, memcmp(buffer, "foo", 3));
|
||||
|
||||
// Now send server -> client.
|
||||
if (type == SOCK_DGRAM) {
|
||||
ASSERT_EQ(3, sendto(server, "bar", 3, 0,
|
||||
reinterpret_cast<sockaddr*>(&addr), addr_size));
|
||||
} else {
|
||||
ASSERT_EQ(3, send(server, "bar", 3, 0));
|
||||
}
|
||||
EXPECT_EQ(3, recv(client, buffer, 3, 0));
|
||||
EXPECT_EQ(0, memcmp(buffer, "bar", 3));
|
||||
|
||||
EXPECT_EQ(0, socket_close(server));
|
||||
EXPECT_EQ(0, socket_close(client));
|
||||
}
|
||||
|
||||
// Tests socket_inaddr_any_server() and socket_network_client() for IPv4 UDP.
|
||||
TEST(SocketsTest, TestIpv4UdpLoopback) {
|
||||
cutils_socket_t server = socket_inaddr_any_server(kTestPort, SOCK_DGRAM);
|
||||
cutils_socket_t client = socket_network_client("127.0.0.1", kTestPort,
|
||||
SOCK_DGRAM);
|
||||
|
||||
TestConnectedSockets(server, client, SOCK_DGRAM);
|
||||
}
|
||||
|
||||
// Tests socket_inaddr_any_server() and socket_network_client() for IPv4 TCP.
|
||||
TEST(SocketsTest, TestIpv4TcpLoopback) {
|
||||
cutils_socket_t server = socket_inaddr_any_server(kTestPort, SOCK_STREAM);
|
||||
ASSERT_NE(INVALID_SOCKET, server);
|
||||
|
||||
cutils_socket_t client = socket_network_client("127.0.0.1", kTestPort,
|
||||
SOCK_STREAM);
|
||||
cutils_socket_t handler = accept(server, nullptr, nullptr);
|
||||
EXPECT_EQ(0, socket_close(server));
|
||||
|
||||
TestConnectedSockets(handler, client, SOCK_STREAM);
|
||||
}
|
||||
|
||||
// Tests socket_inaddr_any_server() and socket_network_client() for IPv6 UDP.
|
||||
TEST(SocketsTest, TestIpv6UdpLoopback) {
|
||||
cutils_socket_t server = socket_inaddr_any_server(kTestPort, SOCK_DGRAM);
|
||||
cutils_socket_t client = socket_network_client("::1", kTestPort,
|
||||
SOCK_DGRAM);
|
||||
|
||||
TestConnectedSockets(server, client, SOCK_DGRAM);
|
||||
}
|
||||
|
||||
// Tests socket_inaddr_any_server() and socket_network_client() for IPv6 TCP.
|
||||
TEST(SocketsTest, TestIpv6TcpLoopback) {
|
||||
cutils_socket_t server = socket_inaddr_any_server(kTestPort, SOCK_STREAM);
|
||||
ASSERT_NE(INVALID_SOCKET, server);
|
||||
|
||||
cutils_socket_t client = socket_network_client("::1", kTestPort,
|
||||
SOCK_STREAM);
|
||||
cutils_socket_t handler = accept(server, nullptr, nullptr);
|
||||
EXPECT_EQ(0, socket_close(server));
|
||||
|
||||
TestConnectedSockets(handler, client, SOCK_STREAM);
|
||||
}
|
Loading…
Reference in a new issue