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
This commit is contained in:
David Pursell 2016-01-14 17:18:27 -08:00
parent 047597b3fc
commit 0eb8e1b706
17 changed files with 399 additions and 145 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

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

View file

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

View file

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

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

View file

@ -45,3 +45,7 @@ bool socket_peer_is_trusted(int fd __android_unused)
return true;
}
int socket_close(int sock) {
return close(sock);
}

View 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);
}

View file

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

View 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);
}