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