xref: /freebsd/tools/regression/sockets/unix_gc/unix_gc.c (revision b3e7694832e81d7a904a10f525f8797b753bf0d3)
1c8c3fc56SRobert Watson /*-
2c8c3fc56SRobert Watson  * Copyright (c) 2007 Robert N. M. Watson
3c8c3fc56SRobert Watson  * All rights reserved.
4c8c3fc56SRobert Watson  *
5c8c3fc56SRobert Watson  * Redistribution and use in source and binary forms, with or without
6c8c3fc56SRobert Watson  * modification, are permitted provided that the following conditions
7c8c3fc56SRobert Watson  * are met:
8c8c3fc56SRobert Watson  * 1. Redistributions of source code must retain the above copyright
9c8c3fc56SRobert Watson  *    notice, this list of conditions and the following disclaimer.
10c8c3fc56SRobert Watson  * 2. Redistributions in binary form must reproduce the above copyright
11c8c3fc56SRobert Watson  *    notice, this list of conditions and the following disclaimer in the
12c8c3fc56SRobert Watson  *    documentation and/or other materials provided with the distribution.
13c8c3fc56SRobert Watson  *
14c8c3fc56SRobert Watson  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15c8c3fc56SRobert Watson  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16c8c3fc56SRobert Watson  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17c8c3fc56SRobert Watson  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18c8c3fc56SRobert Watson  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19c8c3fc56SRobert Watson  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20c8c3fc56SRobert Watson  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21c8c3fc56SRobert Watson  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22c8c3fc56SRobert Watson  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23c8c3fc56SRobert Watson  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24c8c3fc56SRobert Watson  * SUCH DAMAGE.
25c8c3fc56SRobert Watson  */
26c8c3fc56SRobert Watson 
27c8c3fc56SRobert Watson /*
28c8c3fc56SRobert Watson  * A few regression tests for UNIX domain sockets.  Run from single-user mode
29c8c3fc56SRobert Watson  * as it checks the openfiles sysctl to look for leaks, and we don't want that
30c8c3fc56SRobert Watson  * changing due to other processes doing stuff.
31c8c3fc56SRobert Watson  */
32c8c3fc56SRobert Watson 
33c8c3fc56SRobert Watson #include <sys/types.h>
34c8c3fc56SRobert Watson #include <sys/signal.h>
35c8c3fc56SRobert Watson #include <sys/socket.h>
36c8c3fc56SRobert Watson #include <sys/sysctl.h>
37c8c3fc56SRobert Watson #include <sys/un.h>
38c8c3fc56SRobert Watson #include <sys/wait.h>
39c8c3fc56SRobert Watson 
40c8c3fc56SRobert Watson #include <netinet/in.h>
41c8c3fc56SRobert Watson 
42c8c3fc56SRobert Watson #include <err.h>
43c8c3fc56SRobert Watson #include <errno.h>
44c8c3fc56SRobert Watson #include <fcntl.h>
45c8c3fc56SRobert Watson #include <limits.h>
46c8c3fc56SRobert Watson #include <stdio.h>
47c8c3fc56SRobert Watson #include <stdlib.h>
48c8c3fc56SRobert Watson #include <string.h>
49c8c3fc56SRobert Watson #include <unistd.h>
50c8c3fc56SRobert Watson 
51c8c3fc56SRobert Watson static int forcegc = 1;
52c8c3fc56SRobert Watson static char dpath[PATH_MAX];
53c8c3fc56SRobert Watson static const char *test;
54c8c3fc56SRobert Watson 
55c8c3fc56SRobert Watson static int
getsysctl(const char * name)56b0103260SKonstantin Belousov getsysctl(const char *name)
57c8c3fc56SRobert Watson {
58c8c3fc56SRobert Watson 	size_t len;
59c8c3fc56SRobert Watson 	int i;
60c8c3fc56SRobert Watson 
61c8c3fc56SRobert Watson 	len = sizeof(i);
62b0103260SKonstantin Belousov 	if (sysctlbyname(name, &i, &len, NULL, 0) < 0)
63b0103260SKonstantin Belousov 		err(-1, "%s", name);
64c8c3fc56SRobert Watson 	return (i);
65c8c3fc56SRobert Watson }
66c8c3fc56SRobert Watson 
67c8c3fc56SRobert Watson static int
getopenfiles(void)68b0103260SKonstantin Belousov getopenfiles(void)
69b0103260SKonstantin Belousov {
70b0103260SKonstantin Belousov 
71b0103260SKonstantin Belousov 	return (getsysctl("kern.openfiles"));
72b0103260SKonstantin Belousov }
73b0103260SKonstantin Belousov 
74b0103260SKonstantin Belousov static int
getinflight(void)75c8c3fc56SRobert Watson getinflight(void)
76c8c3fc56SRobert Watson {
77c8c3fc56SRobert Watson 
78b0103260SKonstantin Belousov 	return (getsysctl("net.local.inflight"));
79b0103260SKonstantin Belousov }
80b0103260SKonstantin Belousov 
81b0103260SKonstantin Belousov static int
getdeferred(void)82b0103260SKonstantin Belousov getdeferred(void)
83b0103260SKonstantin Belousov {
84b0103260SKonstantin Belousov 
85b0103260SKonstantin Belousov 	return (getsysctl("net.local.deferred"));
86c8c3fc56SRobert Watson }
87c8c3fc56SRobert Watson 
88c8c3fc56SRobert Watson static void
sendfd(int fd,int fdtosend)89c8c3fc56SRobert Watson sendfd(int fd, int fdtosend)
90c8c3fc56SRobert Watson {
91c8c3fc56SRobert Watson 	struct msghdr mh;
92c8c3fc56SRobert Watson 	struct message { struct cmsghdr msg_hdr; int fd; } m;
93c8c3fc56SRobert Watson 	ssize_t len;
94c8c3fc56SRobert Watson 	int after_inflight, before_inflight;
95c8c3fc56SRobert Watson 
96c8c3fc56SRobert Watson 	before_inflight = getinflight();
97c8c3fc56SRobert Watson 
98c8c3fc56SRobert Watson 	bzero(&mh, sizeof(mh));
99c8c3fc56SRobert Watson 	bzero(&m, sizeof(m));
100c8c3fc56SRobert Watson 	mh.msg_control = &m;
101c8c3fc56SRobert Watson 	mh.msg_controllen = sizeof(m);
102c8c3fc56SRobert Watson 	m.msg_hdr.cmsg_len = sizeof(m);
103c8c3fc56SRobert Watson 	m.msg_hdr.cmsg_level = SOL_SOCKET;
104c8c3fc56SRobert Watson 	m.msg_hdr.cmsg_type = SCM_RIGHTS;
105c8c3fc56SRobert Watson 	m.fd = fdtosend;
106c8c3fc56SRobert Watson 	len = sendmsg(fd, &mh, 0);
107c8c3fc56SRobert Watson 	if (len < 0)
108c8c3fc56SRobert Watson 		err(-1, "%s: sendmsg", test);
109c8c3fc56SRobert Watson 	after_inflight = getinflight();
110c8c3fc56SRobert Watson 	if (after_inflight != before_inflight + 1)
111c8c3fc56SRobert Watson 		errx(-1, "%s: sendfd: before %d after %d\n", test,
112c8c3fc56SRobert Watson 		    before_inflight, after_inflight);
113c8c3fc56SRobert Watson }
114c8c3fc56SRobert Watson 
115c8c3fc56SRobert Watson static void
close2(int fd1,int fd2)116c8c3fc56SRobert Watson close2(int fd1, int fd2)
117c8c3fc56SRobert Watson {
118c8c3fc56SRobert Watson 
119c8c3fc56SRobert Watson 	close(fd1);
120c8c3fc56SRobert Watson 	close(fd2);
121c8c3fc56SRobert Watson }
122c8c3fc56SRobert Watson 
123c8c3fc56SRobert Watson static void
close3(int fd1,int fd2,int fd3)124c8c3fc56SRobert Watson close3(int fd1, int fd2, int fd3)
125c8c3fc56SRobert Watson {
126c8c3fc56SRobert Watson 
127c8c3fc56SRobert Watson 	close2(fd1, fd2);
128c8c3fc56SRobert Watson 	close(fd3);
129c8c3fc56SRobert Watson }
130c8c3fc56SRobert Watson 
131c8c3fc56SRobert Watson static void
close4(int fd1,int fd2,int fd3,int fd4)132c8c3fc56SRobert Watson close4(int fd1, int fd2, int fd3, int fd4)
133c8c3fc56SRobert Watson {
134c8c3fc56SRobert Watson 
135c8c3fc56SRobert Watson 	close2(fd1, fd2);
136c8c3fc56SRobert Watson 	close2(fd3, fd4);
137c8c3fc56SRobert Watson }
138c8c3fc56SRobert Watson 
139c8c3fc56SRobert Watson static void
close5(int fd1,int fd2,int fd3,int fd4,int fd5)140c8c3fc56SRobert Watson close5(int fd1, int fd2, int fd3, int fd4, int fd5)
141c8c3fc56SRobert Watson {
142c8c3fc56SRobert Watson 
143c8c3fc56SRobert Watson 	close3(fd1, fd2, fd3);
144c8c3fc56SRobert Watson 	close2(fd4, fd5);
145c8c3fc56SRobert Watson }
146c8c3fc56SRobert Watson 
147c8c3fc56SRobert Watson static int
my_socket(int domain,int type,int proto)148c8c3fc56SRobert Watson my_socket(int domain, int type, int proto)
149c8c3fc56SRobert Watson {
150c8c3fc56SRobert Watson 	int sock;
151c8c3fc56SRobert Watson 
152c8c3fc56SRobert Watson 	sock = socket(domain, type, proto);
153c8c3fc56SRobert Watson 	if (sock < 0)
154c8c3fc56SRobert Watson 		err(-1, "%s: socket", test);
155c8c3fc56SRobert Watson 	return (sock);
156c8c3fc56SRobert Watson }
157c8c3fc56SRobert Watson 
158c8c3fc56SRobert Watson static void
my_bind(int sock,struct sockaddr * sa,socklen_t len)159c8c3fc56SRobert Watson my_bind(int sock, struct sockaddr *sa, socklen_t len)
160c8c3fc56SRobert Watson {
161c8c3fc56SRobert Watson 
162c8c3fc56SRobert Watson 	if (bind(sock, sa, len) < 0)
163c8c3fc56SRobert Watson 		err(-1, "%s: bind", test);
164c8c3fc56SRobert Watson }
165c8c3fc56SRobert Watson 
166c8c3fc56SRobert Watson static void
my_connect(int sock,struct sockaddr * sa,socklen_t len)167c8c3fc56SRobert Watson my_connect(int sock, struct sockaddr *sa, socklen_t len)
168c8c3fc56SRobert Watson {
169c8c3fc56SRobert Watson 
1700ca4746bSRobert Watson 	if (connect(sock, sa, len) < 0 && errno != EINPROGRESS)
171c8c3fc56SRobert Watson 		err(-1, "%s: connect", test);
172c8c3fc56SRobert Watson }
173c8c3fc56SRobert Watson 
174c8c3fc56SRobert Watson static void
my_listen(int sock,int backlog)175c8c3fc56SRobert Watson my_listen(int sock, int backlog)
176c8c3fc56SRobert Watson {
177c8c3fc56SRobert Watson 
178c8c3fc56SRobert Watson 	if (listen(sock, backlog) < 0)
179c8c3fc56SRobert Watson 		err(-1, "%s: listen", test);
180c8c3fc56SRobert Watson }
181c8c3fc56SRobert Watson 
182c8c3fc56SRobert Watson static void
my_socketpair(int * sv)183c8c3fc56SRobert Watson my_socketpair(int *sv)
184c8c3fc56SRobert Watson {
185c8c3fc56SRobert Watson 
186c8c3fc56SRobert Watson 	if (socketpair(PF_UNIX, SOCK_STREAM, 0, sv) < 0)
187c8c3fc56SRobert Watson 		err(-1, "%s: socketpair", test);
188c8c3fc56SRobert Watson }
189c8c3fc56SRobert Watson 
190c8c3fc56SRobert Watson static void
my_getsockname(int s,struct sockaddr * sa,socklen_t * salen)191c8c3fc56SRobert Watson my_getsockname(int s, struct sockaddr *sa, socklen_t *salen)
192c8c3fc56SRobert Watson {
193c8c3fc56SRobert Watson 
194c8c3fc56SRobert Watson 	if (getsockname(s, sa, salen) < 0)
195c8c3fc56SRobert Watson 		err(-1, "%s: getsockname", test);
196c8c3fc56SRobert Watson }
197c8c3fc56SRobert Watson 
198c8c3fc56SRobert Watson static void
setnonblock(int s)199c8c3fc56SRobert Watson setnonblock(int s)
200c8c3fc56SRobert Watson {
201c8c3fc56SRobert Watson 
202c8c3fc56SRobert Watson 	if (fcntl(s, F_SETFL, O_NONBLOCK) < 0)
203c8c3fc56SRobert Watson 		err(-1, "%s: fcntl(F_SETFL, O_NONBLOCK)", test);
204c8c3fc56SRobert Watson }
205c8c3fc56SRobert Watson 
206c8c3fc56SRobert Watson static void
alloc3fds(int * s,int * sv)207c8c3fc56SRobert Watson alloc3fds(int *s, int *sv)
208c8c3fc56SRobert Watson {
209c8c3fc56SRobert Watson 
210c8c3fc56SRobert Watson 	if ((*s = socket(PF_UNIX, SOCK_STREAM, 0)) < 0)
211c8c3fc56SRobert Watson 		err(-1, "%s: socket", test);
212c8c3fc56SRobert Watson 	if (socketpair(PF_UNIX, SOCK_STREAM, 0, sv) < 0)
213c8c3fc56SRobert Watson 		err(-1, "%s: socketpair", test);
214c8c3fc56SRobert Watson }
215c8c3fc56SRobert Watson 
216c8c3fc56SRobert Watson static void
alloc5fds(int * s,int * sva,int * svb)217c8c3fc56SRobert Watson alloc5fds(int *s, int *sva, int *svb)
218c8c3fc56SRobert Watson {
219c8c3fc56SRobert Watson 
220c8c3fc56SRobert Watson 	if ((*s = socket(PF_UNIX, SOCK_STREAM, 0)) < 0)
221c8c3fc56SRobert Watson 		err(-1, "%s: socket", test);
222c8c3fc56SRobert Watson 	if (socketpair(PF_UNIX, SOCK_STREAM, 0, sva) < 0)
223c8c3fc56SRobert Watson 		err(-1, "%s: socketpair", test);
224c8c3fc56SRobert Watson 	if (socketpair(PF_UNIX, SOCK_STREAM, 0, svb) < 0)
225c8c3fc56SRobert Watson 		err(-1, "%s: socketpair", test);
226c8c3fc56SRobert Watson }
227c8c3fc56SRobert Watson 
228c8c3fc56SRobert Watson static void
save_sysctls(int * before_inflight,int * before_openfiles)229c8c3fc56SRobert Watson save_sysctls(int *before_inflight, int *before_openfiles)
230c8c3fc56SRobert Watson {
231c8c3fc56SRobert Watson 
232c8c3fc56SRobert Watson 	*before_inflight = getinflight();
233c8c3fc56SRobert Watson 	*before_openfiles = getopenfiles();
234c8c3fc56SRobert Watson }
235c8c3fc56SRobert Watson 
236c8c3fc56SRobert Watson /*
237c8c3fc56SRobert Watson  * Try hard to make sure that the GC does in fact run before we test the
238c8c3fc56SRobert Watson  * condition of things.
239c8c3fc56SRobert Watson  */
240c8c3fc56SRobert Watson static void
trigger_gc(void)241c8c3fc56SRobert Watson trigger_gc(void)
242c8c3fc56SRobert Watson {
243c8c3fc56SRobert Watson 	int s;
244c8c3fc56SRobert Watson 
245c8c3fc56SRobert Watson 	if (forcegc) {
246c8c3fc56SRobert Watson 		if ((s = socket(PF_UNIX, SOCK_STREAM, 0)) < 0)
247c8c3fc56SRobert Watson 			err(-1, "trigger_gc: socket");
248c8c3fc56SRobert Watson 		close(s);
249c8c3fc56SRobert Watson 	}
250c8c3fc56SRobert Watson 	sleep(1);
251c8c3fc56SRobert Watson }
252c8c3fc56SRobert Watson 
253c8c3fc56SRobert Watson static void
test_sysctls(int before_inflight,int before_openfiles)254c8c3fc56SRobert Watson test_sysctls(int before_inflight, int before_openfiles)
255c8c3fc56SRobert Watson {
256c8c3fc56SRobert Watson 	int after_inflight, after_openfiles;
257c8c3fc56SRobert Watson 
258c8c3fc56SRobert Watson 	trigger_gc();
259c8c3fc56SRobert Watson 	after_inflight = getinflight();
260c8c3fc56SRobert Watson 	if (after_inflight != before_inflight)
261c8c3fc56SRobert Watson 		warnx("%s: before inflight: %d, after inflight: %d",
262c8c3fc56SRobert Watson 		    test, before_inflight, after_inflight);
263c8c3fc56SRobert Watson 
264c8c3fc56SRobert Watson 	after_openfiles = getopenfiles();
265c8c3fc56SRobert Watson 	if (after_openfiles != before_openfiles)
266c8c3fc56SRobert Watson 		warnx("%s: before: %d, after: %d", test, before_openfiles,
267c8c3fc56SRobert Watson 		    after_openfiles);
268c8c3fc56SRobert Watson }
269c8c3fc56SRobert Watson 
270c8c3fc56SRobert Watson static void
twosome_nothing(void)271c8c3fc56SRobert Watson twosome_nothing(void)
272c8c3fc56SRobert Watson {
273c8c3fc56SRobert Watson 	int inflight, openfiles;
274c8c3fc56SRobert Watson 	int sv[2];
275c8c3fc56SRobert Watson 
276c8c3fc56SRobert Watson 	/*
277c8c3fc56SRobert Watson 	 * Create a pair, close in one order.
278c8c3fc56SRobert Watson 	 */
279c8c3fc56SRobert Watson 	test = "twosome_nothing1";
280c8c3fc56SRobert Watson 	printf("%s\n", test);
281c8c3fc56SRobert Watson 	save_sysctls(&inflight, &openfiles);
282c8c3fc56SRobert Watson 	my_socketpair(sv);
283c8c3fc56SRobert Watson 	close2(sv[0], sv[1]);
284c8c3fc56SRobert Watson 	test_sysctls(inflight, openfiles);
285c8c3fc56SRobert Watson 
286c8c3fc56SRobert Watson 	/*
287c8c3fc56SRobert Watson 	 * Create a pair, close in the other order.
288c8c3fc56SRobert Watson 	 */
289c8c3fc56SRobert Watson 	test = "twosome_nothing2";
290c8c3fc56SRobert Watson 	printf("%s\n", test);
291c8c3fc56SRobert Watson 	save_sysctls(&inflight, &openfiles);
292c8c3fc56SRobert Watson 	my_socketpair(sv);
293c8c3fc56SRobert Watson 	close2(sv[0], sv[1]);
294c8c3fc56SRobert Watson 	test_sysctls(inflight, openfiles);
295c8c3fc56SRobert Watson }
296c8c3fc56SRobert Watson 
297c8c3fc56SRobert Watson /*
298c8c3fc56SRobert Watson  * Using a socket pair, send various endpoints over the pair and close in
299c8c3fc56SRobert Watson  * various orders.
300c8c3fc56SRobert Watson  */
301c8c3fc56SRobert Watson static void
twosome_drop_work(const char * testname,int sendvia,int tosend,int closefirst)302c8c3fc56SRobert Watson twosome_drop_work(const char *testname, int sendvia, int tosend, int closefirst)
303c8c3fc56SRobert Watson {
304c8c3fc56SRobert Watson 	int inflight, openfiles;
305c8c3fc56SRobert Watson 	int sv[2];
306c8c3fc56SRobert Watson 
307c8c3fc56SRobert Watson 	printf("%s\n", testname);
308c8c3fc56SRobert Watson 	test = testname;
309c8c3fc56SRobert Watson 	save_sysctls(&inflight, &openfiles);
310c8c3fc56SRobert Watson 	my_socketpair(sv);
311c8c3fc56SRobert Watson 	sendfd(sv[sendvia], sv[tosend]);
312c8c3fc56SRobert Watson 	if (closefirst == 0)
313c8c3fc56SRobert Watson 		close2(sv[0], sv[1]);
314c8c3fc56SRobert Watson 	else
315c8c3fc56SRobert Watson 		close2(sv[1], sv[0]);
316c8c3fc56SRobert Watson 	test_sysctls(inflight, openfiles);
317c8c3fc56SRobert Watson }
318c8c3fc56SRobert Watson 
319c8c3fc56SRobert Watson static void
twosome_drop(void)320c8c3fc56SRobert Watson twosome_drop(void)
321c8c3fc56SRobert Watson {
322c8c3fc56SRobert Watson 
323c8c3fc56SRobert Watson 	/*
324c8c3fc56SRobert Watson 	 * In various combations, some wastefully symmetric, create socket
325c8c3fc56SRobert Watson 	 * pairs and send one or another endpoint over one or another
326c8c3fc56SRobert Watson 	 * endpoint, closing the endpoints in various orders.
327c8c3fc56SRobert Watson 	 */
328c8c3fc56SRobert Watson 	twosome_drop_work("twosome_drop1", 0, 0, 0);
329c8c3fc56SRobert Watson 	twosome_drop_work("twosome_drop2", 0, 0, 1);
330c8c3fc56SRobert Watson 	twosome_drop_work("twosome_drop3", 0, 1, 0);
331c8c3fc56SRobert Watson 	twosome_drop_work("twosome_drop4", 0, 1, 1);
332c8c3fc56SRobert Watson 	twosome_drop_work("twosome_drop5", 1, 0, 0);
333c8c3fc56SRobert Watson 	twosome_drop_work("twosome_drop6", 1, 0, 1);
334c8c3fc56SRobert Watson 	twosome_drop_work("twosome_drop7", 1, 1, 0);
335c8c3fc56SRobert Watson 	twosome_drop_work("twosome_drop8", 1, 1, 1);
336c8c3fc56SRobert Watson }
337c8c3fc56SRobert Watson 
338c8c3fc56SRobert Watson static void
threesome_nothing(void)339c8c3fc56SRobert Watson threesome_nothing(void)
340c8c3fc56SRobert Watson {
341c8c3fc56SRobert Watson 	int inflight, openfiles;
342c8c3fc56SRobert Watson 	int s, sv[2];
343c8c3fc56SRobert Watson 
344c8c3fc56SRobert Watson 	test = "threesome_nothing";
345c8c3fc56SRobert Watson 	printf("%s\n", test);
346c8c3fc56SRobert Watson 	save_sysctls(&inflight, &openfiles);
347c8c3fc56SRobert Watson 	alloc3fds(&s, sv);
348c8c3fc56SRobert Watson 	close3(s, sv[0], sv[1]);
349c8c3fc56SRobert Watson 	test_sysctls(inflight, openfiles);
350c8c3fc56SRobert Watson }
351c8c3fc56SRobert Watson 
352c8c3fc56SRobert Watson /*
353c8c3fc56SRobert Watson  * threesome_drop: create a pair and a spare, send the spare over the pair, and
354c8c3fc56SRobert Watson  * close in various orders and make sure all the fds went away.
355c8c3fc56SRobert Watson  */
356c8c3fc56SRobert Watson static void
threesome_drop(void)357c8c3fc56SRobert Watson threesome_drop(void)
358c8c3fc56SRobert Watson {
359c8c3fc56SRobert Watson 	int inflight, openfiles;
360c8c3fc56SRobert Watson 	int s, sv[2];
361c8c3fc56SRobert Watson 
362c8c3fc56SRobert Watson 	/*
363c8c3fc56SRobert Watson 	 * threesome_drop1: close sent send receive
364c8c3fc56SRobert Watson 	 */
365c8c3fc56SRobert Watson 	test = "threesome_drop1";
366c8c3fc56SRobert Watson 	printf("%s\n", test);
367c8c3fc56SRobert Watson 	save_sysctls(&inflight, &openfiles);
368c8c3fc56SRobert Watson 	alloc3fds(&s, sv);
369c8c3fc56SRobert Watson 	sendfd(sv[0], s);
370c8c3fc56SRobert Watson 	close3(s, sv[0], sv[1]);
371c8c3fc56SRobert Watson 	test_sysctls(inflight, openfiles);
372c8c3fc56SRobert Watson 
373c8c3fc56SRobert Watson 	/*
374c8c3fc56SRobert Watson 	 * threesome_drop2: close sent receive send
375c8c3fc56SRobert Watson 	 */
376c8c3fc56SRobert Watson 	test = "threesome_drop2";
377c8c3fc56SRobert Watson 	printf("%s\n", test);
378c8c3fc56SRobert Watson 	save_sysctls(&inflight, &openfiles);
379c8c3fc56SRobert Watson 	alloc3fds(&s, sv);
380c8c3fc56SRobert Watson 	sendfd(sv[0], s);
381c8c3fc56SRobert Watson 	close3(s, sv[1], sv[0]);
382c8c3fc56SRobert Watson 	test_sysctls(inflight, openfiles);
383c8c3fc56SRobert Watson 
384c8c3fc56SRobert Watson 	/*
385c8c3fc56SRobert Watson 	 * threesome_drop3: close receive sent send
386c8c3fc56SRobert Watson 	 */
387c8c3fc56SRobert Watson 	test = "threesome_drop3";
388c8c3fc56SRobert Watson 	printf("%s\n", test);
389c8c3fc56SRobert Watson 	save_sysctls(&inflight, &openfiles);
390c8c3fc56SRobert Watson 	alloc3fds(&s, sv);
391c8c3fc56SRobert Watson 	sendfd(sv[0], s);
392c8c3fc56SRobert Watson 	close3(sv[1], s, sv[0]);
393c8c3fc56SRobert Watson 	test_sysctls(inflight, openfiles);
394c8c3fc56SRobert Watson 
395c8c3fc56SRobert Watson 	/*
396c8c3fc56SRobert Watson 	 * threesome_drop4: close receive send sent
397c8c3fc56SRobert Watson 	 */
398c8c3fc56SRobert Watson 	test = "threesome_drop4";
399c8c3fc56SRobert Watson 	printf("%s\n", test);
400c8c3fc56SRobert Watson 	save_sysctls(&inflight, &openfiles);
401c8c3fc56SRobert Watson 	alloc3fds(&s, sv);
402c8c3fc56SRobert Watson 	sendfd(sv[0], s);
403c8c3fc56SRobert Watson 	close3(sv[1], sv[0], s);
404c8c3fc56SRobert Watson 	test_sysctls(inflight, openfiles);
405c8c3fc56SRobert Watson 
406c8c3fc56SRobert Watson 	/*
407c8c3fc56SRobert Watson 	 * threesome_drop5: close send receive sent
408c8c3fc56SRobert Watson 	 */
409c8c3fc56SRobert Watson 	test = "threesome_drop5";
410c8c3fc56SRobert Watson 	printf("%s\n", test);
411c8c3fc56SRobert Watson 	save_sysctls(&inflight, &openfiles);
412c8c3fc56SRobert Watson 	alloc3fds(&s, sv);
413c8c3fc56SRobert Watson 	sendfd(sv[0], s);
414c8c3fc56SRobert Watson 	close3(sv[0], sv[1], s);
415c8c3fc56SRobert Watson 	test_sysctls(inflight, openfiles);
416c8c3fc56SRobert Watson 
417c8c3fc56SRobert Watson 	/*
418c8c3fc56SRobert Watson 	 * threesome_drop6: close send sent receive
419c8c3fc56SRobert Watson 	 */
420c8c3fc56SRobert Watson 	test = "threesome_drop6";
421c8c3fc56SRobert Watson 	printf("%s\n", test);
422c8c3fc56SRobert Watson 	save_sysctls(&inflight, &openfiles);
423c8c3fc56SRobert Watson 	alloc3fds(&s, sv);
424c8c3fc56SRobert Watson 	close3(sv[0], s, sv[1]);
425c8c3fc56SRobert Watson 	test_sysctls(inflight, openfiles);
426c8c3fc56SRobert Watson }
427c8c3fc56SRobert Watson 
428c8c3fc56SRobert Watson /*
429c8c3fc56SRobert Watson  * Fivesome tests: create two socket pairs and a spare, send the spare over
430c8c3fc56SRobert Watson  * the first socket pair, then send the first socket pair over the second
431c8c3fc56SRobert Watson  * socket pair, and GC.  Do various closes at various points to exercise
432c8c3fc56SRobert Watson  * various cases.
433c8c3fc56SRobert Watson  */
434c8c3fc56SRobert Watson static void
fivesome_nothing(void)435c8c3fc56SRobert Watson fivesome_nothing(void)
436c8c3fc56SRobert Watson {
437c8c3fc56SRobert Watson 	int inflight, openfiles;
438c8c3fc56SRobert Watson 	int spare, sva[2], svb[2];
439c8c3fc56SRobert Watson 
440c8c3fc56SRobert Watson 	test = "fivesome_nothing";
441c8c3fc56SRobert Watson 	printf("%s\n", test);
442c8c3fc56SRobert Watson 	save_sysctls(&inflight, &openfiles);
443c8c3fc56SRobert Watson 	alloc5fds(&spare, sva, svb);
444c8c3fc56SRobert Watson 	close5(spare, sva[0], sva[1], svb[0], svb[1]);
445c8c3fc56SRobert Watson 	test_sysctls(inflight, openfiles);
446c8c3fc56SRobert Watson }
447c8c3fc56SRobert Watson 
448c8c3fc56SRobert Watson static void
fivesome_drop_work(const char * testname,int close_spare_after_send,int close_sva_after_send)449c8c3fc56SRobert Watson fivesome_drop_work(const char *testname, int close_spare_after_send,
450c8c3fc56SRobert Watson     int close_sva_after_send)
451c8c3fc56SRobert Watson {
452c8c3fc56SRobert Watson 	int inflight, openfiles;
453c8c3fc56SRobert Watson 	int spare, sva[2], svb[2];
454c8c3fc56SRobert Watson 
455c8c3fc56SRobert Watson 	printf("%s\n", testname);
456c8c3fc56SRobert Watson 	test = testname;
457c8c3fc56SRobert Watson 	save_sysctls(&inflight, &openfiles);
458c8c3fc56SRobert Watson 	alloc5fds(&spare, sva, svb);
459c8c3fc56SRobert Watson 
460c8c3fc56SRobert Watson 	/*
461c8c3fc56SRobert Watson 	 * Send spare over sva.
462c8c3fc56SRobert Watson 	 */
463c8c3fc56SRobert Watson 	sendfd(sva[0], spare);
464c8c3fc56SRobert Watson 	if (close_spare_after_send)
465c8c3fc56SRobert Watson 		close(spare);
466c8c3fc56SRobert Watson 
467c8c3fc56SRobert Watson 	/*
468c8c3fc56SRobert Watson 	 * Send sva over svb.
469c8c3fc56SRobert Watson 	 */
470c8c3fc56SRobert Watson 	sendfd(svb[0], sva[0]);
471c8c3fc56SRobert Watson 	sendfd(svb[0], sva[1]);
472c8c3fc56SRobert Watson 	if (close_sva_after_send)
473c8c3fc56SRobert Watson 		close2(sva[0], sva[1]);
474c8c3fc56SRobert Watson 
475c8c3fc56SRobert Watson 	close2(svb[0], svb[1]);
476c8c3fc56SRobert Watson 
477c8c3fc56SRobert Watson 	if (!close_sva_after_send)
478c8c3fc56SRobert Watson 		close2(sva[0], sva[1]);
479c8c3fc56SRobert Watson 	if (!close_spare_after_send)
480c8c3fc56SRobert Watson 		close(spare);
481c8c3fc56SRobert Watson 
482c8c3fc56SRobert Watson 	test_sysctls(inflight, openfiles);
483c8c3fc56SRobert Watson }
484c8c3fc56SRobert Watson 
485c8c3fc56SRobert Watson static void
fivesome_drop(void)486c8c3fc56SRobert Watson fivesome_drop(void)
487c8c3fc56SRobert Watson {
488c8c3fc56SRobert Watson 
489c8c3fc56SRobert Watson 	fivesome_drop_work("fivesome_drop1", 0, 0);
490c8c3fc56SRobert Watson 	fivesome_drop_work("fivesome_drop2", 0, 1);
491c8c3fc56SRobert Watson 	fivesome_drop_work("fivesome_drop3", 1, 0);
492c8c3fc56SRobert Watson 	fivesome_drop_work("fivesome_drop4", 1, 1);
493c8c3fc56SRobert Watson }
494c8c3fc56SRobert Watson 
495c8c3fc56SRobert Watson /*
496c8c3fc56SRobert Watson  * Create a somewhat nasty dual-socket socket intended to upset the garbage
497c8c3fc56SRobert Watson  * collector if mark-and-sweep is wrong.
498c8c3fc56SRobert Watson  */
499c8c3fc56SRobert Watson static void
complex_cycles(void)500c8c3fc56SRobert Watson complex_cycles(void)
501c8c3fc56SRobert Watson {
502c8c3fc56SRobert Watson 	int inflight, openfiles;
503c8c3fc56SRobert Watson 	int spare, sva[2], svb[2];
504c8c3fc56SRobert Watson 
505c8c3fc56SRobert Watson 	test = "complex_cycles";
506c8c3fc56SRobert Watson 	printf("%s\n", test);
507c8c3fc56SRobert Watson 	save_sysctls(&inflight, &openfiles);
508c8c3fc56SRobert Watson 	alloc5fds(&spare, sva, svb);
509c8c3fc56SRobert Watson 	sendfd(sva[0], svb[0]);
510c8c3fc56SRobert Watson 	sendfd(sva[0], svb[1]);
511c8c3fc56SRobert Watson 	sendfd(svb[0], sva[0]);
512c8c3fc56SRobert Watson 	sendfd(svb[0], sva[1]);
513c8c3fc56SRobert Watson 	sendfd(svb[0], spare);
514c8c3fc56SRobert Watson 	sendfd(sva[0], spare);
515c8c3fc56SRobert Watson 	close5(spare, sva[0], sva[1], svb[0], svb[1]);
516c8c3fc56SRobert Watson 	test_sysctls(inflight, openfiles);
517c8c3fc56SRobert Watson }
518c8c3fc56SRobert Watson 
519c8c3fc56SRobert Watson /*
520c8c3fc56SRobert Watson  * Listen sockets can also be passed over UNIX domain sockets, so test
521c8c3fc56SRobert Watson  * various cases, including ones where listen sockets have waiting sockets
522c8c3fc56SRobert Watson  * hanging off them...
523c8c3fc56SRobert Watson  */
524c8c3fc56SRobert Watson static void
listen_nothing(void)525c8c3fc56SRobert Watson listen_nothing(void)
526c8c3fc56SRobert Watson {
527c8c3fc56SRobert Watson 	struct sockaddr_un sun;
528c8c3fc56SRobert Watson 	struct sockaddr_in sin;
529c8c3fc56SRobert Watson 	int inflight, openfiles;
530c8c3fc56SRobert Watson 	int s;
531c8c3fc56SRobert Watson 
532c8c3fc56SRobert Watson 	test = "listen_nothing_unp";
533c8c3fc56SRobert Watson 	printf("%s\n", test);
534c8c3fc56SRobert Watson 	bzero(&sun, sizeof(sun));
535c8c3fc56SRobert Watson 	sun.sun_family = AF_LOCAL;
536c8c3fc56SRobert Watson 	sun.sun_len = sizeof(sun);
537c8c3fc56SRobert Watson 	snprintf(sun.sun_path, sizeof(sun.sun_path), "%s/%s", dpath, test);
538c8c3fc56SRobert Watson 	save_sysctls(&inflight, &openfiles);
539c8c3fc56SRobert Watson 	s = my_socket(PF_LOCAL, SOCK_STREAM, 0);
540c8c3fc56SRobert Watson 	my_bind(s, (struct sockaddr *)&sun, sizeof(sun));
541c8c3fc56SRobert Watson 	my_listen(s, -1);
542c8c3fc56SRobert Watson 	close(s);
543c8c3fc56SRobert Watson 	(void)unlink(sun.sun_path);
544c8c3fc56SRobert Watson 	test_sysctls(inflight, openfiles);
545c8c3fc56SRobert Watson 
546c8c3fc56SRobert Watson 	test = "listen_nothing_inet";
547c8c3fc56SRobert Watson 	printf("%s\n", test);
548c8c3fc56SRobert Watson 	bzero(&sin, sizeof(sin));
549c8c3fc56SRobert Watson 	sin.sin_family = AF_INET;
550c8c3fc56SRobert Watson 	sin.sin_len = sizeof(sin);
551c8c3fc56SRobert Watson 	sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
552c8c3fc56SRobert Watson 	sin.sin_port = htons(0);
553c8c3fc56SRobert Watson 	save_sysctls(&inflight, &openfiles);
554c8c3fc56SRobert Watson 	s = my_socket(PF_INET, SOCK_STREAM, 0);
555c8c3fc56SRobert Watson 	my_bind(s, (struct sockaddr *)&sin, sizeof(sin));
556c8c3fc56SRobert Watson 	my_listen(s, -1);
557c8c3fc56SRobert Watson 	close(s);
558c8c3fc56SRobert Watson 	test_sysctls(inflight, openfiles);
559c8c3fc56SRobert Watson }
560c8c3fc56SRobert Watson 
561c8c3fc56SRobert Watson /*
562c8c3fc56SRobert Watson  * Send a listen UDP socket over a UNIX domain socket.
563c8c3fc56SRobert Watson  *
564c8c3fc56SRobert Watson  * Send a listen TCP socket over a UNIX domain socket.
565c8c3fc56SRobert Watson  *
566c8c3fc56SRobert Watson  * Do each twice, with closing of the listen socket vs. socketpair in
567c8c3fc56SRobert Watson  * different orders.
568c8c3fc56SRobert Watson  */
569c8c3fc56SRobert Watson static void
listen_drop(void)570c8c3fc56SRobert Watson listen_drop(void)
571c8c3fc56SRobert Watson {
572c8c3fc56SRobert Watson 	struct sockaddr_un sun;
573c8c3fc56SRobert Watson 	struct sockaddr_in sin;
574c8c3fc56SRobert Watson 	int inflight, openfiles;
575c8c3fc56SRobert Watson 	int s, sv[2];
576c8c3fc56SRobert Watson 
577c8c3fc56SRobert Watson 	bzero(&sun, sizeof(sun));
578c8c3fc56SRobert Watson 	sun.sun_family = AF_LOCAL;
579c8c3fc56SRobert Watson 	sun.sun_len = sizeof(sun);
580c8c3fc56SRobert Watson 
581c8c3fc56SRobert Watson 	/*
582c8c3fc56SRobert Watson 	 * Close listen socket first.
583c8c3fc56SRobert Watson 	 */
584c8c3fc56SRobert Watson 	test = "listen_drop_unp1";
585c8c3fc56SRobert Watson 	printf("%s\n", test);
586c8c3fc56SRobert Watson 	snprintf(sun.sun_path, sizeof(sun.sun_path), "%s/%s", dpath, test);
587c8c3fc56SRobert Watson 	save_sysctls(&inflight, &openfiles);
588c8c3fc56SRobert Watson 	s = my_socket(PF_LOCAL, SOCK_STREAM, 0);
589c8c3fc56SRobert Watson 	my_bind(s, (struct sockaddr *)&sun, sizeof(sun));
590c8c3fc56SRobert Watson 	my_listen(s, -1);
591c8c3fc56SRobert Watson 	my_socketpair(sv);
592c8c3fc56SRobert Watson 	sendfd(sv[0], s);
593c8c3fc56SRobert Watson 	close3(s, sv[0], sv[1]);
594c8c3fc56SRobert Watson 	test_sysctls(inflight, openfiles);
595c8c3fc56SRobert Watson 
596c8c3fc56SRobert Watson 	/*
597c8c3fc56SRobert Watson 	 * Close socketpair first.
598c8c3fc56SRobert Watson 	 */
599c8c3fc56SRobert Watson 	test = "listen_drop_unp2";
600c8c3fc56SRobert Watson 	printf("%s\n", test);
601c8c3fc56SRobert Watson 	snprintf(sun.sun_path, sizeof(sun.sun_path), "%s/%s", dpath, test);
602c8c3fc56SRobert Watson 	save_sysctls(&inflight, &openfiles);
603c8c3fc56SRobert Watson 	s = my_socket(PF_LOCAL, SOCK_STREAM, 0);
604c8c3fc56SRobert Watson 	my_bind(s, (struct sockaddr *)&sun, sizeof(sun));
605c8c3fc56SRobert Watson 	my_listen(s, -1);
606c8c3fc56SRobert Watson 	my_socketpair(sv);
607c8c3fc56SRobert Watson 	sendfd(sv[0], s);
608c8c3fc56SRobert Watson 	close3(sv[0], sv[1], s);
609c8c3fc56SRobert Watson 	test_sysctls(inflight, openfiles);
610c8c3fc56SRobert Watson 
611c8c3fc56SRobert Watson 	sin.sin_family = AF_INET;
612c8c3fc56SRobert Watson 	sin.sin_len = sizeof(sin);
613c8c3fc56SRobert Watson 	sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
614c8c3fc56SRobert Watson 	sin.sin_port = htons(0);
615c8c3fc56SRobert Watson 
616c8c3fc56SRobert Watson 	/*
617c8c3fc56SRobert Watson 	 * Close listen socket first.
618c8c3fc56SRobert Watson 	 */
619c8c3fc56SRobert Watson 	test = "listen_drop_inet1";
620c8c3fc56SRobert Watson 	printf("%s\n", test);
621c8c3fc56SRobert Watson 	bzero(&sun, sizeof(sun));
622c8c3fc56SRobert Watson 	save_sysctls(&inflight, &openfiles);
623c8c3fc56SRobert Watson 	s = my_socket(PF_INET, SOCK_STREAM, 0);
624c8c3fc56SRobert Watson 	my_bind(s, (struct sockaddr *)&sin, sizeof(sin));
625c8c3fc56SRobert Watson 	my_listen(s, -1);
626c8c3fc56SRobert Watson 	my_socketpair(sv);
627c8c3fc56SRobert Watson 	sendfd(sv[0], s);
628c8c3fc56SRobert Watson 	close3(s, sv[0], sv[1]);
629c8c3fc56SRobert Watson 	test_sysctls(inflight, openfiles);
630c8c3fc56SRobert Watson 
631c8c3fc56SRobert Watson 	/*
632c8c3fc56SRobert Watson 	 * Close socketpair first.
633c8c3fc56SRobert Watson 	 */
634c8c3fc56SRobert Watson 	test = "listen_drop_inet2";
635c8c3fc56SRobert Watson 	printf("%s\n", test);
636c8c3fc56SRobert Watson 	bzero(&sun, sizeof(sun));
637c8c3fc56SRobert Watson 	save_sysctls(&inflight, &openfiles);
638c8c3fc56SRobert Watson 	s = my_socket(PF_INET, SOCK_STREAM, 0);
639c8c3fc56SRobert Watson 	my_bind(s, (struct sockaddr *)&sin, sizeof(sin));
640c8c3fc56SRobert Watson 	my_listen(s, -1);
641c8c3fc56SRobert Watson 	my_socketpair(sv);
642c8c3fc56SRobert Watson 	sendfd(sv[0], s);
643c8c3fc56SRobert Watson 	close3(sv[0], sv[1], s);
644c8c3fc56SRobert Watson 	test_sysctls(inflight, openfiles);
645c8c3fc56SRobert Watson }
646c8c3fc56SRobert Watson 
647c8c3fc56SRobert Watson /*
648c8c3fc56SRobert Watson  * Up things a notch with listen sockets: add connections that can be
649c8c3fc56SRobert Watson  * accepted to the listen queues.
650c8c3fc56SRobert Watson  */
651c8c3fc56SRobert Watson static void
listen_connect_nothing(void)652c8c3fc56SRobert Watson listen_connect_nothing(void)
653c8c3fc56SRobert Watson {
654c8c3fc56SRobert Watson 	struct sockaddr_in sin;
655c8c3fc56SRobert Watson 	int slisten, sconnect, sv[2];
656c8c3fc56SRobert Watson 	int inflight, openfiles;
657c8c3fc56SRobert Watson 	socklen_t len;
658c8c3fc56SRobert Watson 
659c8c3fc56SRobert Watson 	test = "listen_connect_nothing";
660c8c3fc56SRobert Watson 	printf("%s\n", test);
661c8c3fc56SRobert Watson 	save_sysctls(&inflight, &openfiles);
662c8c3fc56SRobert Watson 
663c8c3fc56SRobert Watson 	slisten = my_socket(PF_INET, SOCK_STREAM, 0);
664c8c3fc56SRobert Watson 	my_bind(slisten, (struct sockaddr *)&sin, sizeof(sin));
665c8c3fc56SRobert Watson 	my_listen(slisten, -1);
666c8c3fc56SRobert Watson 
667c8c3fc56SRobert Watson 	my_socketpair(sv);
668c8c3fc56SRobert Watson 
669c8c3fc56SRobert Watson 	len = sizeof(sin);
670c8c3fc56SRobert Watson 	my_getsockname(slisten, (struct sockaddr *)&sin, &len);
671c8c3fc56SRobert Watson 
672c8c3fc56SRobert Watson 	sconnect = my_socket(PF_INET, SOCK_STREAM, 0);
673c8c3fc56SRobert Watson 	setnonblock(sconnect);
674c8c3fc56SRobert Watson 	my_connect(sconnect, (struct sockaddr *)&sin, len);
675c8c3fc56SRobert Watson 
676c8c3fc56SRobert Watson 	sleep(1);
677c8c3fc56SRobert Watson 
678c8c3fc56SRobert Watson 	close4(slisten, sconnect, sv[0], sv[1]);
679c8c3fc56SRobert Watson 
680c8c3fc56SRobert Watson 	test_sysctls(inflight, openfiles);
681c8c3fc56SRobert Watson }
682c8c3fc56SRobert Watson 
683c8c3fc56SRobert Watson static void
listen_connect_drop(void)684c8c3fc56SRobert Watson listen_connect_drop(void)
685c8c3fc56SRobert Watson {
686c8c3fc56SRobert Watson 	struct sockaddr_in sin;
687c8c3fc56SRobert Watson 	int slisten, sconnect, sv[2];
688c8c3fc56SRobert Watson 	int inflight, openfiles;
689c8c3fc56SRobert Watson 	socklen_t len;
690c8c3fc56SRobert Watson 
691c8c3fc56SRobert Watson 	test = "listen_connect_drop";
692c8c3fc56SRobert Watson 	printf("%s\n", test);
693c8c3fc56SRobert Watson 	save_sysctls(&inflight, &openfiles);
694c8c3fc56SRobert Watson 
695c8c3fc56SRobert Watson 	slisten = my_socket(PF_INET, SOCK_STREAM, 0);
696c8c3fc56SRobert Watson 	my_bind(slisten, (struct sockaddr *)&sin, sizeof(sin));
697c8c3fc56SRobert Watson 	my_listen(slisten, -1);
698c8c3fc56SRobert Watson 
699c8c3fc56SRobert Watson 	my_socketpair(sv);
700c8c3fc56SRobert Watson 
701c8c3fc56SRobert Watson 	len = sizeof(sin);
702c8c3fc56SRobert Watson 	my_getsockname(slisten, (struct sockaddr *)&sin, &len);
703c8c3fc56SRobert Watson 
704c8c3fc56SRobert Watson 	sconnect = my_socket(PF_INET, SOCK_STREAM, 0);
705c8c3fc56SRobert Watson 	setnonblock(sconnect);
706c8c3fc56SRobert Watson 	my_connect(sconnect, (struct sockaddr *)&sin, len);
707c8c3fc56SRobert Watson 
708c8c3fc56SRobert Watson 	sleep(1);
709c8c3fc56SRobert Watson 	sendfd(sv[0], slisten);
710c8c3fc56SRobert Watson 	close3(slisten, sv[0], sv[1]);
711c8c3fc56SRobert Watson 	sleep(1);
712c8c3fc56SRobert Watson 	close(sconnect);
713c8c3fc56SRobert Watson 
714c8c3fc56SRobert Watson 	test_sysctls(inflight, openfiles);
715c8c3fc56SRobert Watson }
716c8c3fc56SRobert Watson 
717b0103260SKonstantin Belousov static void
recursion(void)718b0103260SKonstantin Belousov recursion(void)
719b0103260SKonstantin Belousov {
720b0103260SKonstantin Belousov 	int fd[2], ff[2];
721b0103260SKonstantin Belousov 	int inflight, openfiles, deferred, deferred1;
722b0103260SKonstantin Belousov 
723b0103260SKonstantin Belousov 	test = "recursion";
724b0103260SKonstantin Belousov 	printf("%s\n", test);
725b0103260SKonstantin Belousov 	save_sysctls(&inflight, &openfiles);
726b0103260SKonstantin Belousov 	deferred = getdeferred();
727b0103260SKonstantin Belousov 
728b0103260SKonstantin Belousov 	my_socketpair(fd);
729b0103260SKonstantin Belousov 
730b0103260SKonstantin Belousov 	for (;;) {
731b0103260SKonstantin Belousov 		if (socketpair(PF_UNIX, SOCK_STREAM, 0, ff) == -1) {
732b0103260SKonstantin Belousov 			if (errno == EMFILE || errno == ENFILE)
733b0103260SKonstantin Belousov 				break;
734b0103260SKonstantin Belousov 			err(-1, "socketpair");
735b0103260SKonstantin Belousov 		}
736b0103260SKonstantin Belousov 		sendfd(ff[0], fd[0]);
737b0103260SKonstantin Belousov 		sendfd(ff[0], fd[1]);
738b0103260SKonstantin Belousov 		close2(fd[1], fd[0]);
739b0103260SKonstantin Belousov 		fd[0] = ff[0];
740b0103260SKonstantin Belousov 		fd[1] = ff[1];
741b0103260SKonstantin Belousov 	}
742b0103260SKonstantin Belousov 	close2(fd[0], fd[1]);
743b0103260SKonstantin Belousov 	sleep(1);
744b0103260SKonstantin Belousov 	test_sysctls(inflight, openfiles);
745b0103260SKonstantin Belousov 	deferred1 = getdeferred();
746b0103260SKonstantin Belousov 	if (deferred != deferred1)
747b0103260SKonstantin Belousov 		errx(-1, "recursion: deferred before %d after %d", deferred,
748b0103260SKonstantin Belousov 		    deferred1);
749b0103260SKonstantin Belousov }
750b0103260SKonstantin Belousov 
751c8c3fc56SRobert Watson #define	RMDIR	"rm -Rf "
752c8c3fc56SRobert Watson int
main(void)753*f4ce06a9SEnji Cooper main(void)
754c8c3fc56SRobert Watson {
755c8c3fc56SRobert Watson 	char cmd[sizeof(RMDIR) + PATH_MAX];
756c8c3fc56SRobert Watson 	int serrno;
757c8c3fc56SRobert Watson 	pid_t pid;
758c8c3fc56SRobert Watson 
759c8c3fc56SRobert Watson 	strlcpy(dpath, "/tmp/unpgc.XXXXXXXX", sizeof(dpath));
760c8c3fc56SRobert Watson 	if (mkdtemp(dpath) == NULL)
761c8c3fc56SRobert Watson 		err(-1, "mkdtemp");
762c8c3fc56SRobert Watson 
763c8c3fc56SRobert Watson 	/*
764c8c3fc56SRobert Watson 	 * Set up a parent process to GC temporary storage when we're done.
765c8c3fc56SRobert Watson 	 */
766c8c3fc56SRobert Watson 	pid = fork();
767c8c3fc56SRobert Watson 	if (pid < 0) {
768c8c3fc56SRobert Watson 		serrno = errno;
769c8c3fc56SRobert Watson 		(void)rmdir(dpath);
770c8c3fc56SRobert Watson 		errno = serrno;
771c8c3fc56SRobert Watson 		err(-1, "fork");
772c8c3fc56SRobert Watson 	}
773c8c3fc56SRobert Watson 	if (pid > 0) {
774c8c3fc56SRobert Watson 		signal(SIGINT, SIG_IGN);
775c8c3fc56SRobert Watson 		while (waitpid(pid, NULL, 0) != pid);
776c8c3fc56SRobert Watson 		snprintf(cmd, sizeof(cmd), "%s %s", RMDIR, dpath);
777c8c3fc56SRobert Watson 		(void)system(cmd);
778c8c3fc56SRobert Watson 		exit(0);
779c8c3fc56SRobert Watson 	}
780c8c3fc56SRobert Watson 
781c8c3fc56SRobert Watson 	printf("Start: inflight %d open %d\n", getinflight(),
782c8c3fc56SRobert Watson 	    getopenfiles());
783c8c3fc56SRobert Watson 
784c8c3fc56SRobert Watson 	twosome_nothing();
785c8c3fc56SRobert Watson 	twosome_drop();
786c8c3fc56SRobert Watson 
787c8c3fc56SRobert Watson 	threesome_nothing();
788c8c3fc56SRobert Watson 	threesome_drop();
789c8c3fc56SRobert Watson 
790c8c3fc56SRobert Watson 	fivesome_nothing();
791c8c3fc56SRobert Watson 	fivesome_drop();
792c8c3fc56SRobert Watson 
793c8c3fc56SRobert Watson 	complex_cycles();
794c8c3fc56SRobert Watson 
795c8c3fc56SRobert Watson 	listen_nothing();
796c8c3fc56SRobert Watson 	listen_drop();
797c8c3fc56SRobert Watson 
798c8c3fc56SRobert Watson 	listen_connect_nothing();
799c8c3fc56SRobert Watson 	listen_connect_drop();
800c8c3fc56SRobert Watson 
801b0103260SKonstantin Belousov 	recursion();
802b0103260SKonstantin Belousov 
803c8c3fc56SRobert Watson 	printf("Finish: inflight %d open %d\n", getinflight(),
804c8c3fc56SRobert Watson 	    getopenfiles());
805c8c3fc56SRobert Watson 	return (0);
806c8c3fc56SRobert Watson }
807