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$
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