testutil.hpp 11.8 KB
Newer Older
Guido Goldstein's avatar
Guido Goldstein committed
1
/*
2
    Copyright (c) 2007-2017 Contributors as noted in the AUTHORS file
Guido Goldstein's avatar
Guido Goldstein committed
3

4
    This file is part of libzmq, the ZeroMQ core engine in C++.
Guido Goldstein's avatar
Guido Goldstein committed
5

6 7 8
    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
Guido Goldstein's avatar
Guido Goldstein committed
9 10
    (at your option) any later version.

11 12 13 14 15 16 17 18 19 20 21 22 23 24
    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.
Guido Goldstein's avatar
Guido Goldstein committed
25

26
    You should have received a copy of the GNU Lesser General Public License
Guido Goldstein's avatar
Guido Goldstein committed
27 28 29
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

30 31
#ifndef __TESTUTIL_HPP_INCLUDED__
#define __TESTUTIL_HPP_INCLUDED__
Guido Goldstein's avatar
Guido Goldstein committed
32

33
#if defined ZMQ_CUSTOM_PLATFORM_HPP
34 35 36 37
#   include "platform.hpp"
#else
#   include "../src/platform.hpp"
#endif
38 39
#include "../include/zmq.h"
#include "../src/stdint.hpp"
40

41 42 43
//  This defines the settle time used in tests; raise this if we
//  get test failures on slower systems due to binds/connects not
//  settled. Tested to work reliably at 1 msec on a fast PC.
44
#define SETTLE_TIME 300         //  In msec
45 46 47 48 49 50 51 52 53 54 55
//  Commonly used buffer size for ZMQ_LAST_ENDPOINT
#define MAX_SOCKET_STRING sizeof("tcp://127.0.0.1:65536")

//  We need to test codepaths with non-random bind ports. List them here to
//  keep them unique, to allow parallel test runs.
#define ENDPOINT_0 "tcp://127.0.0.1:5555"
#define ENDPOINT_1 "tcp://127.0.0.1:5556"
#define ENDPOINT_2 "tcp://127.0.0.1:5557"
#define ENDPOINT_3 "tcp://127.0.0.1:5558"
#define ENDPOINT_4 "udp://127.0.0.1:5559"
#define ENDPOINT_5 "udp://127.0.0.1:5560"
56

57
#undef NDEBUG
58
#include <time.h>
59
#include <assert.h>
60
#include <stdarg.h>
61
#include <string>
62
#include <string.h>
63

64
#if defined _WIN32
65
#   include "../src/windows.hpp"
66 67 68
#   if defined _MSC_VER
#       include <crtdbg.h>
#       pragma warning(disable:4996)
69 70 71 72
// iphlpapi is needed for if_nametoindex (not on Windows XP)
#       if !defined ZMQ_HAVE_WINDOWS_TARGET_XP
#           pragma comment(lib,"iphlpapi")
#       endif
73
#   endif
74
#else
75
#   include <pthread.h>
76 77 78 79
#   include <unistd.h>
#   include <signal.h>
#   include <stdlib.h>
#   include <sys/wait.h>
80 81 82
#   include <sys/socket.h>
#   include <netinet/in.h>
#   include <arpa/inet.h>
83 84 85 86
#   if defined (ZMQ_HAVE_AIX)
#      include <sys/types.h>
#      include <sys/socketvar.h>
#   endif
87 88
#endif

89 90
//  Bounce a message from client to server and back
//  For REQ/REP or DEALER/DEALER pairs only
91
void
92
bounce (void *server, void *client)
Guido Goldstein's avatar
Guido Goldstein committed
93
{
94 95
    const char *content = "12345678ABCDEFGH12345678abcdefgh";

96 97
    //  Send message from client to server
    int rc = zmq_send (client, content, 32, ZMQ_SNDMORE);
98
    assert (rc == 32);
99
    rc = zmq_send (client, content, 32, 0);
100
    assert (rc == 32);
101

102 103 104
    //  Receive message at server side
    char buffer [32];
    rc = zmq_recv (server, buffer, 32, 0);
105
    assert (rc == 32);
106 107
    //  Check that message is still the same
    assert (memcmp (buffer, content, 32) == 0);
108 109
    int rcvmore;
    size_t sz = sizeof (rcvmore);
110
    rc = zmq_getsockopt (server, ZMQ_RCVMORE, &rcvmore, &sz);
111 112
    assert (rc == 0);
    assert (rcvmore);
113
    rc = zmq_recv (server, buffer, 32, 0);
114
    assert (rc == 32);
115 116
    //  Check that message is still the same
    assert (memcmp (buffer, content, 32) == 0);
117
    rc = zmq_getsockopt (server, ZMQ_RCVMORE, &rcvmore, &sz);
118 119
    assert (rc == 0);
    assert (!rcvmore);
120

121 122
    //  Send two parts back to client
    rc = zmq_send (server, buffer, 32, ZMQ_SNDMORE);
123
    assert (rc == 32);
124
    rc = zmq_send (server, buffer, 32, 0);
125
    assert (rc == 32);
126

127 128
    //  Receive the two parts at the client side
    rc = zmq_recv (client, buffer, 32, 0);
129
    assert (rc == 32);
130 131
    //  Check that message is still the same
    assert (memcmp (buffer, content, 32) == 0);
132
    rc = zmq_getsockopt (client, ZMQ_RCVMORE, &rcvmore, &sz);
133 134
    assert (rc == 0);
    assert (rcvmore);
135
    rc = zmq_recv (client, buffer, 32, 0);
136
    assert (rc == 32);
137 138
    //  Check that message is still the same
    assert (memcmp (buffer, content, 32) == 0);
139
    rc = zmq_getsockopt (client, ZMQ_RCVMORE, &rcvmore, &sz);
140 141
    assert (rc == 0);
    assert (!rcvmore);
Guido Goldstein's avatar
Guido Goldstein committed
142 143
}

MinRK's avatar
MinRK committed
144 145 146 147 148 149 150
//  Same as bounce, but expect messages to never arrive
//  for security or subscriber reasons.
void
expect_bounce_fail (void *server, void *client)
{
    const char *content = "12345678ABCDEFGH12345678abcdefgh";
    char buffer [32];
151
    int timeout = 250;
MinRK's avatar
MinRK committed
152 153

    //  Send message from client to server
154 155 156 157
    int rc = zmq_setsockopt (client, ZMQ_SNDTIMEO, &timeout, sizeof (int));
    assert (rc == 0);
    rc = zmq_send (client, content, 32, ZMQ_SNDMORE);
    assert ((rc == 32) || ((rc == -1) && (errno == EAGAIN)));
MinRK's avatar
MinRK committed
158
    rc = zmq_send (client, content, 32, 0);
159
    assert ((rc == 32) || ((rc == -1) && (errno == EAGAIN)));
MinRK's avatar
MinRK committed
160 161

    //  Receive message at server side (should not succeed)
162
    rc = zmq_setsockopt (server, ZMQ_RCVTIMEO, &timeout, sizeof (int));
MinRK's avatar
MinRK committed
163 164 165
    assert (rc == 0);
    rc = zmq_recv (server, buffer, 32, 0);
    assert (rc == -1);
166
    assert (zmq_errno () == EAGAIN);
MinRK's avatar
MinRK committed
167

168
    //  Send message from server to client to test other direction
169
    //  If connection failed, send may block, without a timeout
170 171
    rc = zmq_setsockopt (server, ZMQ_SNDTIMEO, &timeout, sizeof (int));
    assert (rc == 0);
MinRK's avatar
MinRK committed
172
    rc = zmq_send (server, content, 32, ZMQ_SNDMORE);
173
    assert (rc == 32 || (rc == -1 && zmq_errno () == EAGAIN));
MinRK's avatar
MinRK committed
174
    rc = zmq_send (server, content, 32, 0);
175
    assert (rc == 32 || (rc == -1 && zmq_errno () == EAGAIN));
MinRK's avatar
MinRK committed
176

177 178 179
    //  Receive message at client side (should not succeed)
    rc = zmq_setsockopt (client, ZMQ_RCVTIMEO, &timeout, sizeof (int));
    assert (rc == 0);
MinRK's avatar
MinRK committed
180 181
    rc = zmq_recv (client, buffer, 32, 0);
    assert (rc == -1);
182
    assert (zmq_errno () == EAGAIN);
MinRK's avatar
MinRK committed
183 184
}

185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216
//  Receive 0MQ string from socket and convert into C string
//  Caller must free returned string. Returns NULL if the context
//  is being terminated.
char *
s_recv (void *socket) {
    char buffer [256];
    int size = zmq_recv (socket, buffer, 255, 0);
    if (size == -1)
        return NULL;
    if (size > 255)
        size = 255;
    buffer [size] = 0;
    return strdup (buffer);
}

//  Convert C string to 0MQ string and send to socket
int
s_send (void *socket, const char *string) {
    int size = zmq_send (socket, string, strlen (string), 0);
    return size;
}

//  Sends string as 0MQ string, as multipart non-terminal
int
s_sendmore (void *socket, const char *string) {
    int size = zmq_send (socket, string, strlen (string), ZMQ_SNDMORE);
    return size;
}

#define streq(s1,s2)    (!strcmp ((s1), (s2)))
#define strneq(s1,s2)   (strcmp ((s1), (s2)))

217
const char *SEQ_END = (const char *) 1;
218 219 220 221

//  Sends a message composed of frames that are C strings or null frames.
//  The list must be terminated by SEQ_END.
//  Example: s_send_seq (req, "ABC", 0, "DEF", SEQ_END);
222 223 224

void
s_send_seq (void *socket, ...)
225 226 227 228 229 230 231 232 233 234
{
    va_list ap;
    va_start (ap, socket);
    const char * data = va_arg (ap, const char *);
    while (true)
    {
        const char * prev = data;
        data = va_arg (ap, const char *);
        bool end = data == SEQ_END;

235
        if (!prev) {
236 237 238
            int rc = zmq_send (socket, 0, 0, end ? 0 : ZMQ_SNDMORE);
            assert (rc != -1);
        }
239
        else {
240 241 242 243 244 245 246 247 248 249 250 251 252
            int rc = zmq_send (socket, prev, strlen (prev)+1, end ? 0 : ZMQ_SNDMORE);
            assert (rc != -1);
        }
        if (end)
            break;
    }
    va_end (ap);
}

//  Receives message a number of frames long and checks that the frames have
//  the given data which can be either C strings or 0 for a null frame.
//  The list must be terminated by SEQ_END.
//  Example: s_recv_seq (rep, "ABC", 0, "DEF", SEQ_END);
253 254 255

void
s_recv_seq (void *socket, ...)
256 257 258 259 260 261 262 263 264 265
{
    zmq_msg_t msg;
    zmq_msg_init (&msg);

    int more;
    size_t more_size = sizeof(more);

    va_list ap;
    va_start (ap, socket);
    const char * data = va_arg (ap, const char *);
266

267
    while (true) {
268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290
        int rc = zmq_msg_recv (&msg, socket, 0);
        assert (rc != -1);

        if (!data)
            assert (zmq_msg_size (&msg) == 0);
        else
            assert (strcmp (data, (const char *)zmq_msg_data (&msg)) == 0);

        data = va_arg (ap, const char *);
        bool end = data == SEQ_END;

        rc = zmq_getsockopt (socket, ZMQ_RCVMORE, &more, &more_size);
        assert (rc == 0);

        assert (!more == end);
        if (end)
            break;
    }
    va_end (ap);

    zmq_msg_close (&msg);
}

291

292
//  Sets a zero linger period on a socket and closes it.
293 294
void
close_zero_linger (void *socket)
295 296 297
{
    int linger = 0;
    int rc = zmq_setsockopt (socket, ZMQ_LINGER, &linger, sizeof(linger));
298
    assert (rc == 0 || errno == ETERM);
299 300 301 302
    rc = zmq_close (socket);
    assert (rc == 0);
}

303 304
void
setup_test_environment (void)
305 306
{
#if defined _WIN32
307
#   if defined _MSC_VER
308
    _set_abort_behavior( 0, _WRITE_ABORT_MSG);
309 310
    _CrtSetReportMode( _CRT_ASSERT, _CRTDBG_MODE_FILE );
    _CrtSetReportFile( _CRT_ASSERT, _CRTDBG_FILE_STDERR );
311
#   endif
312 313 314 315
#else
#if defined ZMQ_HAVE_CYGWIN
    // abort test after 121 seconds
    alarm(121);
316
#else
317
#   if !defined ZMQ_DISABLE_TEST_TIMEOUT
318 319
    // abort test after 60 seconds
    alarm(60);
320
#   endif
321
#endif
322
#endif
323 324 325 326 327
#if defined __MVS__
    // z/OS UNIX System Services: Ignore SIGPIPE during test runs, as a
    // workaround for no SO_NOGSIGPIPE socket option.
    signal(SIGPIPE, SIG_IGN);
#endif
328 329
}

330
//  Provide portable millisecond sleep
331 332 333 334 335
//  http://www.cplusplus.com/forum/unices/60161/
//  http://en.cppreference.com/w/cpp/thread/sleep_for

void
msleep (int milliseconds)
336
{
337
#ifdef ZMQ_HAVE_WINDOWS
338
    Sleep (milliseconds);
339
#else
340
    usleep (static_cast <useconds_t> (milliseconds) * 1000);
341 342 343
#endif
}

344 345 346 347 348
// check if IPv6 is available (0/false if not, 1/true if it is)
// only way to reliably check is to actually open a socket and try to bind it
int
is_ipv6_available(void)
{
349 350 351
#if defined (ZMQ_HAVE_WINDOWS) && (_WIN32_WINNT < 0x0600)
    return 0;
#else
352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393
    int rc, ipv6 = 1;
    struct sockaddr_in6 test_addr;

    memset (&test_addr, 0, sizeof (test_addr));
    test_addr.sin6_family = AF_INET6;
    inet_pton (AF_INET6, "::1", &(test_addr.sin6_addr));

#ifdef ZMQ_HAVE_WINDOWS
    SOCKET fd = socket (AF_INET6, SOCK_STREAM, IPPROTO_IP);
    if (fd == INVALID_SOCKET)
        ipv6 = 0;
    else {
        setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const char *)&ipv6, sizeof(int));
        rc = setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (const char *)&ipv6, sizeof(int));
        if (rc == SOCKET_ERROR)
            ipv6 = 0;
        else {
            rc = bind (fd, (struct sockaddr *)&test_addr, sizeof (test_addr));
            if (rc == SOCKET_ERROR)
                ipv6 = 0;
        }
        closesocket (fd);
    }
#else
    int fd = socket (AF_INET6, SOCK_STREAM, IPPROTO_IP);
    if (fd == -1)
        ipv6 = 0;
    else {
        setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &ipv6, sizeof(int));
        rc = setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &ipv6, sizeof(int));
        if (rc != 0)
            ipv6 = 0;
        else {
            rc = bind (fd, (struct sockaddr *)&test_addr, sizeof (test_addr));
            if (rc != 0)
                ipv6 = 0;
        }
        close (fd);
    }
#endif

    return ipv6;
394
#endif // _WIN32_WINNT < 0x0600
395
}
396

Guido Goldstein's avatar
Guido Goldstein committed
397
#endif