unix_bindconnect.c revision 142146
1142146Srwatson/*- 2142146Srwatson * Copyright (c) 2005 Robert N. M. Watson 3142146Srwatson * All rights reserved. 4142146Srwatson * 5142146Srwatson * Redistribution and use in source and binary forms, with or without 6142146Srwatson * modification, are permitted provided that the following conditions 7142146Srwatson * are met: 8142146Srwatson * 1. Redistributions of source code must retain the above copyright 9142146Srwatson * notice, this list of conditions and the following disclaimer. 10142146Srwatson * 2. Redistributions in binary form must reproduce the above copyright 11142146Srwatson * notice, this list of conditions and the following disclaimer in the 12142146Srwatson * documentation and/or other materials provided with the distribution. 13142146Srwatson * 14142146Srwatson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15142146Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16142146Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17142146Srwatson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18142146Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19142146Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20142146Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21142146Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22142146Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23142146Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24142146Srwatson * SUCH DAMAGE. 25142146Srwatson * 26142146Srwatson * $FreeBSD: head/tools/regression/sockets/unix_bindconnect/unix_bindconnect.c 142146 2005-02-20 22:21:53Z rwatson $ 27142146Srwatson */ 28142146Srwatson 29142146Srwatson#include <sys/types.h> 30142146Srwatson#include <sys/socket.h> 31142146Srwatson#include <sys/un.h> 32142146Srwatson 33142146Srwatson#include <err.h> 34142146Srwatson#include <errno.h> 35142146Srwatson#include <limits.h> 36142146Srwatson#include <stdio.h> 37142146Srwatson#include <string.h> 38142146Srwatson#include <unistd.h> 39142146Srwatson 40142146Srwatson/* 41142146Srwatson * Simple regression test to exercise some error cases relating to the use of 42142146Srwatson * bind() and connect() on UNIX domain sockets. In particular, make sure 43142146Srwatson * that when two sockets rendezvous using the file system name space, they 44142146Srwatson * get the expected success/failure cases. 45142146Srwatson * 46142146Srwatson * TODO: 47142146Srwatson * - Check that the resulting file mode/owner are right. 48142146Srwatson * - Do the same tests with UNIX domain sockets. 49142146Srwatson * - Check the results of getsockaddr() and getpeeraddr(). 50142146Srwatson */ 51142146Srwatson 52142146Srwatson#define SOCK_NAME_ONE "socket.1" 53142146Srwatson#define SOCK_NAME_TWO "socket.2" 54142146Srwatson 55142146Srwatson#define UNWIND_MAX 1024 56142146Srwatson 57142146Srwatsonint unwind_len; 58142146Srwatsonstruct unwind { 59142146Srwatson char u_path[PATH_MAX]; 60142146Srwatson} unwind_list[UNWIND_MAX]; 61142146Srwatson 62142146Srwatsonstatic void 63142146Srwatsonpush_path(const char *path) 64142146Srwatson{ 65142146Srwatson 66142146Srwatson if (unwind_len >= UNWIND_MAX) 67142146Srwatson err(-1, "push_path: one path too many (%s)", path); 68142146Srwatson 69142146Srwatson strlcpy(unwind_list[unwind_len].u_path, path, PATH_MAX); 70142146Srwatson unwind_len++; 71142146Srwatson} 72142146Srwatson 73142146Srwatsonstatic void 74142146Srwatsonunwind(void) 75142146Srwatson{ 76142146Srwatson int i; 77142146Srwatson 78142146Srwatson for (i = unwind_len - 1; i >= 0; i--) { 79142146Srwatson unlink(unwind_list[i].u_path); 80142146Srwatson rmdir(unwind_list[i].u_path); 81142146Srwatson } 82142146Srwatson} 83142146Srwatson 84142146Srwatsonstatic int 85142146Srwatsonbind_test(const char *directory_path) 86142146Srwatson{ 87142146Srwatson char socket_path[PATH_MAX]; 88142146Srwatson struct sockaddr_un sun; 89142146Srwatson int sock1, sock2; 90142146Srwatson 91142146Srwatson sock1 = socket(PF_UNIX, SOCK_STREAM, 0); 92142146Srwatson if (sock1 < 0) { 93142146Srwatson warn("bind_test: socket(PF_UNIX, SOCK_STREAM, 0)"); 94142146Srwatson return (-1); 95142146Srwatson } 96142146Srwatson 97142146Srwatson if (snprintf(socket_path, sizeof(socket_path), "%s/%s", 98142146Srwatson directory_path, SOCK_NAME_ONE) >= PATH_MAX) { 99142146Srwatson warn("bind_test: snprintf(socket_path)"); 100142146Srwatson close(sock1); 101142146Srwatson return (-1); 102142146Srwatson } 103142146Srwatson 104142146Srwatson bzero(&sun, sizeof(sun)); 105142146Srwatson sun.sun_len = sizeof(sun); 106142146Srwatson sun.sun_family = AF_UNIX; 107142146Srwatson if (snprintf(sun.sun_path, sizeof(sun.sun_path), "%s", socket_path) 108142146Srwatson >= sizeof(sun.sun_path)) { 109142146Srwatson warn("bind_test: snprintf(sun.sun_path)"); 110142146Srwatson close(sock1); 111142146Srwatson return (-1); 112142146Srwatson } 113142146Srwatson 114142146Srwatson if (bind(sock1, (struct sockaddr *)&sun, sizeof(sun)) < 0) { 115142146Srwatson warn("bind_test: bind(sun) #1"); 116142146Srwatson close(sock1); 117142146Srwatson return (-1); 118142146Srwatson } 119142146Srwatson 120142146Srwatson push_path(socket_path); 121142146Srwatson 122142146Srwatson /* 123142146Srwatson * Once a STREAM UNIX domain socket has been bound, it can't be 124142146Srwatson * rebound. Expected error is EINVAL. 125142146Srwatson */ 126142146Srwatson if (bind(sock1, (struct sockaddr *)&sun, sizeof(sun)) == 0) { 127142146Srwatson warnx("bind_test: bind(sun) #2 succeeded"); 128142146Srwatson close(sock1); 129142146Srwatson return (-1); 130142146Srwatson } 131142146Srwatson if (errno != EINVAL) { 132142146Srwatson warn("bind_test: bind(sun) #2"); 133142146Srwatson close(sock1); 134142146Srwatson return (-1); 135142146Srwatson } 136142146Srwatson 137142146Srwatson sock2 = socket(PF_UNIX, SOCK_STREAM, 0); 138142146Srwatson if (sock2 < 0) { 139142146Srwatson warn("bind_test: socket(PF_UNIX, SOCK_STREAM, 0)"); 140142146Srwatson close(sock1); 141142146Srwatson return (-1); 142142146Srwatson } 143142146Srwatson 144142146Srwatson /* 145142146Srwatson * Since a socket is already bound to the pathname, it can't be bound 146142146Srwatson * to a second socket. Expected error is EADDRINUSE. 147142146Srwatson */ 148142146Srwatson if (bind(sock2, (struct sockaddr *)&sun, sizeof(sun)) == 0) { 149142146Srwatson warnx("bind_test: bind(sun) #3 succeeded"); 150142146Srwatson close(sock1); 151142146Srwatson close(sock2); 152142146Srwatson return (-1); 153142146Srwatson } 154142146Srwatson if (errno != EADDRINUSE) { 155142146Srwatson warn("bind_test: bind(sun) #2"); 156142146Srwatson close(sock1); 157142146Srwatson close(sock2); 158142146Srwatson return (-1); 159142146Srwatson } 160142146Srwatson 161142146Srwatson close(sock1); 162142146Srwatson 163142146Srwatson /* 164142146Srwatson * The socket bound to the pathname has been closed, but the pathname 165142146Srwatson * can't be reused without first being unlinked. Expected error is 166142146Srwatson * EADDRINUSE. 167142146Srwatson */ 168142146Srwatson if (bind(sock2, (struct sockaddr *)&sun, sizeof(sun)) == 0) { 169142146Srwatson warnx("bind_test: bind(sun) #4 succeeded"); 170142146Srwatson close(sock2); 171142146Srwatson return (-1); 172142146Srwatson } 173142146Srwatson if (errno != EADDRINUSE) { 174142146Srwatson warn("bind_test: bind(sun) #4"); 175142146Srwatson close(sock2); 176142146Srwatson return (-1); 177142146Srwatson } 178142146Srwatson 179142146Srwatson unlink(socket_path); 180142146Srwatson 181142146Srwatson /* 182142146Srwatson * The pathname is now free, so the socket should be able to bind to 183142146Srwatson * it. 184142146Srwatson */ 185142146Srwatson if (bind(sock2, (struct sockaddr *)&sun, sizeof(sun)) < 0) { 186142146Srwatson warn("bind_test: bind(sun) #5"); 187142146Srwatson close(sock2); 188142146Srwatson return (-1); 189142146Srwatson } 190142146Srwatson 191142146Srwatson close(sock2); 192142146Srwatson return (0); 193142146Srwatson} 194142146Srwatson 195142146Srwatsonstatic int 196142146Srwatsonconnect_test(const char *directory_path) 197142146Srwatson{ 198142146Srwatson char socket_path[PATH_MAX]; 199142146Srwatson struct sockaddr_un sun; 200142146Srwatson int sock1, sock2; 201142146Srwatson 202142146Srwatson sock1 = socket(PF_UNIX, SOCK_STREAM, 0); 203142146Srwatson if (sock1 < 0) { 204142146Srwatson warn("connect_test: socket(PF_UNIX, SOCK_STREAM, 0)"); 205142146Srwatson return (-1); 206142146Srwatson } 207142146Srwatson 208142146Srwatson if (snprintf(socket_path, sizeof(socket_path), "%s/%s", 209142146Srwatson directory_path, SOCK_NAME_TWO) >= PATH_MAX) { 210142146Srwatson warn("connect_test: snprintf(socket_path)"); 211142146Srwatson close(sock1); 212142146Srwatson return (-1); 213142146Srwatson } 214142146Srwatson 215142146Srwatson bzero(&sun, sizeof(sun)); 216142146Srwatson sun.sun_len = sizeof(sun); 217142146Srwatson sun.sun_family = AF_UNIX; 218142146Srwatson if (snprintf(sun.sun_path, sizeof(sun.sun_path), "%s", socket_path) 219142146Srwatson >= sizeof(sun.sun_path)) { 220142146Srwatson warn("connect_test: snprintf(sun.sun_path)"); 221142146Srwatson close(sock1); 222142146Srwatson return (-1); 223142146Srwatson } 224142146Srwatson 225142146Srwatson /* 226142146Srwatson * Try connecting to a path that doesn't yet exist. Should fail with 227142146Srwatson * ENOENT. 228142146Srwatson */ 229142146Srwatson if (connect(sock1, (struct sockaddr *)&sun, sizeof(sun)) == 0) { 230142146Srwatson warnx("connect_test: connect(sun) #1 succeeded"); 231142146Srwatson close(sock1); 232142146Srwatson return (-1); 233142146Srwatson } 234142146Srwatson if (errno != ENOENT) { 235142146Srwatson warn("connect_test: connect(sun) #1"); 236142146Srwatson close(sock1); 237142146Srwatson return (-1); 238142146Srwatson } 239142146Srwatson 240142146Srwatson if (bind(sock1, (struct sockaddr *)&sun, sizeof(sun)) < 0) { 241142146Srwatson warn("connect_test: bind(sun) #1"); 242142146Srwatson close(sock1); 243142146Srwatson return (-1); 244142146Srwatson } 245142146Srwatson 246142146Srwatson if (listen(sock1, 3) < 0) { 247142146Srwatson warn("connect_test: listen(sock1)"); 248142146Srwatson close(sock1); 249142146Srwatson return (-1); 250142146Srwatson } 251142146Srwatson 252142146Srwatson push_path(socket_path); 253142146Srwatson 254142146Srwatson sock2 = socket(PF_UNIX, SOCK_STREAM, 0); 255142146Srwatson if (sock2 < 0) { 256142146Srwatson warn("socket(PF_UNIX, SOCK_STREAM, 0)"); 257142146Srwatson close(sock1); 258142146Srwatson return (-1); 259142146Srwatson } 260142146Srwatson 261142146Srwatson /* 262142146Srwatson * Do a simple connect and make sure that works. 263142146Srwatson */ 264142146Srwatson if (connect(sock2, (struct sockaddr *)&sun, sizeof(sun)) < 0) { 265142146Srwatson warn("connect(sun) #2"); 266142146Srwatson close(sock1); 267142146Srwatson return (-1); 268142146Srwatson } 269142146Srwatson 270142146Srwatson close(sock2); 271142146Srwatson 272142146Srwatson close(sock1); 273142146Srwatson 274142146Srwatson sock2 = socket(PF_UNIX, SOCK_STREAM, 0); 275142146Srwatson if (sock2 < 0) { 276142146Srwatson warn("socket(PF_UNIX, SOCK_STREAM, 0)"); 277142146Srwatson return (-1); 278142146Srwatson } 279142146Srwatson 280142146Srwatson /* 281142146Srwatson * Confirm that once the listen socket is closed, we get a 282142146Srwatson * connection refused (ECONNREFUSED) when attempting to connect to 283142146Srwatson * the pathname. 284142146Srwatson */ 285142146Srwatson if (connect(sock2, (struct sockaddr *)&sun, sizeof(sun)) == 0) { 286142146Srwatson warnx("connect(sun) #3 succeeded"); 287142146Srwatson close(sock2); 288142146Srwatson return (-1); 289142146Srwatson } 290142146Srwatson if (errno != ECONNREFUSED) { 291142146Srwatson warn("connect(sun) #3"); 292142146Srwatson close(sock2); 293142146Srwatson return (-1); 294142146Srwatson } 295142146Srwatson 296142146Srwatson close(sock2); 297142146Srwatson unlink(socket_path); 298142146Srwatson return (0); 299142146Srwatson} 300142146Srwatsonint 301142146Srwatsonmain(int argc, char *argv[]) 302142146Srwatson{ 303142146Srwatson char directory_path[PATH_MAX]; 304142146Srwatson int error; 305142146Srwatson 306142146Srwatson strlcpy(directory_path, "/tmp/unix_bind.XXXXXXX", PATH_MAX); 307142146Srwatson if (mkdtemp(directory_path) == NULL) 308142146Srwatson err(-1, "mkdtemp"); 309142146Srwatson push_path(directory_path); 310142146Srwatson 311142146Srwatson error = bind_test(directory_path); 312142146Srwatson 313142146Srwatson if (error == 0) 314142146Srwatson error = connect_test(directory_path); 315142146Srwatson 316142146Srwatson unwind(); 317142146Srwatson return (error); 318142146Srwatson} 319