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#if defined(ZMQ_HAVE_WINDOWS)
34#include <winsock2.h>
35#include <ws2tcpip.h>
36#include <stdexcept>
37#define close closesocket
38#else
39#include <sys/socket.h>
40#include <netinet/in.h>
41#include <arpa/inet.h>
42#include <unistd.h>
43#endif
44
45#include <stdlib.h>
46
47static void zap_handler (void *handler_)
48{
49 // Process ZAP requests forever
50 while (true) {
51 char *version = s_recv (handler_);
52 if (!version)
53 break; // Terminating
54
55 char *sequence = s_recv (handler_);
56 char *domain = s_recv (handler_);
57 char *address = s_recv (handler_);
58 char *routing_id = s_recv (handler_);
59 char *mechanism = s_recv (handler_);
60
61 TEST_ASSERT_EQUAL_STRING ("1.0", version);
62 TEST_ASSERT_EQUAL_STRING ("NULL", mechanism);
63
64 send_string_expect_success (handler_, version, ZMQ_SNDMORE);
65 send_string_expect_success (handler_, sequence, ZMQ_SNDMORE);
66 if (streq (domain, "TEST")) {
67 send_string_expect_success (handler_, "200", ZMQ_SNDMORE);
68 send_string_expect_success (handler_, "OK", ZMQ_SNDMORE);
69 send_string_expect_success (handler_, "anonymous", ZMQ_SNDMORE);
70 send_string_expect_success (handler_, "", 0);
71 } else {
72 send_string_expect_success (handler_, "400", ZMQ_SNDMORE);
73 send_string_expect_success (handler_, "BAD DOMAIN", ZMQ_SNDMORE);
74 send_string_expect_success (handler_, "", ZMQ_SNDMORE);
75 send_string_expect_success (handler_, "", 0);
76 }
77 free (version);
78 free (sequence);
79 free (domain);
80 free (address);
81 free (routing_id);
82 free (mechanism);
83 }
84 close_zero_linger (handler_);
85}
86
87void *zap_thread;
88
89static void setup_zap_handler ()
90{
91 // Spawn ZAP handler
92 // We create and bind ZAP socket in main thread to avoid case
93 // where child thread does not start up fast enough.
94 void *handler = zmq_socket (get_test_context (), ZMQ_REP);
95 TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (handler, "inproc://zeromq.zap.01"));
96 zap_thread = zmq_threadstart (&zap_handler, handler);
97}
98
99static void teardown_zap_handler ()
100{
101 // Wait until ZAP handler terminates
102 zmq_threadclose (zap_thread);
103}
104
105void setUp ()
106{
107 setup_test_context ();
108 setup_zap_handler ();
109}
110
111void tearDown ()
112{
113 teardown_test_context ();
114 teardown_zap_handler ();
115}
116
117void test_no_domain ()
118{
119 // We first test client/server with no ZAP domain
120 // Libzmq does not call our ZAP handler, the connect must succeed
121 void *server = test_context_socket (ZMQ_DEALER);
122 void *client = test_context_socket (ZMQ_DEALER);
123 char my_endpoint[MAX_SOCKET_STRING];
124 bind_loopback_ipv4 (server, my_endpoint, sizeof my_endpoint);
125 TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (client, my_endpoint));
126 bounce (server, client);
127 test_context_socket_close_zero_linger (client);
128 test_context_socket_close_zero_linger (server);
129}
130
131void test_wrong_domain_fails ()
132{
133 // Now define a ZAP domain for the server; this enables
134 // authentication. We're using the wrong domain so this test
135 // must fail.
136 void *server = test_context_socket (ZMQ_DEALER);
137 void *client = test_context_socket (ZMQ_DEALER);
138 TEST_ASSERT_SUCCESS_ERRNO (
139 zmq_setsockopt (server, ZMQ_ZAP_DOMAIN, "WRONG", 5));
140 char my_endpoint[MAX_SOCKET_STRING];
141 bind_loopback_ipv4 (server, my_endpoint, sizeof my_endpoint);
142 TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (client, my_endpoint));
143 expect_bounce_fail (server, client);
144 test_context_socket_close_zero_linger (client);
145 test_context_socket_close_zero_linger (server);
146}
147
148void test_success ()
149{
150 // Now use the right domain, the test must pass
151 void *server = test_context_socket (ZMQ_DEALER);
152 void *client = test_context_socket (ZMQ_DEALER);
153 TEST_ASSERT_SUCCESS_ERRNO (
154 zmq_setsockopt (server, ZMQ_ZAP_DOMAIN, "TEST", 4));
155 char my_endpoint[MAX_SOCKET_STRING];
156 bind_loopback_ipv4 (server, my_endpoint, sizeof my_endpoint);
157 TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (client, my_endpoint));
158 bounce (server, client);
159 test_context_socket_close_zero_linger (client);
160 test_context_socket_close_zero_linger (server);
161}
162
163void test_vanilla_socket ()
164{
165 // Unauthenticated messages from a vanilla socket shouldn't be received
166 void *server = test_context_socket (ZMQ_DEALER);
167 TEST_ASSERT_SUCCESS_ERRNO (
168 zmq_setsockopt (server, ZMQ_ZAP_DOMAIN, "WRONG", 5));
169 char my_endpoint[MAX_SOCKET_STRING];
170 bind_loopback_ipv4 (server, my_endpoint, sizeof my_endpoint);
171
172 struct sockaddr_in ip4addr;
173 fd_t s;
174
175 unsigned short int port;
176 int rc = sscanf (my_endpoint, "tcp://127.0.0.1:%hu", &port);
177 TEST_ASSERT_EQUAL_INT (1, rc);
178
179 ip4addr.sin_family = AF_INET;
180 ip4addr.sin_port = htons (port);
181#if defined(ZMQ_HAVE_WINDOWS) && (_WIN32_WINNT < 0x0600)
182 ip4addr.sin_addr.s_addr = inet_addr ("127.0.0.1");
183#else
184 inet_pton (AF_INET, "127.0.0.1", &ip4addr.sin_addr);
185#endif
186
187 s = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
188 rc = connect (s, reinterpret_cast<struct sockaddr *> (&ip4addr),
189 sizeof ip4addr);
190 TEST_ASSERT_GREATER_THAN_INT (-1, rc);
191 // send anonymous ZMTP/1.0 greeting
192 send (s, "\x01\x00", 2, 0);
193 // send sneaky message that shouldn't be received
194 send (s, "\x08\x00sneaky\0", 9, 0);
195 int timeout = 250;
196 zmq_setsockopt (server, ZMQ_RCVTIMEO, &timeout, sizeof (timeout));
197 char *buf = s_recv (server);
198 if (buf != NULL) {
199 printf ("Received unauthenticated message: %s\n", buf);
200 TEST_ASSERT_NULL (buf);
201 }
202 close (s);
203 test_context_socket_close_zero_linger (server);
204}
205
206int main ()
207{
208 setup_test_environment ();
209
210 UNITY_BEGIN ();
211 RUN_TEST (test_no_domain);
212 RUN_TEST (test_wrong_domain_fails);
213 RUN_TEST (test_success);
214 RUN_TEST (test_vanilla_socket);
215 return UNITY_END ();
216}
217