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 <string.h>
34
35SETUP_TEARDOWN_TESTCONTEXT
36
37void test_sockopt_router_notify ()
38{
39 void *router = test_context_socket (ZMQ_ROUTER);
40 int opt_notify;
41
42 int opt_notify_read;
43 size_t opt_notify_read_size = sizeof (opt_notify_read);
44
45
46 // default value is off when socket is constructed
47 TEST_ASSERT_SUCCESS_ERRNO (zmq_getsockopt (
48 router, ZMQ_ROUTER_NOTIFY, &opt_notify_read, &opt_notify_read_size));
49
50 TEST_ASSERT_EQUAL (0, opt_notify_read);
51
52
53 // valid value - Connect
54 opt_notify = ZMQ_NOTIFY_CONNECT;
55 TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (
56 router, ZMQ_ROUTER_NOTIFY, &opt_notify, sizeof (opt_notify)));
57
58 TEST_ASSERT_SUCCESS_ERRNO (zmq_getsockopt (
59 router, ZMQ_ROUTER_NOTIFY, &opt_notify_read, &opt_notify_read_size));
60
61 TEST_ASSERT_EQUAL (opt_notify, opt_notify_read);
62
63
64 // valid value - Disconnect
65 opt_notify = ZMQ_NOTIFY_DISCONNECT;
66 TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (
67 router, ZMQ_ROUTER_NOTIFY, &opt_notify, sizeof (opt_notify)));
68
69 TEST_ASSERT_SUCCESS_ERRNO (zmq_getsockopt (
70 router, ZMQ_ROUTER_NOTIFY, &opt_notify_read, &opt_notify_read_size));
71
72 TEST_ASSERT_EQUAL (opt_notify, opt_notify_read);
73
74
75 // valid value - Off
76 opt_notify = 0;
77 TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (
78 router, ZMQ_ROUTER_NOTIFY, &opt_notify, sizeof (opt_notify)));
79
80 TEST_ASSERT_SUCCESS_ERRNO (zmq_getsockopt (
81 router, ZMQ_ROUTER_NOTIFY, &opt_notify_read, &opt_notify_read_size));
82
83 TEST_ASSERT_EQUAL (opt_notify, opt_notify_read);
84
85
86 // valid value - Both
87 opt_notify = ZMQ_NOTIFY_CONNECT | ZMQ_NOTIFY_DISCONNECT;
88 TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (
89 router, ZMQ_ROUTER_NOTIFY, &opt_notify, sizeof (opt_notify)));
90
91 TEST_ASSERT_SUCCESS_ERRNO (zmq_getsockopt (
92 router, ZMQ_ROUTER_NOTIFY, &opt_notify_read, &opt_notify_read_size));
93
94 TEST_ASSERT_EQUAL (opt_notify, opt_notify_read);
95
96
97 // value boundary
98 opt_notify = -1;
99 TEST_ASSERT_FAILURE_ERRNO (
100 EINVAL, zmq_setsockopt (router, ZMQ_ROUTER_NOTIFY, &opt_notify,
101 sizeof (opt_notify)));
102
103 opt_notify = (ZMQ_NOTIFY_CONNECT | ZMQ_NOTIFY_DISCONNECT) + 1;
104 TEST_ASSERT_FAILURE_ERRNO (
105 EINVAL, zmq_setsockopt (router, ZMQ_ROUTER_NOTIFY, &opt_notify,
106 sizeof (opt_notify)));
107
108 // failures don't update the value
109 TEST_ASSERT_SUCCESS_ERRNO (zmq_getsockopt (
110 router, ZMQ_ROUTER_NOTIFY, &opt_notify_read, &opt_notify_read_size));
111
112 TEST_ASSERT_EQUAL (ZMQ_NOTIFY_CONNECT | ZMQ_NOTIFY_DISCONNECT,
113 opt_notify_read);
114
115
116 test_context_socket_close (router);
117
118
119 // check a non-router socket type
120 void *dealer = test_context_socket (ZMQ_DEALER);
121
122 // setsockopt fails for non-router sockets
123 opt_notify = ZMQ_NOTIFY_CONNECT;
124 TEST_ASSERT_FAILURE_ERRNO (
125 EINVAL, zmq_setsockopt (dealer, ZMQ_ROUTER_NOTIFY, &opt_notify,
126 sizeof (opt_notify)));
127
128 // getsockopts returns off for any non-router socket
129 TEST_ASSERT_SUCCESS_ERRNO (zmq_getsockopt (
130 dealer, ZMQ_ROUTER_NOTIFY, &opt_notify_read, &opt_notify_read_size));
131
132 TEST_ASSERT_EQUAL (0, opt_notify_read);
133
134
135 test_context_socket_close (dealer);
136}
137
138
139void test_router_notify_helper (int opt_notify_)
140{
141 void *router = test_context_socket (ZMQ_ROUTER);
142 int opt_more;
143 size_t opt_more_length = sizeof (opt_more);
144 int opt_events;
145 size_t opt_events_length = sizeof (opt_events);
146 char connect_address[MAX_SOCKET_STRING];
147
148
149 // valid values
150 TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (
151 router, ZMQ_ROUTER_NOTIFY, &opt_notify_, sizeof (opt_notify_)));
152
153 bind_loopback_ipv4 (router, connect_address, sizeof connect_address);
154
155 void *dealer = test_context_socket (ZMQ_DEALER);
156 const char *dealer_routing_id = "X";
157
158 TEST_ASSERT_SUCCESS_ERRNO (
159 zmq_setsockopt (dealer, ZMQ_ROUTING_ID, dealer_routing_id, 1));
160
161 // dealer connects
162 TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (dealer, connect_address));
163
164 // connection notification msg
165 if (opt_notify_ & ZMQ_NOTIFY_CONNECT) {
166 // routing-id only message of the connect
167 recv_string_expect_success (router, dealer_routing_id,
168 0); // 1st part: routing-id
169 recv_string_expect_success (router, "", 0); // 2nd part: empty
170 TEST_ASSERT_SUCCESS_ERRNO (
171 zmq_getsockopt (router, ZMQ_RCVMORE, &opt_more, &opt_more_length));
172 TEST_ASSERT_EQUAL (0, opt_more);
173 }
174
175 // test message from the dealer
176 send_string_expect_success (dealer, "Hello", 0);
177 recv_string_expect_success (router, dealer_routing_id, 0);
178 recv_string_expect_success (router, "Hello", 0);
179 TEST_ASSERT_SUCCESS_ERRNO (
180 zmq_getsockopt (router, ZMQ_RCVMORE, &opt_more, &opt_more_length));
181 TEST_ASSERT_EQUAL (0, opt_more);
182
183 // dealer disconnects
184 TEST_ASSERT_SUCCESS_ERRNO (zmq_disconnect (dealer, connect_address));
185
186 // need one more process_commands() (???)
187 msleep (SETTLE_TIME);
188 zmq_getsockopt (dealer, ZMQ_EVENTS, &opt_events, &opt_events_length);
189
190 // connection notification msg
191 if (opt_notify_ & ZMQ_NOTIFY_DISCONNECT) {
192 // routing-id only message of the connect
193 recv_string_expect_success (router, dealer_routing_id,
194 0); // 1st part: routing-id
195 recv_string_expect_success (router, "", 0); // 2nd part: empty
196 TEST_ASSERT_SUCCESS_ERRNO (
197 zmq_getsockopt (router, ZMQ_RCVMORE, &opt_more, &opt_more_length));
198 TEST_ASSERT_EQUAL (0, opt_more);
199 }
200
201 test_context_socket_close (dealer);
202 test_context_socket_close (router);
203}
204
205
206void test_router_notify_connect ()
207{
208 test_router_notify_helper (ZMQ_NOTIFY_CONNECT);
209}
210
211
212void test_router_notify_disconnect ()
213{
214 test_router_notify_helper (ZMQ_NOTIFY_DISCONNECT);
215}
216
217
218void test_router_notify_both ()
219{
220 test_router_notify_helper (ZMQ_NOTIFY_CONNECT | ZMQ_NOTIFY_DISCONNECT);
221}
222
223
224void test_handshake_fail ()
225{
226 // setup router socket
227 void *router = test_context_socket (ZMQ_ROUTER);
228 int opt_timeout = 200;
229 int opt_notify = ZMQ_NOTIFY_CONNECT | ZMQ_NOTIFY_DISCONNECT;
230 char connect_address[MAX_SOCKET_STRING];
231
232 // valid values
233 TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (
234 router, ZMQ_ROUTER_NOTIFY, &opt_notify, sizeof (opt_notify)));
235
236 TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (
237 router, ZMQ_RCVTIMEO, &opt_timeout, sizeof (opt_timeout)));
238
239 bind_loopback_ipv4 (router, connect_address, sizeof connect_address);
240
241 // send something on raw tcp
242 void *stream = test_context_socket (ZMQ_STREAM);
243 TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (stream, connect_address));
244
245 send_string_expect_success (stream, "not-a-handshake", 0);
246
247 TEST_ASSERT_SUCCESS_ERRNO (zmq_disconnect (stream, connect_address));
248 test_context_socket_close (stream);
249
250 // no notification delivered
251 char buffer[255];
252 TEST_ASSERT_FAILURE_ERRNO (EAGAIN,
253 zmq_recv (router, buffer, sizeof (buffer), 0));
254
255 test_context_socket_close (router);
256}
257
258
259void test_error_during_multipart ()
260{
261 /*
262 * If the disconnect occurs in the middle of the multipart
263 * message, the socket should not add the notification at the
264 * end of the incomplete message. It must discard the incomplete
265 * message, and delivert the notification as a new message.
266 */
267
268 char connect_address[MAX_SOCKET_STRING];
269 char long_str[128] = {0};
270 memset (long_str, '*', sizeof (long_str) - 1);
271
272 // setup router
273 void *router = test_context_socket (ZMQ_ROUTER);
274
275 int opt_notify = ZMQ_NOTIFY_DISCONNECT;
276 TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (
277 router, ZMQ_ROUTER_NOTIFY, &opt_notify, sizeof (opt_notify)));
278
279 int64_t opt_maxmsgsize = 64; // the handshake fails if this is too small
280 TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (
281 router, ZMQ_MAXMSGSIZE, &opt_maxmsgsize, sizeof (opt_maxmsgsize)));
282
283 bind_loopback_ipv4 (router, connect_address, sizeof connect_address);
284
285 // setup dealer
286 void *dealer = test_context_socket (ZMQ_DEALER);
287 const char *dealer_routing_id = "X";
288
289 TEST_ASSERT_SUCCESS_ERRNO (
290 zmq_setsockopt (dealer, ZMQ_ROUTING_ID, dealer_routing_id, 1));
291
292 TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (dealer, connect_address));
293
294
295 // send multipart message, the 2nd part causes a disconnect.
296 send_string_expect_success (dealer, "Hello2", ZMQ_SNDMORE);
297 send_string_expect_success (dealer, long_str, 0);
298
299 // disconnect notification
300 recv_string_expect_success (router, dealer_routing_id, 0);
301 recv_string_expect_success (router, "", 0);
302
303
304 test_context_socket_close (dealer);
305 test_context_socket_close (router);
306}
307
308
309int main (void)
310{
311 setup_test_environment ();
312
313 UNITY_BEGIN ();
314 RUN_TEST (test_sockopt_router_notify);
315 RUN_TEST (test_router_notify_connect);
316 RUN_TEST (test_router_notify_disconnect);
317 RUN_TEST (test_router_notify_both);
318 RUN_TEST (test_handshake_fail);
319 RUN_TEST (test_error_during_multipart);
320
321 return UNITY_END ();
322}
323