testutil.hpp 11.3 KB
Newer Older
Guido Goldstein's avatar
Guido Goldstein committed
1
/*
2
    Copyright (c) 2007-2016 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
#undef NDEBUG
47
#include <time.h>
48
#include <assert.h>
49
#include <stdarg.h>
50
#include <string>
51
#include <string.h>
52

53
#if defined _WIN32
54
#   include "../src/windows.hpp"
55 56 57
#   if defined _MSC_VER
#       include <crtdbg.h>
#       pragma warning(disable:4996)
58 59 60 61
// iphlpapi is needed for if_nametoindex (not on Windows XP)
#       if !defined ZMQ_HAVE_WINDOWS_TARGET_XP
#           pragma comment(lib,"iphlpapi")
#       endif
62
#   endif
63
#else
64
#   include <pthread.h>
65 66 67 68
#   include <unistd.h>
#   include <signal.h>
#   include <stdlib.h>
#   include <sys/wait.h>
69 70 71
#   include <sys/socket.h>
#   include <netinet/in.h>
#   include <arpa/inet.h>
72 73 74 75
#   if defined (ZMQ_HAVE_AIX)
#      include <sys/types.h>
#      include <sys/socketvar.h>
#   endif
76 77
#endif

78 79
//  Bounce a message from client to server and back
//  For REQ/REP or DEALER/DEALER pairs only
80
void
81
bounce (void *server, void *client)
Guido Goldstein's avatar
Guido Goldstein committed
82
{
83 84
    const char *content = "12345678ABCDEFGH12345678abcdefgh";

85 86
    //  Send message from client to server
    int rc = zmq_send (client, content, 32, ZMQ_SNDMORE);
87
    assert (rc == 32);
88
    rc = zmq_send (client, content, 32, 0);
89
    assert (rc == 32);
90

91 92 93
    //  Receive message at server side
    char buffer [32];
    rc = zmq_recv (server, buffer, 32, 0);
94
    assert (rc == 32);
95 96
    //  Check that message is still the same
    assert (memcmp (buffer, content, 32) == 0);
97 98
    int rcvmore;
    size_t sz = sizeof (rcvmore);
99
    rc = zmq_getsockopt (server, ZMQ_RCVMORE, &rcvmore, &sz);
100 101
    assert (rc == 0);
    assert (rcvmore);
102
    rc = zmq_recv (server, buffer, 32, 0);
103
    assert (rc == 32);
104 105
    //  Check that message is still the same
    assert (memcmp (buffer, content, 32) == 0);
106
    rc = zmq_getsockopt (server, ZMQ_RCVMORE, &rcvmore, &sz);
107 108
    assert (rc == 0);
    assert (!rcvmore);
109

110 111
    //  Send two parts back to client
    rc = zmq_send (server, buffer, 32, ZMQ_SNDMORE);
112
    assert (rc == 32);
113
    rc = zmq_send (server, buffer, 32, 0);
114
    assert (rc == 32);
115

116 117
    //  Receive the two parts at the client side
    rc = zmq_recv (client, buffer, 32, 0);
118
    assert (rc == 32);
119 120
    //  Check that message is still the same
    assert (memcmp (buffer, content, 32) == 0);
121
    rc = zmq_getsockopt (client, ZMQ_RCVMORE, &rcvmore, &sz);
122 123
    assert (rc == 0);
    assert (rcvmore);
124
    rc = zmq_recv (client, buffer, 32, 0);
125
    assert (rc == 32);
126 127
    //  Check that message is still the same
    assert (memcmp (buffer, content, 32) == 0);
128
    rc = zmq_getsockopt (client, ZMQ_RCVMORE, &rcvmore, &sz);
129 130
    assert (rc == 0);
    assert (!rcvmore);
Guido Goldstein's avatar
Guido Goldstein committed
131 132
}

MinRK's avatar
MinRK committed
133 134 135 136 137 138 139
//  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];
140
    int timeout = 250;
MinRK's avatar
MinRK committed
141 142

    //  Send message from client to server
143 144 145 146
    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
147
    rc = zmq_send (client, content, 32, 0);
148
    assert ((rc == 32) || ((rc == -1) && (errno == EAGAIN)));
MinRK's avatar
MinRK committed
149 150

    //  Receive message at server side (should not succeed)
151
    rc = zmq_setsockopt (server, ZMQ_RCVTIMEO, &timeout, sizeof (int));
MinRK's avatar
MinRK committed
152 153 154
    assert (rc == 0);
    rc = zmq_recv (server, buffer, 32, 0);
    assert (rc == -1);
155
    assert (zmq_errno () == EAGAIN);
MinRK's avatar
MinRK committed
156

157
    //  Send message from server to client to test other direction
158
    //  If connection failed, send may block, without a timeout
159 160
    rc = zmq_setsockopt (server, ZMQ_SNDTIMEO, &timeout, sizeof (int));
    assert (rc == 0);
MinRK's avatar
MinRK committed
161
    rc = zmq_send (server, content, 32, ZMQ_SNDMORE);
162
    assert (rc == 32 || (rc == -1 && zmq_errno () == EAGAIN));
MinRK's avatar
MinRK committed
163
    rc = zmq_send (server, content, 32, 0);
164
    assert (rc == 32 || (rc == -1 && zmq_errno () == EAGAIN));
MinRK's avatar
MinRK committed
165

166 167 168
    //  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
169 170
    rc = zmq_recv (client, buffer, 32, 0);
    assert (rc == -1);
171
    assert (zmq_errno () == EAGAIN);
MinRK's avatar
MinRK committed
172 173
}

174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205
//  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)))

206
const char *SEQ_END = (const char *) 1;
207 208 209 210

//  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);
211 212 213

void
s_send_seq (void *socket, ...)
214 215 216 217 218 219 220 221 222 223
{
    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;

224
        if (!prev) {
225 226 227
            int rc = zmq_send (socket, 0, 0, end ? 0 : ZMQ_SNDMORE);
            assert (rc != -1);
        }
228
        else {
229 230 231 232 233 234 235 236 237 238 239 240 241
            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);
242 243 244

void
s_recv_seq (void *socket, ...)
245 246 247 248 249 250 251 252 253 254
{
    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 *);
255

256
    while (true) {
257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279
        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);
}

280

281
//  Sets a zero linger period on a socket and closes it.
282 283
void
close_zero_linger (void *socket)
284 285 286
{
    int linger = 0;
    int rc = zmq_setsockopt (socket, ZMQ_LINGER, &linger, sizeof(linger));
287
    assert (rc == 0 || errno == ETERM);
288 289 290 291
    rc = zmq_close (socket);
    assert (rc == 0);
}

292 293
void
setup_test_environment (void)
294 295
{
#if defined _WIN32
296
#   if defined _MSC_VER
297
    _set_abort_behavior( 0, _WRITE_ABORT_MSG);
298 299
    _CrtSetReportMode( _CRT_ASSERT, _CRTDBG_MODE_FILE );
    _CrtSetReportFile( _CRT_ASSERT, _CRTDBG_FILE_STDERR );
300
#   endif
301 302 303 304
#else
#if defined ZMQ_HAVE_CYGWIN
    // abort test after 121 seconds
    alarm(121);
305
#else
306
#   if !defined ZMQ_DISABLE_TEST_TIMEOUT
307 308
    // abort test after 60 seconds
    alarm(60);
309
#   endif
310
#endif
311
#endif
312 313 314 315 316
#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
317 318
}

319
//  Provide portable millisecond sleep
320 321 322 323 324
//  http://www.cplusplus.com/forum/unices/60161/
//  http://en.cppreference.com/w/cpp/thread/sleep_for

void
msleep (int milliseconds)
325
{
326
#ifdef ZMQ_HAVE_WINDOWS
327
    Sleep (milliseconds);
328
#else
329
    usleep (static_cast <useconds_t> (milliseconds) * 1000);
330 331 332
#endif
}

333 334 335 336 337
// 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)
{
338 339 340
#if defined (ZMQ_HAVE_WINDOWS) && (_WIN32_WINNT < 0x0600)
    return 0;
#else
341 342 343 344 345 346 347 348 349 350 351 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
    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;
383
#endif // _WIN32_WINNT < 0x0600
384
}
385

Guido Goldstein's avatar
Guido Goldstein committed
386
#endif