Merge "libcutils: share Windows networking code."

am: 1906de1e0f

* commit '1906de1e0fb70dbae4a713620072113a76d0a22a':
  libcutils: share Windows networking code.
This commit is contained in:
David Pursell 2016-01-21 17:00:57 +00:00 committed by android-build-merger
commit 7a568dbdd6
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);
}