test_router_notify.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  1. /*
  2. Copyright (c) 2007-2017 Contributors as noted in the AUTHORS file
  3. This file is part of libzmq, the ZeroMQ core engine in C++.
  4. libzmq is free software; you can redistribute it and/or modify it under
  5. the terms of the GNU Lesser General Public License (LGPL) as published
  6. by the Free Software Foundation; either version 3 of the License, or
  7. (at your option) any later version.
  8. As a special exception, the Contributors give you permission to link
  9. this library with independent modules to produce an executable,
  10. regardless of the license terms of these independent modules, and to
  11. copy and distribute the resulting executable under terms of your choice,
  12. provided that you also meet, for each linked independent module, the
  13. terms and conditions of the license of that module. An independent
  14. module is a module which is not derived from or based on this library.
  15. If you modify this library, you must extend this exception to your
  16. version of the library.
  17. libzmq is distributed in the hope that it will be useful, but WITHOUT
  18. ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  19. FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
  20. License for more details.
  21. You should have received a copy of the GNU Lesser General Public License
  22. along with this program. If not, see <http://www.gnu.org/licenses/>.
  23. */
  24. #include "testutil.hpp"
  25. #include "testutil_unity.hpp"
  26. #include <string.h>
  27. SETUP_TEARDOWN_TESTCONTEXT
  28. void test_sockopt_router_notify ()
  29. {
  30. void *router = test_context_socket (ZMQ_ROUTER);
  31. int opt_notify;
  32. int opt_notify_read;
  33. size_t opt_notify_read_size = sizeof (opt_notify_read);
  34. // default value is off when socket is constructed
  35. TEST_ASSERT_SUCCESS_ERRNO (zmq_getsockopt (
  36. router, ZMQ_ROUTER_NOTIFY, &opt_notify_read, &opt_notify_read_size));
  37. TEST_ASSERT_EQUAL (0, opt_notify_read);
  38. // valid value - Connect
  39. opt_notify = ZMQ_NOTIFY_CONNECT;
  40. TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (
  41. router, ZMQ_ROUTER_NOTIFY, &opt_notify, sizeof (opt_notify)));
  42. TEST_ASSERT_SUCCESS_ERRNO (zmq_getsockopt (
  43. router, ZMQ_ROUTER_NOTIFY, &opt_notify_read, &opt_notify_read_size));
  44. TEST_ASSERT_EQUAL (opt_notify, opt_notify_read);
  45. // valid value - Disconnect
  46. opt_notify = ZMQ_NOTIFY_DISCONNECT;
  47. TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (
  48. router, ZMQ_ROUTER_NOTIFY, &opt_notify, sizeof (opt_notify)));
  49. TEST_ASSERT_SUCCESS_ERRNO (zmq_getsockopt (
  50. router, ZMQ_ROUTER_NOTIFY, &opt_notify_read, &opt_notify_read_size));
  51. TEST_ASSERT_EQUAL (opt_notify, opt_notify_read);
  52. // valid value - Off
  53. opt_notify = 0;
  54. TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (
  55. router, ZMQ_ROUTER_NOTIFY, &opt_notify, sizeof (opt_notify)));
  56. TEST_ASSERT_SUCCESS_ERRNO (zmq_getsockopt (
  57. router, ZMQ_ROUTER_NOTIFY, &opt_notify_read, &opt_notify_read_size));
  58. TEST_ASSERT_EQUAL (opt_notify, opt_notify_read);
  59. // valid value - Both
  60. opt_notify = ZMQ_NOTIFY_CONNECT | ZMQ_NOTIFY_DISCONNECT;
  61. TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (
  62. router, ZMQ_ROUTER_NOTIFY, &opt_notify, sizeof (opt_notify)));
  63. TEST_ASSERT_SUCCESS_ERRNO (zmq_getsockopt (
  64. router, ZMQ_ROUTER_NOTIFY, &opt_notify_read, &opt_notify_read_size));
  65. TEST_ASSERT_EQUAL (opt_notify, opt_notify_read);
  66. // value boundary
  67. opt_notify = -1;
  68. TEST_ASSERT_FAILURE_ERRNO (
  69. EINVAL, zmq_setsockopt (router, ZMQ_ROUTER_NOTIFY, &opt_notify,
  70. sizeof (opt_notify)));
  71. opt_notify = (ZMQ_NOTIFY_CONNECT | ZMQ_NOTIFY_DISCONNECT) + 1;
  72. TEST_ASSERT_FAILURE_ERRNO (
  73. EINVAL, zmq_setsockopt (router, ZMQ_ROUTER_NOTIFY, &opt_notify,
  74. sizeof (opt_notify)));
  75. // failures don't update the value
  76. TEST_ASSERT_SUCCESS_ERRNO (zmq_getsockopt (
  77. router, ZMQ_ROUTER_NOTIFY, &opt_notify_read, &opt_notify_read_size));
  78. TEST_ASSERT_EQUAL (ZMQ_NOTIFY_CONNECT | ZMQ_NOTIFY_DISCONNECT,
  79. opt_notify_read);
  80. test_context_socket_close (router);
  81. // check a non-router socket type
  82. void *dealer = test_context_socket (ZMQ_DEALER);
  83. // setsockopt fails for non-router sockets
  84. opt_notify = ZMQ_NOTIFY_CONNECT;
  85. TEST_ASSERT_FAILURE_ERRNO (
  86. EINVAL, zmq_setsockopt (dealer, ZMQ_ROUTER_NOTIFY, &opt_notify,
  87. sizeof (opt_notify)));
  88. // getsockopts returns off for any non-router socket
  89. TEST_ASSERT_SUCCESS_ERRNO (zmq_getsockopt (
  90. dealer, ZMQ_ROUTER_NOTIFY, &opt_notify_read, &opt_notify_read_size));
  91. TEST_ASSERT_EQUAL (0, opt_notify_read);
  92. test_context_socket_close (dealer);
  93. }
  94. void test_router_notify_helper (int opt_notify_)
  95. {
  96. void *router = test_context_socket (ZMQ_ROUTER);
  97. int opt_more;
  98. size_t opt_more_length = sizeof (opt_more);
  99. int opt_events;
  100. size_t opt_events_length = sizeof (opt_events);
  101. char connect_address[MAX_SOCKET_STRING];
  102. // valid values
  103. TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (
  104. router, ZMQ_ROUTER_NOTIFY, &opt_notify_, sizeof (opt_notify_)));
  105. bind_loopback_ipv4 (router, connect_address, sizeof connect_address);
  106. void *dealer = test_context_socket (ZMQ_DEALER);
  107. const char *dealer_routing_id = "X";
  108. TEST_ASSERT_SUCCESS_ERRNO (
  109. zmq_setsockopt (dealer, ZMQ_ROUTING_ID, dealer_routing_id, 1));
  110. // dealer connects
  111. TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (dealer, connect_address));
  112. // connection notification msg
  113. if (opt_notify_ & ZMQ_NOTIFY_CONNECT) {
  114. // routing-id only message of the connect
  115. recv_string_expect_success (router, dealer_routing_id,
  116. 0); // 1st part: routing-id
  117. recv_string_expect_success (router, "", 0); // 2nd part: empty
  118. TEST_ASSERT_SUCCESS_ERRNO (
  119. zmq_getsockopt (router, ZMQ_RCVMORE, &opt_more, &opt_more_length));
  120. TEST_ASSERT_EQUAL (0, opt_more);
  121. }
  122. // test message from the dealer
  123. send_string_expect_success (dealer, "Hello", 0);
  124. recv_string_expect_success (router, dealer_routing_id, 0);
  125. recv_string_expect_success (router, "Hello", 0);
  126. TEST_ASSERT_SUCCESS_ERRNO (
  127. zmq_getsockopt (router, ZMQ_RCVMORE, &opt_more, &opt_more_length));
  128. TEST_ASSERT_EQUAL (0, opt_more);
  129. // dealer disconnects
  130. TEST_ASSERT_SUCCESS_ERRNO (zmq_disconnect (dealer, connect_address));
  131. // need one more process_commands() (???)
  132. msleep (SETTLE_TIME);
  133. zmq_getsockopt (dealer, ZMQ_EVENTS, &opt_events, &opt_events_length);
  134. // connection notification msg
  135. if (opt_notify_ & ZMQ_NOTIFY_DISCONNECT) {
  136. // routing-id only message of the connect
  137. recv_string_expect_success (router, dealer_routing_id,
  138. 0); // 1st part: routing-id
  139. recv_string_expect_success (router, "", 0); // 2nd part: empty
  140. TEST_ASSERT_SUCCESS_ERRNO (
  141. zmq_getsockopt (router, ZMQ_RCVMORE, &opt_more, &opt_more_length));
  142. TEST_ASSERT_EQUAL (0, opt_more);
  143. }
  144. test_context_socket_close (dealer);
  145. test_context_socket_close (router);
  146. }
  147. void test_router_notify_connect ()
  148. {
  149. test_router_notify_helper (ZMQ_NOTIFY_CONNECT);
  150. }
  151. void test_router_notify_disconnect ()
  152. {
  153. test_router_notify_helper (ZMQ_NOTIFY_DISCONNECT);
  154. }
  155. void test_router_notify_both ()
  156. {
  157. test_router_notify_helper (ZMQ_NOTIFY_CONNECT | ZMQ_NOTIFY_DISCONNECT);
  158. }
  159. void test_handshake_fail ()
  160. {
  161. // setup router socket
  162. void *router = test_context_socket (ZMQ_ROUTER);
  163. int opt_timeout = 200;
  164. int opt_notify = ZMQ_NOTIFY_CONNECT | ZMQ_NOTIFY_DISCONNECT;
  165. char connect_address[MAX_SOCKET_STRING];
  166. // valid values
  167. TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (
  168. router, ZMQ_ROUTER_NOTIFY, &opt_notify, sizeof (opt_notify)));
  169. TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (
  170. router, ZMQ_RCVTIMEO, &opt_timeout, sizeof (opt_timeout)));
  171. bind_loopback_ipv4 (router, connect_address, sizeof connect_address);
  172. // send something on raw tcp
  173. void *stream = test_context_socket (ZMQ_STREAM);
  174. TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (stream, connect_address));
  175. send_string_expect_success (stream, "not-a-handshake", 0);
  176. TEST_ASSERT_SUCCESS_ERRNO (zmq_disconnect (stream, connect_address));
  177. test_context_socket_close (stream);
  178. // no notification delivered
  179. char buffer[255];
  180. TEST_ASSERT_FAILURE_ERRNO (EAGAIN,
  181. zmq_recv (router, buffer, sizeof (buffer), 0));
  182. test_context_socket_close (router);
  183. }
  184. void test_error_during_multipart ()
  185. {
  186. /*
  187. * If the disconnect occurs in the middle of the multipart
  188. * message, the socket should not add the notification at the
  189. * end of the incomplete message. It must discard the incomplete
  190. * message, and delivert the notification as a new message.
  191. */
  192. char connect_address[MAX_SOCKET_STRING];
  193. char long_str[128] = {0};
  194. memset (long_str, '*', sizeof (long_str) - 1);
  195. // setup router
  196. void *router = test_context_socket (ZMQ_ROUTER);
  197. int opt_notify = ZMQ_NOTIFY_DISCONNECT;
  198. TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (
  199. router, ZMQ_ROUTER_NOTIFY, &opt_notify, sizeof (opt_notify)));
  200. int64_t opt_maxmsgsize = 64; // the handshake fails if this is too small
  201. TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (
  202. router, ZMQ_MAXMSGSIZE, &opt_maxmsgsize, sizeof (opt_maxmsgsize)));
  203. bind_loopback_ipv4 (router, connect_address, sizeof connect_address);
  204. // setup dealer
  205. void *dealer = test_context_socket (ZMQ_DEALER);
  206. const char *dealer_routing_id = "X";
  207. TEST_ASSERT_SUCCESS_ERRNO (
  208. zmq_setsockopt (dealer, ZMQ_ROUTING_ID, dealer_routing_id, 1));
  209. TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (dealer, connect_address));
  210. // send multipart message, the 2nd part causes a disconnect.
  211. send_string_expect_success (dealer, "Hello2", ZMQ_SNDMORE);
  212. send_string_expect_success (dealer, long_str, 0);
  213. // disconnect notification
  214. recv_string_expect_success (router, dealer_routing_id, 0);
  215. recv_string_expect_success (router, "", 0);
  216. test_context_socket_close (dealer);
  217. test_context_socket_close (router);
  218. }
  219. int main (void)
  220. {
  221. setup_test_environment ();
  222. UNITY_BEGIN ();
  223. RUN_TEST (test_sockopt_router_notify);
  224. RUN_TEST (test_router_notify_connect);
  225. RUN_TEST (test_router_notify_disconnect);
  226. RUN_TEST (test_router_notify_both);
  227. RUN_TEST (test_handshake_fail);
  228. RUN_TEST (test_error_during_multipart);
  229. return UNITY_END ();
  230. }