mirror of
https://github.com/zeromq/libzmq.git
synced 2024-12-13 10:52:56 +01:00
Problem: UDP engine does not support IPv6
Solution: Add IPv6 support
This commit is contained in:
parent
7aba6821ac
commit
b0df4be51c
@ -925,7 +925,7 @@ unittests_unittest_mtrie_LDADD = $(top_builddir)/src/.libs/libzmq.a \
|
||||
${UNITY_LIBS} \
|
||||
$(CODE_COVERAGE_LDFLAGS)
|
||||
|
||||
unittests_unittest_ip_resolver_SOURCES = unittests/unittest_ip_resolver.cpp
|
||||
unittests_unittest_ip_resolver_SOURCES = unittests/unittest_ip_resolver.cpp unittests/unittest_resolver_common.hpp
|
||||
unittests_unittest_ip_resolver_CPPFLAGS = -I$(top_srcdir)/src ${UNITY_CPPFLAGS} $(CODE_COVERAGE_CPPFLAGS)
|
||||
unittests_unittest_ip_resolver_CXXFLAGS = $(CODE_COVERAGE_CXXFLAGS)
|
||||
unittests_unittest_ip_resolver_LDADD = $(top_builddir)/src/.libs/libzmq.a \
|
||||
@ -933,7 +933,7 @@ unittests_unittest_ip_resolver_LDADD = $(top_builddir)/src/.libs/libzmq.a \
|
||||
${UNITY_LIBS} \
|
||||
$(CODE_COVERAGE_LDFLAGS)
|
||||
|
||||
unittests_unittest_udp_address_SOURCES = unittests/unittest_udp_address.cpp
|
||||
unittests_unittest_udp_address_SOURCES = unittests/unittest_udp_address.cpp unittests/unittest_resolver_common.hpp
|
||||
unittests_unittest_udp_address_CPPFLAGS = -I$(top_srcdir)/src ${UNITY_CPPFLAGS} $(CODE_COVERAGE_CPPFLAGS)
|
||||
unittests_unittest_udp_address_CXXFLAGS = $(CODE_COVERAGE_CXXFLAGS)
|
||||
unittests_unittest_udp_address_LDADD = $(top_builddir)/src/.libs/libzmq.a \
|
||||
|
@ -46,6 +46,20 @@ uint16_t zmq::ip_addr_t::port () const
|
||||
}
|
||||
}
|
||||
|
||||
const struct sockaddr *zmq::ip_addr_t::as_sockaddr () const
|
||||
{
|
||||
return &generic;
|
||||
}
|
||||
|
||||
size_t zmq::ip_addr_t::sockaddr_len () const
|
||||
{
|
||||
if (family () == AF_INET6) {
|
||||
return sizeof (ipv6);
|
||||
} else {
|
||||
return sizeof (ipv4);
|
||||
}
|
||||
}
|
||||
|
||||
void zmq::ip_addr_t::set_port (uint16_t port)
|
||||
{
|
||||
if (family () == AF_INET6) {
|
||||
|
@ -46,6 +46,10 @@ union ip_addr_t
|
||||
int family () const;
|
||||
bool is_multicast () const;
|
||||
uint16_t port () const;
|
||||
|
||||
const struct sockaddr *as_sockaddr () const;
|
||||
size_t sockaddr_len () const;
|
||||
|
||||
void set_port (uint16_t);
|
||||
|
||||
static ip_addr_t any (int family);
|
||||
|
@ -534,7 +534,8 @@ int zmq::socket_base_t::bind (const char *addr_)
|
||||
|
||||
paddr->resolved.udp_addr = new (std::nothrow) udp_address_t ();
|
||||
alloc_assert (paddr->resolved.udp_addr);
|
||||
rc = paddr->resolved.udp_addr->resolve (address.c_str (), true);
|
||||
rc = paddr->resolved.udp_addr->resolve (address.c_str (), true,
|
||||
options.ipv6);
|
||||
if (rc != 0) {
|
||||
LIBZMQ_DELETE (paddr);
|
||||
return -1;
|
||||
@ -876,7 +877,8 @@ int zmq::socket_base_t::connect (const char *addr_)
|
||||
|
||||
paddr->resolved.udp_addr = new (std::nothrow) udp_address_t ();
|
||||
alloc_assert (paddr->resolved.udp_addr);
|
||||
rc = paddr->resolved.udp_addr->resolve (address.c_str (), false);
|
||||
rc = paddr->resolved.udp_addr->resolve (address.c_str (), false,
|
||||
options.ipv6);
|
||||
if (rc != 0) {
|
||||
LIBZMQ_DELETE (paddr);
|
||||
return -1;
|
||||
|
@ -41,28 +41,26 @@
|
||||
#include <sys/types.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
#include <net/if.h>
|
||||
#include <ctype.h>
|
||||
#endif
|
||||
|
||||
#include "ip_resolver.hpp"
|
||||
|
||||
zmq::udp_address_t::udp_address_t () : is_multicast (false)
|
||||
zmq::udp_address_t::udp_address_t () : bind_interface (-1), is_multicast (false)
|
||||
{
|
||||
memset (&bind_address, 0, sizeof bind_address);
|
||||
memset (&dest_address, 0, sizeof dest_address);
|
||||
bind_address = ip_addr_t::any (AF_INET);
|
||||
target_address = ip_addr_t::any (AF_INET);
|
||||
}
|
||||
|
||||
zmq::udp_address_t::~udp_address_t ()
|
||||
{
|
||||
}
|
||||
|
||||
int zmq::udp_address_t::resolve (const char *name_, bool bind_)
|
||||
int zmq::udp_address_t::resolve (const char *name_, bool bind_, bool ipv6_)
|
||||
{
|
||||
// No IPv6 support yet
|
||||
int family = AF_INET;
|
||||
bool ipv6 = family == AF_INET6;
|
||||
bool has_interface = false;
|
||||
ip_addr_t interface_addr;
|
||||
|
||||
address = name_;
|
||||
|
||||
// If we have a semicolon then we should have an interface specifier in the
|
||||
// URL
|
||||
@ -79,24 +77,38 @@ int zmq::udp_address_t::resolve (const char *name_, bool bind_)
|
||||
// indeterminate socktype.
|
||||
.allow_dns (false)
|
||||
.allow_nic_name (true)
|
||||
.ipv6 (ipv6)
|
||||
.ipv6 (ipv6_)
|
||||
.expect_port (false);
|
||||
|
||||
ip_resolver_t src_resolver (src_resolver_opts);
|
||||
|
||||
const int rc =
|
||||
src_resolver.resolve (&interface_addr, src_name.c_str ());
|
||||
const int rc = src_resolver.resolve (&bind_address, src_name.c_str ());
|
||||
|
||||
if (rc != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (interface_addr.is_multicast ()) {
|
||||
if (bind_address.is_multicast ()) {
|
||||
// It doesn't make sense to have a multicast address as a source
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// This is a hack because we need the interface index when binding
|
||||
// multicast IPv6, we can't do it by address. Unfortunately for the
|
||||
// time being we don't have a generic platform-independent function to
|
||||
// resolve an interface index from an address, so we only support it
|
||||
// when an actual interface name is provided.
|
||||
if (src_name == "*") {
|
||||
bind_interface = 0;
|
||||
} else {
|
||||
bind_interface = if_nametoindex (src_name.c_str ());
|
||||
if (bind_interface == 0) {
|
||||
// Error, probably not an interface name.
|
||||
bind_interface = -1;
|
||||
}
|
||||
}
|
||||
|
||||
has_interface = true;
|
||||
name_ = src_delimiter + 1;
|
||||
}
|
||||
@ -107,19 +119,17 @@ int zmq::udp_address_t::resolve (const char *name_, bool bind_)
|
||||
.allow_dns (!bind_)
|
||||
.allow_nic_name (bind_)
|
||||
.expect_port (true)
|
||||
.ipv6 (ipv6);
|
||||
.ipv6 (ipv6_);
|
||||
|
||||
ip_resolver_t resolver (resolver_opts);
|
||||
|
||||
ip_addr_t target_addr;
|
||||
|
||||
int rc = resolver.resolve (&target_addr, name_);
|
||||
int rc = resolver.resolve (&target_address, name_);
|
||||
if (rc != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
is_multicast = target_addr.is_multicast ();
|
||||
uint16_t port = target_addr.port ();
|
||||
is_multicast = target_address.is_multicast ();
|
||||
uint16_t port = target_address.port ();
|
||||
|
||||
if (has_interface) {
|
||||
// If we have an interface specifier then the target address must be a
|
||||
@ -129,46 +139,43 @@ int zmq::udp_address_t::resolve (const char *name_, bool bind_)
|
||||
return -1;
|
||||
}
|
||||
|
||||
interface_addr.set_port (port);
|
||||
|
||||
dest_address = target_addr.ipv4;
|
||||
bind_address = interface_addr.ipv4;
|
||||
bind_address.set_port (port);
|
||||
} else {
|
||||
// If we don't have an explicit interface specifier then the URL is
|
||||
// ambiguous: if the target address is multicast then it's the
|
||||
// destination address and the bind address is ANY, if it's unicast
|
||||
// then it's the bind address when 'bind_' is true and the destination
|
||||
// otherwise
|
||||
ip_addr_t any = ip_addr_t::any (family);
|
||||
any.set_port (port);
|
||||
|
||||
if (is_multicast) {
|
||||
dest_address = target_addr.ipv4;
|
||||
bind_address = any.ipv4;
|
||||
if (is_multicast || !bind_) {
|
||||
bind_address = ip_addr_t::any (target_address.family ());
|
||||
bind_address.set_port (port);
|
||||
bind_interface = 0;
|
||||
} else {
|
||||
if (bind_) {
|
||||
dest_address = target_addr.ipv4;
|
||||
bind_address = target_addr.ipv4;
|
||||
} else {
|
||||
dest_address = target_addr.ipv4;
|
||||
bind_address = any.ipv4;
|
||||
}
|
||||
// If we were asked for a bind socket and the address
|
||||
// provided was not multicast then it was really meant as
|
||||
// a bind address and the target_address is useless.
|
||||
bind_address = target_address;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_multicast) {
|
||||
multicast = dest_address.sin_addr;
|
||||
if (bind_address.family () != target_address.family ()) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
address = name_;
|
||||
// For IPv6 multicast we *must* have an interface index since we can't
|
||||
// bind by address.
|
||||
if (ipv6_ && is_multicast && bind_interface < 0) {
|
||||
errno = ENODEV;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int zmq::udp_address_t::to_string (std::string &addr_)
|
||||
int zmq::udp_address_t::family () const
|
||||
{
|
||||
addr_ = address;
|
||||
return 0;
|
||||
return bind_address.family ();
|
||||
}
|
||||
|
||||
bool zmq::udp_address_t::is_mcast () const
|
||||
@ -176,41 +183,24 @@ bool zmq::udp_address_t::is_mcast () const
|
||||
return is_multicast;
|
||||
}
|
||||
|
||||
const sockaddr *zmq::udp_address_t::bind_addr () const
|
||||
const zmq::ip_addr_t *zmq::udp_address_t::bind_addr () const
|
||||
{
|
||||
return (sockaddr *) &bind_address;
|
||||
return &bind_address;
|
||||
}
|
||||
|
||||
socklen_t zmq::udp_address_t::bind_addrlen () const
|
||||
int zmq::udp_address_t::bind_if () const
|
||||
{
|
||||
return sizeof (sockaddr_in);
|
||||
return bind_interface;
|
||||
}
|
||||
|
||||
const sockaddr *zmq::udp_address_t::dest_addr () const
|
||||
const zmq::ip_addr_t *zmq::udp_address_t::target_addr () const
|
||||
{
|
||||
return (sockaddr *) &dest_address;
|
||||
return &target_address;
|
||||
}
|
||||
|
||||
socklen_t zmq::udp_address_t::dest_addrlen () const
|
||||
int zmq::udp_address_t::to_string (std::string &addr_)
|
||||
{
|
||||
return sizeof (sockaddr_in);
|
||||
}
|
||||
|
||||
const in_addr zmq::udp_address_t::multicast_ip () const
|
||||
{
|
||||
return multicast;
|
||||
}
|
||||
|
||||
const in_addr zmq::udp_address_t::interface_ip () const
|
||||
{
|
||||
return iface;
|
||||
}
|
||||
|
||||
#if defined ZMQ_HAVE_WINDOWS
|
||||
unsigned short zmq::udp_address_t::family () const
|
||||
#else
|
||||
sa_family_t zmq::udp_address_t::family () const
|
||||
#endif
|
||||
{
|
||||
return AF_INET;
|
||||
// XXX what do (factor TCP code?)
|
||||
addr_ = address;
|
||||
return 0;
|
||||
}
|
||||
|
@ -35,6 +35,8 @@
|
||||
#include <netinet/in.h>
|
||||
#endif
|
||||
|
||||
#include "ip_resolver.hpp"
|
||||
|
||||
namespace zmq
|
||||
{
|
||||
class udp_address_t
|
||||
@ -43,32 +45,24 @@ class udp_address_t
|
||||
udp_address_t ();
|
||||
virtual ~udp_address_t ();
|
||||
|
||||
int resolve (const char *name_, bool receiver_);
|
||||
int resolve (const char *name_, bool receiver_, bool ipv6_);
|
||||
|
||||
// The opposite to resolve()
|
||||
virtual int to_string (std::string &addr_);
|
||||
|
||||
#if defined ZMQ_HAVE_WINDOWS
|
||||
unsigned short family () const;
|
||||
#else
|
||||
sa_family_t family () const;
|
||||
#endif
|
||||
const sockaddr *bind_addr () const;
|
||||
socklen_t bind_addrlen () const;
|
||||
|
||||
const sockaddr *dest_addr () const;
|
||||
socklen_t dest_addrlen () const;
|
||||
int family () const;
|
||||
|
||||
bool is_mcast () const;
|
||||
|
||||
const in_addr multicast_ip () const;
|
||||
const in_addr interface_ip () const;
|
||||
const ip_addr_t *bind_addr () const;
|
||||
int bind_if () const;
|
||||
const ip_addr_t *target_addr () const;
|
||||
|
||||
private:
|
||||
in_addr multicast;
|
||||
in_addr iface;
|
||||
sockaddr_in bind_address;
|
||||
sockaddr_in dest_address;
|
||||
ip_addr_t bind_address;
|
||||
int bind_interface;
|
||||
ip_addr_t target_address;
|
||||
bool is_multicast;
|
||||
std::string address;
|
||||
};
|
||||
|
@ -46,6 +46,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#include "err.hpp"
|
||||
#include "ip.hpp"
|
||||
|
||||
// OSX uses a different name for this socket option
|
||||
#ifndef IPV6_ADD_MEMBERSHIP
|
||||
#define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP
|
||||
#endif
|
||||
|
||||
zmq::udp_engine_t::udp_engine_t (const options_t &options_) :
|
||||
plugged (false),
|
||||
fd (-1),
|
||||
@ -111,9 +116,11 @@ void zmq::udp_engine_t::plug (io_thread_t *io_thread_, session_base_t *session_)
|
||||
|
||||
if (send_enabled) {
|
||||
if (!options.raw_socket) {
|
||||
out_address = address->resolved.udp_addr->dest_addr ();
|
||||
out_addrlen = address->resolved.udp_addr->dest_addrlen ();
|
||||
const ip_addr_t *out = address->resolved.udp_addr->target_addr ();
|
||||
out_address = out->as_sockaddr ();
|
||||
out_addrlen = out->sockaddr_len ();
|
||||
} else {
|
||||
/// XXX fixme ?
|
||||
out_address = (sockaddr *) &raw_address;
|
||||
out_addrlen = sizeof (sockaddr_in);
|
||||
}
|
||||
@ -131,12 +138,29 @@ void zmq::udp_engine_t::plug (io_thread_t *io_thread_, session_base_t *session_)
|
||||
errno_assert (rc == 0);
|
||||
#endif
|
||||
|
||||
const ip_addr_t *bind_addr = address->resolved.udp_addr->bind_addr ();
|
||||
ip_addr_t any = ip_addr_t::any (bind_addr->family ());
|
||||
const ip_addr_t *real_bind_addr;
|
||||
|
||||
bool multicast = address->resolved.udp_addr->is_mcast ();
|
||||
|
||||
if (multicast) {
|
||||
// In multicast we should bind ANY and use the mreq struct to
|
||||
// specify the interface
|
||||
any.set_port (bind_addr->port ());
|
||||
|
||||
real_bind_addr = &any;
|
||||
} else {
|
||||
real_bind_addr = bind_addr;
|
||||
}
|
||||
|
||||
#ifdef ZMQ_HAVE_VXWORKS
|
||||
rc = bind (fd, (sockaddr *) address->resolved.udp_addr->bind_addr (),
|
||||
address->resolved.udp_addr->bind_addrlen ());
|
||||
rc = bind (fd, (sockaddr *) real_bind_addr->as_sockaddr (),
|
||||
real_bind_addr->sockaddr_len ());
|
||||
#else
|
||||
rc = bind (fd, address->resolved.udp_addr->bind_addr (),
|
||||
address->resolved.udp_addr->bind_addrlen ());
|
||||
rc = bind (fd, real_bind_addr->as_sockaddr (),
|
||||
real_bind_addr->sockaddr_len ());
|
||||
|
||||
#endif
|
||||
#ifdef ZMQ_HAVE_WINDOWS
|
||||
wsa_assert (rc != SOCKET_ERROR);
|
||||
@ -144,12 +168,37 @@ void zmq::udp_engine_t::plug (io_thread_t *io_thread_, session_base_t *session_)
|
||||
errno_assert (rc == 0);
|
||||
#endif
|
||||
|
||||
if (address->resolved.udp_addr->is_mcast ()) {
|
||||
struct ip_mreq mreq;
|
||||
mreq.imr_multiaddr = address->resolved.udp_addr->multicast_ip ();
|
||||
mreq.imr_interface = address->resolved.udp_addr->interface_ip ();
|
||||
rc = setsockopt (fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *) &mreq,
|
||||
sizeof (mreq));
|
||||
if (multicast) {
|
||||
const ip_addr_t *mcast_addr =
|
||||
address->resolved.udp_addr->target_addr ();
|
||||
|
||||
if (mcast_addr->family () == AF_INET) {
|
||||
struct ip_mreq mreq;
|
||||
mreq.imr_multiaddr = mcast_addr->ipv4.sin_addr;
|
||||
mreq.imr_interface = bind_addr->ipv4.sin_addr;
|
||||
|
||||
rc = setsockopt (fd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
|
||||
(char *) &mreq, sizeof (mreq));
|
||||
|
||||
errno_assert (rc == 0);
|
||||
} else if (mcast_addr->family () == AF_INET6) {
|
||||
struct ipv6_mreq mreq;
|
||||
int iface = address->resolved.udp_addr->bind_if ();
|
||||
|
||||
zmq_assert (iface >= -1);
|
||||
|
||||
mreq.ipv6mr_multiaddr = mcast_addr->ipv6.sin6_addr;
|
||||
mreq.ipv6mr_interface = iface;
|
||||
|
||||
rc = setsockopt (fd, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP,
|
||||
(char *) &mreq, sizeof (mreq));
|
||||
|
||||
errno_assert (rc == 0);
|
||||
} else {
|
||||
// Shouldn't happen
|
||||
abort ();
|
||||
}
|
||||
|
||||
#ifdef ZMQ_HAVE_WINDOWS
|
||||
wsa_assert (rc != SOCKET_ERROR);
|
||||
#else
|
||||
|
@ -32,6 +32,18 @@
|
||||
|
||||
#include <unity.h>
|
||||
|
||||
// Helper macro to define the v4/v6 function pairs
|
||||
#define MAKE_TEST_V4V6(_test) \
|
||||
static void _test##_ipv4 () { _test (false); } \
|
||||
\
|
||||
static void _test##_ipv6 () \
|
||||
{ \
|
||||
if (!is_ipv6_available ()) { \
|
||||
TEST_IGNORE_MESSAGE ("ipv6 is not available"); \
|
||||
} \
|
||||
_test (true); \
|
||||
}
|
||||
|
||||
void setUp ()
|
||||
{
|
||||
setup_test_context ();
|
||||
@ -111,16 +123,19 @@ void test_join_twice_fails ()
|
||||
test_context_socket_close (dish);
|
||||
}
|
||||
|
||||
void test_radio_dish_tcp_poll ()
|
||||
void test_radio_dish_tcp_poll (int ipv6_)
|
||||
{
|
||||
size_t len = MAX_SOCKET_STRING;
|
||||
char my_endpoint[MAX_SOCKET_STRING];
|
||||
|
||||
void *radio = test_context_socket (ZMQ_RADIO);
|
||||
bind_loopback_ipv4 (radio, my_endpoint, len);
|
||||
bind_loopback (radio, ipv6_, my_endpoint, len);
|
||||
|
||||
void *dish = test_context_socket (ZMQ_DISH);
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (dish, ZMQ_IPV6, &ipv6_, sizeof (int)));
|
||||
|
||||
// Joining
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_join (dish, "Movies"));
|
||||
|
||||
@ -175,22 +190,31 @@ void test_radio_dish_tcp_poll ()
|
||||
test_context_socket_close (dish);
|
||||
test_context_socket_close (radio);
|
||||
}
|
||||
MAKE_TEST_V4V6 (test_radio_dish_tcp_poll)
|
||||
|
||||
void test_dish_connect_fails ()
|
||||
void test_dish_connect_fails (int ipv6_)
|
||||
{
|
||||
void *dish = test_context_socket (ZMQ_DISH);
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (dish, ZMQ_IPV6, &ipv6_, sizeof (int)));
|
||||
|
||||
const char *url = ipv6_ ? "udp://[::1]:5556" : "udp://127.0.0.1:5556";
|
||||
|
||||
// Connecting dish should fail
|
||||
TEST_ASSERT_FAILURE_ERRNO (ENOCOMPATPROTO,
|
||||
zmq_connect (dish, "udp://127.0.0.1:5556"));
|
||||
TEST_ASSERT_FAILURE_ERRNO (ENOCOMPATPROTO, zmq_connect (dish, url));
|
||||
|
||||
test_context_socket_close (dish);
|
||||
}
|
||||
MAKE_TEST_V4V6 (test_dish_connect_fails)
|
||||
|
||||
void test_radio_bind_fails ()
|
||||
void test_radio_bind_fails (int ipv6_)
|
||||
{
|
||||
void *radio = test_context_socket (ZMQ_RADIO);
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (radio, ZMQ_IPV6, &ipv6_, sizeof (int)));
|
||||
|
||||
// Connecting dish should fail
|
||||
// Bind radio should fail
|
||||
TEST_ASSERT_FAILURE_ERRNO (ENOCOMPATPROTO,
|
||||
@ -198,14 +222,22 @@ void test_radio_bind_fails ()
|
||||
|
||||
test_context_socket_close (radio);
|
||||
}
|
||||
MAKE_TEST_V4V6 (test_radio_bind_fails)
|
||||
|
||||
void test_radio_dish_udp ()
|
||||
void test_radio_dish_udp (int ipv6_)
|
||||
{
|
||||
void *radio = test_context_socket (ZMQ_RADIO);
|
||||
void *dish = test_context_socket (ZMQ_DISH);
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (radio, ZMQ_IPV6, &ipv6_, sizeof (int)));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (dish, ZMQ_IPV6, &ipv6_, sizeof (int)));
|
||||
|
||||
const char *radio_url = ipv6_ ? "udp://[::1]:5556" : "udp://127.0.0.1:5556";
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (dish, "udp://*:5556"));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (radio, "udp://127.0.0.1:5556"));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (radio, radio_url));
|
||||
|
||||
msleep (SETTLE_TIME);
|
||||
|
||||
@ -217,6 +249,7 @@ void test_radio_dish_udp ()
|
||||
test_context_socket_close (dish);
|
||||
test_context_socket_close (radio);
|
||||
}
|
||||
MAKE_TEST_V4V6 (test_radio_dish_udp)
|
||||
|
||||
int main (void)
|
||||
{
|
||||
@ -226,10 +259,14 @@ int main (void)
|
||||
RUN_TEST (test_leave_unjoined_fails);
|
||||
RUN_TEST (test_join_too_long_fails);
|
||||
RUN_TEST (test_join_twice_fails);
|
||||
RUN_TEST (test_radio_bind_fails);
|
||||
RUN_TEST (test_dish_connect_fails);
|
||||
RUN_TEST (test_radio_dish_tcp_poll);
|
||||
RUN_TEST (test_radio_dish_udp);
|
||||
RUN_TEST (test_radio_bind_fails_ipv4);
|
||||
RUN_TEST (test_radio_bind_fails_ipv6);
|
||||
RUN_TEST (test_dish_connect_fails_ipv4);
|
||||
RUN_TEST (test_dish_connect_fails_ipv6);
|
||||
RUN_TEST (test_radio_dish_tcp_poll_ipv4);
|
||||
RUN_TEST (test_radio_dish_tcp_poll_ipv6);
|
||||
RUN_TEST (test_radio_dish_udp_ipv4);
|
||||
RUN_TEST (test_radio_dish_udp_ipv6);
|
||||
|
||||
return UNITY_END ();
|
||||
}
|
||||
|
@ -26,7 +26,7 @@ include_directories("${CMAKE_SOURCE_DIR}/include" "${CMAKE_SOURCE_DIR}/src" "${C
|
||||
|
||||
foreach(test ${unittests})
|
||||
# target_sources not supported before CMake 3.1
|
||||
add_executable(${test} ${test}.cpp)
|
||||
add_executable(${test} ${test}.cpp "unittest_resolver_common.hpp")
|
||||
|
||||
# per-test directories not generated on OS X / Darwin
|
||||
if (NOT ${CMAKE_CXX_COMPILER_ID} MATCHES "Clang.*")
|
||||
|
@ -19,6 +19,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include <unity.h>
|
||||
#include "../tests/testutil.hpp"
|
||||
#include "../unittests/unittest_resolver_common.hpp"
|
||||
|
||||
#include <ip_resolver.hpp>
|
||||
#include <ip.hpp>
|
||||
@ -155,41 +156,9 @@ static void test_resolve (zmq::ip_resolver_options_t opts_,
|
||||
TEST_ASSERT_EQUAL (0, rc);
|
||||
}
|
||||
|
||||
#if defined ZMQ_HAVE_WINDOWS
|
||||
if (family == AF_INET6 && expected_addr_v4_failover_ != NULL &&
|
||||
addr.family () == AF_INET) {
|
||||
// We've requested an IPv6 but the system gave us an IPv4, use the
|
||||
// failover address
|
||||
family = AF_INET;
|
||||
expected_addr_ = expected_addr_v4_failover_;
|
||||
}
|
||||
#else
|
||||
(void)expected_addr_v4_failover_;
|
||||
#endif
|
||||
|
||||
TEST_ASSERT_EQUAL (family, addr.family ());
|
||||
|
||||
if (family == AF_INET6) {
|
||||
struct in6_addr expected_addr;
|
||||
const sockaddr_in6 *ip6_addr = &addr.ipv6;
|
||||
|
||||
assert (test_inet_pton (AF_INET6, expected_addr_, &expected_addr) == 1);
|
||||
|
||||
int neq = memcmp (&ip6_addr->sin6_addr, &expected_addr,
|
||||
sizeof (expected_addr_));
|
||||
|
||||
TEST_ASSERT_EQUAL (0, neq);
|
||||
TEST_ASSERT_EQUAL (htons (expected_port_), ip6_addr->sin6_port);
|
||||
TEST_ASSERT_EQUAL (expected_zone_, ip6_addr->sin6_scope_id);
|
||||
} else {
|
||||
struct in_addr expected_addr;
|
||||
const sockaddr_in *ip4_addr = &addr.ipv4;
|
||||
|
||||
assert (test_inet_pton (AF_INET, expected_addr_, &expected_addr) == 1);
|
||||
|
||||
TEST_ASSERT_EQUAL (expected_addr.s_addr, ip4_addr->sin_addr.s_addr);
|
||||
TEST_ASSERT_EQUAL (htons (expected_port_), ip4_addr->sin_port);
|
||||
}
|
||||
validate_address (family, &addr, expected_addr_,
|
||||
expected_port_, expected_zone_,
|
||||
expected_addr_v4_failover_);
|
||||
}
|
||||
|
||||
// Helper macro to define the v4/v6 function pairs
|
||||
|
73
unittests/unittest_resolver_common.hpp
Normal file
73
unittests/unittest_resolver_common.hpp
Normal file
@ -0,0 +1,73 @@
|
||||
/*
|
||||
Copyright (c) 2018 Contributors as noted in the AUTHORS file
|
||||
|
||||
This file is part of 0MQ.
|
||||
|
||||
0MQ is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
0MQ is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __UNITTEST_RESOLVER_COMMON_INCLUDED__
|
||||
#define __UNITTEST_RESOLVER_COMMON_INCLUDED__
|
||||
|
||||
#include <ip_resolver.hpp>
|
||||
|
||||
// Attempt a resolution and test the results.
|
||||
//
|
||||
// On windows we can receive an IPv4 address even when an IPv6 is requested, if
|
||||
// we're in this situation then we compare to 'expected_addr_v4_failover_'
|
||||
// instead.
|
||||
void validate_address(int family, const zmq::ip_addr_t *addr_,
|
||||
const char *expected_addr_,
|
||||
uint16_t expected_port_ = 0,
|
||||
uint16_t expected_zone_ = 0,
|
||||
const char *expected_addr_v4_failover_ = NULL)
|
||||
{
|
||||
#if defined ZMQ_HAVE_WINDOWS
|
||||
if (family == AF_INET6 && expected_addr_v4_failover_ != NULL &&
|
||||
addr_->family () == AF_INET) {
|
||||
// We've requested an IPv6 but the system gave us an IPv4, use the
|
||||
// failover address
|
||||
family = AF_INET;
|
||||
expected_addr_ = expected_addr_v4_failover_;
|
||||
}
|
||||
#else
|
||||
(void)expected_addr_v4_failover_;
|
||||
#endif
|
||||
|
||||
TEST_ASSERT_EQUAL (family, addr_->family ());
|
||||
|
||||
if (family == AF_INET6) {
|
||||
struct in6_addr expected_addr;
|
||||
const sockaddr_in6 *ip6_addr = &addr_->ipv6;
|
||||
|
||||
assert (test_inet_pton (AF_INET6, expected_addr_, &expected_addr) == 1);
|
||||
|
||||
int neq = memcmp (&ip6_addr->sin6_addr, &expected_addr,
|
||||
sizeof (expected_addr_));
|
||||
|
||||
TEST_ASSERT_EQUAL (0, neq);
|
||||
TEST_ASSERT_EQUAL (htons (expected_port_), ip6_addr->sin6_port);
|
||||
TEST_ASSERT_EQUAL (expected_zone_, ip6_addr->sin6_scope_id);
|
||||
} else {
|
||||
struct in_addr expected_addr;
|
||||
const sockaddr_in *ip4_addr = &addr_->ipv4;
|
||||
|
||||
assert (test_inet_pton (AF_INET, expected_addr_, &expected_addr) == 1);
|
||||
|
||||
TEST_ASSERT_EQUAL (expected_addr.s_addr, ip4_addr->sin_addr.s_addr);
|
||||
TEST_ASSERT_EQUAL (htons (expected_port_), ip4_addr->sin_port);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // __UNITTEST_RESOLVER_COMMON_INCLUDED__
|
@ -19,6 +19,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include <unity.h>
|
||||
#include "../tests/testutil.hpp"
|
||||
#include "../unittests/unittest_resolver_common.hpp"
|
||||
|
||||
#include <ip.hpp>
|
||||
#include <udp_address.hpp>
|
||||
@ -33,16 +34,23 @@ void tearDown ()
|
||||
|
||||
// Test an UDP address resolution. If 'dest_addr_' is NULL assume the
|
||||
// resolution is supposed to fail.
|
||||
static void test_resolve (bool bind_, const char *name_, const char *dest_addr_,
|
||||
static void test_resolve (bool bind_,
|
||||
int family_,
|
||||
const char *name_,
|
||||
const char *target_addr_,
|
||||
uint16_t expected_port_,
|
||||
const char *bind_addr_,
|
||||
bool multicast_)
|
||||
{
|
||||
if (family_ == AF_INET6 && !is_ipv6_available ()) {
|
||||
TEST_IGNORE_MESSAGE ("ipv6 is not available");
|
||||
}
|
||||
|
||||
zmq::udp_address_t addr;
|
||||
|
||||
int rc = addr.resolve (name_, bind_);
|
||||
int rc = addr.resolve (name_, bind_, family_ == AF_INET6);
|
||||
|
||||
if (dest_addr_ == NULL) {
|
||||
if (target_addr_ == NULL) {
|
||||
TEST_ASSERT_EQUAL (-1, rc);
|
||||
TEST_ASSERT_EQUAL (EINVAL, errno);
|
||||
return;
|
||||
@ -52,140 +60,224 @@ static void test_resolve (bool bind_, const char *name_, const char *dest_addr_,
|
||||
|
||||
TEST_ASSERT_EQUAL (multicast_, addr.is_mcast ());
|
||||
|
||||
struct sockaddr_in *dest = (struct sockaddr_in *)addr.dest_addr ();
|
||||
struct in_addr expected_dest;
|
||||
assert (test_inet_pton (AF_INET, dest_addr_, &expected_dest) == 1);
|
||||
|
||||
TEST_ASSERT_EQUAL (AF_INET, dest->sin_family);
|
||||
TEST_ASSERT_EQUAL (expected_dest.s_addr, dest->sin_addr.s_addr);
|
||||
TEST_ASSERT_EQUAL (htons (expected_port_), dest->sin_port);
|
||||
|
||||
struct sockaddr_in *bind = (struct sockaddr_in *)addr.bind_addr ();
|
||||
struct in_addr expected_bind;
|
||||
|
||||
if (bind_addr_ == NULL) {
|
||||
// Bind ANY
|
||||
bind_addr_ = "0.0.0.0";
|
||||
if (family_ == AF_INET) {
|
||||
bind_addr_ = "0.0.0.0";
|
||||
} else {
|
||||
bind_addr_ = "::";
|
||||
}
|
||||
}
|
||||
|
||||
assert (test_inet_pton (AF_INET, bind_addr_, &expected_bind) == 1);
|
||||
|
||||
TEST_ASSERT_EQUAL (AF_INET, bind->sin_family);
|
||||
TEST_ASSERT_EQUAL (expected_bind.s_addr, bind->sin_addr.s_addr);
|
||||
TEST_ASSERT_EQUAL (htons (expected_port_), bind->sin_port);
|
||||
validate_address (family_, addr.target_addr(), target_addr_, expected_port_);
|
||||
validate_address (family_, addr.bind_addr(), bind_addr_, expected_port_);
|
||||
}
|
||||
|
||||
static void test_resolve_bind (const char *name_, const char *dest_addr_,
|
||||
uint16_t expected_port_ = 0,
|
||||
static void test_resolve_bind (int family_,
|
||||
const char *name_, const char *dest_addr_,
|
||||
uint16_t expected_port_ = 0,
|
||||
const char *bind_addr_ = NULL,
|
||||
bool multicast_ = false)
|
||||
{
|
||||
test_resolve (true, name_, dest_addr_, expected_port_, bind_addr_,
|
||||
test_resolve (true, family_, name_, dest_addr_, expected_port_, bind_addr_,
|
||||
multicast_);
|
||||
}
|
||||
|
||||
static void test_resolve_connect (const char *name_, const char *dest_addr_,
|
||||
static void test_resolve_connect (int family_, const char *name_, const char *dest_addr_,
|
||||
uint16_t expected_port_ = 0,
|
||||
const char *bind_addr_ = NULL,
|
||||
bool multicast_ = false)
|
||||
{
|
||||
test_resolve (false, name_, dest_addr_, expected_port_, bind_addr_,
|
||||
test_resolve (false, family_, name_, dest_addr_, expected_port_, bind_addr_,
|
||||
multicast_);
|
||||
}
|
||||
|
||||
static void test_resolve_ipv4_simple ()
|
||||
{
|
||||
test_resolve_connect ("127.0.0.1:5555", "127.0.0.1", 5555);
|
||||
test_resolve_connect (AF_INET, "127.0.0.1:5555", "127.0.0.1", 5555);
|
||||
}
|
||||
|
||||
static void test_resolve_ipv6_simple ()
|
||||
{
|
||||
test_resolve_connect (AF_INET6, "[::1]:123", "::1", 123);
|
||||
}
|
||||
|
||||
static void test_resolve_ipv4_bind ()
|
||||
{
|
||||
test_resolve_bind ("127.0.0.1:5555", "127.0.0.1", 5555, "127.0.0.1");
|
||||
test_resolve_bind (AF_INET, "127.0.0.1:5555", "127.0.0.1", 5555, "127.0.0.1");
|
||||
}
|
||||
|
||||
static void test_resolve_ipv6_bind ()
|
||||
{
|
||||
test_resolve_bind (AF_INET6, "[abcd::1234:1]:5555", "abcd::1234:1", 5555, "abcd::1234:1");
|
||||
}
|
||||
|
||||
static void test_resolve_ipv4_bind_any ()
|
||||
{
|
||||
test_resolve_bind ("*:*", "0.0.0.0", 0, "0.0.0.0");
|
||||
test_resolve_bind (AF_INET, "*:*", "0.0.0.0", 0, "0.0.0.0");
|
||||
}
|
||||
|
||||
static void test_resolve_ipv6_bind_any ()
|
||||
{
|
||||
test_resolve_bind (AF_INET6, "*:*", "::", 0, "::");
|
||||
}
|
||||
|
||||
static void test_resolve_ipv4_bind_anyport ()
|
||||
{
|
||||
test_resolve_bind ("127.0.0.1:*", "127.0.0.1", 0, "127.0.0.1");
|
||||
test_resolve_bind (AF_INET, "127.0.0.1:*", "127.0.0.1", 0, "127.0.0.1");
|
||||
}
|
||||
|
||||
static void test_resolve_ipv6_bind_anyport ()
|
||||
{
|
||||
test_resolve_bind (AF_INET6, "[1:2:3:4::5]:*", "1:2:3:4::5", 0, "1:2:3:4::5");
|
||||
}
|
||||
|
||||
static void test_resolve_ipv4_bind_any_port ()
|
||||
{
|
||||
test_resolve_bind ("*:5555", "0.0.0.0", 5555, "0.0.0.0");
|
||||
test_resolve_bind (AF_INET, "*:5555", "0.0.0.0", 5555, "0.0.0.0");
|
||||
}
|
||||
|
||||
static void test_resolve_ipv6_bind_any_port ()
|
||||
{
|
||||
test_resolve_bind (AF_INET6, "*:5555", "::", 5555, "::");
|
||||
}
|
||||
|
||||
static void test_resolve_ipv4_connect_any ()
|
||||
{
|
||||
// Cannot use wildcard for connection
|
||||
test_resolve_connect ("*:5555", NULL);
|
||||
test_resolve_connect (AF_INET, "*:5555", NULL);
|
||||
}
|
||||
|
||||
static void test_resolve_ipv6_connect_any ()
|
||||
{
|
||||
// Cannot use wildcard for connection
|
||||
test_resolve_connect (AF_INET6, "*:5555", NULL);
|
||||
}
|
||||
|
||||
static void test_resolve_ipv4_connect_anyport ()
|
||||
{
|
||||
test_resolve_connect ("127.0.0.1:*", NULL);
|
||||
test_resolve_connect (AF_INET, "127.0.0.1:*", NULL);
|
||||
}
|
||||
|
||||
static void test_resolve_ipv6_connect_anyport ()
|
||||
{
|
||||
test_resolve_connect (AF_INET6, "[::1]:*", NULL);
|
||||
}
|
||||
|
||||
static void test_resolve_ipv4_connect_port0 ()
|
||||
{
|
||||
test_resolve_connect ("127.0.0.1:0", "127.0.0.1", 0);
|
||||
test_resolve_connect (AF_INET, "127.0.0.1:0", "127.0.0.1", 0);
|
||||
}
|
||||
|
||||
static void test_resolve_ipv6_connect_port0 ()
|
||||
{
|
||||
test_resolve_connect (AF_INET6, "[2000:abcd::1]:0", "2000:abcd::1", 0);
|
||||
}
|
||||
|
||||
static void test_resolve_ipv4_bind_mcast ()
|
||||
{
|
||||
test_resolve_bind ("239.0.0.1:1234", "239.0.0.1", 1234, "0.0.0.0", true);
|
||||
test_resolve_bind (AF_INET, "239.0.0.1:1234", "239.0.0.1", 1234, "0.0.0.0", true);
|
||||
}
|
||||
|
||||
static void test_resolve_ipv6_bind_mcast ()
|
||||
{
|
||||
test_resolve_bind (AF_INET6, "[ff00::1]:1234", "ff00::1", 1234, "::", true);
|
||||
}
|
||||
|
||||
static void test_resolve_ipv4_connect_mcast ()
|
||||
{
|
||||
test_resolve_connect ("239.0.0.1:2222", "239.0.0.1", 2222, NULL, true);
|
||||
test_resolve_connect (AF_INET, "239.0.0.1:2222", "239.0.0.1", 2222, NULL, true);
|
||||
}
|
||||
|
||||
static void test_resolve_ipv6_simple ()
|
||||
static void test_resolve_ipv6_connect_mcast ()
|
||||
{
|
||||
test_resolve_connect (AF_INET6, "[ff00::1]:2222", "ff00::1", 2222, NULL, true);
|
||||
}
|
||||
|
||||
static void test_resolve_ipv4_mcast_src_bind ()
|
||||
{
|
||||
test_resolve_bind (AF_INET, "127.0.0.1;230.2.8.12:5555", "230.2.8.12", 5555,
|
||||
"127.0.0.1", true);
|
||||
}
|
||||
|
||||
static void test_resolve_ipv6_mcast_src_bind ()
|
||||
{
|
||||
if (!is_ipv6_available ()) {
|
||||
TEST_IGNORE_MESSAGE ("ipv6 is not available");
|
||||
}
|
||||
|
||||
// IPv6 not yet supported
|
||||
test_resolve_connect ("::1", NULL);
|
||||
}
|
||||
zmq::udp_address_t addr;
|
||||
int rc = addr.resolve ("[::1];[ffab::4]:5555", true, true);
|
||||
|
||||
static void test_resolve_ipv4_mcast_src_bind ()
|
||||
{
|
||||
test_resolve_bind ("127.0.0.1;230.2.8.12:5555", "230.2.8.12", 5555,
|
||||
"127.0.0.1", true);
|
||||
// For the time being this fails because we only support binding multicast
|
||||
// by interface name, not interface IP
|
||||
TEST_ASSERT_EQUAL (-1, rc);
|
||||
TEST_ASSERT_EQUAL (ENODEV, errno);
|
||||
}
|
||||
|
||||
static void test_resolve_ipv4_mcast_src_bind_any ()
|
||||
{
|
||||
test_resolve_bind ("*;230.2.8.12:5555", "230.2.8.12", 5555,
|
||||
test_resolve_bind (AF_INET, "*;230.2.8.12:5555", "230.2.8.12", 5555,
|
||||
"0.0.0.0", true);
|
||||
}
|
||||
|
||||
static void test_resolve_ipv6_mcast_src_bind_any ()
|
||||
{
|
||||
test_resolve_bind (AF_INET6, "*;[ffff::]:5555", "ffff::", 5555,
|
||||
"::", true);
|
||||
}
|
||||
|
||||
static void test_resolve_ipv4_mcast_src_connect ()
|
||||
{
|
||||
test_resolve_connect ("8.9.10.11;230.2.8.12:5555", "230.2.8.12", 5555,
|
||||
test_resolve_connect (AF_INET, "8.9.10.11;230.2.8.12:5555", "230.2.8.12", 5555,
|
||||
"8.9.10.11", true);
|
||||
}
|
||||
|
||||
static void test_resolve_ipv6_mcast_src_connect ()
|
||||
{
|
||||
if (!is_ipv6_available ()) {
|
||||
TEST_IGNORE_MESSAGE ("ipv6 is not available");
|
||||
}
|
||||
|
||||
zmq::udp_address_t addr;
|
||||
int rc = addr.resolve ("[1:2:3::4];[ff01::1]:5555", false, true);
|
||||
|
||||
// For the time being this fails because we only support binding multicast
|
||||
// by interface name, not interface IP
|
||||
TEST_ASSERT_EQUAL (-1, rc);
|
||||
TEST_ASSERT_EQUAL (ENODEV, errno);
|
||||
}
|
||||
|
||||
static void test_resolve_ipv4_mcast_src_connect_any ()
|
||||
{
|
||||
test_resolve_connect ("*;230.2.8.12:5555", "230.2.8.12", 5555,
|
||||
test_resolve_connect (AF_INET, "*;230.2.8.12:5555", "230.2.8.12", 5555,
|
||||
"0.0.0.0", true);
|
||||
}
|
||||
|
||||
static void test_resolve_ipv6_mcast_src_connect_any ()
|
||||
{
|
||||
test_resolve_connect (AF_INET6, "*;[ff10::1]:5555", "ff10::1", 5555,
|
||||
"::", true);
|
||||
}
|
||||
|
||||
static void test_resolve_ipv4_mcast_src_bind_bad ()
|
||||
{
|
||||
test_resolve_bind ("127.0.0.1;1.2.3.4:5555", NULL);
|
||||
test_resolve_bind (AF_INET, "127.0.0.1;1.2.3.4:5555", NULL);
|
||||
}
|
||||
|
||||
static void test_resolve_ipv6_mcast_src_bind_bad ()
|
||||
{
|
||||
test_resolve_bind (AF_INET6, "[::1];[fe00::1]:5555", NULL);
|
||||
}
|
||||
|
||||
static void test_resolve_ipv4_mcast_src_connect_bad ()
|
||||
{
|
||||
test_resolve_connect ("127.0.0.1;1.2.3.4:5555", NULL);
|
||||
test_resolve_connect (AF_INET, "127.0.0.1;1.2.3.4:5555", NULL);
|
||||
}
|
||||
|
||||
static void test_resolve_ipv6_mcast_src_connect_bad ()
|
||||
{
|
||||
test_resolve_connect (AF_INET6, "[::1];[fe00:1]:5555", NULL);
|
||||
}
|
||||
|
||||
int main (void)
|
||||
@ -196,22 +288,37 @@ int main (void)
|
||||
UNITY_BEGIN ();
|
||||
|
||||
RUN_TEST (test_resolve_ipv4_simple);
|
||||
RUN_TEST (test_resolve_ipv4_bind);
|
||||
RUN_TEST (test_resolve_ipv4_bind_any);
|
||||
RUN_TEST (test_resolve_ipv4_bind_anyport);
|
||||
RUN_TEST (test_resolve_ipv4_bind_any_port);
|
||||
RUN_TEST (test_resolve_ipv4_connect_any);
|
||||
RUN_TEST (test_resolve_ipv4_connect_anyport);
|
||||
RUN_TEST (test_resolve_ipv4_connect_port0);
|
||||
RUN_TEST (test_resolve_ipv4_bind_mcast);
|
||||
RUN_TEST (test_resolve_ipv4_connect_mcast);
|
||||
RUN_TEST (test_resolve_ipv6_simple);
|
||||
RUN_TEST (test_resolve_ipv4_bind);
|
||||
RUN_TEST (test_resolve_ipv6_bind);
|
||||
RUN_TEST (test_resolve_ipv4_bind_any);
|
||||
RUN_TEST (test_resolve_ipv6_bind_any);
|
||||
RUN_TEST (test_resolve_ipv4_bind_anyport);
|
||||
RUN_TEST (test_resolve_ipv6_bind_anyport);
|
||||
RUN_TEST (test_resolve_ipv4_bind_any_port);
|
||||
RUN_TEST (test_resolve_ipv6_bind_any_port);
|
||||
RUN_TEST (test_resolve_ipv4_connect_any);
|
||||
RUN_TEST (test_resolve_ipv6_connect_any);
|
||||
RUN_TEST (test_resolve_ipv4_connect_anyport);
|
||||
RUN_TEST (test_resolve_ipv6_connect_anyport);
|
||||
RUN_TEST (test_resolve_ipv4_connect_port0);
|
||||
RUN_TEST (test_resolve_ipv6_connect_port0);
|
||||
RUN_TEST (test_resolve_ipv4_bind_mcast);
|
||||
RUN_TEST (test_resolve_ipv6_bind_mcast);
|
||||
RUN_TEST (test_resolve_ipv4_connect_mcast);
|
||||
RUN_TEST (test_resolve_ipv6_connect_mcast);
|
||||
RUN_TEST (test_resolve_ipv4_mcast_src_bind);
|
||||
RUN_TEST (test_resolve_ipv6_mcast_src_bind);
|
||||
RUN_TEST (test_resolve_ipv4_mcast_src_bind_any);
|
||||
RUN_TEST (test_resolve_ipv6_mcast_src_bind_any);
|
||||
RUN_TEST (test_resolve_ipv4_mcast_src_connect);
|
||||
RUN_TEST (test_resolve_ipv6_mcast_src_connect);
|
||||
RUN_TEST (test_resolve_ipv4_mcast_src_connect_any);
|
||||
RUN_TEST (test_resolve_ipv6_mcast_src_connect_any);
|
||||
RUN_TEST (test_resolve_ipv4_mcast_src_bind_bad);
|
||||
RUN_TEST (test_resolve_ipv6_mcast_src_bind_bad);
|
||||
RUN_TEST (test_resolve_ipv4_mcast_src_connect_bad);
|
||||
RUN_TEST (test_resolve_ipv6_mcast_src_connect_bad);
|
||||
|
||||
zmq::shutdown_network ();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user