xref: /freebsd/contrib/libevent/test/test-fdleak.c (revision c43e99fd14c915adcb7173dd49c31e803ceadfe0)
1*c43e99fdSEd Maste /*
2*c43e99fdSEd Maste  * Copyright (c) 2012 Ross Lagerwall <rosslagerwall@gmail.com>
3*c43e99fdSEd Maste  *
4*c43e99fdSEd Maste  * Redistribution and use in source and binary forms, with or without
5*c43e99fdSEd Maste  * modification, are permitted provided that the following conditions
6*c43e99fdSEd Maste  * are met:
7*c43e99fdSEd Maste  * 1. Redistributions of source code must retain the above copyright
8*c43e99fdSEd Maste  *    notice, this list of conditions and the following disclaimer.
9*c43e99fdSEd Maste  * 2. Redistributions in binary form must reproduce the above copyright
10*c43e99fdSEd Maste  *    notice, this list of conditions and the following disclaimer in the
11*c43e99fdSEd Maste  *    documentation and/or other materials provided with the distribution.
12*c43e99fdSEd Maste  * 3. The name of the author may not be used to endorse or promote products
13*c43e99fdSEd Maste  *    derived from this software without specific prior written permission.
14*c43e99fdSEd Maste  *
15*c43e99fdSEd Maste  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16*c43e99fdSEd Maste  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17*c43e99fdSEd Maste  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18*c43e99fdSEd Maste  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19*c43e99fdSEd Maste  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20*c43e99fdSEd Maste  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21*c43e99fdSEd Maste  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22*c43e99fdSEd Maste  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23*c43e99fdSEd Maste  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24*c43e99fdSEd Maste  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25*c43e99fdSEd Maste  */
26*c43e99fdSEd Maste 
27*c43e99fdSEd Maste #include "event2/event-config.h"
28*c43e99fdSEd Maste 
29*c43e99fdSEd Maste #ifdef _WIN32
30*c43e99fdSEd Maste #define WIN32_LEAN_AND_MEAN
31*c43e99fdSEd Maste #include <windows.h>
32*c43e99fdSEd Maste #endif
33*c43e99fdSEd Maste #include <string.h>
34*c43e99fdSEd Maste #include <stdlib.h>
35*c43e99fdSEd Maste #include <errno.h>
36*c43e99fdSEd Maste #ifdef EVENT__HAVE_SYS_TIME_H
37*c43e99fdSEd Maste #include <sys/time.h>
38*c43e99fdSEd Maste #endif
39*c43e99fdSEd Maste #ifdef EVENT__HAVE_SYS_RESOURCE_H
40*c43e99fdSEd Maste #include <sys/resource.h>
41*c43e99fdSEd Maste #endif
42*c43e99fdSEd Maste #ifdef EVENT__HAVE_NETINET_IN_H
43*c43e99fdSEd Maste #include <netinet/in.h>
44*c43e99fdSEd Maste #endif
45*c43e99fdSEd Maste 
46*c43e99fdSEd Maste #include "event2/event.h"
47*c43e99fdSEd Maste #include "event2/bufferevent.h"
48*c43e99fdSEd Maste #include "event2/buffer.h"
49*c43e99fdSEd Maste #include "event2/listener.h"
50*c43e99fdSEd Maste 
51*c43e99fdSEd Maste /* Number of requests to make. Setting this too high might result in the machine
52*c43e99fdSEd Maste    running out of ephemeral ports */
53*c43e99fdSEd Maste #ifdef _WIN32
54*c43e99fdSEd Maste #define MAX_REQUESTS 1000
55*c43e99fdSEd Maste #else
56*c43e99fdSEd Maste #define MAX_REQUESTS 4000
57*c43e99fdSEd Maste #endif
58*c43e99fdSEd Maste 
59*c43e99fdSEd Maste /* Provide storage for the address, both for the server & the clients */
60*c43e99fdSEd Maste static struct sockaddr_in saddr;
61*c43e99fdSEd Maste 
62*c43e99fdSEd Maste /* Number of sucessful requests so far */
63*c43e99fdSEd Maste static int num_requests;
64*c43e99fdSEd Maste 
65*c43e99fdSEd Maste static void start_client(struct event_base *base);
66*c43e99fdSEd Maste 
67*c43e99fdSEd Maste static void
68*c43e99fdSEd Maste my_perror(const char *s)
69*c43e99fdSEd Maste {
70*c43e99fdSEd Maste 	fprintf(stderr, "%s: %s",
71*c43e99fdSEd Maste 	    s, evutil_socket_error_to_string(EVUTIL_SOCKET_ERROR()));
72*c43e99fdSEd Maste }
73*c43e99fdSEd Maste 
74*c43e99fdSEd Maste /*
75*c43e99fdSEd Maste ===============================================
76*c43e99fdSEd Maste Server functions
77*c43e99fdSEd Maste ===============================================
78*c43e99fdSEd Maste */
79*c43e99fdSEd Maste 
80*c43e99fdSEd Maste /* Read a byte from the client and write it back */
81*c43e99fdSEd Maste static void
82*c43e99fdSEd Maste server_read_cb(struct bufferevent *bev, void *ctx)
83*c43e99fdSEd Maste {
84*c43e99fdSEd Maste 	while (evbuffer_get_length(bufferevent_get_input(bev))) {
85*c43e99fdSEd Maste 		unsigned char tmp;
86*c43e99fdSEd Maste 		bufferevent_read(bev, &tmp, 1);
87*c43e99fdSEd Maste 		bufferevent_write(bev, &tmp, 1);
88*c43e99fdSEd Maste 	}
89*c43e99fdSEd Maste }
90*c43e99fdSEd Maste 
91*c43e99fdSEd Maste /* Wait for an EOF and then free the bufferevent */
92*c43e99fdSEd Maste static void
93*c43e99fdSEd Maste server_event_cb(struct bufferevent *bev, short events, void *ctx)
94*c43e99fdSEd Maste {
95*c43e99fdSEd Maste 	if (events & BEV_EVENT_ERROR) {
96*c43e99fdSEd Maste 		my_perror("Error from bufferevent");
97*c43e99fdSEd Maste 		exit(1);
98*c43e99fdSEd Maste 	} else if (events & (BEV_EVENT_EOF | BEV_EVENT_ERROR)) {
99*c43e99fdSEd Maste 		bufferevent_free(bev);
100*c43e99fdSEd Maste 	}
101*c43e99fdSEd Maste }
102*c43e99fdSEd Maste 
103*c43e99fdSEd Maste /* Accept a client socket and set it up to for reading & writing */
104*c43e99fdSEd Maste static void
105*c43e99fdSEd Maste listener_accept_cb(struct evconnlistener *listener, evutil_socket_t sock,
106*c43e99fdSEd Maste                    struct sockaddr *addr, int len, void *ptr)
107*c43e99fdSEd Maste {
108*c43e99fdSEd Maste 	struct event_base *base = evconnlistener_get_base(listener);
109*c43e99fdSEd Maste 	struct bufferevent *bev = bufferevent_socket_new(base, sock,
110*c43e99fdSEd Maste                                                          BEV_OPT_CLOSE_ON_FREE);
111*c43e99fdSEd Maste 
112*c43e99fdSEd Maste 	bufferevent_setcb(bev, server_read_cb, NULL, server_event_cb, NULL);
113*c43e99fdSEd Maste 	bufferevent_enable(bev, EV_READ|EV_WRITE);
114*c43e99fdSEd Maste }
115*c43e99fdSEd Maste 
116*c43e99fdSEd Maste /* Start the server listening on a random port and start the first client. */
117*c43e99fdSEd Maste static void
118*c43e99fdSEd Maste start_loop(void)
119*c43e99fdSEd Maste {
120*c43e99fdSEd Maste 	struct event_base *base;
121*c43e99fdSEd Maste 	struct evconnlistener *listener;
122*c43e99fdSEd Maste 	struct sockaddr_storage ss;
123*c43e99fdSEd Maste 	ev_socklen_t socklen = sizeof(ss);
124*c43e99fdSEd Maste 	evutil_socket_t fd;
125*c43e99fdSEd Maste 
126*c43e99fdSEd Maste 	base = event_base_new();
127*c43e99fdSEd Maste 	if (base == NULL) {
128*c43e99fdSEd Maste 		puts("Could not open event base!");
129*c43e99fdSEd Maste 		exit(1);
130*c43e99fdSEd Maste 	}
131*c43e99fdSEd Maste 
132*c43e99fdSEd Maste 	listener = evconnlistener_new_bind(base, listener_accept_cb, NULL,
133*c43e99fdSEd Maste 	    LEV_OPT_CLOSE_ON_FREE|LEV_OPT_REUSEABLE,
134*c43e99fdSEd Maste 	    -1, (struct sockaddr *)&saddr, sizeof(saddr));
135*c43e99fdSEd Maste 	if (listener == NULL) {
136*c43e99fdSEd Maste 		my_perror("Could not create listener!");
137*c43e99fdSEd Maste 		exit(1);
138*c43e99fdSEd Maste 	}
139*c43e99fdSEd Maste 	fd = evconnlistener_get_fd(listener);
140*c43e99fdSEd Maste 	if (fd < 0) {
141*c43e99fdSEd Maste 		puts("Couldn't get fd from listener");
142*c43e99fdSEd Maste 		exit(1);
143*c43e99fdSEd Maste 	}
144*c43e99fdSEd Maste 	if (getsockname(fd, (struct sockaddr *)&ss, &socklen) < 0) {
145*c43e99fdSEd Maste 		my_perror("getsockname()");
146*c43e99fdSEd Maste 		exit(1);
147*c43e99fdSEd Maste 	}
148*c43e99fdSEd Maste 	memcpy(&saddr, &ss, sizeof(saddr));
149*c43e99fdSEd Maste 	if (saddr.sin_family != AF_INET) {
150*c43e99fdSEd Maste 		puts("AF mismatch from getsockname().");
151*c43e99fdSEd Maste 		exit(1);
152*c43e99fdSEd Maste 	}
153*c43e99fdSEd Maste 
154*c43e99fdSEd Maste 	start_client(base);
155*c43e99fdSEd Maste 
156*c43e99fdSEd Maste 	event_base_dispatch(base);
157*c43e99fdSEd Maste }
158*c43e99fdSEd Maste 
159*c43e99fdSEd Maste /*
160*c43e99fdSEd Maste ===============================================
161*c43e99fdSEd Maste Client functions
162*c43e99fdSEd Maste ===============================================
163*c43e99fdSEd Maste */
164*c43e99fdSEd Maste 
165*c43e99fdSEd Maste /* Check that the server sends back the same byte that the client sent.
166*c43e99fdSEd Maste    If MAX_REQUESTS have been reached, exit. Otherwise, start another client. */
167*c43e99fdSEd Maste static void
168*c43e99fdSEd Maste client_read_cb(struct bufferevent *bev, void *ctx)
169*c43e99fdSEd Maste {
170*c43e99fdSEd Maste 	unsigned char tmp;
171*c43e99fdSEd Maste 	struct event_base *base = bufferevent_get_base(bev);
172*c43e99fdSEd Maste 
173*c43e99fdSEd Maste 	bufferevent_read(bev, &tmp, 1);
174*c43e99fdSEd Maste 	if (tmp != 'A') {
175*c43e99fdSEd Maste 		puts("Incorrect data received!");
176*c43e99fdSEd Maste 		exit(2);
177*c43e99fdSEd Maste 	}
178*c43e99fdSEd Maste 	bufferevent_free(bev);
179*c43e99fdSEd Maste 
180*c43e99fdSEd Maste 	num_requests++;
181*c43e99fdSEd Maste 	if (num_requests == MAX_REQUESTS) {
182*c43e99fdSEd Maste 		event_base_loopbreak(base);
183*c43e99fdSEd Maste 	} else {
184*c43e99fdSEd Maste 		start_client(base);
185*c43e99fdSEd Maste 	}
186*c43e99fdSEd Maste }
187*c43e99fdSEd Maste 
188*c43e99fdSEd Maste /* Send a byte to the server. */
189*c43e99fdSEd Maste static void
190*c43e99fdSEd Maste client_event_cb(struct bufferevent *bev, short events, void *ctx)
191*c43e99fdSEd Maste {
192*c43e99fdSEd Maste 	if (events & BEV_EVENT_CONNECTED) {
193*c43e99fdSEd Maste 		unsigned char tmp = 'A';
194*c43e99fdSEd Maste 		bufferevent_write(bev, &tmp, 1);
195*c43e99fdSEd Maste 	} else if (events & BEV_EVENT_ERROR) {
196*c43e99fdSEd Maste 		puts("Client socket got error!");
197*c43e99fdSEd Maste 		exit(2);
198*c43e99fdSEd Maste 	}
199*c43e99fdSEd Maste 
200*c43e99fdSEd Maste 	bufferevent_enable(bev, EV_READ);
201*c43e99fdSEd Maste }
202*c43e99fdSEd Maste 
203*c43e99fdSEd Maste /* Open a client socket to connect to localhost on sin */
204*c43e99fdSEd Maste static void
205*c43e99fdSEd Maste start_client(struct event_base *base)
206*c43e99fdSEd Maste {
207*c43e99fdSEd Maste 	struct bufferevent *bev = bufferevent_socket_new(base, -1,
208*c43e99fdSEd Maste                                                          BEV_OPT_CLOSE_ON_FREE);
209*c43e99fdSEd Maste 	bufferevent_setcb(bev, client_read_cb, NULL, client_event_cb, NULL);
210*c43e99fdSEd Maste 
211*c43e99fdSEd Maste 	if (bufferevent_socket_connect(bev, (struct sockaddr *)&saddr,
212*c43e99fdSEd Maste                                        sizeof(saddr)) < 0) {
213*c43e99fdSEd Maste 		my_perror("Could not connect!");
214*c43e99fdSEd Maste 		bufferevent_free(bev);
215*c43e99fdSEd Maste 		exit(2);
216*c43e99fdSEd Maste 	}
217*c43e99fdSEd Maste }
218*c43e99fdSEd Maste 
219*c43e99fdSEd Maste int
220*c43e99fdSEd Maste main(int argc, char **argv)
221*c43e99fdSEd Maste {
222*c43e99fdSEd Maste #ifdef EVENT__HAVE_SETRLIMIT
223*c43e99fdSEd Maste 	/* Set the fd limit to a low value so that any fd leak is caught without
224*c43e99fdSEd Maste 	making many requests. */
225*c43e99fdSEd Maste 	struct rlimit rl;
226*c43e99fdSEd Maste 	rl.rlim_cur = rl.rlim_max = 20;
227*c43e99fdSEd Maste 	if (setrlimit(RLIMIT_NOFILE, &rl) == -1) {
228*c43e99fdSEd Maste 		my_perror("setrlimit");
229*c43e99fdSEd Maste 		exit(3);
230*c43e99fdSEd Maste 	}
231*c43e99fdSEd Maste #endif
232*c43e99fdSEd Maste 
233*c43e99fdSEd Maste #ifdef _WIN32
234*c43e99fdSEd Maste 	WSADATA WSAData;
235*c43e99fdSEd Maste 	WSAStartup(0x101, &WSAData);
236*c43e99fdSEd Maste #endif
237*c43e99fdSEd Maste 
238*c43e99fdSEd Maste 	/* Set up an address, used by both client & server. */
239*c43e99fdSEd Maste 	memset(&saddr, 0, sizeof(saddr));
240*c43e99fdSEd Maste 	saddr.sin_family = AF_INET;
241*c43e99fdSEd Maste 	saddr.sin_addr.s_addr = htonl(0x7f000001);
242*c43e99fdSEd Maste 	saddr.sin_port = 0; /* Tell the implementation to pick a port. */
243*c43e99fdSEd Maste 
244*c43e99fdSEd Maste 	start_loop();
245*c43e99fdSEd Maste 
246*c43e99fdSEd Maste 	return 0;
247*c43e99fdSEd Maste }
248*c43e99fdSEd Maste 
249*c43e99fdSEd Maste /* XXX why does this test cause so much latency sometimes (OSX 10.5)? */
250