/src/libzmq/tests/testutil.cpp
Line | Count | Source |
1 | | /* SPDX-License-Identifier: MPL-2.0 */ |
2 | | #include "testutil.hpp" |
3 | | #include "testutil_unity.hpp" |
4 | | |
5 | | #include <stdarg.h> |
6 | | #include <string.h> |
7 | | |
8 | | #if defined _WIN32 |
9 | | #include "../src/windows.hpp" |
10 | | #if defined ZMQ_HAVE_WINDOWS |
11 | | #if defined ZMQ_HAVE_IPC |
12 | | #include <direct.h> |
13 | | #include <afunix.h> |
14 | | #endif |
15 | | #include <crtdbg.h> |
16 | | #pragma warning(disable : 4996) |
17 | | // iphlpapi is needed for if_nametoindex (not on Windows XP) |
18 | | #if _WIN32_WINNT > _WIN32_WINNT_WINXP |
19 | | #pragma comment(lib, "iphlpapi") |
20 | | #endif |
21 | | #endif |
22 | | #else |
23 | | #include <pthread.h> |
24 | | #include <unistd.h> |
25 | | #include <signal.h> |
26 | | #include <stdlib.h> |
27 | | #include <grp.h> |
28 | | #include <sys/wait.h> |
29 | | #include <sys/socket.h> |
30 | | #include <sys/types.h> |
31 | | #include <netinet/in.h> |
32 | | #include <arpa/inet.h> |
33 | | #include <net/if.h> |
34 | | #include <netdb.h> |
35 | | #include <sys/un.h> |
36 | | #include <dirent.h> |
37 | | #if defined(ZMQ_HAVE_AIX) |
38 | | #include <sys/types.h> |
39 | | #include <sys/socketvar.h> |
40 | | #endif |
41 | | #endif |
42 | | |
43 | | #if defined(ZMQ_HAVE_VSOCK) |
44 | | #include "linux/vm_sockets.h" |
45 | | #include <sys/ioctl.h> |
46 | | #include <fcntl.h> |
47 | | #endif |
48 | | |
49 | | #ifndef PATH_MAX |
50 | | #define PATH_MAX 1024 |
51 | | #endif |
52 | | |
53 | | const char *SEQ_END = (const char *) 1; |
54 | | |
55 | | const char bounce_content[] = "12345678ABCDEFGH12345678abcdefgh"; |
56 | | |
57 | | static void send_bounce_msg (void *socket_) |
58 | 0 | { |
59 | 0 | send_string_expect_success (socket_, bounce_content, ZMQ_SNDMORE); |
60 | 0 | send_string_expect_success (socket_, bounce_content, 0); |
61 | 0 | } |
62 | | |
63 | | static void recv_bounce_msg (void *socket_) |
64 | 0 | { |
65 | 0 | recv_string_expect_success (socket_, bounce_content, 0); |
66 | 0 | int rcvmore; |
67 | 0 | size_t sz = sizeof (rcvmore); |
68 | 0 | TEST_ASSERT_SUCCESS_ERRNO ( |
69 | 0 | zmq_getsockopt (socket_, ZMQ_RCVMORE, &rcvmore, &sz)); |
70 | 0 | TEST_ASSERT_TRUE (rcvmore); |
71 | 0 | recv_string_expect_success (socket_, bounce_content, 0); |
72 | 0 | TEST_ASSERT_SUCCESS_ERRNO ( |
73 | 0 | zmq_getsockopt (socket_, ZMQ_RCVMORE, &rcvmore, &sz)); |
74 | 0 | TEST_ASSERT_FALSE (rcvmore); |
75 | 0 | } |
76 | | |
77 | | void bounce (void *server_, void *client_) |
78 | 0 | { |
79 | | // Send message from client to server |
80 | 0 | send_bounce_msg (client_); |
81 | | |
82 | | // Receive message at server side and |
83 | | // check that message is still the same |
84 | 0 | recv_bounce_msg (server_); |
85 | | |
86 | | // Send two parts back to client |
87 | 0 | send_bounce_msg (server_); |
88 | | |
89 | | // Receive the two parts at the client side |
90 | 0 | recv_bounce_msg (client_); |
91 | 0 | } |
92 | | |
93 | | static void send_bounce_msg_may_fail (void *socket_) |
94 | 0 | { |
95 | 0 | int timeout = 250; |
96 | 0 | TEST_ASSERT_SUCCESS_ERRNO ( |
97 | 0 | zmq_setsockopt (socket_, ZMQ_SNDTIMEO, &timeout, sizeof (int))); |
98 | 0 | int rc = zmq_send (socket_, bounce_content, 32, ZMQ_SNDMORE); |
99 | 0 | TEST_ASSERT_TRUE ((rc == 32) || ((rc == -1) && (errno == EAGAIN))); |
100 | 0 | rc = zmq_send (socket_, bounce_content, 32, 0); |
101 | 0 | TEST_ASSERT_TRUE ((rc == 32) || ((rc == -1) && (errno == EAGAIN))); |
102 | 0 | } |
103 | | |
104 | | static void recv_bounce_msg_fail (void *socket_) |
105 | 0 | { |
106 | 0 | int timeout = 250; |
107 | 0 | char buffer[32]; |
108 | 0 | TEST_ASSERT_SUCCESS_ERRNO ( |
109 | 0 | zmq_setsockopt (socket_, ZMQ_RCVTIMEO, &timeout, sizeof (int))); |
110 | 0 | TEST_ASSERT_FAILURE_ERRNO (EAGAIN, zmq_recv (socket_, buffer, 32, 0)); |
111 | 0 | } |
112 | | |
113 | | void expect_bounce_fail (void *server_, void *client_) |
114 | 0 | { |
115 | | // Send message from client to server |
116 | 0 | send_bounce_msg_may_fail (client_); |
117 | | |
118 | | // Receive message at server side (should not succeed) |
119 | 0 | recv_bounce_msg_fail (server_); |
120 | | |
121 | | // Send message from server to client to test other direction |
122 | | // If connection failed, send may block, without a timeout |
123 | 0 | send_bounce_msg_may_fail (server_); |
124 | | |
125 | | // Receive message at client side (should not succeed) |
126 | 0 | recv_bounce_msg_fail (client_); |
127 | 0 | } |
128 | | |
129 | | char *s_recv (void *socket_) |
130 | 0 | { |
131 | 0 | char buffer[256]; |
132 | 0 | int size = zmq_recv (socket_, buffer, 255, 0); |
133 | 0 | if (size == -1) |
134 | 0 | return NULL; |
135 | 0 | if (size > 255) |
136 | 0 | size = 255; |
137 | 0 | buffer[size] = 0; |
138 | 0 | return strdup (buffer); |
139 | 0 | } |
140 | | |
141 | | void s_send_seq (void *socket_, ...) |
142 | 0 | { |
143 | 0 | va_list ap; |
144 | 0 | va_start (ap, socket_); |
145 | 0 | const char *data = va_arg (ap, const char *); |
146 | 0 | while (true) { |
147 | 0 | const char *prev = data; |
148 | 0 | data = va_arg (ap, const char *); |
149 | 0 | bool end = data == SEQ_END; |
150 | |
|
151 | 0 | if (!prev) { |
152 | 0 | TEST_ASSERT_SUCCESS_ERRNO ( |
153 | 0 | zmq_send (socket_, 0, 0, end ? 0 : ZMQ_SNDMORE)); |
154 | 0 | } else { |
155 | 0 | TEST_ASSERT_SUCCESS_ERRNO (zmq_send ( |
156 | 0 | socket_, prev, strlen (prev) + 1, end ? 0 : ZMQ_SNDMORE)); |
157 | 0 | } |
158 | 0 | if (end) |
159 | 0 | break; |
160 | 0 | } |
161 | 0 | va_end (ap); |
162 | 0 | } |
163 | | |
164 | | void s_recv_seq (void *socket_, ...) |
165 | 0 | { |
166 | 0 | zmq_msg_t msg; |
167 | 0 | zmq_msg_init (&msg); |
168 | |
|
169 | 0 | int more; |
170 | 0 | size_t more_size = sizeof (more); |
171 | |
|
172 | 0 | va_list ap; |
173 | 0 | va_start (ap, socket_); |
174 | 0 | const char *data = va_arg (ap, const char *); |
175 | |
|
176 | 0 | while (true) { |
177 | 0 | TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_recv (&msg, socket_, 0)); |
178 | |
|
179 | 0 | if (!data) |
180 | 0 | TEST_ASSERT_EQUAL_INT (0, zmq_msg_size (&msg)); |
181 | 0 | else |
182 | 0 | TEST_ASSERT_EQUAL_STRING (data, (const char *) zmq_msg_data (&msg)); |
183 | |
|
184 | 0 | data = va_arg (ap, const char *); |
185 | 0 | bool end = data == SEQ_END; |
186 | |
|
187 | 0 | TEST_ASSERT_SUCCESS_ERRNO ( |
188 | 0 | zmq_getsockopt (socket_, ZMQ_RCVMORE, &more, &more_size)); |
189 | |
|
190 | 0 | TEST_ASSERT_TRUE (!more == end); |
191 | 0 | if (end) |
192 | 0 | break; |
193 | 0 | } |
194 | 0 | va_end (ap); |
195 | |
|
196 | 0 | zmq_msg_close (&msg); |
197 | 0 | } |
198 | | |
199 | | void close_zero_linger (void *socket_) |
200 | 0 | { |
201 | 0 | int linger = 0; |
202 | 0 | int rc = zmq_setsockopt (socket_, ZMQ_LINGER, &linger, sizeof (linger)); |
203 | 0 | TEST_ASSERT_TRUE (rc == 0 || errno == ETERM); |
204 | 0 | TEST_ASSERT_SUCCESS_ERRNO (zmq_close (socket_)); |
205 | 0 | } |
206 | | |
207 | | void setup_test_environment (int timeout_seconds_) |
208 | 0 | { |
209 | | #if defined _WIN32 |
210 | | #if defined _MSC_VER |
211 | | _set_abort_behavior (0, _WRITE_ABORT_MSG); |
212 | | _CrtSetReportMode (_CRT_ASSERT, _CRTDBG_MODE_FILE); |
213 | | _CrtSetReportFile (_CRT_ASSERT, _CRTDBG_FILE_STDERR); |
214 | | #endif |
215 | | #else |
216 | | #if defined ZMQ_HAVE_CYGWIN |
217 | | // abort test after 121 seconds |
218 | | alarm (121); |
219 | | #else |
220 | 0 | #if !defined ZMQ_DISABLE_TEST_TIMEOUT |
221 | | // abort test after timeout_seconds_ seconds |
222 | 0 | alarm (timeout_seconds_); |
223 | 0 | #endif |
224 | 0 | #endif |
225 | 0 | #endif |
226 | | #if defined __MVS__ |
227 | | // z/OS UNIX System Services: Ignore SIGPIPE during test runs, as a |
228 | | // workaround for no SO_NOGSIGPIPE socket option. |
229 | | signal (SIGPIPE, SIG_IGN); |
230 | | #endif |
231 | 0 | } |
232 | | |
233 | | void msleep (int milliseconds_) |
234 | 0 | { |
235 | | #ifdef ZMQ_HAVE_WINDOWS |
236 | | Sleep (milliseconds_); |
237 | | #else |
238 | 0 | usleep (static_cast<useconds_t> (milliseconds_) * 1000); |
239 | 0 | #endif |
240 | 0 | } |
241 | | |
242 | | int is_ipv6_available () |
243 | 0 | { |
244 | | #if defined(ZMQ_HAVE_WINDOWS) && (_WIN32_WINNT < 0x0600) |
245 | | return 0; |
246 | | #else |
247 | 0 | int rc, ipv6 = 1; |
248 | 0 | struct sockaddr_in6 test_addr; |
249 | |
|
250 | 0 | memset (&test_addr, 0, sizeof (test_addr)); |
251 | 0 | test_addr.sin6_family = AF_INET6; |
252 | 0 | inet_pton (AF_INET6, "::1", &(test_addr.sin6_addr)); |
253 | |
|
254 | 0 | fd_t fd = socket (AF_INET6, SOCK_STREAM, IPPROTO_IP); |
255 | 0 | if (fd == retired_fd) |
256 | 0 | ipv6 = 0; |
257 | 0 | else { |
258 | | #ifdef ZMQ_HAVE_WINDOWS |
259 | | setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, (const char *) &ipv6, |
260 | | sizeof (int)); |
261 | | rc = setsockopt (fd, IPPROTO_IPV6, IPV6_V6ONLY, (const char *) &ipv6, |
262 | | sizeof (int)); |
263 | | if (rc == SOCKET_ERROR) |
264 | | ipv6 = 0; |
265 | | else { |
266 | | rc = bind (fd, (struct sockaddr *) &test_addr, sizeof (test_addr)); |
267 | | if (rc == SOCKET_ERROR) |
268 | | ipv6 = 0; |
269 | | } |
270 | | #else |
271 | 0 | setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, &ipv6, sizeof (int)); |
272 | 0 | rc = setsockopt (fd, IPPROTO_IPV6, IPV6_V6ONLY, &ipv6, sizeof (int)); |
273 | 0 | if (rc != 0) |
274 | 0 | ipv6 = 0; |
275 | 0 | else { |
276 | 0 | rc = bind (fd, reinterpret_cast<struct sockaddr *> (&test_addr), |
277 | 0 | sizeof (test_addr)); |
278 | 0 | if (rc != 0) |
279 | 0 | ipv6 = 0; |
280 | 0 | } |
281 | 0 | #endif |
282 | 0 | close (fd); |
283 | 0 | } |
284 | |
|
285 | 0 | return ipv6; |
286 | 0 | #endif // _WIN32_WINNT < 0x0600 |
287 | 0 | } |
288 | | |
289 | | int is_tipc_available () |
290 | 0 | { |
291 | | #ifndef ZMQ_HAVE_TIPC |
292 | | return 0; |
293 | | #else |
294 | 0 | int tipc = 0; |
295 | |
|
296 | 0 | void *ctx = zmq_init (1); |
297 | 0 | TEST_ASSERT_NOT_NULL (ctx); |
298 | 0 | void *rep = zmq_socket (ctx, ZMQ_REP); |
299 | 0 | TEST_ASSERT_NOT_NULL (rep); |
300 | 0 | tipc = zmq_bind (rep, "tipc://{5560,0,0}"); |
301 | |
|
302 | 0 | zmq_close (rep); |
303 | 0 | zmq_ctx_term (ctx); |
304 | |
|
305 | 0 | return tipc == 0; |
306 | 0 | #endif // ZMQ_HAVE_TIPC |
307 | 0 | } |
308 | | |
309 | | int is_vsock_available () |
310 | 0 | { |
311 | 0 | #ifndef ZMQ_HAVE_VSOCK |
312 | 0 | return 0; |
313 | | #else |
314 | | unsigned int cid = VMADDR_CID_ANY; |
315 | | int vsock = -1; |
316 | | |
317 | | if ((vsock = open ("/dev/vsock", O_RDONLY, 0)) < 0) { |
318 | | TEST_IGNORE_MESSAGE ("failed to open /dev/vsock, skipping test"); |
319 | | } else if (ioctl (vsock, IOCTL_VM_SOCKETS_GET_LOCAL_CID, &cid) < 0) { |
320 | | TEST_IGNORE_MESSAGE ("failed to get local cid, skipping test"); |
321 | | } |
322 | | |
323 | | if (vsock >= 0) { |
324 | | close (vsock); |
325 | | } |
326 | | |
327 | | if (cid == VMADDR_CID_ANY) { |
328 | | TEST_IGNORE_MESSAGE ( |
329 | | "vsock_loopback environment unavailable, skipping test"); |
330 | | } |
331 | | |
332 | | return cid != VMADDR_CID_ANY; |
333 | | #endif // ZMQ_HAVE_VSOCK |
334 | 0 | } |
335 | | |
336 | | int test_inet_pton (int af_, const char *src_, void *dst_) |
337 | 0 | { |
338 | | #if defined(ZMQ_HAVE_WINDOWS) && (_WIN32_WINNT < 0x0600) |
339 | | if (af_ == AF_INET) { |
340 | | struct in_addr *ip4addr = (struct in_addr *) dst_; |
341 | | |
342 | | ip4addr->s_addr = inet_addr (src_); |
343 | | |
344 | | // INADDR_NONE is -1 which is also a valid representation for IP |
345 | | // 255.255.255.255 |
346 | | if (ip4addr->s_addr == INADDR_NONE |
347 | | && strcmp (src_, "255.255.255.255") != 0) { |
348 | | return 0; |
349 | | } |
350 | | |
351 | | // Success |
352 | | return 1; |
353 | | } else { |
354 | | // Not supported. |
355 | | return 0; |
356 | | } |
357 | | #else |
358 | 0 | return inet_pton (af_, src_, dst_); |
359 | 0 | #endif |
360 | 0 | } |
361 | | |
362 | | sockaddr_in bind_bsd_socket (int socket_) |
363 | 0 | { |
364 | 0 | struct sockaddr_in saddr; |
365 | 0 | memset (&saddr, 0, sizeof (saddr)); |
366 | 0 | saddr.sin_family = AF_INET; |
367 | 0 | saddr.sin_addr.s_addr = htonl (INADDR_LOOPBACK); |
368 | 0 | #if !defined(_WIN32_WINNT) || (_WIN32_WINNT >= 0x0600) |
369 | 0 | saddr.sin_port = 0; |
370 | | #else |
371 | | saddr.sin_port = htons (PORT_6); |
372 | | #endif |
373 | |
|
374 | 0 | TEST_ASSERT_SUCCESS_RAW_ERRNO ( |
375 | 0 | bind (socket_, (struct sockaddr *) &saddr, sizeof (saddr))); |
376 | |
|
377 | 0 | #if !defined(_WIN32_WINNT) || (_WIN32_WINNT >= 0x0600) |
378 | 0 | socklen_t saddr_len = sizeof (saddr); |
379 | 0 | TEST_ASSERT_SUCCESS_RAW_ERRNO ( |
380 | 0 | getsockname (socket_, (struct sockaddr *) &saddr, &saddr_len)); |
381 | 0 | #endif |
382 | |
|
383 | 0 | return saddr; |
384 | 0 | } |
385 | | |
386 | | fd_t connect_socket (const char *endpoint_, const int af_, const int protocol_) |
387 | 0 | { |
388 | 0 | struct sockaddr_storage addr; |
389 | | // OSX is very opinionated and wants the size to match the AF family type |
390 | 0 | socklen_t addr_len; |
391 | 0 | const fd_t s_pre = socket (af_, SOCK_STREAM, |
392 | 0 | protocol_ == IPPROTO_UDP ? IPPROTO_UDP |
393 | 0 | : protocol_ == IPPROTO_TCP ? IPPROTO_TCP |
394 | 0 | : 0); |
395 | | #ifdef ZMQ_HAVE_WINDOWS |
396 | | TEST_ASSERT_NOT_EQUAL (INVALID_SOCKET, s_pre); |
397 | | #else |
398 | 0 | TEST_ASSERT_NOT_EQUAL (-1, s_pre); |
399 | 0 | #endif |
400 | |
|
401 | 0 | if (af_ == AF_INET || af_ == AF_INET6) { |
402 | 0 | const char *port = strrchr (endpoint_, ':') + 1; |
403 | 0 | char address[MAX_SOCKET_STRING]; |
404 | | // getaddrinfo does not like [x:y::z] |
405 | 0 | if (*strchr (endpoint_, '/') + 2 == '[') { |
406 | 0 | strcpy (address, strchr (endpoint_, '[') + 1); |
407 | 0 | address[strlen (address) - strlen (port) - 2] = '\0'; |
408 | 0 | } else { |
409 | 0 | strcpy (address, strchr (endpoint_, '/') + 2); |
410 | 0 | address[strlen (address) - strlen (port) - 1] = '\0'; |
411 | 0 | } |
412 | |
|
413 | 0 | struct addrinfo *in, hint; |
414 | 0 | memset (&hint, 0, sizeof (struct addrinfo)); |
415 | 0 | hint.ai_flags = AI_NUMERICSERV; |
416 | 0 | hint.ai_family = af_; |
417 | 0 | hint.ai_socktype = protocol_ == IPPROTO_UDP ? SOCK_DGRAM : SOCK_STREAM; |
418 | 0 | hint.ai_protocol = protocol_ == IPPROTO_UDP ? IPPROTO_UDP : IPPROTO_TCP; |
419 | |
|
420 | 0 | TEST_ASSERT_SUCCESS_RAW_ZERO_ERRNO ( |
421 | 0 | getaddrinfo (address, port, &hint, &in)); |
422 | 0 | TEST_ASSERT_NOT_NULL (in); |
423 | 0 | memcpy (&addr, in->ai_addr, in->ai_addrlen); |
424 | 0 | addr_len = (socklen_t) in->ai_addrlen; |
425 | 0 | freeaddrinfo (in); |
426 | 0 | } else { |
427 | 0 | #if defined(ZMQ_HAVE_IPC) |
428 | | // Cannot cast addr as gcc 4.4 will fail with strict aliasing errors |
429 | 0 | (*(struct sockaddr_un *) &addr).sun_family = AF_UNIX; |
430 | 0 | strcpy ((*(struct sockaddr_un *) &addr).sun_path, endpoint_); |
431 | 0 | addr_len = sizeof (struct sockaddr_un); |
432 | | #else |
433 | | return retired_fd; |
434 | | #endif |
435 | 0 | } |
436 | |
|
437 | 0 | TEST_ASSERT_SUCCESS_RAW_ERRNO ( |
438 | 0 | connect (s_pre, (struct sockaddr *) &addr, addr_len)); |
439 | |
|
440 | 0 | return s_pre; |
441 | 0 | } |
442 | | |
443 | | fd_t bind_socket_resolve_port (const char *address_, |
444 | | const char *port_, |
445 | | char *my_endpoint_, |
446 | | const int af_, |
447 | | const int protocol_) |
448 | 0 | { |
449 | 0 | struct sockaddr_storage addr; |
450 | | // OSX is very opinionated and wants the size to match the AF family type |
451 | 0 | socklen_t addr_len; |
452 | 0 | const fd_t s_pre = socket (af_, SOCK_STREAM, |
453 | 0 | protocol_ == IPPROTO_UDP ? IPPROTO_UDP |
454 | 0 | : protocol_ == IPPROTO_TCP ? IPPROTO_TCP |
455 | 0 | : 0); |
456 | | #ifdef ZMQ_HAVE_WINDOWS |
457 | | TEST_ASSERT_NOT_EQUAL (INVALID_SOCKET, s_pre); |
458 | | #else |
459 | 0 | TEST_ASSERT_NOT_EQUAL (-1, s_pre); |
460 | 0 | #endif |
461 | |
|
462 | 0 | if (af_ == AF_INET || af_ == AF_INET6) { |
463 | | #ifdef ZMQ_HAVE_WINDOWS |
464 | | const char flag = '\1'; |
465 | | #elif defined ZMQ_HAVE_VXWORKS |
466 | | char flag = '\1'; |
467 | | #else |
468 | 0 | int flag = 1; |
469 | 0 | #endif |
470 | 0 | struct addrinfo *in, hint; |
471 | 0 | memset (&hint, 0, sizeof (struct addrinfo)); |
472 | 0 | hint.ai_flags = AI_NUMERICSERV; |
473 | 0 | hint.ai_family = af_; |
474 | 0 | hint.ai_socktype = protocol_ == IPPROTO_UDP ? SOCK_DGRAM : SOCK_STREAM; |
475 | 0 | hint.ai_protocol = protocol_ == IPPROTO_UDP ? IPPROTO_UDP : IPPROTO_TCP; |
476 | |
|
477 | 0 | TEST_ASSERT_SUCCESS_RAW_ERRNO ( |
478 | 0 | setsockopt (s_pre, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof (int))); |
479 | 0 | TEST_ASSERT_SUCCESS_RAW_ZERO_ERRNO ( |
480 | 0 | getaddrinfo (address_, port_, &hint, &in)); |
481 | 0 | TEST_ASSERT_NOT_NULL (in); |
482 | 0 | memcpy (&addr, in->ai_addr, in->ai_addrlen); |
483 | 0 | addr_len = (socklen_t) in->ai_addrlen; |
484 | 0 | freeaddrinfo (in); |
485 | 0 | } else { |
486 | 0 | #if defined(ZMQ_HAVE_IPC) |
487 | | // Cannot cast addr as gcc 4.4 will fail with strict aliasing errors |
488 | 0 | (*(struct sockaddr_un *) &addr).sun_family = AF_UNIX; |
489 | 0 | addr_len = sizeof (struct sockaddr_un); |
490 | | #if defined ZMQ_HAVE_WINDOWS |
491 | | char buffer[MAX_PATH] = ""; |
492 | | |
493 | | TEST_ASSERT_SUCCESS_RAW_ERRNO (tmpnam_s (buffer)); |
494 | | TEST_ASSERT_SUCCESS_RAW_ERRNO (_mkdir (buffer)); |
495 | | strcat (buffer, "/ipc"); |
496 | | #else |
497 | 0 | char buffer[PATH_MAX] = ""; |
498 | 0 | strcpy (buffer, "tmpXXXXXX"); |
499 | 0 | #ifdef HAVE_MKDTEMP |
500 | 0 | TEST_ASSERT_TRUE (mkdtemp (buffer)); |
501 | 0 | strcat (buffer, "/socket"); |
502 | | #else |
503 | | int fd = mkstemp (buffer); |
504 | | TEST_ASSERT_TRUE (fd != -1); |
505 | | close (fd); |
506 | | #endif |
507 | 0 | #endif |
508 | 0 | strcpy ((*(struct sockaddr_un *) &addr).sun_path, buffer); |
509 | 0 | memcpy (my_endpoint_, "ipc://", 7); |
510 | 0 | strcat (my_endpoint_, buffer); |
511 | | |
512 | | // TODO check return value of unlink |
513 | 0 | unlink (buffer); |
514 | | #else |
515 | | return retired_fd; |
516 | | #endif |
517 | 0 | } |
518 | |
|
519 | 0 | TEST_ASSERT_SUCCESS_RAW_ERRNO ( |
520 | 0 | bind (s_pre, (struct sockaddr *) &addr, addr_len)); |
521 | 0 | TEST_ASSERT_SUCCESS_RAW_ERRNO (listen (s_pre, SOMAXCONN)); |
522 | |
|
523 | 0 | if (af_ == AF_INET || af_ == AF_INET6) { |
524 | 0 | addr_len = sizeof (struct sockaddr_storage); |
525 | 0 | TEST_ASSERT_SUCCESS_RAW_ERRNO ( |
526 | 0 | getsockname (s_pre, (struct sockaddr *) &addr, &addr_len)); |
527 | 0 | snprintf ( |
528 | 0 | my_endpoint_, 6 + strlen (address_) + 7 * sizeof (char), "%s://%s:%u", |
529 | 0 | protocol_ == IPPROTO_TCP ? "tcp" |
530 | 0 | : protocol_ == IPPROTO_UDP ? "udp" |
531 | 0 | : protocol_ == IPPROTO_WSS ? "wss" |
532 | 0 | : "ws", |
533 | 0 | address_, |
534 | 0 | af_ == AF_INET ? ntohs ((*(struct sockaddr_in *) &addr).sin_port) |
535 | 0 | : ntohs ((*(struct sockaddr_in6 *) &addr).sin6_port)); |
536 | 0 | } |
537 | |
|
538 | 0 | return s_pre; |
539 | 0 | } |
540 | | |
541 | | bool streq (const char *lhs_, const char *rhs_) |
542 | 0 | { |
543 | 0 | return strcmp (lhs_, rhs_) == 0; |
544 | 0 | } |
545 | | |
546 | | bool strneq (const char *lhs_, const char *rhs_) |
547 | 0 | { |
548 | 0 | return strcmp (lhs_, rhs_) != 0; |
549 | 0 | } |
550 | | |
551 | | #if defined _WIN32 |
552 | | int fuzzer_corpus_encode (const char *dirname, |
553 | | uint8_t ***data, |
554 | | size_t **len, |
555 | | size_t *num_cases) |
556 | | { |
557 | | (void) dirname; |
558 | | (void) data; |
559 | | (void) len; |
560 | | (void) num_cases; |
561 | | |
562 | | return -1; |
563 | | } |
564 | | |
565 | | #else |
566 | | |
567 | | int fuzzer_corpus_encode (const char *dirname, |
568 | | uint8_t ***data, |
569 | | size_t **len, |
570 | | size_t *num_cases) |
571 | 0 | { |
572 | 0 | TEST_ASSERT_NOT_NULL (dirname); |
573 | 0 | TEST_ASSERT_NOT_NULL (data); |
574 | 0 | TEST_ASSERT_NOT_NULL (len); |
575 | |
|
576 | 0 | struct dirent *ent; |
577 | 0 | DIR *dir = opendir (dirname); |
578 | 0 | if (!dir) |
579 | 0 | return -1; |
580 | | |
581 | 0 | *len = NULL; |
582 | 0 | *data = NULL; |
583 | 0 | *num_cases = 0; |
584 | |
|
585 | 0 | while ((ent = readdir (dir)) != NULL) { |
586 | 0 | if (!strcmp (ent->d_name, ".") || !strcmp (ent->d_name, "..")) |
587 | 0 | continue; |
588 | | |
589 | 0 | char *filename = |
590 | 0 | (char *) malloc (strlen (dirname) + strlen (ent->d_name) + 2); |
591 | 0 | TEST_ASSERT_NOT_NULL (filename); |
592 | 0 | strcpy (filename, dirname); |
593 | 0 | strcat (filename, "/"); |
594 | 0 | strcat (filename, ent->d_name); |
595 | 0 | FILE *f = fopen (filename, "r"); |
596 | 0 | free (filename); |
597 | 0 | if (!f) |
598 | 0 | continue; |
599 | | |
600 | 0 | fseek (f, 0, SEEK_END); |
601 | 0 | size_t file_len = ftell (f); |
602 | 0 | fseek (f, 0, SEEK_SET); |
603 | 0 | if (file_len == 0) { |
604 | 0 | fclose (f); |
605 | 0 | continue; |
606 | 0 | } |
607 | | |
608 | 0 | *len = (size_t *) realloc (*len, (*num_cases + 1) * sizeof (size_t)); |
609 | 0 | TEST_ASSERT_NOT_NULL (*len); |
610 | 0 | *(*len + *num_cases) = file_len; |
611 | 0 | *data = |
612 | 0 | (uint8_t **) realloc (*data, (*num_cases + 1) * sizeof (uint8_t *)); |
613 | 0 | TEST_ASSERT_NOT_NULL (*data); |
614 | 0 | *(*data + *num_cases) = |
615 | 0 | (uint8_t *) malloc (file_len * sizeof (uint8_t)); |
616 | 0 | TEST_ASSERT_NOT_NULL (*(*data + *num_cases)); |
617 | 0 | size_t read_bytes = 0; |
618 | 0 | read_bytes = fread (*(*data + *num_cases), 1, file_len, f); |
619 | 0 | TEST_ASSERT_EQUAL (file_len, read_bytes); |
620 | 0 | (*num_cases)++; |
621 | |
|
622 | 0 | fclose (f); |
623 | 0 | } |
624 | |
|
625 | 0 | closedir (dir); |
626 | |
|
627 | 0 | return 0; |
628 | 0 | } |
629 | | #endif |