1 /* 2 * Copyright (c) 2009-2012 Niels Provos and Nick Mathewson 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 3. The name of the author may not be used to endorse or promote products 13 * derived from this software without specific prior written permission. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 #include "util-internal.h" 27 28 #ifdef _WIN32 29 #include <winsock2.h> 30 #include <windows.h> 31 #endif 32 33 #include <sys/types.h> 34 35 #ifndef _WIN32 36 #include <sys/socket.h> 37 #include <netinet/in.h> 38 # ifdef _XOPEN_SOURCE_EXTENDED 39 # include <arpa/inet.h> 40 # endif 41 #include <unistd.h> 42 #endif 43 #ifdef EVENT__HAVE_SYS_RESOURCE_H 44 #include <sys/resource.h> 45 #endif 46 47 #include <string.h> 48 49 #include "event2/listener.h" 50 #include "event2/event.h" 51 #include "event2/util.h" 52 53 #include "regress.h" 54 #include "tinytest.h" 55 #include "tinytest_macros.h" 56 57 static void 58 acceptcb(struct evconnlistener *listener, evutil_socket_t fd, 59 struct sockaddr *addr, int socklen, void *arg) 60 { 61 int *ptr = arg; 62 --*ptr; 63 TT_BLATHER(("Got one for %p", ptr)); 64 evutil_closesocket(fd); 65 66 if (! *ptr) 67 evconnlistener_disable(listener); 68 } 69 70 static void 71 regress_pick_a_port(void *arg) 72 { 73 struct basic_test_data *data = arg; 74 struct event_base *base = data->base; 75 struct evconnlistener *listener1 = NULL, *listener2 = NULL; 76 struct sockaddr_in sin; 77 int count1 = 2, count2 = 1; 78 struct sockaddr_storage ss1, ss2; 79 struct sockaddr_in *sin1, *sin2; 80 ev_socklen_t slen1 = sizeof(ss1), slen2 = sizeof(ss2); 81 unsigned int flags = 82 LEV_OPT_CLOSE_ON_FREE|LEV_OPT_REUSEABLE|LEV_OPT_CLOSE_ON_EXEC; 83 evutil_socket_t fd1, fd2, fd3; 84 85 fd1 = fd2 = fd3 = EVUTIL_INVALID_SOCKET; 86 87 if (data->setup_data && strstr((char*)data->setup_data, "ts")) { 88 flags |= LEV_OPT_THREADSAFE; 89 } 90 91 memset(&sin, 0, sizeof(sin)); 92 sin.sin_family = AF_INET; 93 sin.sin_addr.s_addr = htonl(0x7f000001); /* 127.0.0.1 */ 94 sin.sin_port = 0; /* "You pick!" */ 95 96 listener1 = evconnlistener_new_bind(base, acceptcb, &count1, 97 flags, -1, (struct sockaddr *)&sin, sizeof(sin)); 98 tt_assert(listener1); 99 listener2 = evconnlistener_new_bind(base, acceptcb, &count2, 100 flags, -1, (struct sockaddr *)&sin, sizeof(sin)); 101 tt_assert(listener2); 102 103 tt_assert(evconnlistener_get_fd(listener1) != EVUTIL_INVALID_SOCKET); 104 tt_assert(evconnlistener_get_fd(listener2) != EVUTIL_INVALID_SOCKET); 105 tt_assert(getsockname(evconnlistener_get_fd(listener1), 106 (struct sockaddr*)&ss1, &slen1) == 0); 107 tt_assert(getsockname(evconnlistener_get_fd(listener2), 108 (struct sockaddr*)&ss2, &slen2) == 0); 109 tt_int_op(ss1.ss_family, ==, AF_INET); 110 tt_int_op(ss2.ss_family, ==, AF_INET); 111 112 sin1 = (struct sockaddr_in*)&ss1; 113 sin2 = (struct sockaddr_in*)&ss2; 114 tt_int_op(ntohl(sin1->sin_addr.s_addr), ==, 0x7f000001); 115 tt_int_op(ntohl(sin2->sin_addr.s_addr), ==, 0x7f000001); 116 tt_int_op(sin1->sin_port, !=, sin2->sin_port); 117 118 tt_ptr_op(evconnlistener_get_base(listener1), ==, base); 119 tt_ptr_op(evconnlistener_get_base(listener2), ==, base); 120 121 fd1 = fd2 = fd3 = EVUTIL_INVALID_SOCKET; 122 evutil_socket_connect_(&fd1, (struct sockaddr*)&ss1, slen1); 123 evutil_socket_connect_(&fd2, (struct sockaddr*)&ss1, slen1); 124 evutil_socket_connect_(&fd3, (struct sockaddr*)&ss2, slen2); 125 126 #ifdef _WIN32 127 Sleep(100); /* XXXX this is a stupid stopgap. */ 128 #endif 129 event_base_dispatch(base); 130 131 tt_int_op(count1, ==, 0); 132 tt_int_op(count2, ==, 0); 133 134 end: 135 if (fd1>=0) 136 EVUTIL_CLOSESOCKET(fd1); 137 if (fd2>=0) 138 EVUTIL_CLOSESOCKET(fd2); 139 if (fd3>=0) 140 EVUTIL_CLOSESOCKET(fd3); 141 if (listener1) 142 evconnlistener_free(listener1); 143 if (listener2) 144 evconnlistener_free(listener2); 145 } 146 147 static void 148 errorcb(struct evconnlistener *lis, void *data_) 149 { 150 int *data = data_; 151 *data = 1000; 152 evconnlistener_disable(lis); 153 } 154 155 static void 156 regress_listener_error(void *arg) 157 { 158 struct basic_test_data *data = arg; 159 struct event_base *base = data->base; 160 struct evconnlistener *listener = NULL; 161 int count = 1; 162 unsigned int flags = LEV_OPT_CLOSE_ON_FREE|LEV_OPT_REUSEABLE; 163 164 if (data->setup_data && strstr((char*)data->setup_data, "ts")) { 165 flags |= LEV_OPT_THREADSAFE; 166 } 167 168 /* send, so that pair[0] will look 'readable'*/ 169 tt_int_op(send(data->pair[1], "hello", 5, 0), >, 0); 170 171 /* Start a listener with a bogus socket. */ 172 listener = evconnlistener_new(base, acceptcb, &count, 173 flags, 0, 174 data->pair[0]); 175 tt_assert(listener); 176 177 evconnlistener_set_error_cb(listener, errorcb); 178 179 tt_assert(listener); 180 181 event_base_dispatch(base); 182 tt_int_op(count,==,1000); /* set by error cb */ 183 184 end: 185 if (listener) 186 evconnlistener_free(listener); 187 } 188 189 static void 190 acceptcb_free(struct evconnlistener *listener, evutil_socket_t fd, 191 struct sockaddr *addr, int socklen, void *arg) 192 { 193 int *ptr = arg; 194 --*ptr; 195 TT_BLATHER(("Got one for %p", ptr)); 196 evutil_closesocket(fd); 197 198 if (! *ptr) 199 evconnlistener_free(listener); 200 } 201 static void 202 regress_listener_close_accepted_fd(void *arg) 203 { 204 struct basic_test_data *data = arg; 205 struct event_base *base = data->base; 206 struct evconnlistener *listener = NULL; 207 struct sockaddr_in sin; 208 struct sockaddr_storage ss; 209 ev_socklen_t slen = sizeof(ss); 210 int count = 1; 211 unsigned int flags = LEV_OPT_CLOSE_ON_FREE|LEV_OPT_REUSEABLE; 212 evutil_socket_t fd = EVUTIL_INVALID_SOCKET; 213 214 memset(&sin, 0, sizeof(sin)); 215 sin.sin_family = AF_INET; 216 sin.sin_addr.s_addr = htonl(0x7f000001); /* 127.0.0.1 */ 217 sin.sin_port = 0; /* "You pick!" */ 218 219 /* Start a listener with a bogus socket. */ 220 listener = evconnlistener_new_bind(base, acceptcb_free, &count, 221 flags, -1, (struct sockaddr *)&sin, sizeof(sin)); 222 tt_assert(listener); 223 224 tt_assert(getsockname(evconnlistener_get_fd(listener), 225 (struct sockaddr*)&ss, &slen) == 0); 226 evutil_socket_connect_(&fd, (struct sockaddr*)&ss, slen); 227 228 event_base_dispatch(base); 229 230 end: 231 ; 232 } 233 234 static void 235 regress_listener_immediate_close(void *arg) 236 { 237 struct basic_test_data *data = arg; 238 struct event_base *base = data->base; 239 struct evconnlistener *listener = NULL; 240 struct sockaddr_in sin; 241 struct sockaddr_storage ss; 242 ev_socklen_t slen = sizeof(ss); 243 int count = 1; 244 unsigned int flags = LEV_OPT_CLOSE_ON_FREE|LEV_OPT_REUSEABLE; 245 evutil_socket_t fd1 = EVUTIL_INVALID_SOCKET, fd2 = EVUTIL_INVALID_SOCKET; 246 247 memset(&sin, 0, sizeof(sin)); 248 sin.sin_family = AF_INET; 249 sin.sin_addr.s_addr = htonl(0x7f000001); /* 127.0.0.1 */ 250 sin.sin_port = 0; /* "You pick!" */ 251 252 /* Start a listener with a bogus socket. */ 253 listener = evconnlistener_new_bind(base, acceptcb, &count, 254 flags, -1, (struct sockaddr *)&sin, sizeof(sin)); 255 tt_assert(listener); 256 257 tt_assert(getsockname(evconnlistener_get_fd(listener), 258 (struct sockaddr*)&ss, &slen) == 0); 259 260 evutil_socket_connect_(&fd1, (struct sockaddr*)&ss, slen); 261 evutil_socket_connect_(&fd2, (struct sockaddr*)&ss, slen); 262 263 event_base_dispatch(base); 264 265 tt_int_op(count, ==, 0); 266 267 end: 268 if (listener) 269 evconnlistener_free(listener); 270 } 271 272 #ifdef EVENT__HAVE_SETRLIMIT 273 static void 274 regress_listener_error_unlock(void *arg) 275 { 276 struct basic_test_data *data = arg; 277 struct event_base *base = data->base; 278 struct evconnlistener *listener = NULL; 279 unsigned int flags = 280 LEV_OPT_CLOSE_ON_FREE|LEV_OPT_REUSEABLE|LEV_OPT_THREADSAFE; 281 282 tt_int_op(send(data->pair[1], "hello", 5, 0), >, 0); 283 284 /* Start a listener with a bogus socket. */ 285 listener = evconnlistener_new(base, acceptcb, NULL, flags, 0, data->pair[0]); 286 tt_assert(listener); 287 288 /** accept() must errored out with EMFILE */ 289 { 290 struct rlimit rl; 291 rl.rlim_cur = rl.rlim_max = data->pair[1]; 292 if (setrlimit(RLIMIT_NOFILE, &rl) == -1) { 293 TT_DIE(("Can't change RLIMIT_NOFILE")); 294 } 295 } 296 297 event_base_loop(base, EVLOOP_ONCE); 298 299 /** with lock debugging, can fail on lock->count assertion */ 300 301 end: 302 if (listener) 303 evconnlistener_free(listener); 304 } 305 #endif 306 307 struct testcase_t listener_testcases[] = { 308 309 { "randport", regress_pick_a_port, TT_FORK|TT_NEED_BASE, 310 &basic_setup, NULL}, 311 312 { "randport_ts", regress_pick_a_port, TT_FORK|TT_NEED_BASE, 313 &basic_setup, (char*)"ts"}, 314 315 #ifdef EVENT__HAVE_SETRLIMIT 316 { "error_unlock", regress_listener_error_unlock, 317 TT_FORK|TT_NEED_BASE|TT_NEED_SOCKETPAIR|TT_NO_LOGS, 318 &basic_setup, NULL}, 319 #endif 320 321 { "error", regress_listener_error, 322 TT_FORK|TT_NEED_BASE|TT_NEED_SOCKETPAIR, 323 &basic_setup, NULL}, 324 325 { "error_ts", regress_listener_error, 326 TT_FORK|TT_NEED_BASE|TT_NEED_SOCKETPAIR, 327 &basic_setup, (char*)"ts"}, 328 329 { "close_accepted_fd", regress_listener_close_accepted_fd, 330 TT_FORK|TT_NEED_BASE, &basic_setup, NULL, }, 331 332 { "immediate_close", regress_listener_immediate_close, 333 TT_FORK|TT_NEED_BASE, &basic_setup, NULL, }, 334 335 END_OF_TESTCASES, 336 }; 337 338 struct testcase_t listener_iocp_testcases[] = { 339 { "randport", regress_pick_a_port, 340 TT_FORK|TT_NEED_BASE|TT_ENABLE_IOCP, 341 &basic_setup, NULL}, 342 343 { "error", regress_listener_error, 344 TT_FORK|TT_NEED_BASE|TT_NEED_SOCKETPAIR|TT_ENABLE_IOCP, 345 &basic_setup, NULL}, 346 347 END_OF_TESTCASES, 348 }; 349