| 1 | /* |
| 2 | Copyright (c) 2018 Contributors as noted in the AUTHORS file |
| 3 | |
| 4 | This file is part of 0MQ. |
| 5 | |
| 6 | 0MQ is free software; you can redistribute it and/or modify it under |
| 7 | the terms of the GNU Lesser General Public License as published by |
| 8 | the Free Software Foundation; either version 3 of the License, or |
| 9 | (at your option) any later version. |
| 10 | |
| 11 | 0MQ is distributed in the hope that it will be useful, |
| 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 14 | GNU Lesser General Public License for more details. |
| 15 | |
| 16 | You should have received a copy of the GNU Lesser General Public License |
| 17 | along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 18 | */ |
| 19 | |
| 20 | #include "../tests/testutil.hpp" |
| 21 | |
| 22 | #include <poller.hpp> |
| 23 | #include <i_poll_events.hpp> |
| 24 | #include <ip.hpp> |
| 25 | |
| 26 | #include <unity.h> |
| 27 | |
| 28 | #ifndef _WIN32 |
| 29 | #include <unistd.h> |
| 30 | #define closesocket close |
| 31 | #endif |
| 32 | |
| 33 | void setUp () |
| 34 | { |
| 35 | } |
| 36 | void tearDown () |
| 37 | { |
| 38 | } |
| 39 | |
| 40 | void test_create () |
| 41 | { |
| 42 | zmq::thread_ctx_t thread_ctx; |
| 43 | zmq::poller_t poller (thread_ctx); |
| 44 | } |
| 45 | |
| 46 | #if 0 |
| 47 | // TODO this triggers an assertion. should it be a valid use case? |
| 48 | void test_start_empty () |
| 49 | { |
| 50 | zmq::thread_ctx_t thread_ctx; |
| 51 | zmq::poller_t poller (thread_ctx); |
| 52 | poller.start (); |
| 53 | msleep (SETTLE_TIME); |
| 54 | } |
| 55 | #endif |
| 56 | |
| 57 | struct test_events_t : zmq::i_poll_events |
| 58 | { |
| 59 | test_events_t (zmq::fd_t fd_, zmq::poller_t &poller_) : |
| 60 | _fd (fd_), |
| 61 | _poller (poller_) |
| 62 | { |
| 63 | (void) _fd; |
| 64 | } |
| 65 | |
| 66 | virtual void in_event () |
| 67 | { |
| 68 | _poller.rm_fd (_handle); |
| 69 | _handle = (zmq::poller_t::handle_t) NULL; |
| 70 | |
| 71 | // this must only be incremented after rm_fd |
| 72 | in_events.add (1); |
| 73 | } |
| 74 | |
| 75 | |
| 76 | virtual void out_event () |
| 77 | { |
| 78 | // TODO |
| 79 | } |
| 80 | |
| 81 | |
| 82 | virtual void timer_event (int id_) |
| 83 | { |
| 84 | LIBZMQ_UNUSED (id_); |
| 85 | _poller.rm_fd (_handle); |
| 86 | _handle = (zmq::poller_t::handle_t) NULL; |
| 87 | |
| 88 | // this must only be incremented after rm_fd |
| 89 | timer_events.add (1); |
| 90 | } |
| 91 | |
| 92 | void set_handle (zmq::poller_t::handle_t handle_) { _handle = handle_; } |
| 93 | |
| 94 | zmq::atomic_counter_t in_events, timer_events; |
| 95 | |
| 96 | private: |
| 97 | zmq::fd_t _fd; |
| 98 | zmq::poller_t &_poller; |
| 99 | zmq::poller_t::handle_t _handle; |
| 100 | }; |
| 101 | |
| 102 | void wait_in_events (test_events_t &events_) |
| 103 | { |
| 104 | void *watch = zmq_stopwatch_start (); |
| 105 | while (events_.in_events.get () < 1) { |
| 106 | #ifdef ZMQ_BUILD_DRAFT |
| 107 | TEST_ASSERT_LESS_OR_EQUAL_MESSAGE (SETTLE_TIME, |
| 108 | zmq_stopwatch_intermediate (watch), |
| 109 | "Timeout waiting for in event" ); |
| 110 | #endif |
| 111 | } |
| 112 | zmq_stopwatch_stop (watch); |
| 113 | } |
| 114 | |
| 115 | void wait_timer_events (test_events_t &events_) |
| 116 | { |
| 117 | void *watch = zmq_stopwatch_start (); |
| 118 | while (events_.timer_events.get () < 1) { |
| 119 | #ifdef ZMQ_BUILD_DRAFT |
| 120 | TEST_ASSERT_LESS_OR_EQUAL_MESSAGE (SETTLE_TIME, |
| 121 | zmq_stopwatch_intermediate (watch), |
| 122 | "Timeout waiting for timer event" ); |
| 123 | #endif |
| 124 | } |
| 125 | zmq_stopwatch_stop (watch); |
| 126 | } |
| 127 | |
| 128 | void create_nonblocking_fdpair (zmq::fd_t *r_, zmq::fd_t *w_) |
| 129 | { |
| 130 | int rc = zmq::make_fdpair (r_, w_); |
| 131 | TEST_ASSERT_EQUAL_INT (0, rc); |
| 132 | TEST_ASSERT_NOT_EQUAL (zmq::retired_fd, *r_); |
| 133 | TEST_ASSERT_NOT_EQUAL (zmq::retired_fd, *w_); |
| 134 | zmq::unblock_socket (*r_); |
| 135 | zmq::unblock_socket (*w_); |
| 136 | } |
| 137 | |
| 138 | void send_signal (zmq::fd_t w_) |
| 139 | { |
| 140 | #if defined ZMQ_HAVE_EVENTFD |
| 141 | const uint64_t inc = 1; |
| 142 | ssize_t sz = write (w_, &inc, sizeof (inc)); |
| 143 | assert (sz == sizeof (inc)); |
| 144 | #else |
| 145 | { |
| 146 | char msg[] = "test" ; |
| 147 | int rc = send (w_, msg, sizeof (msg), 0); |
| 148 | assert (rc == sizeof (msg)); |
| 149 | } |
| 150 | #endif |
| 151 | } |
| 152 | |
| 153 | void close_fdpair (zmq::fd_t w_, zmq::fd_t r_) |
| 154 | { |
| 155 | int rc = closesocket (w_); |
| 156 | TEST_ASSERT_EQUAL_INT (0, rc); |
| 157 | #if !defined ZMQ_HAVE_EVENTFD |
| 158 | rc = closesocket (r_); |
| 159 | TEST_ASSERT_EQUAL_INT (0, rc); |
| 160 | #else |
| 161 | LIBZMQ_UNUSED (r_); |
| 162 | #endif |
| 163 | } |
| 164 | |
| 165 | void test_add_fd_and_start_and_receive_data () |
| 166 | { |
| 167 | zmq::thread_ctx_t thread_ctx; |
| 168 | zmq::poller_t poller (thread_ctx); |
| 169 | |
| 170 | zmq::fd_t r, w; |
| 171 | create_nonblocking_fdpair (&r, &w); |
| 172 | |
| 173 | test_events_t events (r, poller); |
| 174 | |
| 175 | zmq::poller_t::handle_t handle = poller.add_fd (r, &events); |
| 176 | events.set_handle (handle); |
| 177 | poller.set_pollin (handle); |
| 178 | poller.start (); |
| 179 | |
| 180 | send_signal (w); |
| 181 | |
| 182 | wait_in_events (events); |
| 183 | |
| 184 | // required cleanup |
| 185 | close_fdpair (w, r); |
| 186 | } |
| 187 | |
| 188 | void test_add_fd_and_remove_by_timer () |
| 189 | { |
| 190 | zmq::fd_t r, w; |
| 191 | create_nonblocking_fdpair (&r, &w); |
| 192 | |
| 193 | zmq::thread_ctx_t thread_ctx; |
| 194 | zmq::poller_t poller (thread_ctx); |
| 195 | |
| 196 | test_events_t events (r, poller); |
| 197 | |
| 198 | zmq::poller_t::handle_t handle = poller.add_fd (r, &events); |
| 199 | events.set_handle (handle); |
| 200 | |
| 201 | poller.add_timer (50, &events, 0); |
| 202 | poller.start (); |
| 203 | |
| 204 | wait_timer_events (events); |
| 205 | |
| 206 | // required cleanup |
| 207 | close_fdpair (w, r); |
| 208 | } |
| 209 | |
| 210 | #ifdef _WIN32 |
| 211 | void test_add_fd_with_pending_failing_connect () |
| 212 | { |
| 213 | zmq::thread_ctx_t thread_ctx; |
| 214 | zmq::poller_t poller (thread_ctx); |
| 215 | |
| 216 | zmq::fd_t bind_socket = socket (AF_INET, SOCK_STREAM, 0); |
| 217 | sockaddr_in addr = {0}; |
| 218 | addr.sin_family = AF_INET; |
| 219 | addr.sin_addr.s_addr = htonl (INADDR_LOOPBACK); |
| 220 | addr.sin_port = 0; |
| 221 | TEST_ASSERT_EQUAL_INT (0, bind (bind_socket, |
| 222 | reinterpret_cast<const sockaddr *> (&addr), |
| 223 | sizeof (addr))); |
| 224 | |
| 225 | int addr_len = static_cast<int> (sizeof (addr)); |
| 226 | TEST_ASSERT_EQUAL_INT (0, getsockname (bind_socket, |
| 227 | reinterpret_cast<sockaddr *> (&addr), |
| 228 | &addr_len)); |
| 229 | |
| 230 | zmq::fd_t connect_socket = socket (AF_INET, SOCK_STREAM, 0); |
| 231 | zmq::unblock_socket (connect_socket); |
| 232 | |
| 233 | TEST_ASSERT_EQUAL_INT ( |
| 234 | -1, connect (connect_socket, reinterpret_cast<const sockaddr *> (&addr), |
| 235 | sizeof (addr))); |
| 236 | TEST_ASSERT_EQUAL_INT (WSAEWOULDBLOCK, WSAGetLastError ()); |
| 237 | |
| 238 | test_events_t events (connect_socket, poller); |
| 239 | |
| 240 | zmq::poller_t::handle_t handle = poller.add_fd (connect_socket, &events); |
| 241 | events.set_handle (handle); |
| 242 | poller.set_pollin (handle); |
| 243 | poller.start (); |
| 244 | |
| 245 | wait_in_events (events); |
| 246 | |
| 247 | int value; |
| 248 | int value_len = sizeof (value); |
| 249 | TEST_ASSERT_EQUAL_INT (0, getsockopt (connect_socket, SOL_SOCKET, SO_ERROR, |
| 250 | reinterpret_cast<char *> (&value), |
| 251 | &value_len)); |
| 252 | TEST_ASSERT_EQUAL_INT (WSAECONNREFUSED, value); |
| 253 | |
| 254 | // required cleanup |
| 255 | close (connect_socket); |
| 256 | close (bind_socket); |
| 257 | } |
| 258 | #endif |
| 259 | |
| 260 | int main (void) |
| 261 | { |
| 262 | UNITY_BEGIN (); |
| 263 | |
| 264 | zmq::initialize_network (); |
| 265 | setup_test_environment (); |
| 266 | |
| 267 | RUN_TEST (test_create); |
| 268 | RUN_TEST (test_add_fd_and_start_and_receive_data); |
| 269 | RUN_TEST (test_add_fd_and_remove_by_timer); |
| 270 | |
| 271 | #if defined _WIN32 |
| 272 | RUN_TEST (test_add_fd_with_pending_failing_connect); |
| 273 | #endif |
| 274 | |
| 275 | zmq::shutdown_network (); |
| 276 | |
| 277 | return UNITY_END (); |
| 278 | } |
| 279 | |