From 84ad4bf0ff108d53e7c6bc52d508059924b2ae67 Mon Sep 17 00:00:00 2001 From: Luca Boccassi Date: Mon, 1 Feb 2016 17:03:55 +0000 Subject: [PATCH] Problem: cannot use new pre-allocated FD with TCP Solution: parse the value set by the ZMQ_PRE_ALLOCATED_FD sockopt when creating a new TCP socket and use it if valid. Add new tests/test_pre_allocated_fd_tcp.cpp unit test. --- .gitignore | 1 + Makefile.am | 6 + src/tcp_listener.cpp | 10 +- tests/CMakeLists.txt | 1 + tests/test_pre_allocated_fd_tcp.cpp | 206 ++++++++++++++++++++++++++++ 5 files changed, 222 insertions(+), 2 deletions(-) create mode 100644 tests/test_pre_allocated_fd_tcp.cpp diff --git a/.gitignore b/.gitignore index 5a0f7244..29be73d3 100644 --- a/.gitignore +++ b/.gitignore @@ -126,6 +126,7 @@ test_radio_dish test_udp test_large_msg test_pre_allocated_fd_ipc +test_pre_allocated_fd_tcp tests/test*.log tests/test*.trs src/platform.hpp* diff --git a/Makefile.am b/Makefile.am index 833ea848..6c966199 100644 --- a/Makefile.am +++ b/Makefile.am @@ -618,6 +618,7 @@ test_apps += \ tests/test_pair_ipc \ tests/test_reqrep_ipc \ tests/test_pre_allocated_fd_ipc \ + tests/test_pre_allocated_fd_tcp \ tests/test_timeo \ tests/test_filter_ipc @@ -645,6 +646,11 @@ tests_test_pre_allocated_fd_ipc_SOURCES = \ tests/testutil.hpp tests_test_pre_allocated_fd_ipc_LDADD = src/libzmq.la +tests_test_pre_allocated_fd_tcp_SOURCES = \ + tests/test_pre_allocated_fd_tcp.cpp \ + tests/testutil.hpp +tests_test_pre_allocated_fd_tcp_LDADD = src/libzmq.la + if HAVE_FORK test_apps += tests/test_fork diff --git a/src/tcp_listener.cpp b/src/tcp_listener.cpp index ad382715..5c8f7e4e 100644 --- a/src/tcp_listener.cpp +++ b/src/tcp_listener.cpp @@ -166,6 +166,14 @@ int zmq::tcp_listener_t::set_address (const char *addr_) if (rc != 0) return -1; + address.to_string (endpoint); + + if (options.pre_allocated_fd != -1) { + s = options.pre_allocated_fd; + socket->event_listening (endpoint, (int) s); + return 0; + } + // Create a listening socket. s = open_socket (address.family (), SOCK_STREAM, IPPROTO_TCP); #ifdef ZMQ_HAVE_WINDOWS @@ -224,8 +232,6 @@ int zmq::tcp_listener_t::set_address (const char *addr_) errno_assert (rc == 0); #endif - address.to_string (endpoint); - // Bind the socket to the network interface and port. rc = bind (s, address.addr (), address.addrlen ()); #ifdef ZMQ_HAVE_WINDOWS diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 438142ad..4a8b4a7e 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -91,6 +91,7 @@ if(NOT WIN32) test_router_mandatory_hwm test_term_endpoint_tipc test_pre_allocated_fd_ipc + test_pre_allocated_fd_tcp ) if(HAVE_FORK) list(APPEND tests test_fork) diff --git a/tests/test_pre_allocated_fd_tcp.cpp b/tests/test_pre_allocated_fd_tcp.cpp new file mode 100644 index 00000000..701ff62f --- /dev/null +++ b/tests/test_pre_allocated_fd_tcp.cpp @@ -0,0 +1,206 @@ +/* + Copyright (c) 2016 Contributors as noted in the AUTHORS file + + This file is part of libzmq, the ZeroMQ core engine in C++. + + libzmq is free software; you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License (LGPL) as published + by the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + As a special exception, the Contributors give you permission to link + this library with independent modules to produce an executable, + regardless of the license terms of these independent modules, and to + copy and distribute the resulting executable under terms of your choice, + provided that you also meet, for each linked independent module, the + terms and conditions of the license of that module. An independent + module is a module which is not derived from or based on this library. + If you modify this library, you must extend this exception to your + version of the library. + + libzmq 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 . +*/ + +#include +#include +#include +#include "testutil.hpp" + +void pre_allocate_sock (void *zmq_socket, const char *address, + const char *port) +{ + struct addrinfo *addr; + int rc = getaddrinfo (address, port, NULL, &addr); + assert (rc == 0); + + int s_pre = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP); + assert (s_pre != -1); + + int flag = 1; + rc = setsockopt (s_pre, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof (int)); + assert (rc == 0); + + rc = bind (s_pre, addr->ai_addr, addr->ai_addrlen); + assert (rc == 0); + + rc = listen (s_pre, SOMAXCONN); + assert (rc == 0); + + rc = zmq_setsockopt (zmq_socket, ZMQ_PRE_ALLOCATED_FD, &s_pre, + sizeof (s_pre)); + assert(rc == 0); +} + +void test_req_rep () +{ + void *ctx = zmq_ctx_new (); + assert (ctx); + + void *sb = zmq_socket (ctx, ZMQ_REP); + assert (sb); + + pre_allocate_sock(sb, "127.0.0.1", "5560"); + + int rc = zmq_bind (sb, "tcp://127.0.0.1:5560"); + assert (rc == 0); + + void *sc = zmq_socket (ctx, ZMQ_REQ); + assert (sc); + rc = zmq_connect (sc, "tcp://127.0.0.1:5560"); + assert (rc == 0); + + bounce (sb, sc); + + rc = zmq_close (sc); + assert (rc == 0); + + rc = zmq_close (sb); + assert (rc == 0); + + rc = zmq_ctx_term (ctx); + assert (rc == 0); +} + +void test_pair () +{ + void *ctx = zmq_ctx_new (); + assert (ctx); + + void *sb = zmq_socket (ctx, ZMQ_PAIR); + assert (sb); + + pre_allocate_sock(sb, "127.0.0.1", "5560"); + + int rc = zmq_bind (sb, "tcp://127.0.0.1:5560"); + assert (rc == 0); + + void *sc = zmq_socket (ctx, ZMQ_PAIR); + assert (sc); + rc = zmq_connect (sc, "tcp://127.0.0.1:5560"); + assert (rc == 0); + + bounce (sb, sc); + + rc = zmq_close (sc); + assert (rc == 0); + + rc = zmq_close (sb); + assert (rc == 0); + + rc = zmq_ctx_term (ctx); + assert (rc == 0); +} + +void test_client_server () +{ + void *ctx = zmq_ctx_new (); + assert (ctx); + + void *sb = zmq_socket (ctx, ZMQ_SERVER); + assert (sb); + + pre_allocate_sock(sb, "127.0.0.1", "5560"); + + int rc = zmq_bind (sb, "tcp://127.0.0.1:5560"); + assert (rc == 0); + + void *sc = zmq_socket (ctx, ZMQ_CLIENT); + assert (sc); + rc = zmq_connect (sc, "tcp://127.0.0.1:5560"); + assert (rc == 0); + + zmq_msg_t msg; + rc = zmq_msg_init_size (&msg, 1); + assert (rc == 0); + + char *data = (char *) zmq_msg_data (&msg); + data [0] = 1; + + rc = zmq_msg_send (&msg, sc, ZMQ_SNDMORE); + assert (rc == -1); + + rc = zmq_msg_send (&msg, sc, 0); + assert (rc == 1); + + rc = zmq_msg_init (&msg); + assert (rc == 0); + + rc = zmq_msg_recv (&msg, sb, 0); + assert (rc == 1); + + uint32_t routing_id = zmq_msg_routing_id (&msg); + assert (routing_id != 0); + + rc = zmq_msg_close (&msg); + assert (rc == 0); + + rc = zmq_msg_init_size (&msg, 1); + assert (rc == 0); + + data = (char *)zmq_msg_data (&msg); + data[0] = 2; + + rc = zmq_msg_set_routing_id (&msg, routing_id); + assert (rc == 0); + + rc = zmq_msg_send (&msg, sb, ZMQ_SNDMORE); + assert (rc == -1); + + rc = zmq_msg_send (&msg, sb, 0); + assert (rc == 1); + + rc = zmq_msg_recv (&msg, sc, 0); + assert (rc == 1); + + routing_id = zmq_msg_routing_id (&msg); + assert (routing_id == 0); + + rc = zmq_msg_close (&msg); + assert (rc == 0); + + rc = zmq_close (sc); + assert (rc == 0); + + rc = zmq_close (sb); + assert (rc == 0); + + rc = zmq_ctx_term (ctx); + assert (rc == 0); +} + +int main (void) +{ + setup_test_environment(); + + test_req_rep(); + test_pair(); + test_client_server(); + + return 0 ; +}