Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Udp parser #3075

Merged
merged 2 commits into from
May 3, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -898,7 +898,8 @@ test_apps += \
unittests/unittest_poller \
unittests/unittest_ypipe \
unittests/unittest_mtrie \
unittests/unittest_ip_resolver
unittests/unittest_ip_resolver \
unittests/unittest_udp_address

unittests_unittest_poller_SOURCES = unittests/unittest_poller.cpp
unittests_unittest_poller_CPPFLAGS = -I$(top_srcdir)/src ${UNITY_CPPFLAGS} $(CODE_COVERAGE_CPPFLAGS)
Expand Down Expand Up @@ -931,6 +932,14 @@ unittests_unittest_ip_resolver_LDADD = $(top_builddir)/src/.libs/libzmq.a \
${src_libzmq_la_LIBADD} \
${UNITY_LIBS} \
$(CODE_COVERAGE_LDFLAGS)

unittests_unittest_udp_address_SOURCES = unittests/unittest_udp_address.cpp
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_libzmq_la_LIBADD} \
${UNITY_LIBS} \
$(CODE_COVERAGE_LDFLAGS)
endif

check_PROGRAMS = ${test_apps}
Expand Down
43 changes: 18 additions & 25 deletions src/udp_address.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@
#include <ctype.h>
#endif

#include "ip_resolver.hpp"

zmq::udp_address_t::udp_address_t () : is_multicast (false)
{
memset (&bind_address, 0, sizeof bind_address);
Expand All @@ -56,38 +58,29 @@ zmq::udp_address_t::~udp_address_t ()

int zmq::udp_address_t::resolve (const char *name_, bool bind_)
{
// Find the ':' at end that separates address from the port number.
const char *delimiter = strrchr (name_, ':');
if (!delimiter) {
errno = EINVAL;
return -1;
}
ip_resolver_options_t resolver_opts;

// Separate the address/port.
std::string addr_str (name_, delimiter - name_);
std::string port_str (delimiter + 1);
resolver_opts.bindable (bind_)
.allow_dns (!bind_)
.allow_nic_name (bind_)
.expect_port (true)
.ipv6 (false);

// Parse the port number (0 is not a valid port).
uint16_t port = (uint16_t) atoi (port_str.c_str ());
if (port == 0) {
errno = EINVAL;
ip_resolver_t resolver (resolver_opts);
ip_addr_t addr;

int rc = resolver.resolve (&addr, name_);
if (rc != 0) {
return -1;
}

dest_address.sin_family = AF_INET;
dest_address.sin_port = htons (port);

// Only when the udp should bind we allow * as the address
if (addr_str == "*" && bind_)
dest_address.sin_addr.s_addr = htonl (INADDR_ANY);
else
dest_address.sin_addr.s_addr = inet_addr (addr_str.c_str ());

if (dest_address.sin_addr.s_addr == INADDR_NONE) {
errno = EINVAL;
if (addr.generic.sa_family != AF_INET) {
// Shouldn't happen
return -1;
}

dest_address = addr.ipv4;

// we will check only first byte of IP
// and if it from 224 to 239, then it can
// represent multicast IP.
Expand All @@ -110,7 +103,7 @@ int zmq::udp_address_t::resolve (const char *name_, bool bind_)
bind_address = dest_address;
else {
bind_address.sin_family = AF_INET;
bind_address.sin_port = htons (port);
bind_address.sin_port = dest_address.sin_port;
bind_address.sin_addr.s_addr = htonl (INADDR_ANY);
}

Expand Down
1 change: 1 addition & 0 deletions unittests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ set(unittests
unittest_poller
unittest_mtrie
unittest_ip_resolver
unittest_udp_address
)

#IF (ENABLE_DRAFTS)
Expand Down
163 changes: 163 additions & 0 deletions unittests/unittest_udp_address.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
/*
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/>.
*/

#include <unity.h>
#include "../tests/testutil.hpp"

#include <ip.hpp>
#include <udp_address.hpp>

void setUp ()
{
}

void tearDown ()
{
}

// Test an UDP address resolution. If 'bind_addr_' is not NULL
// request a bind address. If 'dest_addr_' is NULL assume the
// resolution is supposed to fail.
static void test_resolve (const char *name_, const char *dest_addr_,
uint16_t expected_port_ = 0,
const char *bind_addr_ = NULL,
bool multicast_ = false)
{
zmq::udp_address_t addr;
bool bound = bind_addr_ != NULL;

int rc = addr.resolve (name_, bound);

if (dest_addr_ == NULL) {
TEST_ASSERT_EQUAL (-1, rc);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe check for a specific errno here?

TEST_ASSERT_EQUAL (EINVAL, errno);
return;
} else {
TEST_ASSERT_EQUAL (0, rc);
}

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

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

static void test_resolve_ipv4_simple ()
{
test_resolve ("127.0.0.1:5555", "127.0.0.1", 5555);
}

static void test_resolve_ipv4_bind ()
{
test_resolve ("127.0.0.1:5555", "127.0.0.1", 5555, "127.0.0.1");
}

static void test_resolve_ipv4_bind_any ()
{
test_resolve ("*:*", "0.0.0.0", 0, "0.0.0.0");
}

static void test_resolve_ipv4_bind_anyport ()
{
test_resolve ("127.0.0.1:*", "127.0.0.1", 0, "127.0.0.1");
}

static void test_resolve_ipv4_bind_any_port ()
{
test_resolve ("*:5555", "0.0.0.0", 5555, "0.0.0.0");
}

static void test_resolve_ipv4_connect_any ()
{
// Cannot use wildcard for connection
test_resolve ("*:5555", NULL);
}

static void test_resolve_ipv4_connect_anyport ()
{
test_resolve ("127.0.0.1:*", NULL);
}

static void test_resolve_ipv4_connect_port0 ()
{
test_resolve ("127.0.0.1:0", "127.0.0.1", 0);
}

static void test_resolve_ipv4_bind_mcast ()
{
test_resolve ("239.0.0.1:1234", "239.0.0.1", 1234, "0.0.0.0", true);
}

static void test_resolve_ipv4_connect_mcast ()
{
test_resolve ("239.0.0.1:2222", "239.0.0.1", 2222, NULL, true);
}

static void test_resolve_ipv6_simple ()
{
if (!is_ipv6_available ()) {
TEST_IGNORE_MESSAGE ("ipv6 is not available");
}

// IPv6 not yet supported
test_resolve ("::1", NULL);
}

int main (void)
{
zmq::initialize_network ();
setup_test_environment ();

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

zmq::shutdown_network ();

return UNITY_END ();
}