1/*
2 Copyright (c) 2016-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#include <unistd.h>
36
37SETUP_TEARDOWN_TESTCONTEXT
38
39#if !defined(ZMQ_HAVE_WINDOWS)
40#include <sys/socket.h>
41#include <sys/un.h>
42#include <netdb.h>
43#include <unistd.h>
44
45int setup_socket_and_set_fd (void *zmq_socket_,
46 int af_,
47 int protocol_,
48 const sockaddr *addr_,
49 size_t addr_len_)
50{
51 const int s_pre =
52 TEST_ASSERT_SUCCESS_ERRNO (socket (af_, SOCK_STREAM, protocol_));
53
54 if (af_ == AF_INET) {
55 int flag = 1;
56 TEST_ASSERT_SUCCESS_ERRNO (
57 setsockopt (s_pre, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof (int)));
58 }
59
60 TEST_ASSERT_SUCCESS_ERRNO (bind (s_pre, addr_, addr_len_));
61 TEST_ASSERT_SUCCESS_ERRNO (listen (s_pre, SOMAXCONN));
62
63 TEST_ASSERT_SUCCESS_ERRNO (
64 zmq_setsockopt (zmq_socket_, ZMQ_USE_FD, &s_pre, sizeof (s_pre)));
65
66 return s_pre;
67}
68
69typedef void (*pre_allocate_sock_fun_t) (void *, char *);
70
71void setup_socket_pair (pre_allocate_sock_fun_t pre_allocate_sock_fun_,
72 int bind_socket_type_,
73 int connect_socket_type_,
74 void **out_sb_,
75 void **out_sc_)
76{
77 *out_sb_ = test_context_socket (bind_socket_type_);
78
79 char my_endpoint[MAX_SOCKET_STRING];
80 pre_allocate_sock_fun_ (*out_sb_, my_endpoint);
81
82 TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (*out_sb_, my_endpoint));
83
84 *out_sc_ = test_context_socket (connect_socket_type_);
85 TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (*out_sc_, my_endpoint));
86}
87
88void test_socket_pair (pre_allocate_sock_fun_t pre_allocate_sock_fun_,
89 int bind_socket_type_,
90 int connect_socket_type_)
91{
92 void *sb, *sc;
93 setup_socket_pair (pre_allocate_sock_fun_, bind_socket_type_,
94 connect_socket_type_, &sb, &sc);
95
96 bounce (sb, sc);
97
98 test_context_socket_close (sc);
99 test_context_socket_close (sb);
100}
101
102void test_req_rep (pre_allocate_sock_fun_t pre_allocate_sock_fun_)
103{
104 test_socket_pair (pre_allocate_sock_fun_, ZMQ_REP, ZMQ_REQ);
105}
106
107void test_pair (pre_allocate_sock_fun_t pre_allocate_sock_fun_)
108{
109 test_socket_pair (pre_allocate_sock_fun_, ZMQ_PAIR, ZMQ_PAIR);
110}
111
112void test_client_server (pre_allocate_sock_fun_t pre_allocate_sock_fun_)
113{
114#if defined(ZMQ_SERVER) && defined(ZMQ_CLIENT)
115 void *sb, *sc;
116 setup_socket_pair (pre_allocate_sock_fun_, ZMQ_SERVER, ZMQ_CLIENT, &sb,
117 &sc);
118
119 zmq_msg_t msg;
120 TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_init_size (&msg, 1));
121
122 char *data = static_cast<char *> (zmq_msg_data (&msg));
123 data[0] = 1;
124
125 int rc = zmq_msg_send (&msg, sc, ZMQ_SNDMORE);
126 // TODO which error code is expected?
127 TEST_ASSERT_EQUAL_INT (-1, rc);
128
129 rc = zmq_msg_send (&msg, sc, 0);
130 TEST_ASSERT_EQUAL_INT (1, rc);
131
132 TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_init (&msg));
133
134 rc = zmq_msg_recv (&msg, sb, 0);
135 TEST_ASSERT_EQUAL_INT (1, rc);
136
137 uint32_t routing_id = zmq_msg_routing_id (&msg);
138 TEST_ASSERT_NOT_EQUAL (0, routing_id);
139
140 TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_close (&msg));
141
142 TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_init_size (&msg, 1));
143
144 data = static_cast<char *> (zmq_msg_data (&msg));
145 data[0] = 2;
146
147 TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_set_routing_id (&msg, routing_id));
148
149 rc = zmq_msg_send (&msg, sb, ZMQ_SNDMORE);
150 // TODO which error code is expected?
151 TEST_ASSERT_EQUAL_INT (-1, rc);
152
153 rc = zmq_msg_send (&msg, sb, 0);
154 TEST_ASSERT_EQUAL_INT (1, rc);
155
156 rc = zmq_msg_recv (&msg, sc, 0);
157 TEST_ASSERT_EQUAL_INT (1, rc);
158
159 routing_id = zmq_msg_routing_id (&msg);
160 TEST_ASSERT_EQUAL_INT (0, routing_id);
161
162 TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_close (&msg));
163
164 test_context_socket_close (sc);
165 test_context_socket_close (sb);
166#endif
167}
168
169uint16_t pre_allocate_sock_tcp_int (void *zmq_socket_,
170 const char *address_,
171 const char *port_)
172{
173 struct addrinfo *addr, hint;
174 hint.ai_flags = 0;
175 hint.ai_family = AF_INET;
176 hint.ai_socktype = SOCK_STREAM;
177 hint.ai_protocol = IPPROTO_TCP;
178 hint.ai_addrlen = 0;
179 hint.ai_canonname = NULL;
180 hint.ai_addr = NULL;
181 hint.ai_next = NULL;
182
183 TEST_ASSERT_SUCCESS_ERRNO (getaddrinfo (address_, port_, &hint, &addr));
184
185 const int s_pre = setup_socket_and_set_fd (
186 zmq_socket_, AF_INET, IPPROTO_TCP, addr->ai_addr, addr->ai_addrlen);
187
188 struct sockaddr_in sin;
189 socklen_t len = sizeof (sin);
190 TEST_ASSERT_SUCCESS_ERRNO (
191 getsockname (s_pre, (struct sockaddr *) &sin, &len));
192
193 freeaddrinfo (addr);
194
195 return ntohs (sin.sin_port);
196}
197
198void pre_allocate_sock_tcp (void *socket_, char *my_endpoint_)
199{
200 const uint16_t port = pre_allocate_sock_tcp_int (socket_, "127.0.0.1", "0");
201 sprintf (my_endpoint_, "tcp://127.0.0.1:%u", port);
202}
203
204void test_req_rep_tcp ()
205{
206 test_req_rep (pre_allocate_sock_tcp);
207}
208
209void test_pair_tcp ()
210{
211 test_pair (pre_allocate_sock_tcp);
212}
213
214void test_client_server_tcp ()
215{
216#if defined(ZMQ_SERVER) && defined(ZMQ_CLIENT)
217 test_client_server (pre_allocate_sock_tcp);
218#endif
219}
220
221void pre_allocate_sock_ipc_int (void *zmq_socket_, const char *path_)
222{
223 struct sockaddr_un addr;
224 addr.sun_family = AF_UNIX;
225 strcpy (addr.sun_path, path_);
226
227 // TODO check return value of unlink
228 unlink (path_);
229
230 setup_socket_and_set_fd (zmq_socket_, AF_UNIX, 0,
231 reinterpret_cast<struct sockaddr *> (&addr),
232 sizeof (struct sockaddr_un));
233}
234
235char ipc_endpoint[16];
236
237void pre_allocate_sock_ipc (void *sb_, char *my_endpoint_)
238{
239 strcpy (ipc_endpoint, "tmpXXXXXX");
240
241#ifdef HAVE_MKDTEMP
242 TEST_ASSERT_TRUE (mkdtemp (ipc_endpoint));
243 strcat (ipc_endpoint, "/ipc");
244#else
245 int fd = mkstemp (ipc_endpoint);
246 TEST_ASSERT_TRUE (fd != -1);
247 close (fd);
248#endif
249
250 pre_allocate_sock_ipc_int (sb_, ipc_endpoint);
251 strcpy (my_endpoint_, "ipc://");
252 strcat (my_endpoint_, ipc_endpoint);
253}
254
255void test_req_rep_ipc ()
256{
257 test_req_rep (pre_allocate_sock_ipc);
258
259 TEST_ASSERT_SUCCESS_ERRNO (unlink (ipc_endpoint));
260}
261
262void test_pair_ipc ()
263{
264 test_pair (pre_allocate_sock_ipc);
265
266 TEST_ASSERT_SUCCESS_ERRNO (unlink (ipc_endpoint));
267}
268
269void test_client_server_ipc ()
270{
271#if defined(ZMQ_SERVER) && defined(ZMQ_CLIENT)
272 test_client_server (pre_allocate_sock_ipc);
273
274 TEST_ASSERT_SUCCESS_ERRNO (unlink (ipc_endpoint));
275#endif
276}
277
278int main ()
279{
280 setup_test_environment ();
281
282 UNITY_BEGIN ();
283 RUN_TEST (test_req_rep_tcp);
284 RUN_TEST (test_pair_tcp);
285 RUN_TEST (test_client_server_tcp);
286
287 RUN_TEST (test_req_rep_ipc);
288 RUN_TEST (test_pair_ipc);
289 RUN_TEST (test_client_server_ipc);
290
291 return UNITY_END ();
292}
293#else
294int main ()
295{
296 return 0;
297}
298#endif
299