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