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