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#include <string.h>
34
35SETUP_TEARDOWN_TESTCONTEXT
36
37#ifdef ZMQ_BUILD_DRAFT_API
38bool send_msg_to_peer_if_ready (void *router_, const char *peer_routing_id_)
39{
40 int rc = TEST_ASSERT_SUCCESS_MESSAGE_ERRNO (
41 zmq_socket_get_peer_state (router_, peer_routing_id_, 1),
42 peer_routing_id_);
43 if (rc & ZMQ_POLLOUT) {
44 send_string_expect_success (router_, peer_routing_id_,
45 ZMQ_SNDMORE | ZMQ_DONTWAIT);
46 send_string_expect_success (router_, "Hello", ZMQ_DONTWAIT);
47
48 return true;
49 }
50 return false;
51}
52#endif
53
54void test_get_peer_state ()
55{
56#ifdef ZMQ_BUILD_DRAFT_API
57 void *router = test_context_socket (ZMQ_ROUTER);
58
59 int mandatory = 1;
60 TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (router, ZMQ_ROUTER_MANDATORY,
61 &mandatory, sizeof (mandatory)));
62
63 const char *my_endpoint = "inproc://test_get_peer_state";
64 TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (router, my_endpoint));
65
66 void *dealer1 = test_context_socket (ZMQ_DEALER);
67 void *dealer2 = test_context_socket (ZMQ_DEALER);
68
69 // Lower HWMs to allow doing the test with fewer messages
70 const int hwm = 100;
71 TEST_ASSERT_SUCCESS_ERRNO (
72 zmq_setsockopt (router, ZMQ_SNDHWM, &hwm, sizeof (int)));
73 TEST_ASSERT_SUCCESS_ERRNO (
74 zmq_setsockopt (dealer1, ZMQ_RCVHWM, &hwm, sizeof (int)));
75 TEST_ASSERT_SUCCESS_ERRNO (
76 zmq_setsockopt (dealer2, ZMQ_RCVHWM, &hwm, sizeof (int)));
77
78 const char *dealer1_routing_id = "X";
79 const char *dealer2_routing_id = "Y";
80
81 // Name dealer1 "X" and connect it to our router
82 TEST_ASSERT_SUCCESS_ERRNO (
83 zmq_setsockopt (dealer1, ZMQ_ROUTING_ID, dealer1_routing_id, 1));
84 TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (dealer1, my_endpoint));
85
86 // Name dealer2 "Y" and connect it to our router
87 TEST_ASSERT_SUCCESS_ERRNO (
88 zmq_setsockopt (dealer2, ZMQ_ROUTING_ID, dealer2_routing_id, 1));
89 TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (dealer2, my_endpoint));
90
91 // Get message from both dealers to know when connection is ready
92 send_string_expect_success (dealer1, "Hello", 0);
93 recv_string_expect_success (router, dealer1_routing_id, 0);
94 recv_string_expect_success (router, "Hello", 0);
95
96 send_string_expect_success (dealer2, "Hello", 0);
97 recv_string_expect_success (router, dealer2_routing_id, 0);
98 recv_string_expect_success (router, "Hello", 0);
99
100 void *poller = zmq_poller_new ();
101 TEST_ASSERT_NOT_NULL (poller);
102
103 // Poll on router and dealer1, but not on dealer2
104 TEST_ASSERT_SUCCESS_ERRNO (
105 zmq_poller_add (poller, router, NULL, ZMQ_POLLOUT));
106 TEST_ASSERT_SUCCESS_ERRNO (
107 zmq_poller_add (poller, dealer1, NULL, ZMQ_POLLIN));
108
109 const unsigned int count = 10000;
110 const unsigned int event_size = 2;
111 bool dealer2_blocked = false;
112 unsigned int dealer1_sent = 0, dealer2_sent = 0, dealer1_received = 0;
113 zmq_poller_event_t events[event_size];
114 for (unsigned int iteration = 0; iteration < count; ++iteration) {
115 TEST_ASSERT_SUCCESS_ERRNO (
116 zmq_poller_wait_all (poller, events, event_size, -1));
117 for (unsigned int event_no = 0; event_no < event_size; ++event_no) {
118 const zmq_poller_event_t &current_event = events[event_no];
119 if (current_event.socket == router
120 && current_event.events & ZMQ_POLLOUT) {
121 if (send_msg_to_peer_if_ready (router, dealer1_routing_id))
122 ++dealer1_sent;
123
124 if (send_msg_to_peer_if_ready (router, dealer2_routing_id))
125 ++dealer2_sent;
126 else
127 dealer2_blocked = true;
128 }
129 if (current_event.socket == dealer1
130 && current_event.events & ZMQ_POLLIN) {
131 recv_string_expect_success (dealer1, "Hello", ZMQ_DONTWAIT);
132 int more;
133 size_t more_size = sizeof (more);
134 TEST_ASSERT_SUCCESS_ERRNO (
135 zmq_getsockopt (dealer1, ZMQ_RCVMORE, &more, &more_size));
136 TEST_ASSERT_FALSE (more);
137
138 ++dealer1_received;
139 }
140 // never read from dealer2, so its pipe becomes full eventually
141 }
142 }
143 printf ("dealer1_sent = %u, dealer2_sent = %u, dealer1_received = %u\n",
144 dealer1_sent, dealer2_sent, dealer1_received);
145 TEST_ASSERT_TRUE (dealer2_blocked);
146 zmq_poller_destroy (&poller);
147
148 test_context_socket_close (router);
149 test_context_socket_close (dealer1);
150 test_context_socket_close (dealer2);
151#endif
152}
153
154void test_get_peer_state_corner_cases ()
155{
156#ifdef ZMQ_BUILD_DRAFT_API
157 const char peer_routing_id[] = "foo";
158
159 // call get_peer_state with NULL socket
160 int rc = zmq_socket_get_peer_state (NULL, peer_routing_id,
161 strlen (peer_routing_id));
162 TEST_ASSERT_EQUAL_INT (-1, rc);
163 TEST_ASSERT_EQUAL_INT (ENOTSOCK, errno);
164
165 void *dealer = test_context_socket (ZMQ_DEALER);
166 void *router = test_context_socket (ZMQ_ROUTER);
167
168 // call get_peer_state with a non-ROUTER socket
169 rc = zmq_socket_get_peer_state (dealer, peer_routing_id,
170 strlen (peer_routing_id));
171 TEST_ASSERT_EQUAL_INT (-1, rc);
172 TEST_ASSERT_EQUAL_INT (ENOTSUP, errno);
173
174 // call get_peer_state for an unknown routing id
175 rc = zmq_socket_get_peer_state (router, peer_routing_id,
176 strlen (peer_routing_id));
177 TEST_ASSERT_EQUAL_INT (-1, rc);
178 TEST_ASSERT_EQUAL_INT (EHOSTUNREACH, errno);
179
180 test_context_socket_close (router);
181 test_context_socket_close (dealer);
182#endif
183}
184
185void test_basic ()
186{
187 char my_endpoint[MAX_SOCKET_STRING];
188 void *router = test_context_socket (ZMQ_ROUTER);
189 bind_loopback_ipv4 (router, my_endpoint, sizeof my_endpoint);
190
191 // Send a message to an unknown peer with the default setting
192 // This will not report any error
193 send_string_expect_success (router, "UNKNOWN", ZMQ_SNDMORE);
194 send_string_expect_success (router, "DATA", 0);
195
196 // Send a message to an unknown peer with mandatory routing
197 // This will fail
198 int mandatory = 1;
199 TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (router, ZMQ_ROUTER_MANDATORY,
200 &mandatory, sizeof (mandatory)));
201 int rc = zmq_send (router, "UNKNOWN", 7, ZMQ_SNDMORE);
202 TEST_ASSERT_EQUAL_INT (-1, rc);
203 TEST_ASSERT_EQUAL_INT (EHOSTUNREACH, errno);
204
205 // Create dealer called "X" and connect it to our router
206 void *dealer = test_context_socket (ZMQ_DEALER);
207 TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (dealer, ZMQ_ROUTING_ID, "X", 1));
208 TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (dealer, my_endpoint));
209
210 // Get message from dealer to know when connection is ready
211 send_string_expect_success (dealer, "Hello", 0);
212 recv_string_expect_success (router, "X", 0);
213
214 // Send a message to connected dealer now
215 // It should work
216 send_string_expect_success (router, "X", ZMQ_SNDMORE);
217 send_string_expect_success (router, "Hello", 0);
218
219 test_context_socket_close (router);
220 test_context_socket_close (dealer);
221}
222
223int main (void)
224{
225 setup_test_environment ();
226
227 UNITY_BEGIN ();
228 RUN_TEST (test_basic);
229 RUN_TEST (test_get_peer_state);
230 RUN_TEST (test_get_peer_state_corner_cases);
231
232 return UNITY_END ();
233}
234