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