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
51static int forcegc = 1;
52static char dpath[PATH_MAX];
53static const char *test;
54
55static int
56getsysctl(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
67static int
68getopenfiles(void)
69{
70
71	return (getsysctl("kern.openfiles"));
72}
73
74static int
75getinflight(void)
76{
77
78	return (getsysctl("net.local.inflight"));
79}
80
81static int
82getdeferred(void)
83{
84
85	return (getsysctl("net.local.deferred"));
86}
87
88static void
89sendfd(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
115static void
116close2(int fd1, int fd2)
117{
118
119	close(fd1);
120	close(fd2);
121}
122
123static void
124close3(int fd1, int fd2, int fd3)
125{
126
127	close2(fd1, fd2);
128	close(fd3);
129}
130
131static void
132close4(int fd1, int fd2, int fd3, int fd4)
133{
134
135	close2(fd1, fd2);
136	close2(fd3, fd4);
137}
138
139static void
140close5(int fd1, int fd2, int fd3, int fd4, int fd5)
141{
142
143	close3(fd1, fd2, fd3);
144	close2(fd4, fd5);
145}
146
147static int
148my_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
158static void
159my_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
166static void
167my_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
174static void
175my_listen(int sock, int backlog)
176{
177
178	if (listen(sock, backlog) < 0)
179		err(-1, "%s: listen", test);
180}
181
182static void
183my_socketpair(int *sv)
184{
185
186	if (socketpair(PF_UNIX, SOCK_STREAM, 0, sv) < 0)
187		err(-1, "%s: socketpair", test);
188}
189
190static void
191my_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
198static void
199setnonblock(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
206static void
207alloc3fds(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
216static void
217alloc5fds(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
228static void
229save_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 */
240static void
241trigger_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
253static void
254test_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
270static void
271twosome_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 */
301static void
302twosome_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
319static void
320twosome_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
338static void
339threesome_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 */
356static void
357threesome_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 */
434static void
435fivesome_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
448static void
449fivesome_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
485static void
486fivesome_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 */
499static void
500complex_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 */
524static void
525listen_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 */
569static void
570listen_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 */
651static void
652listen_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
683static void
684listen_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
717static void
718recursion(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 "
752int
753main(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