1/*
2 Copyright (c) 2007-2019 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#include "testutil.hpp"
30#include "testutil_unity.hpp"
31
32#include <stdarg.h>
33#include <string.h>
34
35#if defined _WIN32
36#include "../src/windows.hpp"
37#if defined _MSC_VER
38#include <crtdbg.h>
39#pragma warning(disable : 4996)
40// iphlpapi is needed for if_nametoindex (not on Windows XP)
41#if _WIN32_WINNT > _WIN32_WINNT_WINXP
42#pragma comment(lib, "iphlpapi")
43#endif
44#endif
45#else
46#include <pthread.h>
47#include <unistd.h>
48#include <signal.h>
49#include <stdlib.h>
50#include <grp.h>
51#include <sys/wait.h>
52#include <sys/socket.h>
53#include <sys/types.h>
54#include <netinet/in.h>
55#include <arpa/inet.h>
56#include <net/if.h>
57#include <netdb.h>
58#if defined(ZMQ_HAVE_AIX)
59#include <sys/types.h>
60#include <sys/socketvar.h>
61#endif
62#endif
63
64const char *SEQ_END = (const char *) 1;
65
66const char bounce_content[] = "12345678ABCDEFGH12345678abcdefgh";
67
68static void send_bounce_msg (void *socket_)
69{
70 send_string_expect_success (socket_, bounce_content, ZMQ_SNDMORE);
71 send_string_expect_success (socket_, bounce_content, 0);
72}
73
74static void recv_bounce_msg (void *socket_)
75{
76 recv_string_expect_success (socket_, bounce_content, 0);
77 int rcvmore;
78 size_t sz = sizeof (rcvmore);
79 TEST_ASSERT_SUCCESS_ERRNO (
80 zmq_getsockopt (socket_, ZMQ_RCVMORE, &rcvmore, &sz));
81 TEST_ASSERT_TRUE (rcvmore);
82 recv_string_expect_success (socket_, bounce_content, 0);
83 TEST_ASSERT_SUCCESS_ERRNO (
84 zmq_getsockopt (socket_, ZMQ_RCVMORE, &rcvmore, &sz));
85 TEST_ASSERT_FALSE (rcvmore);
86}
87
88void bounce (void *server_, void *client_)
89{
90 // Send message from client to server
91 send_bounce_msg (client_);
92
93 // Receive message at server side and
94 // check that message is still the same
95 recv_bounce_msg (server_);
96
97 // Send two parts back to client
98 send_bounce_msg (server_);
99
100 // Receive the two parts at the client side
101 recv_bounce_msg (client_);
102}
103
104static void send_bounce_msg_may_fail (void *socket_)
105{
106 int timeout = 250;
107 TEST_ASSERT_SUCCESS_ERRNO (
108 zmq_setsockopt (socket_, ZMQ_SNDTIMEO, &timeout, sizeof (int)));
109 int rc = zmq_send (socket_, bounce_content, 32, ZMQ_SNDMORE);
110 TEST_ASSERT_TRUE ((rc == 32) || ((rc == -1) && (errno == EAGAIN)));
111 rc = zmq_send (socket_, bounce_content, 32, 0);
112 TEST_ASSERT_TRUE ((rc == 32) || ((rc == -1) && (errno == EAGAIN)));
113}
114
115static void recv_bounce_msg_fail (void *socket_)
116{
117 int timeout = 250;
118 char buffer[32];
119 TEST_ASSERT_SUCCESS_ERRNO (
120 zmq_setsockopt (socket_, ZMQ_RCVTIMEO, &timeout, sizeof (int)));
121 TEST_ASSERT_FAILURE_ERRNO (EAGAIN, zmq_recv (socket_, buffer, 32, 0));
122}
123
124void expect_bounce_fail (void *server_, void *client_)
125{
126 // Send message from client to server
127 send_bounce_msg_may_fail (client_);
128
129 // Receive message at server side (should not succeed)
130 recv_bounce_msg_fail (server_);
131
132 // Send message from server to client to test other direction
133 // If connection failed, send may block, without a timeout
134 send_bounce_msg_may_fail (server_);
135
136 // Receive message at client side (should not succeed)
137 recv_bounce_msg_fail (client_);
138}
139
140char *s_recv (void *socket_)
141{
142 char buffer[256];
143 int size = zmq_recv (socket_, buffer, 255, 0);
144 if (size == -1)
145 return NULL;
146 if (size > 255)
147 size = 255;
148 buffer[size] = 0;
149 return strdup (buffer);
150}
151
152void s_send_seq (void *socket_, ...)
153{
154 va_list ap;
155 va_start (ap, socket_);
156 const char *data = va_arg (ap, const char *);
157 while (true) {
158 const char *prev = data;
159 data = va_arg (ap, const char *);
160 bool end = data == SEQ_END;
161
162 if (!prev) {
163 TEST_ASSERT_SUCCESS_ERRNO (
164 zmq_send (socket_, 0, 0, end ? 0 : ZMQ_SNDMORE));
165 } else {
166 TEST_ASSERT_SUCCESS_ERRNO (zmq_send (
167 socket_, prev, strlen (prev) + 1, end ? 0 : ZMQ_SNDMORE));
168 }
169 if (end)
170 break;
171 }
172 va_end (ap);
173}
174
175void s_recv_seq (void *socket_, ...)
176{
177 zmq_msg_t msg;
178 zmq_msg_init (&msg);
179
180 int more;
181 size_t more_size = sizeof (more);
182
183 va_list ap;
184 va_start (ap, socket_);
185 const char *data = va_arg (ap, const char *);
186
187 while (true) {
188 TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_recv (&msg, socket_, 0));
189
190 if (!data)
191 TEST_ASSERT_EQUAL_INT (0, zmq_msg_size (&msg));
192 else
193 TEST_ASSERT_EQUAL_STRING (data, (const char *) zmq_msg_data (&msg));
194
195 data = va_arg (ap, const char *);
196 bool end = data == SEQ_END;
197
198 TEST_ASSERT_SUCCESS_ERRNO (
199 zmq_getsockopt (socket_, ZMQ_RCVMORE, &more, &more_size));
200
201 TEST_ASSERT_TRUE (!more == end);
202 if (end)
203 break;
204 }
205 va_end (ap);
206
207 zmq_msg_close (&msg);
208}
209
210void close_zero_linger (void *socket_)
211{
212 int linger = 0;
213 int rc = zmq_setsockopt (socket_, ZMQ_LINGER, &linger, sizeof (linger));
214 TEST_ASSERT_TRUE (rc == 0 || errno == ETERM);
215 TEST_ASSERT_SUCCESS_ERRNO (zmq_close (socket_));
216}
217
218void setup_test_environment ()
219{
220#if defined _WIN32
221#if defined _MSC_VER
222 _set_abort_behavior (0, _WRITE_ABORT_MSG);
223 _CrtSetReportMode (_CRT_ASSERT, _CRTDBG_MODE_FILE);
224 _CrtSetReportFile (_CRT_ASSERT, _CRTDBG_FILE_STDERR);
225#endif
226#else
227#if defined ZMQ_HAVE_CYGWIN
228 // abort test after 121 seconds
229 alarm (121);
230#else
231#if !defined ZMQ_DISABLE_TEST_TIMEOUT
232 // abort test after 60 seconds
233 alarm (60);
234#endif
235#endif
236#endif
237#if defined __MVS__
238 // z/OS UNIX System Services: Ignore SIGPIPE during test runs, as a
239 // workaround for no SO_NOGSIGPIPE socket option.
240 signal (SIGPIPE, SIG_IGN);
241#endif
242}
243
244void msleep (int milliseconds_)
245{
246#ifdef ZMQ_HAVE_WINDOWS
247 Sleep (milliseconds_);
248#else
249 usleep (static_cast<useconds_t> (milliseconds_) * 1000);
250#endif
251}
252
253int is_ipv6_available ()
254{
255#if defined(ZMQ_HAVE_WINDOWS) && (_WIN32_WINNT < 0x0600)
256 return 0;
257#else
258 int rc, ipv6 = 1;
259 struct sockaddr_in6 test_addr;
260
261 memset (&test_addr, 0, sizeof (test_addr));
262 test_addr.sin6_family = AF_INET6;
263 inet_pton (AF_INET6, "::1", &(test_addr.sin6_addr));
264
265 fd_t fd = socket (AF_INET6, SOCK_STREAM, IPPROTO_IP);
266 if (fd == retired_fd)
267 ipv6 = 0;
268 else {
269#ifdef ZMQ_HAVE_WINDOWS
270 setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, (const char *) &ipv6,
271 sizeof (int));
272 rc = setsockopt (fd, IPPROTO_IPV6, IPV6_V6ONLY, (const char *) &ipv6,
273 sizeof (int));
274 if (rc == SOCKET_ERROR)
275 ipv6 = 0;
276 else {
277 rc = bind (fd, (struct sockaddr *) &test_addr, sizeof (test_addr));
278 if (rc == SOCKET_ERROR)
279 ipv6 = 0;
280 }
281#else
282 setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, &ipv6, sizeof (int));
283 rc = setsockopt (fd, IPPROTO_IPV6, IPV6_V6ONLY, &ipv6, sizeof (int));
284 if (rc != 0)
285 ipv6 = 0;
286 else {
287 rc = bind (fd, reinterpret_cast<struct sockaddr *> (&test_addr),
288 sizeof (test_addr));
289 if (rc != 0)
290 ipv6 = 0;
291 }
292#endif
293 close (fd);
294 }
295
296 return ipv6;
297#endif // _WIN32_WINNT < 0x0600
298}
299
300int is_tipc_available ()
301{
302#ifndef ZMQ_HAVE_TIPC
303 return 0;
304#else
305 int tipc = 0;
306
307 void *ctx = zmq_init (1);
308 TEST_ASSERT_NOT_NULL (ctx);
309 void *rep = zmq_socket (ctx, ZMQ_REP);
310 TEST_ASSERT_NOT_NULL (rep);
311 tipc = zmq_bind (rep, "tipc://{5560,0,0}");
312
313 zmq_close (rep);
314 zmq_ctx_term (ctx);
315
316 return tipc == 0;
317#endif // ZMQ_HAVE_TIPC
318}
319
320int test_inet_pton (int af_, const char *src_, void *dst_)
321{
322#if defined(ZMQ_HAVE_WINDOWS) && (_WIN32_WINNT < 0x0600)
323 if (af_ == AF_INET) {
324 struct in_addr *ip4addr = (struct in_addr *) dst_;
325
326 ip4addr->s_addr = inet_addr (src_);
327
328 // INADDR_NONE is -1 which is also a valid representation for IP
329 // 255.255.255.255
330 if (ip4addr->s_addr == INADDR_NONE
331 && strcmp (src_, "255.255.255.255") != 0) {
332 return 0;
333 }
334
335 // Success
336 return 1;
337 } else {
338 // Not supported.
339 return 0;
340 }
341#else
342 return inet_pton (af_, src_, dst_);
343#endif
344}
345
346sockaddr_in bind_bsd_socket (int socket_)
347{
348 struct sockaddr_in saddr;
349 memset (&saddr, 0, sizeof (saddr));
350 saddr.sin_family = AF_INET;
351 saddr.sin_addr.s_addr = INADDR_ANY;
352#if !defined(_WIN32_WINNT) || (_WIN32_WINNT >= 0x0600)
353 saddr.sin_port = 0;
354#else
355 saddr.sin_port = htons (PORT_6);
356#endif
357
358 TEST_ASSERT_SUCCESS_RAW_ERRNO (
359 bind (socket_, (struct sockaddr *) &saddr, sizeof (saddr)));
360
361#if !defined(_WIN32_WINNT) || (_WIN32_WINNT >= 0x0600)
362 socklen_t saddr_len = sizeof (saddr);
363 TEST_ASSERT_SUCCESS_RAW_ERRNO (
364 getsockname (socket_, (struct sockaddr *) &saddr, &saddr_len));
365#endif
366
367 return saddr;
368}
369
370bool streq (const char *lhs_, const char *rhs_)
371{
372 return strcmp (lhs_, rhs_) == 0;
373}
374
375bool strneq (const char *lhs_, const char *rhs_)
376{
377 return strcmp (lhs_, rhs_) != 0;
378}
379