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