unix_sendtorace.c revision 281974
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: stable/10/tools/regression/sockets/unix_sendtorace/unix_sendtorace.c 281974 2015-04-25 05:31:52Z ngie $
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	ITERATIONS	1000000
49
50static char socket_path[] = "tmp.XXXXXX";
51
52static void
53stream_server(int listenfd)
54{
55	int acceptfd;
56
57	while (1) {
58		acceptfd = accept(listenfd, NULL, NULL);
59		if (acceptfd < 0) {
60			warn("stream_server: accept");
61			continue;
62		}
63		sleep(1);
64		close(acceptfd);
65	}
66}
67
68static void
69stream_client(void)
70{
71	struct sockaddr_un sun;
72	ssize_t len;
73	char c = 0;
74	int fd, i;
75
76	bzero(&sun, sizeof(sun));
77	sun.sun_len = sizeof(sun);
78	sun.sun_family = AF_UNIX;
79	strcpy(sun.sun_path, socket_path);
80	for (i = 0; i < ITERATIONS; i++) {
81		fd = socket(PF_UNIX, SOCK_STREAM, 0);
82		if (fd < 0) {
83			warn("stream_client: socket");
84			return;
85		}
86		len = sendto(fd, &c, sizeof(c), 0, (struct sockaddr *)&sun,
87		    sizeof(sun));
88		if (len < 0)
89			warn("stream_client: sendto");
90		close(fd);
91	}
92}
93
94static void
95stream_test(void)
96{
97	struct sockaddr_un sun;
98	pid_t childpid;
99	int listenfd;
100
101	listenfd = socket(PF_UNIX, SOCK_STREAM, 0);
102	if (listenfd < 0)
103		err(-1, "stream_test: socket");
104
105	bzero(&sun, sizeof(sun));
106	sun.sun_len = sizeof(sun);
107	sun.sun_family = AF_UNIX;
108	strcpy(sun.sun_path, socket_path);
109
110	if (bind(listenfd, (struct sockaddr *)&sun, sizeof(sun)) < 0)
111		err(-1, "stream_test: bind");
112
113	if (listen(listenfd, -1) < 0)
114		err(-1, "stream_test: listen");
115
116	childpid = fork();
117	if (childpid < 0)
118		err(-1, "stream_test: fork");
119
120	if (childpid != 0) {
121		sleep(1);
122		stream_client();
123		kill(childpid, SIGTERM);
124		sleep(1);
125	} else
126		stream_server(listenfd);
127
128	(void)unlink(socket_path);
129}
130
131static void
132datagram_server(int serverfd)
133{
134	ssize_t len;
135	char c;
136
137	while (1) {
138		len = recv(serverfd, &c, sizeof(c), 0);
139		if (len < 0)
140			warn("datagram_server: recv");
141	}
142}
143
144static void
145datagram_client(void)
146{
147	struct sockaddr_un sun;
148	ssize_t len;
149	char c = 0;
150	int fd, i;
151
152	bzero(&sun, sizeof(sun));
153	sun.sun_len = sizeof(sun);
154	sun.sun_family = AF_UNIX;
155	strcpy(sun.sun_path, socket_path);
156	for (i = 0; i < ITERATIONS; i++) {
157		fd = socket(PF_UNIX, SOCK_DGRAM, 0);
158		if (fd < 0) {
159			warn("datagram_client: socket");
160			return;
161		}
162		len = sendto(fd, &c, sizeof(c), 0, (struct sockaddr *)&sun,
163		    sizeof(sun));
164		if (len < 0)
165			warn("datagram_client: sendto");
166		close(fd);
167	}
168}
169
170static void
171datagram_test(void)
172{
173	struct sockaddr_un sun;
174	pid_t childpid;
175	int serverfd;
176
177	serverfd = socket(PF_UNIX, SOCK_DGRAM, 0);
178	if (serverfd < 0)
179		err(-1, "datagram_test: socket");
180
181	bzero(&sun, sizeof(sun));
182	sun.sun_len = sizeof(sun);
183	sun.sun_family = AF_UNIX;
184	strcpy(sun.sun_path, socket_path);
185
186	if (bind(serverfd, (struct sockaddr *)&sun, sizeof(sun)) < 0)
187		err(-1, "datagram_test: bind");
188
189	childpid = fork();
190	if (childpid < 0)
191		err(-1, "datagram_test: fork");
192
193	if (childpid != 0) {
194		sleep(1);
195		datagram_client();
196		kill(childpid, SIGTERM);
197		sleep(1);
198	} else
199		datagram_server(serverfd);
200
201	(void)unlink(socket_path);
202}
203
204int
205main(void)
206{
207
208	if (mkstemp(socket_path) == -1)
209		err(1, "mkstemp failed");
210	(void)unlink(socket_path);
211	datagram_test();
212	if (0)
213		stream_test();
214	return (0);
215}
216