Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in / Register
Toggle navigation
L
libzmq
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Packages
Packages
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
submodule
libzmq
Commits
b0df4be5
Commit
b0df4be5
authored
May 04, 2018
by
Lionel Flandrin
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Problem: UDP engine does not support IPv6
Solution: Add IPv6 support
parent
7aba6821
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
281 additions
and
149 deletions
+281
-149
Makefile.am
Makefile.am
+2
-2
ip_resolver.cpp
src/ip_resolver.cpp
+14
-0
ip_resolver.hpp
src/ip_resolver.hpp
+4
-0
socket_base.cpp
src/socket_base.cpp
+4
-2
udp_address.cpp
src/udp_address.cpp
+59
-69
udp_address.hpp
src/udp_address.hpp
+10
-16
udp_engine.cpp
src/udp_engine.cpp
+61
-12
test_radio_dish.cpp
tests/test_radio_dish.cpp
+49
-12
CMakeLists.txt
unittests/CMakeLists.txt
+1
-1
unittest_ip_resolver.cpp
unittests/unittest_ip_resolver.cpp
+4
-35
unittest_resolver_common.hpp
unittests/unittest_resolver_common.hpp
+73
-0
unittest_udp_address.cpp
unittests/unittest_udp_address.cpp
+0
-0
No files found.
Makefile.am
View file @
b0df4be5
...
...
@@ -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
\
...
...
src/ip_resolver.cpp
View file @
b0df4be5
...
...
@@ -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
)
{
...
...
src/ip_resolver.hpp
View file @
b0df4be5
...
...
@@ -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
);
...
...
src/socket_base.cpp
View file @
b0df4be5
...
...
@@ -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
;
...
...
src/udp_address.cpp
View file @
b0df4be5
...
...
@@ -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_addr
ess
.
is_multicast
();
uint16_t
port
=
target_addr
ess
.
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
{
return
(
sockaddr
*
)
&
bind_address
;
}
socklen_t
zmq
::
udp_address_t
::
bind_addrlen
()
const
{
return
sizeof
(
sockaddr_in
);
}
const
sockaddr
*
zmq
::
udp_address_t
::
dest_addr
()
const
const
zmq
::
ip_addr_t
*
zmq
::
udp_address_t
::
bind_addr
()
const
{
return
(
sockaddr
*
)
&
dest
_address
;
return
&
bind
_address
;
}
socklen_t
zmq
::
udp_address_t
::
dest_addrlen
()
const
int
zmq
::
udp_address_t
::
bind_if
()
const
{
return
sizeof
(
sockaddr_in
)
;
return
bind_interface
;
}
const
in_addr
zmq
::
udp_address_t
::
multicast_ip
()
const
const
zmq
::
ip_addr_t
*
zmq
::
udp_address_t
::
target_addr
()
const
{
return
multicast
;
return
&
target_address
;
}
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
int
zmq
::
udp_address_t
::
to_string
(
std
::
string
&
addr_
)
{
return
AF_INET
;
// XXX what do (factor TCP code?)
addr_
=
address
;
return
0
;
}
src/udp_address.hpp
View file @
b0df4be5
...
...
@@ -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
;
};
...
...
src/udp_engine.cpp
View file @
b0df4be5
...
...
@@ -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_addr
len
());
rc
=
bind
(
fd
,
(
sockaddr
*
)
real_bind_addr
->
as_sock
addr
(),
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
...
...
tests/test_radio_dish.cpp
View file @
b0df4be5
...
...
@@ -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
();
}
unittests/CMakeLists.txt
View file @
b0df4be5
...
...
@@ -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.*"
)
...
...
unittests/unittest_ip_resolver.cpp
View file @
b0df4be5
...
...
@@ -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
...
...
unittests/unittest_resolver_common.hpp
0 → 100644
View file @
b0df4be5
/*
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__
unittests/unittest_udp_address.cpp
View file @
b0df4be5
This diff is collapsed.
Click to expand it.
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment