test_use_fd.cpp 8.1 KB
Newer Older
1
/*
2
    Copyright (c) 2016-2017 Contributors as noted in the AUTHORS file
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30

    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 <http://www.gnu.org/licenses/>.
*/

#include "testutil.hpp"
31 32 33 34 35 36 37 38 39 40 41 42 43 44
#include "testutil_unity.hpp"

#include <unity.h>

void setUp ()
{
    setup_test_context ();
}

void tearDown ()
{
    teardown_test_context ();
}

45

46
#if !defined(ZMQ_HAVE_WINDOWS)
47 48
#include <sys/socket.h>
#include <sys/un.h>
49 50
#include <netdb.h>

51 52 53 54 55
int setup_socket_and_set_fd (void *zmq_socket_,
                             int af_,
                             int protocol_,
                             const sockaddr *addr_,
                             size_t addr_len_)
56
{
57 58
    const int s_pre =
      TEST_ASSERT_SUCCESS_ERRNO (socket (af_, SOCK_STREAM, protocol_));
59

60 61
    if (af_ == AF_INET) {
        int flag = 1;
62 63
        TEST_ASSERT_SUCCESS_ERRNO (
          setsockopt (s_pre, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof (int)));
64
    }
65

66 67
    TEST_ASSERT_SUCCESS_ERRNO (bind (s_pre, addr_, addr_len_));
    TEST_ASSERT_SUCCESS_ERRNO (listen (s_pre, SOMAXCONN));
68

69 70
    TEST_ASSERT_SUCCESS_ERRNO (
      zmq_setsockopt (zmq_socket_, ZMQ_USE_FD, &s_pre, sizeof (s_pre)));
71

72
    return s_pre;
73 74
}

75
typedef void (*pre_allocate_sock_fun_t) (void *, char *);
76

77
void setup_socket_pair (pre_allocate_sock_fun_t pre_allocate_sock_fun_,
78 79 80 81 82
                        int bind_socket_type_,
                        int connect_socket_type_,
                        void **out_sb_,
                        void **out_sc_)
{
83
    *out_sb_ = test_context_socket (bind_socket_type_);
84

85
    char my_endpoint[MAX_SOCKET_STRING];
86
    pre_allocate_sock_fun_ (*out_sb_, my_endpoint);
87

88
    TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (*out_sb_, my_endpoint));
89

90 91
    *out_sc_ = test_context_socket (connect_socket_type_);
    TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (*out_sc_, my_endpoint));
92 93
}

94 95 96
void test_socket_pair (pre_allocate_sock_fun_t pre_allocate_sock_fun_,
                       int bind_socket_type_,
                       int connect_socket_type_)
97
{
98
    void *sb, *sc;
99
    setup_socket_pair (pre_allocate_sock_fun_, bind_socket_type_,
100
                       connect_socket_type_, &sb, &sc);
101 102 103

    bounce (sb, sc);

104 105
    test_context_socket_close (sc);
    test_context_socket_close (sb);
106 107
}

108 109 110 111 112 113 114 115 116 117 118
void test_req_rep (pre_allocate_sock_fun_t pre_allocate_sock_fun_)
{
    test_socket_pair (pre_allocate_sock_fun_, ZMQ_REP, ZMQ_REQ);
}

void test_pair (pre_allocate_sock_fun_t pre_allocate_sock_fun_)
{
    test_socket_pair (pre_allocate_sock_fun_, ZMQ_PAIR, ZMQ_PAIR);
}

void test_client_server (pre_allocate_sock_fun_t pre_allocate_sock_fun_)
119
{
120
#if defined(ZMQ_SERVER) && defined(ZMQ_CLIENT)
121
    void *sb, *sc;
122
    setup_socket_pair (pre_allocate_sock_fun_, ZMQ_SERVER, ZMQ_CLIENT, &sb,
123
                       &sc);
124 125

    zmq_msg_t msg;
126
    TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_init_size (&msg, 1));
127 128

    char *data = (char *) zmq_msg_data (&msg);
129
    data[0] = 1;
130

131 132 133
    int rc = zmq_msg_send (&msg, sc, ZMQ_SNDMORE);
    // TODO which error code is expected?
    TEST_ASSERT_EQUAL_INT (-1, rc);
134 135

    rc = zmq_msg_send (&msg, sc, 0);
136
    TEST_ASSERT_EQUAL_INT (1, rc);
137

138
    TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_init (&msg));
139 140

    rc = zmq_msg_recv (&msg, sb, 0);
141
    TEST_ASSERT_EQUAL_INT (1, rc);
142 143

    uint32_t routing_id = zmq_msg_routing_id (&msg);
144
    TEST_ASSERT_NOT_EQUAL (0, routing_id);
145

146
    TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_close (&msg));
147

148
    TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_init_size (&msg, 1));
149

150
    data = (char *) zmq_msg_data (&msg);
151 152
    data[0] = 2;

153
    TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_set_routing_id (&msg, routing_id));
154 155

    rc = zmq_msg_send (&msg, sb, ZMQ_SNDMORE);
156 157
    // TODO which error code is expected?
    TEST_ASSERT_EQUAL_INT (-1, rc);
158 159

    rc = zmq_msg_send (&msg, sb, 0);
160
    TEST_ASSERT_EQUAL_INT (1, rc);
161 162

    rc = zmq_msg_recv (&msg, sc, 0);
163
    TEST_ASSERT_EQUAL_INT (1, rc);
164 165

    routing_id = zmq_msg_routing_id (&msg);
166
    TEST_ASSERT_EQUAL_INT (0, routing_id);
167

168
    TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_close (&msg));
169

170 171
    test_context_socket_close (sc);
    test_context_socket_close (sb);
172
#endif
173 174
}

175 176 177 178 179 180 181 182 183 184 185 186 187 188
uint16_t pre_allocate_sock_tcp_int (void *zmq_socket_,
                                    const char *address_,
                                    const char *port_)
{
    struct addrinfo *addr, hint;
    hint.ai_flags = 0;
    hint.ai_family = AF_INET;
    hint.ai_socktype = SOCK_STREAM;
    hint.ai_protocol = IPPROTO_TCP;
    hint.ai_addrlen = 0;
    hint.ai_canonname = NULL;
    hint.ai_addr = NULL;
    hint.ai_next = NULL;

189
    TEST_ASSERT_SUCCESS_ERRNO (getaddrinfo (address_, port_, &hint, &addr));
190 191 192 193 194 195

    const int s_pre = setup_socket_and_set_fd (
      zmq_socket_, AF_INET, IPPROTO_TCP, addr->ai_addr, addr->ai_addrlen);

    struct sockaddr_in sin;
    socklen_t len = sizeof (sin);
196 197
    TEST_ASSERT_SUCCESS_ERRNO (
      getsockname (s_pre, (struct sockaddr *) &sin, &len));
198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239

    freeaddrinfo (addr);

    return ntohs (sin.sin_port);
}

void pre_allocate_sock_tcp (void *socket_, char *my_endpoint_)
{
    const uint16_t port = pre_allocate_sock_tcp_int (socket_, "127.0.0.1", "0");
    sprintf (my_endpoint_, "tcp://127.0.0.1:%u", port);
}

void test_req_rep_tcp ()
{
    test_req_rep (pre_allocate_sock_tcp);
}

void test_pair_tcp ()
{
    test_pair (pre_allocate_sock_tcp);
}

void test_client_server_tcp ()
{
#if defined(ZMQ_SERVER) && defined(ZMQ_CLIENT)
    test_client_server (pre_allocate_sock_tcp);
#endif
}

void pre_allocate_sock_ipc_int (void *zmq_socket_, const char *path_)
{
    struct sockaddr_un addr;
    addr.sun_family = AF_UNIX;
    strcpy (addr.sun_path, path_);

    // TODO check return value of unlink
    unlink (path_);

    setup_socket_and_set_fd (zmq_socket_, AF_UNIX, 0, (struct sockaddr *) &addr,
                             sizeof (struct sockaddr_un));
}

240 241
char ipc_endpoint[16];

242 243
void pre_allocate_sock_ipc (void *sb_, char *my_endpoint_)
{
244 245 246 247 248 249 250 251 252 253 254 255 256 257
    strcpy (ipc_endpoint, "tmpXXXXXX");

#ifdef HAVE_MKDTEMP
    TEST_ASSERT_TRUE (mkdtemp (ipc_endpoint));
    strcat (ipc_endpoint, "/ipc");
#else
    int fd = mkstemp (ipc_endpoint);
    TEST_ASSERT_TRUE (fd != -1);
    close (fd);
#endif

    pre_allocate_sock_ipc_int (sb_, ipc_endpoint);
    strcpy (my_endpoint_, "ipc://");
    strcat (my_endpoint_, ipc_endpoint);
258 259 260 261 262 263
}

void test_req_rep_ipc ()
{
    test_req_rep (pre_allocate_sock_ipc);

264
    TEST_ASSERT_SUCCESS_ERRNO (unlink (ipc_endpoint));
265 266 267 268 269 270
}

void test_pair_ipc ()
{
    test_pair (pre_allocate_sock_ipc);

271
    TEST_ASSERT_SUCCESS_ERRNO (unlink (ipc_endpoint));
272 273 274 275 276 277 278
}

void test_client_server_ipc ()
{
#if defined(ZMQ_SERVER) && defined(ZMQ_CLIENT)
    test_client_server (pre_allocate_sock_ipc);

279
    TEST_ASSERT_SUCCESS_ERRNO (unlink (ipc_endpoint));
280 281 282 283
#endif
}

int main ()
284
{
285
    setup_test_environment ();
286

287 288 289 290
    UNITY_BEGIN ();
    RUN_TEST (test_req_rep_tcp);
    RUN_TEST (test_pair_tcp);
    RUN_TEST (test_client_server_tcp);
291

292 293 294
    RUN_TEST (test_req_rep_ipc);
    RUN_TEST (test_pair_ipc);
    RUN_TEST (test_client_server_ipc);
295

296
    return UNITY_END ();
297
}
298
#else
299
int main ()
300
{
301
    return 0;
302 303
}
#endif