diff --git a/src/ipc_address.cpp b/src/ipc_address.cpp index 100e9600..448e3429 100644 --- a/src/ipc_address.cpp +++ b/src/ipc_address.cpp @@ -36,20 +36,20 @@ #include "err.hpp" #include -#include zmq::ipc_address_t::ipc_address_t () { - memset (&address, 0, sizeof address); + memset (&_address, 0, sizeof _address); } -zmq::ipc_address_t::ipc_address_t (const sockaddr *sa_, socklen_t sa_len_) +zmq::ipc_address_t::ipc_address_t (const sockaddr *sa_, socklen_t sa_len_) : + _addrlen (sa_len_) { zmq_assert (sa_ && sa_len_ > 0); - memset (&address, 0, sizeof address); + memset (&_address, 0, sizeof _address); if (sa_->sa_family == AF_UNIX) - memcpy (&address, sa_, sa_len_); + memcpy (&_address, sa_, sa_len_); } zmq::ipc_address_t::~ipc_address_t () @@ -58,7 +58,8 @@ zmq::ipc_address_t::~ipc_address_t () int zmq::ipc_address_t::resolve (const char *path_) { - if (strlen (path_) >= sizeof address.sun_path) { + const size_t path_len = strlen (path_); + if (path_len >= sizeof _address.sun_path) { errno = ENAMETOOLONG; return -1; } @@ -67,42 +68,52 @@ int zmq::ipc_address_t::resolve (const char *path_) return -1; } - address.sun_family = AF_UNIX; - strcpy (address.sun_path, path_); + _address.sun_family = AF_UNIX; + memcpy (_address.sun_path, path_, path_len + 1); /* Abstract sockets start with '\0' */ if (path_[0] == '@') - *address.sun_path = '\0'; + *_address.sun_path = '\0'; + + _addrlen = offsetof (sockaddr_un, sun_path) + path_len; return 0; } int zmq::ipc_address_t::to_string (std::string &addr_) const { - if (address.sun_family != AF_UNIX) { + if (_address.sun_family != AF_UNIX) { addr_.clear (); return -1; } - std::stringstream s; - s << "ipc://"; - if (!address.sun_path[0] && address.sun_path[1]) - s << "@" << address.sun_path + 1; - else - s << address.sun_path; - addr_ = s.str (); + const char prefix[] = "ipc://"; + char buf[sizeof prefix + sizeof _address.sun_path]; + char *pos = buf; + memcpy (pos, prefix, sizeof prefix - 1); + pos += sizeof prefix - 1; + const char *src_pos = _address.sun_path; + if (!_address.sun_path[0] && _address.sun_path[1]) { + *pos++ = '@'; + src_pos++; + } + // according to http://man7.org/linux/man-pages/man7/unix.7.html, NOTES + // section, address.sun_path might not always be null-terminated; therefore, + // we calculate the length based of addrlen + const size_t src_len = + strnlen (src_pos, _addrlen - offsetof (sockaddr_un, sun_path) + - (src_pos - _address.sun_path)); + memcpy (pos, src_pos, src_len); + addr_.assign (buf, pos - buf + src_len); return 0; } const sockaddr *zmq::ipc_address_t::addr () const { - return reinterpret_cast (&address); + return reinterpret_cast (&_address); } socklen_t zmq::ipc_address_t::addrlen () const { - if (!address.sun_path[0] && address.sun_path[1]) - return static_cast (strlen (address.sun_path + 1)) - + sizeof (sa_family_t) + 1; - return static_cast (sizeof address); + return _addrlen; } #endif diff --git a/src/ipc_address.hpp b/src/ipc_address.hpp index 006a0d2f..37f8447e 100644 --- a/src/ipc_address.hpp +++ b/src/ipc_address.hpp @@ -57,7 +57,8 @@ class ipc_address_t socklen_t addrlen () const; private: - struct sockaddr_un address; + struct sockaddr_un _address; + size_t _addrlen; ipc_address_t (const ipc_address_t &); const ipc_address_t &operator= (const ipc_address_t &); diff --git a/tests/test_monitor.cpp b/tests/test_monitor.cpp index a9058faa..4af013b1 100644 --- a/tests/test_monitor.cpp +++ b/tests/test_monitor.cpp @@ -171,7 +171,7 @@ void test_monitor_versioned_basic (bind_function_t bind_function_, event = get_monitor_event_v2 (client_mon, NULL, &client_local_address, &client_remote_address); } - TEST_ASSERT_EQUAL (ZMQ_EVENT_CONNECTED, event); + TEST_ASSERT_EQUAL_HEX64 (ZMQ_EVENT_CONNECTED, event); TEST_ASSERT_EQUAL_STRING (server_endpoint, client_remote_address); TEST_ASSERT_EQUAL_STRING_LEN (expected_prefix_, client_local_address, strlen (expected_prefix_)); @@ -192,11 +192,11 @@ void test_monitor_versioned_basic (bind_function_t bind_function_, event = get_monitor_event_v2 (server_mon, NULL, NULL, NULL); // Sometimes the server sees the client closing before it gets closed. if (event != ZMQ_EVENT_DISCONNECTED) { - TEST_ASSERT_EQUAL_INT (ZMQ_EVENT_CLOSED, event); + TEST_ASSERT_EQUAL_HEX64 (ZMQ_EVENT_CLOSED, event); event = get_monitor_event_v2 (server_mon, NULL, NULL, NULL); } if (event != ZMQ_EVENT_DISCONNECTED) { - TEST_ASSERT_EQUAL_INT (ZMQ_EVENT_MONITOR_STOPPED, event); + TEST_ASSERT_EQUAL_HEX64 (ZMQ_EVENT_MONITOR_STOPPED, event); } free (client_local_address); free (client_remote_address); @@ -218,6 +218,18 @@ void test_monitor_versioned_basic_tcp_ipv6 () static const char prefix[] = "tcp://[::1]:"; test_monitor_versioned_basic (bind_loopback_ipv6, prefix); } + +void test_monitor_versioned_basic_ipc () +{ + static const char prefix[] = "ipc://"; + test_monitor_versioned_basic (bind_loopback_ipc, prefix); +} + +void test_monitor_versioned_basic_tipc () +{ + static const char prefix[] = "tipc://"; + test_monitor_versioned_basic (bind_loopback_tipc, prefix); +} #endif int main () @@ -231,6 +243,8 @@ int main () #ifdef ZMQ_BUILD_DRAFT_API RUN_TEST (test_monitor_versioned_basic_tcp_ipv4); RUN_TEST (test_monitor_versioned_basic_tcp_ipv6); + RUN_TEST (test_monitor_versioned_basic_ipc); + RUN_TEST (test_monitor_versioned_basic_tipc); #endif return UNITY_END (); diff --git a/tests/testutil.hpp b/tests/testutil.hpp index 42b19372..69b7fe54 100644 --- a/tests/testutil.hpp +++ b/tests/testutil.hpp @@ -43,7 +43,9 @@ // settled. Tested to work reliably at 1 msec on a fast PC. #define SETTLE_TIME 300 // In msec // Commonly used buffer size for ZMQ_LAST_ENDPOINT -#define MAX_SOCKET_STRING sizeof ("tcp://[::ffff:127.127.127.127]:65536") +// this used to be sizeof ("tcp://[::ffff:127.127.127.127]:65536"), but this +// may be too short for ipc wildcard binds, e.g. +#define MAX_SOCKET_STRING 256 // We need to test codepaths with non-random bind ports. List them here to // keep them unique, to allow parallel test runs. diff --git a/tests/testutil_monitoring.hpp b/tests/testutil_monitoring.hpp index ee2d0a0b..1554391a 100644 --- a/tests/testutil_monitoring.hpp +++ b/tests/testutil_monitoring.hpp @@ -306,7 +306,7 @@ void expect_monitor_event_v2 (void *monitor_, expected_remote_address_ ? &remote_address : NULL); bool failed = false; if (event != expected_event_) { - fprintf (stderr, "Expected monitor event %lld, but received %lld\n", + fprintf (stderr, "Expected monitor event %llx, but received %llx\n", (long long) expected_event_, (long long) event); failed = true; } diff --git a/tests/testutil_unity.hpp b/tests/testutil_unity.hpp index 1fe04c0e..aad1c7c6 100644 --- a/tests/testutil_unity.hpp +++ b/tests/testutil_unity.hpp @@ -31,6 +31,8 @@ along with this program. If not, see . #include "../include/zmq.h" +#include "testutil.hpp" + #include #include @@ -327,6 +329,24 @@ void bind_loopback_ipv6 (void *socket_, char *my_endpoint_, size_t len_) bind_loopback (socket_, true, my_endpoint_, len_); } +void bind_loopback_ipc (void *socket_, char *my_endpoint_, size_t len_) +{ + if (!zmq_has ("ipc")) { + TEST_IGNORE_MESSAGE ("ipc is not available"); + } + + test_bind (socket_, "ipc://*", my_endpoint_, len_); +} + +void bind_loopback_tipc (void *socket_, char *my_endpoint_, size_t len_) +{ + if (!is_tipc_available ()) { + TEST_IGNORE_MESSAGE ("tipc is not available"); + } + + test_bind (socket_, "tipc://<*>", my_endpoint_, len_); +} + // utility function to create a random IPC endpoint, similar to what a ipc://* // wildcard binding does, but in a way it can be reused for multiple binds void make_random_ipc_endpoint (char *out_endpoint_)