1/*
2 Copyright (c) 2007-2017 Contributors as noted in the AUTHORS file
3
4 This file is part of libzmq, the ZeroMQ core engine in C++.
5
6 libzmq is free software; you can redistribute it and/or modify it under
7 the terms of the GNU Lesser General Public License (LGPL) as published
8 by the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
10
11 As a special exception, the Contributors give you permission to link
12 this library with independent modules to produce an executable,
13 regardless of the license terms of these independent modules, and to
14 copy and distribute the resulting executable under terms of your choice,
15 provided that you also meet, for each linked independent module, the
16 terms and conditions of the license of that module. An independent
17 module is a module which is not derived from or based on this library.
18 If you modify this library, you must extend this exception to your
19 version of the library.
20
21 libzmq is distributed in the hope that it will be useful, but WITHOUT
22 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
23 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
24 License for more details.
25
26 You should have received a copy of the GNU Lesser General Public License
27 along with this program. If not, see <http://www.gnu.org/licenses/>.
28*/
29
30#include "testutil.hpp"
31#include "testutil_unity.hpp"
32
33#include <stdlib.h>
34#include <string.h>
35
36SETUP_TEARDOWN_TESTCONTEXT
37
38// Read one event off the monitor socket; return value and address
39// by reference, if not null, and event number by value. Returns -1
40// in case of error.
41
42static int get_monitor_event (void *monitor_, int *value_, char **address_)
43{
44 // First frame in message contains event number and value
45 zmq_msg_t msg;
46 zmq_msg_init (&msg);
47 if (zmq_msg_recv (&msg, monitor_, 0) == -1)
48 return -1; // Interruped, presumably
49 TEST_ASSERT_TRUE (zmq_msg_more (&msg));
50
51 uint8_t *data = static_cast<uint8_t *> (zmq_msg_data (&msg));
52 uint16_t event = *reinterpret_cast<uint16_t *> (data);
53 if (value_)
54 *value_ = *reinterpret_cast<uint32_t *> (data + 2);
55
56 // Second frame in message contains event address
57 zmq_msg_init (&msg);
58 if (zmq_msg_recv (&msg, monitor_, 0) == -1)
59 return -1; // Interruped, presumably
60 TEST_ASSERT_TRUE (!zmq_msg_more (&msg));
61
62 if (address_) {
63 uint8_t *data = static_cast<uint8_t *> (zmq_msg_data (&msg));
64 size_t size = zmq_msg_size (&msg);
65 *address_ = static_cast<char *> (malloc (size + 1));
66 memcpy (*address_, data, size);
67 *address_[size] = 0;
68 }
69 return event;
70}
71
72static void test_stream_handshake_timeout_accept ()
73{
74 char my_endpoint[MAX_SOCKET_STRING];
75
76 // We use this socket in raw mode, to make a connection and send nothing
77 void *stream = test_context_socket (ZMQ_STREAM);
78
79 int zero = 0;
80 TEST_ASSERT_SUCCESS_ERRNO (
81 zmq_setsockopt (stream, ZMQ_LINGER, &zero, sizeof (zero)));
82
83 // We'll be using this socket to test TCP stream handshake timeout
84 void *dealer = test_context_socket (ZMQ_DEALER);
85 TEST_ASSERT_SUCCESS_ERRNO (
86 zmq_setsockopt (dealer, ZMQ_LINGER, &zero, sizeof (zero)));
87 int val, tenth = 100;
88 size_t vsize = sizeof (val);
89
90 // check for the expected default handshake timeout value - 30 sec
91 TEST_ASSERT_SUCCESS_ERRNO (
92 zmq_getsockopt (dealer, ZMQ_HANDSHAKE_IVL, &val, &vsize));
93 TEST_ASSERT_EQUAL (sizeof (val), vsize);
94 TEST_ASSERT_EQUAL_INT (30000, val);
95 // make handshake timeout faster - 1/10 sec
96 TEST_ASSERT_SUCCESS_ERRNO (
97 zmq_setsockopt (dealer, ZMQ_HANDSHAKE_IVL, &tenth, sizeof (tenth)));
98 vsize = sizeof (val);
99 // make sure zmq_setsockopt changed the value
100 TEST_ASSERT_SUCCESS_ERRNO (
101 zmq_getsockopt (dealer, ZMQ_HANDSHAKE_IVL, &val, &vsize));
102 TEST_ASSERT_EQUAL (sizeof (val), vsize);
103 TEST_ASSERT_EQUAL_INT (tenth, val);
104
105 // Create and connect a socket for collecting monitor events on dealer
106 void *dealer_mon = test_context_socket (ZMQ_PAIR);
107
108 TEST_ASSERT_SUCCESS_ERRNO (zmq_socket_monitor (
109 dealer, "inproc://monitor-dealer",
110 ZMQ_EVENT_CONNECTED | ZMQ_EVENT_DISCONNECTED | ZMQ_EVENT_ACCEPTED));
111
112 // Connect to the inproc endpoint so we'll get events
113 TEST_ASSERT_SUCCESS_ERRNO (
114 zmq_connect (dealer_mon, "inproc://monitor-dealer"));
115
116 // bind dealer socket to accept connection from non-sending stream socket
117 bind_loopback_ipv4 (dealer, my_endpoint, sizeof my_endpoint);
118
119 TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (stream, my_endpoint));
120
121 // we should get ZMQ_EVENT_ACCEPTED and then ZMQ_EVENT_DISCONNECTED
122 int event = get_monitor_event (dealer_mon, NULL, NULL);
123 TEST_ASSERT_EQUAL_INT (ZMQ_EVENT_ACCEPTED, event);
124 event = get_monitor_event (dealer_mon, NULL, NULL);
125 TEST_ASSERT_EQUAL_INT (ZMQ_EVENT_DISCONNECTED, event);
126
127 test_context_socket_close (dealer);
128 test_context_socket_close (dealer_mon);
129 test_context_socket_close (stream);
130}
131
132static void test_stream_handshake_timeout_connect ()
133{
134 char my_endpoint[MAX_SOCKET_STRING];
135
136 // We use this socket in raw mode, to accept a connection and send nothing
137 void *stream = test_context_socket (ZMQ_STREAM);
138
139 int zero = 0;
140 TEST_ASSERT_SUCCESS_ERRNO (
141 zmq_setsockopt (stream, ZMQ_LINGER, &zero, sizeof (zero)));
142
143 bind_loopback_ipv4 (stream, my_endpoint, sizeof my_endpoint);
144
145 // We'll be using this socket to test TCP stream handshake timeout
146 void *dealer = test_context_socket (ZMQ_DEALER);
147 TEST_ASSERT_SUCCESS_ERRNO (
148 zmq_setsockopt (dealer, ZMQ_LINGER, &zero, sizeof (zero)));
149 int val, tenth = 100;
150 size_t vsize = sizeof (val);
151
152 // check for the expected default handshake timeout value - 30 sec
153 TEST_ASSERT_SUCCESS_ERRNO (
154 zmq_getsockopt (dealer, ZMQ_HANDSHAKE_IVL, &val, &vsize));
155 TEST_ASSERT_EQUAL (sizeof (val), vsize);
156 TEST_ASSERT_EQUAL_INT (30000, val);
157 // make handshake timeout faster - 1/10 sec
158 TEST_ASSERT_SUCCESS_ERRNO (
159 zmq_setsockopt (dealer, ZMQ_HANDSHAKE_IVL, &tenth, sizeof (tenth)));
160 vsize = sizeof (val);
161 // make sure zmq_setsockopt changed the value
162 TEST_ASSERT_SUCCESS_ERRNO (
163 zmq_getsockopt (dealer, ZMQ_HANDSHAKE_IVL, &val, &vsize));
164 TEST_ASSERT_EQUAL (sizeof (val), vsize);
165 TEST_ASSERT_EQUAL_INT (tenth, val);
166
167 // Create and connect a socket for collecting monitor events on dealer
168 void *dealer_mon = test_context_socket (ZMQ_PAIR);
169
170 TEST_ASSERT_SUCCESS_ERRNO (zmq_socket_monitor (
171 dealer, "inproc://monitor-dealer",
172 ZMQ_EVENT_CONNECTED | ZMQ_EVENT_DISCONNECTED | ZMQ_EVENT_ACCEPTED));
173
174 // Connect to the inproc endpoint so we'll get events
175 TEST_ASSERT_SUCCESS_ERRNO (
176 zmq_connect (dealer_mon, "inproc://monitor-dealer"));
177
178 // connect dealer socket to non-sending stream socket
179 TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (dealer, my_endpoint));
180
181 // we should get ZMQ_EVENT_CONNECTED and then ZMQ_EVENT_DISCONNECTED
182 int event = get_monitor_event (dealer_mon, NULL, NULL);
183 TEST_ASSERT_EQUAL_INT (ZMQ_EVENT_CONNECTED, event);
184 event = get_monitor_event (dealer_mon, NULL, NULL);
185 TEST_ASSERT_EQUAL_INT (ZMQ_EVENT_DISCONNECTED, event);
186
187 test_context_socket_close (dealer);
188 test_context_socket_close (dealer_mon);
189 test_context_socket_close (stream);
190}
191
192int main ()
193{
194 setup_test_environment ();
195
196 UNITY_BEGIN ();
197 RUN_TEST (test_stream_handshake_timeout_accept);
198 RUN_TEST (test_stream_handshake_timeout_connect);
199 return UNITY_END ();
200}
201