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_unity.hpp"
30 
31 #include <stdlib.h>
32 #include <string.h>
33 
34 #ifdef _WIN32
35 #include <direct.h>
36 #else
37 #include <unistd.h>
38 #endif
39 
test_assert_success_message_errno_helper(int rc_,const char * msg_,const char * expr_,int line_)40 int test_assert_success_message_errno_helper (int rc_,
41                                               const char *msg_,
42                                               const char *expr_,
43                                               int line_)
44 {
45     if (rc_ == -1) {
46         char buffer[512];
47         buffer[sizeof (buffer) - 1] =
48           0; // to ensure defined behavior with VC++ <= 2013
49         snprintf (buffer, sizeof (buffer) - 1,
50                   "%s failed%s%s%s, errno = %i (%s)", expr_,
51                   msg_ ? " (additional info: " : "", msg_ ? msg_ : "",
52                   msg_ ? ")" : "", zmq_errno (), zmq_strerror (zmq_errno ()));
53         UNITY_TEST_FAIL (line_, buffer);
54     }
55     return rc_;
56 }
57 
test_assert_success_message_raw_errno_helper(int rc_,const char * msg_,const char * expr_,int line_,bool zero)58 int test_assert_success_message_raw_errno_helper (
59   int rc_, const char *msg_, const char *expr_, int line_, bool zero)
60 {
61     if (rc_ == -1 || (zero && rc_ != 0)) {
62 #if defined ZMQ_HAVE_WINDOWS
63         int current_errno = WSAGetLastError ();
64 #else
65         int current_errno = errno;
66 #endif
67 
68         char buffer[512];
69         buffer[sizeof (buffer) - 1] =
70           0; // to ensure defined behavior with VC++ <= 2013
71         snprintf (
72           buffer, sizeof (buffer) - 1, "%s failed%s%s%s with %d, errno = %i/%s",
73           expr_, msg_ ? " (additional info: " : "", msg_ ? msg_ : "",
74           msg_ ? ")" : "", rc_, current_errno, strerror (current_errno));
75         UNITY_TEST_FAIL (line_, buffer);
76     }
77     return rc_;
78 }
79 
test_assert_success_message_raw_zero_errno_helper(int rc_,const char * msg_,const char * expr_,int line_)80 int test_assert_success_message_raw_zero_errno_helper (int rc_,
81                                                        const char *msg_,
82                                                        const char *expr_,
83                                                        int line_)
84 {
85     return test_assert_success_message_raw_errno_helper (rc_, msg_, expr_,
86                                                          line_, true);
87 }
88 
test_assert_failure_message_raw_errno_helper(int rc_,int expected_errno_,const char * msg_,const char * expr_,int line_)89 int test_assert_failure_message_raw_errno_helper (
90   int rc_, int expected_errno_, const char *msg_, const char *expr_, int line_)
91 {
92     char buffer[512];
93     buffer[sizeof (buffer) - 1] =
94       0; // to ensure defined behavior with VC++ <= 2013
95     if (rc_ != -1) {
96         snprintf (buffer, sizeof (buffer) - 1,
97                   "%s was unexpectedly successful%s%s%s, expected "
98                   "errno = %i, actual return value = %i",
99                   expr_, msg_ ? " (additional info: " : "", msg_ ? msg_ : "",
100                   msg_ ? ")" : "", expected_errno_, rc_);
101         UNITY_TEST_FAIL (line_, buffer);
102     } else {
103 #if defined ZMQ_HAVE_WINDOWS
104         int current_errno = WSAGetLastError ();
105 #else
106         int current_errno = errno;
107 #endif
108         if (current_errno != expected_errno_) {
109             snprintf (buffer, sizeof (buffer) - 1,
110                       "%s failed with an unexpected error%s%s%s, expected "
111                       "errno = %i, actual errno = %i",
112                       expr_, msg_ ? " (additional info: " : "",
113                       msg_ ? msg_ : "", msg_ ? ")" : "", expected_errno_,
114                       current_errno);
115             UNITY_TEST_FAIL (line_, buffer);
116         }
117     }
118     return rc_;
119 }
120 
send_string_expect_success(void * socket_,const char * str_,int flags_)121 void send_string_expect_success (void *socket_, const char *str_, int flags_)
122 {
123     const size_t len = str_ ? strlen (str_) : 0;
124     const int rc = zmq_send (socket_, str_, len, flags_);
125     TEST_ASSERT_EQUAL_INT ((int) len, rc);
126 }
127 
recv_string_expect_success(void * socket_,const char * str_,int flags_)128 void recv_string_expect_success (void *socket_, const char *str_, int flags_)
129 {
130     const size_t len = str_ ? strlen (str_) : 0;
131     char buffer[255];
132     TEST_ASSERT_LESS_OR_EQUAL_MESSAGE (sizeof (buffer), len,
133                                        "recv_string_expect_success cannot be "
134                                        "used for strings longer than 255 "
135                                        "characters");
136 
137     const int rc = TEST_ASSERT_SUCCESS_ERRNO (
138       zmq_recv (socket_, buffer, sizeof (buffer), flags_));
139     TEST_ASSERT_EQUAL_INT ((int) len, rc);
140     if (str_)
141         TEST_ASSERT_EQUAL_STRING_LEN (str_, buffer, len);
142 }
143 
internal_manage_test_context(bool init_,bool clear_)144 static void *internal_manage_test_context (bool init_, bool clear_)
145 {
146     static void *test_context = NULL;
147     if (clear_) {
148         TEST_ASSERT_NOT_NULL (test_context);
149         TEST_ASSERT_SUCCESS_ERRNO (zmq_ctx_term (test_context));
150         test_context = NULL;
151     } else {
152         if (init_) {
153             TEST_ASSERT_NULL (test_context);
154             test_context = zmq_ctx_new ();
155             TEST_ASSERT_NOT_NULL (test_context);
156         }
157     }
158     return test_context;
159 }
160 
internal_manage_test_sockets(void * socket_,bool add_)161 static void internal_manage_test_sockets (void *socket_, bool add_)
162 {
163     static void *test_sockets[MAX_TEST_SOCKETS];
164     static size_t test_socket_count = 0;
165     if (!socket_) {
166         TEST_ASSERT_FALSE (add_);
167 
168         // force-close all sockets
169         if (test_socket_count) {
170             for (size_t i = 0; i < test_socket_count; ++i) {
171                 close_zero_linger (test_sockets[i]);
172             }
173             fprintf (stderr,
174                      "WARNING: Forced closure of %i sockets, this is an "
175                      "implementation error unless the test case failed\n",
176                      static_cast<int> (test_socket_count));
177             test_socket_count = 0;
178         }
179     } else {
180         if (add_) {
181             ++test_socket_count;
182             TEST_ASSERT_LESS_THAN_MESSAGE (MAX_TEST_SOCKETS, test_socket_count,
183                                            "MAX_TEST_SOCKETS must be "
184                                            "increased, or you cannot use the "
185                                            "test context");
186             test_sockets[test_socket_count - 1] = socket_;
187         } else {
188             bool found = false;
189             for (size_t i = 0; i < test_socket_count; ++i) {
190                 if (test_sockets[i] == socket_) {
191                     found = true;
192                 }
193                 if (found) {
194                     if (i < test_socket_count)
195                         test_sockets[i] = test_sockets[i + 1];
196                 }
197             }
198             TEST_ASSERT_TRUE_MESSAGE (found,
199                                       "Attempted to close a socket that was "
200                                       "not created by test_context_socket");
201             --test_socket_count;
202         }
203     }
204 }
205 
setup_test_context()206 void setup_test_context ()
207 {
208     internal_manage_test_context (true, false);
209 }
210 
get_test_context()211 void *get_test_context ()
212 {
213     return internal_manage_test_context (false, false);
214 }
215 
teardown_test_context()216 void teardown_test_context ()
217 {
218     // this condition allows an explicit call to teardown_test_context from a
219     // test. if this is never used, it should probably be removed, to detect
220     // misuses
221     if (get_test_context ()) {
222         internal_manage_test_sockets (NULL, false);
223         internal_manage_test_context (false, true);
224     }
225 }
226 
test_context_socket(int type_)227 void *test_context_socket (int type_)
228 {
229     void *const socket = zmq_socket (get_test_context (), type_);
230     TEST_ASSERT_NOT_NULL (socket);
231     internal_manage_test_sockets (socket, true);
232     return socket;
233 }
234 
test_context_socket_close(void * socket_)235 void *test_context_socket_close (void *socket_)
236 {
237     TEST_ASSERT_SUCCESS_ERRNO (zmq_close (socket_));
238     internal_manage_test_sockets (socket_, false);
239     return socket_;
240 }
241 
test_context_socket_close_zero_linger(void * socket_)242 void *test_context_socket_close_zero_linger (void *socket_)
243 {
244     const int linger = 0;
245     int rc = zmq_setsockopt (socket_, ZMQ_LINGER, &linger, sizeof (linger));
246     TEST_ASSERT_TRUE (rc == 0 || zmq_errno () == ETERM);
247     return test_context_socket_close (socket_);
248 }
249 
test_bind(void * socket_,const char * bind_address_,char * my_endpoint_,size_t len_)250 void test_bind (void *socket_,
251                 const char *bind_address_,
252                 char *my_endpoint_,
253                 size_t len_)
254 {
255     TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (socket_, bind_address_));
256     TEST_ASSERT_SUCCESS_ERRNO (
257       zmq_getsockopt (socket_, ZMQ_LAST_ENDPOINT, my_endpoint_, &len_));
258 }
259 
bind_loopback(void * socket_,int ipv6_,char * my_endpoint_,size_t len_)260 void bind_loopback (void *socket_, int ipv6_, char *my_endpoint_, size_t len_)
261 {
262     if (ipv6_ && !is_ipv6_available ()) {
263         TEST_IGNORE_MESSAGE ("ipv6 is not available");
264     }
265 
266     TEST_ASSERT_SUCCESS_ERRNO (
267       zmq_setsockopt (socket_, ZMQ_IPV6, &ipv6_, sizeof (int)));
268 
269     test_bind (socket_, ipv6_ ? "tcp://[::1]:*" : "tcp://127.0.0.1:*",
270                my_endpoint_, len_);
271 }
272 
bind_loopback_ipv4(void * socket_,char * my_endpoint_,size_t len_)273 void bind_loopback_ipv4 (void *socket_, char *my_endpoint_, size_t len_)
274 {
275     bind_loopback (socket_, false, my_endpoint_, len_);
276 }
277 
bind_loopback_ipv6(void * socket_,char * my_endpoint_,size_t len_)278 void bind_loopback_ipv6 (void *socket_, char *my_endpoint_, size_t len_)
279 {
280     bind_loopback (socket_, true, my_endpoint_, len_);
281 }
282 
bind_loopback_ipc(void * socket_,char * my_endpoint_,size_t len_)283 void bind_loopback_ipc (void *socket_, char *my_endpoint_, size_t len_)
284 {
285     if (!zmq_has ("ipc")) {
286         TEST_IGNORE_MESSAGE ("ipc is not available");
287     }
288 
289     test_bind (socket_, "ipc://*", my_endpoint_, len_);
290 }
291 
bind_loopback_tipc(void * socket_,char * my_endpoint_,size_t len_)292 void bind_loopback_tipc (void *socket_, char *my_endpoint_, size_t len_)
293 {
294     if (!is_tipc_available ()) {
295         TEST_IGNORE_MESSAGE ("tipc is not available");
296     }
297 
298     test_bind (socket_, "tipc://<*>", my_endpoint_, len_);
299 }
300 
301 #if defined(ZMQ_HAVE_IPC)
make_random_ipc_endpoint(char * out_endpoint_)302 void make_random_ipc_endpoint (char *out_endpoint_)
303 {
304 #ifdef ZMQ_HAVE_WINDOWS
305     char random_file[MAX_PATH];
306 
307     {
308         const errno_t rc = tmpnam_s (random_file);
309         TEST_ASSERT_EQUAL (0, rc);
310     }
311 
312     // TODO or use CreateDirectoryA and specify permissions?
313     const int rc = _mkdir (random_file);
314     TEST_ASSERT_EQUAL (0, rc);
315 
316     strcat (random_file, "/ipc");
317 
318 #else
319     char random_file[16];
320     strcpy (random_file, "tmpXXXXXX");
321 
322 #ifdef HAVE_MKDTEMP
323     TEST_ASSERT_TRUE (mkdtemp (random_file));
324     strcat (random_file, "/ipc");
325 #else
326     int fd = mkstemp (random_file);
327     TEST_ASSERT_TRUE (fd != -1);
328     close (fd);
329 #endif
330 #endif
331 
332     strcpy (out_endpoint_, "ipc://");
333     strcat (out_endpoint_, random_file);
334 }
335 #endif
336