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