From 4f35d1af1aeac59345aeec4390f920d3f3d3e1fa Mon Sep 17 00:00:00 2001 From: Luca Boccassi Date: Sat, 25 Apr 2020 19:53:44 +0100 Subject: [PATCH] Problem: using BSD sockets in test is duplicated across many tests Solution: refactor in testutil.lib, so that they can be used for fuzzers too --- tests/test_heartbeats.cpp | 16 +-- tests/test_mock_pub_sub.cpp | 31 +----- tests/test_security_curve.cpp | 45 +-------- tests/test_security_gssapi.cpp | 29 +----- tests/test_security_null.cpp | 19 +--- tests/test_security_plain.cpp | 32 +----- tests/test_socks.cpp | 19 +--- tests/test_stream_exceeds_buffer.cpp | 17 +--- tests/test_use_fd.cpp | 98 ++---------------- tests/testutil.cpp | 146 +++++++++++++++++++++++++++ tests/testutil.hpp | 24 +++++ 11 files changed, 196 insertions(+), 280 deletions(-) diff --git a/tests/test_heartbeats.cpp b/tests/test_heartbeats.cpp index 943b6792..b1dac3a1 100644 --- a/tests/test_heartbeats.cpp +++ b/tests/test_heartbeats.cpp @@ -226,21 +226,7 @@ static void test_heartbeat_timeout (int server_type_, int mock_ping_) prep_server_socket (!mock_ping_, 0, &server, &server_mon, my_endpoint, MAX_SOCKET_STRING, server_type_); - struct sockaddr_in ip4addr; - raw_socket s; - - ip4addr.sin_family = AF_INET; - ip4addr.sin_port = htons (atoi (strrchr (my_endpoint, ':') + 1)); -#if defined(ZMQ_HAVE_WINDOWS) && (_WIN32_WINNT < 0x0600) - ip4addr.sin_addr.s_addr = inet_addr ("127.0.0.1"); -#else - inet_pton (AF_INET, "127.0.0.1", &ip4addr.sin_addr); -#endif - - s = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP); - rc = TEST_ASSERT_SUCCESS_RAW_ERRNO ( - connect (s, (struct sockaddr *) &ip4addr, sizeof ip4addr)); - TEST_ASSERT_GREATER_THAN_INT (-1, rc); + fd_t s = connect_socket (my_endpoint); // Mock a ZMTP 3 client so we can forcibly time out a connection mock_handshake (s, mock_ping_); diff --git a/tests/test_mock_pub_sub.cpp b/tests/test_mock_pub_sub.cpp index 6795bb7e..d1940d0f 100644 --- a/tests/test_mock_pub_sub.cpp +++ b/tests/test_mock_pub_sub.cpp @@ -19,17 +19,6 @@ #include "testutil.hpp" #include "testutil_unity.hpp" -#if defined(ZMQ_HAVE_WINDOWS) -#include -#include -#include -#define close closesocket -typedef SOCKET raw_socket; -#else -#include -#include -typedef int raw_socket; -#endif #include #include @@ -67,7 +56,7 @@ static int get_monitor_event (void *monitor_) return -1; } -static void recv_with_retry (raw_socket fd_, char *buffer_, int bytes_) +static void recv_with_retry (fd_t fd_, char *buffer_, int bytes_) { int received = 0; while (true) { @@ -81,7 +70,7 @@ static void recv_with_retry (raw_socket fd_, char *buffer_, int bytes_) } } -static void mock_handshake (raw_socket fd_, bool sub_command, bool mock_pub) +static void mock_handshake (fd_t fd_, bool sub_command, bool mock_pub) { const uint8_t zmtp_greeting[33] = {0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0x7f, 3, 0, 'N', 'U', 'L', 'L', 0}; @@ -158,21 +147,7 @@ static void test_mock_pub_sub (bool sub_command_, bool mock_pub_) prep_server_socket (&server, &server_mon, my_endpoint, MAX_SOCKET_STRING, mock_pub_ ? ZMQ_SUB : ZMQ_XPUB); - struct sockaddr_in ip4addr; - raw_socket s; - - ip4addr.sin_family = AF_INET; - ip4addr.sin_port = htons (atoi (strrchr (my_endpoint, ':') + 1)); -#if defined(ZMQ_HAVE_WINDOWS) && (_WIN32_WINNT < 0x0600) - ip4addr.sin_addr.s_addr = inet_addr ("127.0.0.1"); -#else - inet_pton (AF_INET, "127.0.0.1", &ip4addr.sin_addr); -#endif - - s = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP); - rc = TEST_ASSERT_SUCCESS_RAW_ERRNO ( - connect (s, (struct sockaddr *) &ip4addr, sizeof ip4addr)); - TEST_ASSERT_GREATER_THAN_INT (-1, rc); + fd_t s = connect_socket (my_endpoint); // Mock a ZMTP 3 client so we can forcibly try sub commands mock_handshake (s, sub_command_, mock_pub_); diff --git a/tests/test_security_curve.cpp b/tests/test_security_curve.cpp index bcf8076b..796f7894 100644 --- a/tests/test_security_curve.cpp +++ b/tests/test_security_curve.cpp @@ -47,17 +47,6 @@ #include "testutil.hpp" #include "testutil_security.hpp" -#if defined(ZMQ_HAVE_WINDOWS) -#include -#include -#include -#define close closesocket -#else -#include -#include -#include -#include -#endif #include #include "../src/tweetnacl.h" @@ -223,34 +212,10 @@ void test_curve_security_with_plain_client_credentials () expect_zmtp_mechanism_mismatch (client, my_endpoint, server, server_mon); } -fd_t connect_vanilla_socket (char *my_endpoint_) -{ - fd_t s; - struct sockaddr_in ip4addr; - - unsigned short int port; - int rc = sscanf (my_endpoint_, "tcp://127.0.0.1:%hu", &port); - TEST_ASSERT_EQUAL_INT (1, rc); - - ip4addr.sin_family = AF_INET; - ip4addr.sin_port = htons (port); -#if defined(ZMQ_HAVE_WINDOWS) && (_WIN32_WINNT < 0x0600) - ip4addr.sin_addr.s_addr = inet_addr ("127.0.0.1"); -#else - inet_pton (AF_INET, "127.0.0.1", &ip4addr.sin_addr); -#endif - - s = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP); - rc = connect (s, reinterpret_cast (&ip4addr), - sizeof (ip4addr)); - TEST_ASSERT_GREATER_THAN_INT (-1, rc); - return s; -} - void test_curve_security_unauthenticated_message () { // Unauthenticated messages from a vanilla socket shouldn't be received - fd_t s = connect_vanilla_socket (my_endpoint); + fd_t s = connect_socket (my_endpoint); // send anonymous ZMTP/1.0 greeting send (s, "\x01\x00", 2, 0); // send sneaky message that shouldn't be received @@ -288,7 +253,7 @@ void send_greeting (fd_t s_) void test_curve_security_invalid_hello_wrong_length () { - fd_t s = connect_vanilla_socket (my_endpoint); + fd_t s = connect_socket (my_endpoint); // send GREETING send_greeting (s); @@ -355,7 +320,7 @@ template void send_command (fd_t s_, char (&command_)[N]) void test_curve_security_invalid_hello_command_name () { - fd_t s = connect_vanilla_socket (my_endpoint); + fd_t s = connect_socket (my_endpoint); send_greeting (s); @@ -377,7 +342,7 @@ void test_curve_security_invalid_hello_command_name () void test_curve_security_invalid_hello_version () { - fd_t s = connect_vanilla_socket (my_endpoint); + fd_t s = connect_socket (my_endpoint); send_greeting (s); @@ -429,7 +394,7 @@ void recv_greeting (fd_t fd_) fd_t connect_exchange_greeting_and_send_hello ( char *my_endpoint_, zmq::curve_client_tools_t &tools_) { - fd_t s = connect_vanilla_socket (my_endpoint_); + fd_t s = connect_socket (my_endpoint_); send_greeting (s); recv_greeting (s); diff --git a/tests/test_security_gssapi.cpp b/tests/test_security_gssapi.cpp index 39d66f94..ea4de370 100644 --- a/tests/test_security_gssapi.cpp +++ b/tests/test_security_gssapi.cpp @@ -30,17 +30,6 @@ #include "testutil.hpp" #include "testutil_monitoring.hpp" #include "testutil_unity.hpp" -#if defined(ZMQ_HAVE_WINDOWS) -#include -#include -#include -#define close closesocket -#else -#include -#include -#include -#include -#endif #include #include @@ -253,23 +242,7 @@ void test_plain_creds () // Unauthenticated messages from a vanilla socket shouldn't be received void test_vanilla_socket () { - struct sockaddr_in ip4addr; - int s; - unsigned short int port; - int rc = sscanf (my_endpoint, "tcp://127.0.0.1:%hu", &port); - TEST_ASSERT_EQUAL_INT (1, rc); - ip4addr.sin_family = AF_INET; - ip4addr.sin_port = htons (port); -#if defined(ZMQ_HAVE_WINDOWS) && (_WIN32_WINNT < 0x0600) - ip4addr.sin_addr.s_addr = inet_addr ("127.0.0.1"); -#else - inet_pton (AF_INET, "127.0.0.1", &ip4addr.sin_addr); -#endif - - s = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP); - rc = connect (s, reinterpret_cast (&ip4addr), - sizeof (ip4addr)); - TEST_ASSERT_GREATER_THAN (-1, rc); + fd_t s = connect_socket (my_endpoint); // send anonymous ZMTP/1.0 greeting send (s, "\x01\x00", 2, 0); // send sneaky message that shouldn't be received diff --git a/tests/test_security_null.cpp b/tests/test_security_null.cpp index 069c543c..d6e17a2d 100644 --- a/tests/test_security_null.cpp +++ b/tests/test_security_null.cpp @@ -169,25 +169,8 @@ void test_vanilla_socket () char my_endpoint[MAX_SOCKET_STRING]; bind_loopback_ipv4 (server, my_endpoint, sizeof my_endpoint); - struct sockaddr_in ip4addr; - fd_t s; + fd_t s = connect_socket (my_endpoint); - unsigned short int port; - int rc = sscanf (my_endpoint, "tcp://127.0.0.1:%hu", &port); - TEST_ASSERT_EQUAL_INT (1, rc); - - ip4addr.sin_family = AF_INET; - ip4addr.sin_port = htons (port); -#if defined(ZMQ_HAVE_WINDOWS) && (_WIN32_WINNT < 0x0600) - ip4addr.sin_addr.s_addr = inet_addr ("127.0.0.1"); -#else - inet_pton (AF_INET, "127.0.0.1", &ip4addr.sin_addr); -#endif - - s = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP); - rc = connect (s, reinterpret_cast (&ip4addr), - sizeof ip4addr); - TEST_ASSERT_GREATER_THAN_INT (-1, rc); // send anonymous ZMTP/1.0 greeting send (s, "\x01\x00", 2, 0); // send sneaky message that shouldn't be received diff --git a/tests/test_security_plain.cpp b/tests/test_security_plain.cpp index acb3789c..7cfc53c9 100644 --- a/tests/test_security_plain.cpp +++ b/tests/test_security_plain.cpp @@ -30,18 +30,6 @@ #include "testutil.hpp" #include "testutil_unity.hpp" -#if defined(ZMQ_HAVE_WINDOWS) -#include -#include -#include -#define close closesocket -#else -#include -#include -#include -#include -#endif - #include #include @@ -195,25 +183,7 @@ void test_plain_wrong_credentials_fails () void test_plain_vanilla_socket () { // Unauthenticated messages from a vanilla socket shouldn't be received - struct sockaddr_in ip4addr; - fd_t s; - - unsigned short int port; - int rc = sscanf (my_endpoint, "tcp://127.0.0.1:%hu", &port); - TEST_ASSERT_EQUAL_INT (1, rc); - - ip4addr.sin_family = AF_INET; - ip4addr.sin_port = htons (port); -#if defined(ZMQ_HAVE_WINDOWS) && (_WIN32_WINNT < 0x0600) - ip4addr.sin_addr.s_addr = inet_addr ("127.0.0.1"); -#else - inet_pton (AF_INET, "127.0.0.1", &ip4addr.sin_addr); -#endif - - s = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP); - rc = connect (s, reinterpret_cast (&ip4addr), - sizeof (ip4addr)); - TEST_ASSERT_GREATER_THAN_INT (-1, rc); + fd_t s = connect_socket (my_endpoint); // send anonymous ZMTP/1.0 greeting send (s, "\x01\x00", 2, 0); // send sneaky message that shouldn't be received diff --git a/tests/test_socks.cpp b/tests/test_socks.cpp index 89c3b933..396c76fb 100644 --- a/tests/test_socks.cpp +++ b/tests/test_socks.cpp @@ -105,21 +105,10 @@ void *setup_socks_server (char *socks_server_address, int socks_server_address_len) { fprintf (stderr, "socks_server: setup socks server\n"); - int server_fd = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP); - TEST_ASSERT_NOT_EQUAL (-1, server_fd); - int flag = 1; - int res; -#ifdef _WIN32 - res = setsockopt (server_fd, SOL_SOCKET, SO_REUSEADDR, (const char *) &flag, - sizeof (int)); -#else - res = setsockopt (server_fd, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof (int)); -#endif - TEST_ASSERT_SUCCESS_RAW_ERRNO (res); - struct sockaddr_in saddr = bind_bsd_socket (server_fd); - int nbytes = snprintf (socks_server_address, socks_server_address_len, - "127.0.0.1:%d", ntohs (saddr.sin_port)); - TEST_ASSERT (nbytes >= 0 && nbytes < socks_server_address_len); + int server_fd = + bind_socket_resolve_port ("127.0.0.1", "0", socks_server_address); + memmove (socks_server_address, strchr (socks_server_address, '/') + 2, + strlen (strchr (socks_server_address, '/') + 1)); fprintf (stderr, "socks_server: bound to: tcp://%s\n", socks_server_address); return (void *) (intptr_t) server_fd; diff --git a/tests/test_stream_exceeds_buffer.cpp b/tests/test_stream_exceeds_buffer.cpp index 767946d7..e8478ad4 100644 --- a/tests/test_stream_exceeds_buffer.cpp +++ b/tests/test_stream_exceeds_buffer.cpp @@ -32,12 +32,6 @@ #include -#ifndef _WIN32 -#include -#include -#include -#endif - SETUP_TEARDOWN_TESTCONTEXT void test_stream_exceeds_buffer () @@ -47,16 +41,7 @@ void test_stream_exceeds_buffer () unsigned char rcvbuf[msgsize]; char my_endpoint[MAX_SOCKET_STRING]; - int server_sock = - TEST_ASSERT_SUCCESS_RAW_ERRNO (socket (AF_INET, SOCK_STREAM, 0)); - int enable = 1; - TEST_ASSERT_SUCCESS_RAW_ERRNO (setsockopt (server_sock, SOL_SOCKET, - SO_REUSEADDR, (char *) &enable, - sizeof (enable))); - struct sockaddr_in saddr = bind_bsd_socket (server_sock); - TEST_ASSERT_SUCCESS_RAW_ERRNO (listen (server_sock, 1)); - - sprintf (my_endpoint, "tcp://127.0.0.1:%d", ntohs (saddr.sin_port)); + int server_sock = bind_socket_resolve_port ("127.0.0.1", "0", my_endpoint); void *zsock = test_context_socket (ZMQ_STREAM); TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (zsock, my_endpoint)); diff --git a/tests/test_use_fd.cpp b/tests/test_use_fd.cpp index 98de2199..f15ffea0 100644 --- a/tests/test_use_fd.cpp +++ b/tests/test_use_fd.cpp @@ -37,33 +37,12 @@ SETUP_TEARDOWN_TESTCONTEXT #if !defined(ZMQ_HAVE_WINDOWS) -#include -#include -#include -#include -int setup_socket_and_set_fd (void *zmq_socket_, - int af_, - int protocol_, - const sockaddr *addr_, - size_t addr_len_) +void pre_allocate_sock_tcp (void *socket_, char *my_endpoint_) { - const int s_pre = - TEST_ASSERT_SUCCESS_ERRNO (socket (af_, SOCK_STREAM, protocol_)); - - if (af_ == AF_INET) { - int flag = 1; - TEST_ASSERT_SUCCESS_ERRNO ( - setsockopt (s_pre, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof (int))); - } - - TEST_ASSERT_SUCCESS_ERRNO (bind (s_pre, addr_, addr_len_)); - TEST_ASSERT_SUCCESS_ERRNO (listen (s_pre, SOMAXCONN)); - + fd_t s = bind_socket_resolve_port ("127.0.0.1", "0", my_endpoint_); TEST_ASSERT_SUCCESS_ERRNO ( - zmq_setsockopt (zmq_socket_, ZMQ_USE_FD, &s_pre, sizeof (s_pre))); - - return s_pre; + zmq_setsockopt (socket_, ZMQ_USE_FD, &s, sizeof (s))); } typedef void (*pre_allocate_sock_fun_t) (void *, char *); @@ -166,41 +145,6 @@ void test_client_server (pre_allocate_sock_fun_t pre_allocate_sock_fun_) #endif } -uint16_t pre_allocate_sock_tcp_int (void *zmq_socket_, - const char *address_, - const char *port_) -{ - struct addrinfo *addr, hint; - hint.ai_flags = 0; - hint.ai_family = AF_INET; - hint.ai_socktype = SOCK_STREAM; - hint.ai_protocol = IPPROTO_TCP; - hint.ai_addrlen = 0; - hint.ai_canonname = NULL; - hint.ai_addr = NULL; - hint.ai_next = NULL; - - TEST_ASSERT_SUCCESS_ERRNO (getaddrinfo (address_, port_, &hint, &addr)); - - const int s_pre = setup_socket_and_set_fd ( - zmq_socket_, AF_INET, IPPROTO_TCP, addr->ai_addr, addr->ai_addrlen); - - struct sockaddr_in sin; - socklen_t len = sizeof (sin); - TEST_ASSERT_SUCCESS_ERRNO ( - getsockname (s_pre, (struct sockaddr *) &sin, &len)); - - freeaddrinfo (addr); - - return ntohs (sin.sin_port); -} - -void pre_allocate_sock_tcp (void *socket_, char *my_endpoint_) -{ - const uint16_t port = pre_allocate_sock_tcp_int (socket_, "127.0.0.1", "0"); - sprintf (my_endpoint_, "tcp://127.0.0.1:%u", port); -} - void test_req_rep_tcp () { test_req_rep (pre_allocate_sock_tcp); @@ -218,38 +162,14 @@ void test_client_server_tcp () #endif } -void pre_allocate_sock_ipc_int (void *zmq_socket_, const char *path_) -{ - struct sockaddr_un addr; - addr.sun_family = AF_UNIX; - strcpy (addr.sun_path, path_); - - // TODO check return value of unlink - unlink (path_); - - setup_socket_and_set_fd (zmq_socket_, AF_UNIX, 0, - reinterpret_cast (&addr), - sizeof (struct sockaddr_un)); -} - -char ipc_endpoint[16]; +char ipc_endpoint[MAX_SOCKET_STRING] = ""; void pre_allocate_sock_ipc (void *sb_, char *my_endpoint_) { - strcpy (ipc_endpoint, "tmpXXXXXX"); - -#ifdef HAVE_MKDTEMP - TEST_ASSERT_TRUE (mkdtemp (ipc_endpoint)); - strcat (ipc_endpoint, "/ipc"); -#else - int fd = mkstemp (ipc_endpoint); - TEST_ASSERT_TRUE (fd != -1); - close (fd); -#endif - - pre_allocate_sock_ipc_int (sb_, ipc_endpoint); - strcpy (my_endpoint_, "ipc://"); - strcat (my_endpoint_, ipc_endpoint); + fd_t s = bind_socket_resolve_port ("", "", my_endpoint_, AF_UNIX, 0); + TEST_ASSERT_SUCCESS_ERRNO ( + zmq_setsockopt (sb_, ZMQ_USE_FD, &s, sizeof (s))); + strcpy (ipc_endpoint, strchr (my_endpoint_, '/') + 2); } void test_req_rep_ipc () @@ -277,7 +197,7 @@ void test_client_server_ipc () int main () { - setup_test_environment (); + setup_test_environment (0); UNITY_BEGIN (); RUN_TEST (test_req_rep_tcp); diff --git a/tests/testutil.cpp b/tests/testutil.cpp index c63cfabf..c602b0ca 100644 --- a/tests/testutil.cpp +++ b/tests/testutil.cpp @@ -35,6 +35,10 @@ #if defined _WIN32 #include "../src/windows.hpp" #if defined _MSC_VER +#if defined ZMQ_HAVE_IPC +#include +#include +#endif #include #pragma warning(disable : 4996) // iphlpapi is needed for if_nametoindex (not on Windows XP) @@ -55,6 +59,7 @@ #include #include #include +#include #if defined(ZMQ_HAVE_AIX) #include #include @@ -365,6 +370,147 @@ sockaddr_in bind_bsd_socket (int socket_) return saddr; } +fd_t connect_socket (const char *endpoint_, const int af_, const int protocol_) +{ + struct sockaddr_storage addr; + // OSX is very opinionated and wants the size to match the AF family type + socklen_t addr_len = sizeof (addr); + const fd_t s_pre = socket (af_, SOCK_STREAM, protocol_); + TEST_ASSERT_NOT_EQUAL (-1, s_pre); + + if (af_ == AF_INET || af_ == AF_INET6) { + const char *port = strrchr (endpoint_, ':') + 1; + char address[MAX_SOCKET_STRING]; + // getaddrinfo does not like [x:y::z] + if (*strchr (endpoint_, '/') + 2 == '[') { + strcpy (address, strchr (endpoint_, '[') + 1); + address[strlen (address) - strlen (port) - 2] = '\0'; + } else { + strcpy (address, strchr (endpoint_, '/') + 2); + address[strlen (address) - strlen (port) - 1] = '\0'; + } + + struct addrinfo *in, hint; + hint.ai_flags = AI_NUMERICSERV; + hint.ai_family = af_; + hint.ai_socktype = SOCK_STREAM; + hint.ai_protocol = protocol_; + hint.ai_addrlen = 0; + hint.ai_canonname = NULL; + hint.ai_addr = NULL; + hint.ai_next = NULL; + + TEST_ASSERT_SUCCESS_RAW_ZERO_ERRNO ( + getaddrinfo (address, port, &hint, &in)); + TEST_ASSERT_NOT_NULL (in); + memcpy (&addr, in->ai_addr, in->ai_addrlen); + addr_len = (socklen_t) in->ai_addrlen; + freeaddrinfo (in); + } +#if defined(ZMQ_HAVE_IPC) + else { + struct sockaddr_un *un_addr = (struct sockaddr_un *) &addr; + addr_len = sizeof (struct sockaddr_un); + un_addr->sun_family = AF_UNIX; + strcpy (un_addr->sun_path, endpoint_); + } +#endif + + TEST_ASSERT_SUCCESS_RAW_ERRNO ( + connect (s_pre, (struct sockaddr *) &addr, addr_len)); + + return s_pre; +} + +fd_t bind_socket_resolve_port (const char *address_, + const char *port_, + char *my_endpoint_, + const int af_, + const int protocol_) +{ + struct sockaddr_storage addr; + // OSX is very opinionated and wants the size to match the AF family type + socklen_t addr_len = sizeof (addr); + const fd_t s_pre = socket (af_, SOCK_STREAM, protocol_); + TEST_ASSERT_NOT_EQUAL (-1, s_pre); + + if (af_ == AF_INET || af_ == AF_INET6) { +#ifdef ZMQ_HAVE_WINDOWS + const char flag = '\1'; +#elif defined ZMQ_HAVE_VXWORKS + char flag = '\1'; +#else + int flag = 1; +#endif + struct addrinfo *in, hint; + hint.ai_flags = AI_NUMERICSERV; + hint.ai_family = af_; + hint.ai_socktype = protocol_ == IPPROTO_UDP ? SOCK_DGRAM : SOCK_STREAM; + hint.ai_protocol = protocol_; + hint.ai_addrlen = 0; + hint.ai_canonname = NULL; + hint.ai_addr = NULL; + hint.ai_next = NULL; + + TEST_ASSERT_SUCCESS_RAW_ERRNO ( + setsockopt (s_pre, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof (int))); + TEST_ASSERT_SUCCESS_RAW_ZERO_ERRNO ( + getaddrinfo (address_, port_, &hint, &in)); + TEST_ASSERT_NOT_NULL (in); + memcpy (&addr, in->ai_addr, in->ai_addrlen); + addr_len = (socklen_t) in->ai_addrlen; + freeaddrinfo (in); + } +#if defined(ZMQ_HAVE_IPC) + else { + struct sockaddr_un *un_addr = (struct sockaddr_un *) &addr; + addr_len = sizeof (struct sockaddr_un); + un_addr->sun_family = AF_UNIX; +#if defined ZMQ_HAVE_WINDOWS + char buffer[MAX_PATH] = ""; + + TEST_ASSERT_SUCCESS_RAW_ERRNO (tmpnam_s (buffer)); + TEST_ASSERT_SUCCESS_RAW_ERRNO (_mkdir (buffer)); + strcat (buffer, "/ipc"); +#else + char buffer[PATH_MAX] = ""; + strcpy (buffer, "tmpXXXXXX"); +#ifdef HAVE_MKDTEMP + TEST_ASSERT_TRUE (mkdtemp (buffer)); + strcat (buffer, "/socket"); +#else + int fd = mkstemp (buffer); + TEST_ASSERT_TRUE (fd != -1); + close (fd); +#endif +#endif + strcpy (un_addr->sun_path, buffer); + memcpy (my_endpoint_, "ipc://", 7); + strcat (my_endpoint_, buffer); + + // TODO check return value of unlink + unlink (buffer); + } +#endif + + TEST_ASSERT_SUCCESS_RAW_ERRNO ( + bind (s_pre, (struct sockaddr *) &addr, addr_len)); + TEST_ASSERT_SUCCESS_RAW_ERRNO (listen (s_pre, SOMAXCONN)); + + if (af_ == AF_INET || af_ == AF_INET6) { + addr_len = sizeof (struct sockaddr_storage); + TEST_ASSERT_SUCCESS_RAW_ERRNO ( + getsockname (s_pre, (struct sockaddr *) &addr, &addr_len)); + sprintf (my_endpoint_, "%s://%s:%u", + protocol_ == IPPROTO_TCP ? "tcp" : "udp", address_, + af_ == AF_INET + ? ntohs (((struct sockaddr_in *) &addr)->sin_port) + : ntohs (((struct sockaddr_in6 *) &addr)->sin6_port)); + } + + return s_pre; +} + bool streq (const char *lhs_, const char *rhs_) { return strcmp (lhs_, rhs_) == 0; diff --git a/tests/testutil.hpp b/tests/testutil.hpp index 6661f33b..ab009c70 100644 --- a/tests/testutil.hpp +++ b/tests/testutil.hpp @@ -38,6 +38,14 @@ #include "../include/zmq.h" #include "../src/stdint.hpp" +// For AF_INET and IPPROTO_TCP +#if defined _WIN32 +#include "../src/windows.hpp" +#else +#include +#include +#endif + // This defines the settle time used in tests; raise this if we // get test failures on slower systems due to binds/connects not // settled. Tested to work reliably at 1 msec on a fast PC. @@ -172,4 +180,20 @@ int test_inet_pton (int af_, const char *src_, void *dst_); // Binds an ipv4 BSD socket to an ephemeral port, returns the compiled sockaddr struct sockaddr_in bind_bsd_socket (int socket); +// Connects a BSD socket to the ZMQ endpoint. Works with ipv4/ipv6/unix. +fd_t connect_socket (const char *endpoint_, + const int af_ = AF_INET, + const int protocol_ = IPPROTO_TCP); + +// Binds a BSD socket to an ephemeral port, returns the file descriptor. +// The resulting ZMQ endpoint will be stored in my_endpoint, including the protocol +// prefix, so ensure it is writable and of appropriate size. +// Works with ipv4/ipv6/unix. With unix sockets address_/port_ can be empty and +// my_endpoint_ will contain a random path. +fd_t bind_socket_resolve_port (const char *address_, + const char *port_, + char *my_endpoint_, + const int af_ = AF_INET, + const int protocol_ = IPPROTO_TCP); + #endif