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
51static void
52stream_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
67static void
68stream_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
93static void
94stream_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
130static void
131datagram_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
143static void
144datagram_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
169static void
170datagram_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
203int
204main(int argc, char *argv[])
205{
206
207	(void)unlink(PATH);
208	datagram_test();
209	if (0)
210		stream_test();
211	return (0);
212}
213