1164298Srwatson/*-
2164298Srwatson * Copyright (c) 2006 Robert N. M. Watson
3164298Srwatson * All rights reserved.
4164298Srwatson *
5164298Srwatson * Redistribution and use in source and binary forms, with or without
6164298Srwatson * modification, are permitted provided that the following conditions
7164298Srwatson * are met:
8164298Srwatson * 1. Redistributions of source code must retain the above copyright
9164298Srwatson *    notice, this list of conditions and the following disclaimer.
10164298Srwatson * 2. Redistributions in binary form must reproduce the above copyright
11164298Srwatson *    notice, this list of conditions and the following disclaimer in the
12164298Srwatson *    documentation and/or other materials provided with the distribution.
13164298Srwatson *
14164298Srwatson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15164298Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16164298Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17164298Srwatson * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18164298Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19164298Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20164298Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21164298Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22164298Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23164298Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24164298Srwatson * SUCH DAMAGE.
25164298Srwatson *
26164298Srwatson * $FreeBSD$
27164298Srwatson */
28164298Srwatson
29164298Srwatson/*
30164298Srwatson * Attempts to exercise UNIX domain socket races relating to the non-atomic
31164298Srwatson * connect-and-send properties of sendto().  As the result of such a race is
32164298Srwatson * a kernel panic, this test simply completes or doesn't.
33164298Srwatson *
34164298Srwatson * XXX: Despite implementing support for sendto() on stream sockets with
35164298Srwatson * implied connect, the appropriate flag isn't set in the FreeBSD kernel so
36164298Srwatson * it does not work.  For now, don't call the stream test.
37164298Srwatson */
38164298Srwatson
39164298Srwatson#include <sys/types.h>
40164298Srwatson#include <sys/socket.h>
41164298Srwatson#include <sys/un.h>
42164298Srwatson
43164298Srwatson#include <err.h>
44164298Srwatson#include <signal.h>
45164298Srwatson#include <string.h>
46164298Srwatson#include <unistd.h>
47164298Srwatson
48164298Srwatson#define	PATH		"/tmp/123"
49164298Srwatson#define	ITERATIONS	1000000
50164298Srwatson
51164298Srwatsonstatic void
52164298Srwatsonstream_server(int listenfd)
53164298Srwatson{
54164298Srwatson	int acceptfd;
55164298Srwatson
56164298Srwatson	while (1) {
57164298Srwatson		acceptfd = accept(listenfd, NULL, NULL);
58164298Srwatson		if (acceptfd < 0) {
59164298Srwatson			warn("stream_server: accept");
60164298Srwatson			continue;
61164298Srwatson		}
62164298Srwatson		sleep(1);
63164298Srwatson		close(acceptfd);
64164298Srwatson	}
65164298Srwatson}
66164298Srwatson
67164298Srwatsonstatic void
68164298Srwatsonstream_client(void)
69164298Srwatson{
70164298Srwatson	struct sockaddr_un sun;
71164298Srwatson	ssize_t len;
72164298Srwatson	char c = 0;
73164298Srwatson	int fd, i;
74164298Srwatson
75164298Srwatson	bzero(&sun, sizeof(sun));
76164298Srwatson	sun.sun_len = sizeof(sun);
77164298Srwatson	sun.sun_family = AF_UNIX;
78164298Srwatson	strcpy(sun.sun_path, PATH);
79164298Srwatson	for (i = 0; i < ITERATIONS; i++) {
80164298Srwatson		fd = socket(PF_UNIX, SOCK_STREAM, 0);
81164298Srwatson		if (fd < 0) {
82164298Srwatson			warn("stream_client: socket");
83164298Srwatson			return;
84164298Srwatson		}
85164298Srwatson		len = sendto(fd, &c, sizeof(c), 0, (struct sockaddr *)&sun,
86164298Srwatson		    sizeof(sun));
87164298Srwatson		if (len < 0)
88164298Srwatson			warn("stream_client: sendto");
89164298Srwatson		close(fd);
90164298Srwatson	}
91164298Srwatson}
92164298Srwatson
93164298Srwatsonstatic void
94164298Srwatsonstream_test(void)
95164298Srwatson{
96164298Srwatson	struct sockaddr_un sun;
97164298Srwatson	pid_t childpid;
98164298Srwatson	int listenfd;
99164298Srwatson
100164298Srwatson	listenfd = socket(PF_UNIX, SOCK_STREAM, 0);
101164298Srwatson	if (listenfd < 0)
102164298Srwatson		err(-1, "stream_test: socket");
103164298Srwatson
104164298Srwatson	bzero(&sun, sizeof(sun));
105164298Srwatson	sun.sun_len = sizeof(sun);
106164298Srwatson	sun.sun_family = AF_UNIX;
107164298Srwatson	strcpy(sun.sun_path, PATH);
108164298Srwatson
109164298Srwatson	if (bind(listenfd, (struct sockaddr *)&sun, sizeof(sun)) < 0)
110164298Srwatson		err(-1, "stream_test: bind");
111164298Srwatson
112164298Srwatson	if (listen(listenfd, -1) < 0)
113164298Srwatson		err(-1, "stream_test: listen");
114164298Srwatson
115164298Srwatson	childpid = fork();
116164298Srwatson	if (childpid < 0)
117164298Srwatson		err(-1, "stream_test: fork");
118164298Srwatson
119164298Srwatson	if (childpid != 0) {
120164298Srwatson		sleep(1);
121164298Srwatson		stream_client();
122164298Srwatson		kill(childpid, SIGTERM);
123164298Srwatson		sleep(1);
124164298Srwatson	} else
125164298Srwatson		stream_server(listenfd);
126164298Srwatson
127164298Srwatson	(void)unlink(PATH);
128164298Srwatson}
129164298Srwatson
130164298Srwatsonstatic void
131164298Srwatsondatagram_server(int serverfd)
132164298Srwatson{
133164298Srwatson	ssize_t len;
134164298Srwatson	char c;
135164298Srwatson
136164298Srwatson	while (1) {
137164298Srwatson		len = recv(serverfd, &c, sizeof(c), 0);
138164298Srwatson		if (len < 0)
139164298Srwatson			warn("datagram_server: recv");
140164298Srwatson	}
141164298Srwatson}
142164298Srwatson
143164298Srwatsonstatic void
144164298Srwatsondatagram_client(void)
145164298Srwatson{
146164298Srwatson	struct sockaddr_un sun;
147164298Srwatson	ssize_t len;
148164298Srwatson	char c = 0;
149164298Srwatson	int fd, i;
150164298Srwatson
151164298Srwatson	bzero(&sun, sizeof(sun));
152164298Srwatson	sun.sun_len = sizeof(sun);
153164298Srwatson	sun.sun_family = AF_UNIX;
154164298Srwatson	strcpy(sun.sun_path, PATH);
155164298Srwatson	for (i = 0; i < ITERATIONS; i++) {
156164298Srwatson		fd = socket(PF_UNIX, SOCK_DGRAM, 0);
157164298Srwatson		if (fd < 0) {
158164298Srwatson			warn("datagram_client: socket");
159164298Srwatson			return;
160164298Srwatson		}
161164298Srwatson		len = sendto(fd, &c, sizeof(c), 0, (struct sockaddr *)&sun,
162164298Srwatson		    sizeof(sun));
163164298Srwatson		if (len < 0)
164164298Srwatson			warn("datagram_client: sendto");
165164298Srwatson		close(fd);
166164298Srwatson	}
167164298Srwatson}
168164298Srwatson
169164298Srwatsonstatic void
170164298Srwatsondatagram_test(void)
171164298Srwatson{
172164298Srwatson	struct sockaddr_un sun;
173164298Srwatson	pid_t childpid;
174164298Srwatson	int serverfd;
175164298Srwatson
176164298Srwatson	serverfd = socket(PF_UNIX, SOCK_DGRAM, 0);
177164298Srwatson	if (serverfd < 0)
178164298Srwatson		err(-1, "datagram_test: socket");
179164298Srwatson
180164298Srwatson	bzero(&sun, sizeof(sun));
181164298Srwatson	sun.sun_len = sizeof(sun);
182164298Srwatson	sun.sun_family = AF_UNIX;
183164298Srwatson	strcpy(sun.sun_path, PATH);
184164298Srwatson
185164298Srwatson	if (bind(serverfd, (struct sockaddr *)&sun, sizeof(sun)) < 0)
186164298Srwatson		err(-1, "datagram_test: bind");
187164298Srwatson
188164298Srwatson	childpid = fork();
189164298Srwatson	if (childpid < 0)
190164298Srwatson		err(-1, "datagram_test: fork");
191164298Srwatson
192164298Srwatson	if (childpid != 0) {
193164298Srwatson		sleep(1);
194164298Srwatson		datagram_client();
195164298Srwatson		kill(childpid, SIGTERM);
196164298Srwatson		sleep(1);
197164298Srwatson	} else
198164298Srwatson		datagram_server(serverfd);
199164298Srwatson
200164298Srwatson	(void)unlink(PATH);
201164298Srwatson}
202164298Srwatson
203164298Srwatsonint
204164298Srwatsonmain(int argc, char *argv[])
205164298Srwatson{
206164298Srwatson
207164298Srwatson	(void)unlink(PATH);
208164298Srwatson	datagram_test();
209164298Srwatson	if (0)
210164298Srwatson		stream_test();
211164298Srwatson	return (0);
212164298Srwatson}
213