1 /*- 2 * Copyright (c) 2006 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 * Attempts to exercise UNIX domain socket races relating to the non-atomic 29 * connect-and-send properties of sendto(). As the result of such a race is 30 * a kernel panic, this test simply completes or doesn't. 31 * 32 * XXX: Despite implementing support for sendto() on stream sockets with 33 * implied connect, the appropriate flag isn't set in the FreeBSD kernel so 34 * it does not work. For now, don't call the stream test. 35 */ 36 37 #include <sys/types.h> 38 #include <sys/socket.h> 39 #include <sys/un.h> 40 41 #include <err.h> 42 #include <signal.h> 43 #include <string.h> 44 #include <unistd.h> 45 46 #define ITERATIONS 1000000 47 48 static char socket_path[] = "tmp.XXXXXX"; 49 50 static void 51 stream_server(int listenfd) 52 { 53 int acceptfd; 54 55 while (1) { 56 acceptfd = accept(listenfd, NULL, NULL); 57 if (acceptfd < 0) { 58 warn("stream_server: accept"); 59 continue; 60 } 61 sleep(1); 62 close(acceptfd); 63 } 64 } 65 66 static void 67 stream_client(void) 68 { 69 struct sockaddr_un sun; 70 ssize_t len; 71 char c = 0; 72 int fd, i; 73 74 bzero(&sun, sizeof(sun)); 75 sun.sun_len = sizeof(sun); 76 sun.sun_family = AF_UNIX; 77 strcpy(sun.sun_path, socket_path); 78 for (i = 0; i < ITERATIONS; i++) { 79 fd = socket(PF_UNIX, SOCK_STREAM, 0); 80 if (fd < 0) { 81 warn("stream_client: socket"); 82 return; 83 } 84 len = sendto(fd, &c, sizeof(c), 0, (struct sockaddr *)&sun, 85 sizeof(sun)); 86 if (len < 0) 87 warn("stream_client: sendto"); 88 close(fd); 89 } 90 } 91 92 static void 93 stream_test(void) 94 { 95 struct sockaddr_un sun; 96 pid_t childpid; 97 int listenfd; 98 99 listenfd = socket(PF_UNIX, SOCK_STREAM, 0); 100 if (listenfd < 0) 101 err(-1, "stream_test: socket"); 102 103 bzero(&sun, sizeof(sun)); 104 sun.sun_len = sizeof(sun); 105 sun.sun_family = AF_UNIX; 106 strcpy(sun.sun_path, socket_path); 107 108 if (bind(listenfd, (struct sockaddr *)&sun, sizeof(sun)) < 0) 109 err(-1, "stream_test: bind"); 110 111 if (listen(listenfd, -1) < 0) 112 err(-1, "stream_test: listen"); 113 114 childpid = fork(); 115 if (childpid < 0) 116 err(-1, "stream_test: fork"); 117 118 if (childpid != 0) { 119 sleep(1); 120 stream_client(); 121 kill(childpid, SIGTERM); 122 sleep(1); 123 } else 124 stream_server(listenfd); 125 126 (void)unlink(socket_path); 127 } 128 129 static void 130 datagram_server(int serverfd) 131 { 132 ssize_t len; 133 char c; 134 135 while (1) { 136 len = recv(serverfd, &c, sizeof(c), 0); 137 if (len < 0) 138 warn("datagram_server: recv"); 139 } 140 } 141 142 static void 143 datagram_client(void) 144 { 145 struct sockaddr_un sun; 146 ssize_t len; 147 char c = 0; 148 int fd, i; 149 150 bzero(&sun, sizeof(sun)); 151 sun.sun_len = sizeof(sun); 152 sun.sun_family = AF_UNIX; 153 strcpy(sun.sun_path, socket_path); 154 for (i = 0; i < ITERATIONS; i++) { 155 fd = socket(PF_UNIX, SOCK_DGRAM, 0); 156 if (fd < 0) { 157 warn("datagram_client: socket"); 158 return; 159 } 160 len = sendto(fd, &c, sizeof(c), 0, (struct sockaddr *)&sun, 161 sizeof(sun)); 162 if (len < 0) 163 warn("datagram_client: sendto"); 164 close(fd); 165 } 166 } 167 168 static void 169 datagram_test(void) 170 { 171 struct sockaddr_un sun; 172 pid_t childpid; 173 int serverfd; 174 175 serverfd = socket(PF_UNIX, SOCK_DGRAM, 0); 176 if (serverfd < 0) 177 err(-1, "datagram_test: socket"); 178 179 bzero(&sun, sizeof(sun)); 180 sun.sun_len = sizeof(sun); 181 sun.sun_family = AF_UNIX; 182 strcpy(sun.sun_path, socket_path); 183 184 if (bind(serverfd, (struct sockaddr *)&sun, sizeof(sun)) < 0) 185 err(-1, "datagram_test: bind"); 186 187 childpid = fork(); 188 if (childpid < 0) 189 err(-1, "datagram_test: fork"); 190 191 if (childpid != 0) { 192 sleep(1); 193 datagram_client(); 194 kill(childpid, SIGTERM); 195 sleep(1); 196 } else 197 datagram_server(serverfd); 198 199 (void)unlink(socket_path); 200 } 201 202 int 203 main(void) 204 { 205 206 if (mkstemp(socket_path) == -1) 207 err(1, "mkstemp failed"); 208 (void)unlink(socket_path); 209 datagram_test(); 210 if (0) 211 stream_test(); 212 return (0); 213 } 214