xref: /minix3/minix/tests/test90.c (revision baa5830f282f97301f08e45ae8705c0513f18989)
1*baa5830fSDavid van Moolenbroek /* Advanced tests for UNIX Domain Sockets - by D.C. van Moolenbroek */
2*baa5830fSDavid van Moolenbroek /*
3*baa5830fSDavid van Moolenbroek  * This is a somewhat random collection of in-depth tests, complementing the
4*baa5830fSDavid van Moolenbroek  * more general functionality tests in test56.  The overall test set is still
5*baa5830fSDavid van Moolenbroek  * by no means expected to be "complete."  The subtests are in random order.
6*baa5830fSDavid van Moolenbroek  */
7*baa5830fSDavid van Moolenbroek #include <stdlib.h>
8*baa5830fSDavid van Moolenbroek #include <string.h>
9*baa5830fSDavid van Moolenbroek #include <sys/wait.h>
10*baa5830fSDavid van Moolenbroek #include <sys/socket.h>
11*baa5830fSDavid van Moolenbroek #include <sys/un.h>
12*baa5830fSDavid van Moolenbroek #include <sys/ioctl.h>
13*baa5830fSDavid van Moolenbroek #include <sys/sysctl.h>
14*baa5830fSDavid van Moolenbroek #include <signal.h>
15*baa5830fSDavid van Moolenbroek #include <unistd.h>
16*baa5830fSDavid van Moolenbroek #include <fcntl.h>
17*baa5830fSDavid van Moolenbroek #include <stddef.h>
18*baa5830fSDavid van Moolenbroek #include <assert.h>
19*baa5830fSDavid van Moolenbroek 
20*baa5830fSDavid van Moolenbroek #include "common.h"
21*baa5830fSDavid van Moolenbroek #include "socklib.h"
22*baa5830fSDavid van Moolenbroek 
23*baa5830fSDavid van Moolenbroek #define ITERATIONS	1
24*baa5830fSDavid van Moolenbroek 
25*baa5830fSDavid van Moolenbroek #define SOCK_PATH_A	"sock_a"
26*baa5830fSDavid van Moolenbroek #define SOCK_PATH_B	"sock_b"
27*baa5830fSDavid van Moolenbroek #define SOCK_PATH_C	"sock_c"
28*baa5830fSDavid van Moolenbroek #define SOCK_PATH_D	"sock_d"
29*baa5830fSDavid van Moolenbroek 
30*baa5830fSDavid van Moolenbroek #define SOCK_PATH_A_X	".//sock_a"
31*baa5830fSDavid van Moolenbroek #define SOCK_PATH_A_Y	"./././sock_a"
32*baa5830fSDavid van Moolenbroek 
33*baa5830fSDavid van Moolenbroek #define PRINT_STATS	0
34*baa5830fSDavid van Moolenbroek 
35*baa5830fSDavid van Moolenbroek /*
36*baa5830fSDavid van Moolenbroek  * Check that the given returned socket address matches the given path.  A NULL
37*baa5830fSDavid van Moolenbroek  * path may be passed in to indicate the result should be for an unbound
38*baa5830fSDavid van Moolenbroek  * socket.
39*baa5830fSDavid van Moolenbroek  */
40*baa5830fSDavid van Moolenbroek static void
check_addr(struct sockaddr_un * sun,socklen_t len,const char * path)41*baa5830fSDavid van Moolenbroek check_addr(struct sockaddr_un * sun, socklen_t len, const char * path)
42*baa5830fSDavid van Moolenbroek {
43*baa5830fSDavid van Moolenbroek 
44*baa5830fSDavid van Moolenbroek 	if (len < offsetof(struct sockaddr_un, sun_path)) e(0);
45*baa5830fSDavid van Moolenbroek 
46*baa5830fSDavid van Moolenbroek 	if (sun->sun_family != AF_UNIX) e(0);
47*baa5830fSDavid van Moolenbroek 	if (sun->sun_len != len - ((path != NULL) ? 1 : 0)) e(0);
48*baa5830fSDavid van Moolenbroek 
49*baa5830fSDavid van Moolenbroek 	len -= offsetof(struct sockaddr_un, sun_path);
50*baa5830fSDavid van Moolenbroek 
51*baa5830fSDavid van Moolenbroek 	if (path != NULL) {
52*baa5830fSDavid van Moolenbroek 		if (len != strlen(path) + 1) e(0);
53*baa5830fSDavid van Moolenbroek 		if (sun->sun_path[len - 1] != '\0') e(0);
54*baa5830fSDavid van Moolenbroek 		if (strcmp(sun->sun_path, path)) e(0);
55*baa5830fSDavid van Moolenbroek 	} else
56*baa5830fSDavid van Moolenbroek 		if (len != 0) e(0);
57*baa5830fSDavid van Moolenbroek }
58*baa5830fSDavid van Moolenbroek 
59*baa5830fSDavid van Moolenbroek /*
60*baa5830fSDavid van Moolenbroek  * Get a socket of the given type, bound to the given path.  Return the file
61*baa5830fSDavid van Moolenbroek  * descriptor, as well as the bound addres in 'sun'.
62*baa5830fSDavid van Moolenbroek  */
63*baa5830fSDavid van Moolenbroek static int
get_bound_socket(int type,const char * path,struct sockaddr_un * sun)64*baa5830fSDavid van Moolenbroek get_bound_socket(int type, const char * path, struct sockaddr_un * sun)
65*baa5830fSDavid van Moolenbroek {
66*baa5830fSDavid van Moolenbroek 	int fd;
67*baa5830fSDavid van Moolenbroek 
68*baa5830fSDavid van Moolenbroek 	if ((fd = socket(AF_UNIX, type, 0)) < 0) e(0);
69*baa5830fSDavid van Moolenbroek 
70*baa5830fSDavid van Moolenbroek 	(void)unlink(path);
71*baa5830fSDavid van Moolenbroek 
72*baa5830fSDavid van Moolenbroek 	memset(sun, 0, sizeof(*sun));
73*baa5830fSDavid van Moolenbroek 	sun->sun_family = AF_UNIX;
74*baa5830fSDavid van Moolenbroek 	strlcpy(sun->sun_path, path, sizeof(sun->sun_path));
75*baa5830fSDavid van Moolenbroek 
76*baa5830fSDavid van Moolenbroek 	if (bind(fd, (struct sockaddr *)sun, sizeof(*sun)) != 0) e(0);
77*baa5830fSDavid van Moolenbroek 
78*baa5830fSDavid van Moolenbroek 	return fd;
79*baa5830fSDavid van Moolenbroek }
80*baa5830fSDavid van Moolenbroek 
81*baa5830fSDavid van Moolenbroek /*
82*baa5830fSDavid van Moolenbroek  * Get a pair of connected sockets.
83*baa5830fSDavid van Moolenbroek  */
84*baa5830fSDavid van Moolenbroek static void
get_socket_pair(int type,int fd[2])85*baa5830fSDavid van Moolenbroek get_socket_pair(int type, int fd[2])
86*baa5830fSDavid van Moolenbroek {
87*baa5830fSDavid van Moolenbroek 	struct sockaddr_un sunA, sunB;
88*baa5830fSDavid van Moolenbroek 
89*baa5830fSDavid van Moolenbroek 	if ((type & ~SOCK_FLAGS_MASK) == SOCK_DGRAM) {
90*baa5830fSDavid van Moolenbroek 		fd[0] = get_bound_socket(type, SOCK_PATH_A, &sunA);
91*baa5830fSDavid van Moolenbroek 		fd[1] = get_bound_socket(type, SOCK_PATH_B, &sunB);
92*baa5830fSDavid van Moolenbroek 
93*baa5830fSDavid van Moolenbroek 		if (connect(fd[0], (struct sockaddr *)&sunB,
94*baa5830fSDavid van Moolenbroek 		    sizeof(sunB)) != 0) e(0);
95*baa5830fSDavid van Moolenbroek 		if (connect(fd[1], (struct sockaddr *)&sunA,
96*baa5830fSDavid van Moolenbroek 		    sizeof(sunA)) != 0) e(0);
97*baa5830fSDavid van Moolenbroek 
98*baa5830fSDavid van Moolenbroek 		if (unlink(SOCK_PATH_A) != 0) e(0);
99*baa5830fSDavid van Moolenbroek 		if (unlink(SOCK_PATH_B) != 0) e(0);
100*baa5830fSDavid van Moolenbroek 	} else
101*baa5830fSDavid van Moolenbroek 		if (socketpair(AF_UNIX, type, 0, fd) != 0) e(0);
102*baa5830fSDavid van Moolenbroek }
103*baa5830fSDavid van Moolenbroek 
104*baa5830fSDavid van Moolenbroek /*
105*baa5830fSDavid van Moolenbroek  * Return the receive buffer size of the given socket.
106*baa5830fSDavid van Moolenbroek  */
107*baa5830fSDavid van Moolenbroek static int
get_rcvbuf_len(int fd)108*baa5830fSDavid van Moolenbroek get_rcvbuf_len(int fd)
109*baa5830fSDavid van Moolenbroek {
110*baa5830fSDavid van Moolenbroek 	socklen_t len;
111*baa5830fSDavid van Moolenbroek 	int val;
112*baa5830fSDavid van Moolenbroek 
113*baa5830fSDavid van Moolenbroek 	len = sizeof(val);
114*baa5830fSDavid van Moolenbroek 	if (getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &val, &len) != 0) e(0);
115*baa5830fSDavid van Moolenbroek 
116*baa5830fSDavid van Moolenbroek 	if (len != sizeof(val)) e(0);
117*baa5830fSDavid van Moolenbroek 	if (val <= 0) e(0);
118*baa5830fSDavid van Moolenbroek 
119*baa5830fSDavid van Moolenbroek 	return val;
120*baa5830fSDavid van Moolenbroek }
121*baa5830fSDavid van Moolenbroek 
122*baa5830fSDavid van Moolenbroek static const enum state unix_connect_states[] = {
123*baa5830fSDavid van Moolenbroek 		S_NEW,		S_N_SHUT_R,	S_N_SHUT_W,	S_N_SHUT_RW,
124*baa5830fSDavid van Moolenbroek 		S_BOUND,	S_LISTENING,	S_L_SHUT_R,	S_L_SHUT_W,
125*baa5830fSDavid van Moolenbroek 		S_L_SHUT_RW,	S_CONNECTING,	S_CONNECTED,	S_ACCEPTED,
126*baa5830fSDavid van Moolenbroek 		S_SHUT_R,	S_SHUT_W,	S_SHUT_RW,	S_RSHUT_R,
127*baa5830fSDavid van Moolenbroek 		S_RSHUT_W,	S_RSHUT_RW,	S_SHUT2_R,	S_SHUT2_W,
128*baa5830fSDavid van Moolenbroek 		S_SHUT2_RW,	S_PRE_EOF,	S_AT_EOF,	S_POST_EOF,
129*baa5830fSDavid van Moolenbroek 		S_PRE_SHUT_R,	S_EOF_SHUT_R,	S_POST_SHUT_R,	S_PRE_SHUT_W,
130*baa5830fSDavid van Moolenbroek 		S_EOF_SHUT_W,	S_POST_SHUT_W,	S_PRE_SHUT_RW,	S_EOF_SHUT_RW,
131*baa5830fSDavid van Moolenbroek 		S_POST_SHUT_RW,	S_AT_RESET,	S_POST_RESET,	S_POST_FAILED
132*baa5830fSDavid van Moolenbroek 		/*
133*baa5830fSDavid van Moolenbroek 		 * It is impossible to generate the S_PRE_RESET state: we can
134*baa5830fSDavid van Moolenbroek 		 * only generate a reset on a connected socket for which the
135*baa5830fSDavid van Moolenbroek 		 * other end is pending acceptance, by closing the listening
136*baa5830fSDavid van Moolenbroek 		 * socket.  That means we cannot send data to the connected end
137*baa5830fSDavid van Moolenbroek 		 * (from the listening socket) before triggering the reset.
138*baa5830fSDavid van Moolenbroek 		 *
139*baa5830fSDavid van Moolenbroek 		 * It is impossible to generate the S_FAILED state: even a non-
140*baa5830fSDavid van Moolenbroek 		 * blocking connect will always fail immediately when it cannot
141*baa5830fSDavid van Moolenbroek 		 * connect to the target.
142*baa5830fSDavid van Moolenbroek 		 */
143*baa5830fSDavid van Moolenbroek };
144*baa5830fSDavid van Moolenbroek 
145*baa5830fSDavid van Moolenbroek static const int unix_connect_results[][__arraycount(unix_connect_states)] = {
146*baa5830fSDavid van Moolenbroek 	[C_ACCEPT]		= {
147*baa5830fSDavid van Moolenbroek 		-EINVAL,	-EINVAL,	-EINVAL,	-EINVAL,
148*baa5830fSDavid van Moolenbroek 		-EINVAL,	-EAGAIN,	-ECONNABORTED,	-ECONNABORTED,
149*baa5830fSDavid van Moolenbroek 		-ECONNABORTED,	-EINVAL,	-EINVAL,	-EINVAL,
150*baa5830fSDavid van Moolenbroek 		-EINVAL,	-EINVAL,	-EINVAL,	-EINVAL,
151*baa5830fSDavid van Moolenbroek 		-EINVAL,	-EINVAL,	-EINVAL,	-EINVAL,
152*baa5830fSDavid van Moolenbroek 		-EINVAL,	-EINVAL,	-EINVAL,	-EINVAL,
153*baa5830fSDavid van Moolenbroek 		-EINVAL,	-EINVAL,	-EINVAL,	-EINVAL,
154*baa5830fSDavid van Moolenbroek 		-EINVAL,	-EINVAL,	-EINVAL,	-EINVAL,
155*baa5830fSDavid van Moolenbroek 		-EINVAL,	-EINVAL,	-EINVAL,	-EINVAL,
156*baa5830fSDavid van Moolenbroek 	},
157*baa5830fSDavid van Moolenbroek 	[C_BIND]		= {
158*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
159*baa5830fSDavid van Moolenbroek 		-EINVAL,	-EINVAL,	-EINVAL,	-EINVAL,
160*baa5830fSDavid van Moolenbroek 		-EINVAL,	0,		0,		-EINVAL,
161*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
162*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
163*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
164*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
165*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
166*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
167*baa5830fSDavid van Moolenbroek 	},
168*baa5830fSDavid van Moolenbroek 	[C_CONNECT]		= {
169*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
170*baa5830fSDavid van Moolenbroek 		0,		-EOPNOTSUPP,	-EOPNOTSUPP,	-EOPNOTSUPP,
171*baa5830fSDavid van Moolenbroek 		-EOPNOTSUPP,	-EALREADY,	-EISCONN,	-EISCONN,
172*baa5830fSDavid van Moolenbroek 		-EISCONN,	-EISCONN,	-EISCONN,	-EISCONN,
173*baa5830fSDavid van Moolenbroek 		-EISCONN,	-EISCONN,	-EISCONN,	-EISCONN,
174*baa5830fSDavid van Moolenbroek 		-EISCONN,	0,		0,		0,
175*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
176*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
177*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
178*baa5830fSDavid van Moolenbroek 	},
179*baa5830fSDavid van Moolenbroek 	[C_GETPEERNAME]		= {
180*baa5830fSDavid van Moolenbroek 		-ENOTCONN,	-ENOTCONN,	-ENOTCONN,	-ENOTCONN,
181*baa5830fSDavid van Moolenbroek 		-ENOTCONN,	-ENOTCONN,	-ENOTCONN,	-ENOTCONN,
182*baa5830fSDavid van Moolenbroek 		-ENOTCONN,	-ENOTCONN,	0,		0,
183*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
184*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
185*baa5830fSDavid van Moolenbroek 		0,		-ENOTCONN,	-ENOTCONN,	-ENOTCONN,
186*baa5830fSDavid van Moolenbroek 		-ENOTCONN,	-ENOTCONN,	-ENOTCONN,	-ENOTCONN,
187*baa5830fSDavid van Moolenbroek 		-ENOTCONN,	-ENOTCONN,	-ENOTCONN,	-ENOTCONN,
188*baa5830fSDavid van Moolenbroek 		-ENOTCONN,	-ENOTCONN,	-ENOTCONN,	-ENOTCONN,
189*baa5830fSDavid van Moolenbroek 	},
190*baa5830fSDavid van Moolenbroek 	[C_GETSOCKNAME]		= {
191*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
192*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
193*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
194*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
195*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
196*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
197*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
198*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
199*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
200*baa5830fSDavid van Moolenbroek 	},
201*baa5830fSDavid van Moolenbroek 	[C_GETSOCKOPT_ERR]	= {
202*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
203*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
204*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
205*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
206*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
207*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
208*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
209*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
210*baa5830fSDavid van Moolenbroek 		0,		-ECONNRESET,	0,		0,
211*baa5830fSDavid van Moolenbroek 	},
212*baa5830fSDavid van Moolenbroek 	[C_GETSOCKOPT_KA]	= {
213*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
214*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
215*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
216*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
217*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
218*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
219*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
220*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
221*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
222*baa5830fSDavid van Moolenbroek 	},
223*baa5830fSDavid van Moolenbroek 	[C_GETSOCKOPT_RB]	= {
224*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
225*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
226*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
227*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
228*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
229*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
230*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
231*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
232*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
233*baa5830fSDavid van Moolenbroek 	},
234*baa5830fSDavid van Moolenbroek 	[C_IOCTL_NREAD]		= {
235*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
236*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
237*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
238*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
239*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
240*baa5830fSDavid van Moolenbroek 		0,		1,		0,		0,
241*baa5830fSDavid van Moolenbroek 		0,		0,		0,		1,
242*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
243*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
244*baa5830fSDavid van Moolenbroek 	},
245*baa5830fSDavid van Moolenbroek 	[C_LISTEN]		= {
246*baa5830fSDavid van Moolenbroek 		-EDESTADDRREQ,	-EDESTADDRREQ,	-EDESTADDRREQ,	-EDESTADDRREQ,
247*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
248*baa5830fSDavid van Moolenbroek 		0,		-EINVAL,	-EINVAL,	-EINVAL,
249*baa5830fSDavid van Moolenbroek 		-EINVAL,	-EINVAL,	-EINVAL,	-EINVAL,
250*baa5830fSDavid van Moolenbroek 		-EINVAL,	-EINVAL,	-EINVAL,	-EINVAL,
251*baa5830fSDavid van Moolenbroek 		-EINVAL,	-EDESTADDRREQ,	-EDESTADDRREQ,	-EDESTADDRREQ,
252*baa5830fSDavid van Moolenbroek 		-EDESTADDRREQ,	-EDESTADDRREQ,	-EDESTADDRREQ,	-EDESTADDRREQ,
253*baa5830fSDavid van Moolenbroek 		-EDESTADDRREQ,	-EDESTADDRREQ,	-EDESTADDRREQ,	-EDESTADDRREQ,
254*baa5830fSDavid van Moolenbroek 		-EDESTADDRREQ,	-EDESTADDRREQ,	-EDESTADDRREQ,	-EDESTADDRREQ,
255*baa5830fSDavid van Moolenbroek 	},
256*baa5830fSDavid van Moolenbroek 	[C_RECV]		= {
257*baa5830fSDavid van Moolenbroek 		-ENOTCONN,	0,		-ENOTCONN,	0,
258*baa5830fSDavid van Moolenbroek 		-ENOTCONN,	-ENOTCONN,	0,		-ENOTCONN,
259*baa5830fSDavid van Moolenbroek 		0,		-EAGAIN,	-EAGAIN,	-EAGAIN,
260*baa5830fSDavid van Moolenbroek 		0,		-EAGAIN,	0,		-EAGAIN,
261*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
262*baa5830fSDavid van Moolenbroek 		0,		1,		0,		0,
263*baa5830fSDavid van Moolenbroek 		0,		0,		0,		1,
264*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
265*baa5830fSDavid van Moolenbroek 		0,		-ECONNRESET,	0,		-ENOTCONN,
266*baa5830fSDavid van Moolenbroek 	},
267*baa5830fSDavid van Moolenbroek 	[C_RECVFROM]		= {
268*baa5830fSDavid van Moolenbroek 		-ENOTCONN,	0,		-ENOTCONN,	0,
269*baa5830fSDavid van Moolenbroek 		-ENOTCONN,	-ENOTCONN,	0,		-ENOTCONN,
270*baa5830fSDavid van Moolenbroek 		0,		-EAGAIN,	-EAGAIN,	-EAGAIN,
271*baa5830fSDavid van Moolenbroek 		0,		-EAGAIN,	0,		-EAGAIN,
272*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
273*baa5830fSDavid van Moolenbroek 		0,		1,		0,		0,
274*baa5830fSDavid van Moolenbroek 		0,		0,		0,		1,
275*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
276*baa5830fSDavid van Moolenbroek 		0,		-ECONNRESET,	0,		-ENOTCONN,
277*baa5830fSDavid van Moolenbroek 	},
278*baa5830fSDavid van Moolenbroek 	[C_SEND]		= {
279*baa5830fSDavid van Moolenbroek 		-ENOTCONN,	-ENOTCONN,	-EPIPE,		-EPIPE,
280*baa5830fSDavid van Moolenbroek 		-ENOTCONN,	-ENOTCONN,	-ENOTCONN,	-EPIPE,
281*baa5830fSDavid van Moolenbroek 		-EPIPE,		-EAGAIN,	1,		1,
282*baa5830fSDavid van Moolenbroek 		1,		-EPIPE,		-EPIPE,		-EPIPE,
283*baa5830fSDavid van Moolenbroek 		1,		-EPIPE,		-EPIPE,		-EPIPE,
284*baa5830fSDavid van Moolenbroek 		-EPIPE,		-EPIPE,		-EPIPE,		-EPIPE,
285*baa5830fSDavid van Moolenbroek 		-EPIPE,		-EPIPE,		-EPIPE,		-EPIPE,
286*baa5830fSDavid van Moolenbroek 		-EPIPE,		-EPIPE,		-EPIPE,		-EPIPE,
287*baa5830fSDavid van Moolenbroek 		-EPIPE,		-ECONNRESET,	-EPIPE,		-ENOTCONN,
288*baa5830fSDavid van Moolenbroek 	},
289*baa5830fSDavid van Moolenbroek 	[C_SENDTO]		= {
290*baa5830fSDavid van Moolenbroek 		-ENOTCONN,	-ENOTCONN,	-EPIPE,		-EPIPE,
291*baa5830fSDavid van Moolenbroek 		-ENOTCONN,	-ENOTCONN,	-ENOTCONN,	-EPIPE,
292*baa5830fSDavid van Moolenbroek 		-EPIPE,		-EAGAIN,	1,		1,
293*baa5830fSDavid van Moolenbroek 		1,		-EPIPE,		-EPIPE,		-EPIPE,
294*baa5830fSDavid van Moolenbroek 		1,		-EPIPE,		-EPIPE,		-EPIPE,
295*baa5830fSDavid van Moolenbroek 		-EPIPE,		-EPIPE,		-EPIPE,		-EPIPE,
296*baa5830fSDavid van Moolenbroek 		-EPIPE,		-EPIPE,		-EPIPE,		-EPIPE,
297*baa5830fSDavid van Moolenbroek 		-EPIPE,		-EPIPE,		-EPIPE,		-EPIPE,
298*baa5830fSDavid van Moolenbroek 		-EPIPE,		-ECONNRESET,	-EPIPE,		-ENOTCONN,
299*baa5830fSDavid van Moolenbroek 	},
300*baa5830fSDavid van Moolenbroek 	[C_SELECT_R]		= {
301*baa5830fSDavid van Moolenbroek 		1,		1,		1,		1,
302*baa5830fSDavid van Moolenbroek 		1,		0,		1,		1,
303*baa5830fSDavid van Moolenbroek 		1,		0,		0,		0,
304*baa5830fSDavid van Moolenbroek 		1,		0,		1,		0,
305*baa5830fSDavid van Moolenbroek 		1,		1,		1,		1,
306*baa5830fSDavid van Moolenbroek 		1,		1,		1,		1,
307*baa5830fSDavid van Moolenbroek 		1,		1,		1,		1,
308*baa5830fSDavid van Moolenbroek 		1,		1,		1,		1,
309*baa5830fSDavid van Moolenbroek 		1,		1,		1,		1,
310*baa5830fSDavid van Moolenbroek 	},
311*baa5830fSDavid van Moolenbroek 	[C_SELECT_W]		= {
312*baa5830fSDavid van Moolenbroek 		1,		1,		1,		1,
313*baa5830fSDavid van Moolenbroek 		1,		1,		1,		1,
314*baa5830fSDavid van Moolenbroek 		1,		0,		1,		1,
315*baa5830fSDavid van Moolenbroek 		1,		1,		1,		1,
316*baa5830fSDavid van Moolenbroek 		1,		1,		1,		1,
317*baa5830fSDavid van Moolenbroek 		1,		1,		1,		1,
318*baa5830fSDavid van Moolenbroek 		1,		1,		1,		1,
319*baa5830fSDavid van Moolenbroek 		1,		1,		1,		1,
320*baa5830fSDavid van Moolenbroek 		1,		1,		1,		1,
321*baa5830fSDavid van Moolenbroek 	},
322*baa5830fSDavid van Moolenbroek 	[C_SELECT_X]		= {
323*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
324*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
325*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
326*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
327*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
328*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
329*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
330*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
331*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
332*baa5830fSDavid van Moolenbroek 	},
333*baa5830fSDavid van Moolenbroek 	[C_SETSOCKOPT_BC]	= {
334*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
335*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
336*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
337*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
338*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
339*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
340*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
341*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
342*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
343*baa5830fSDavid van Moolenbroek 	},
344*baa5830fSDavid van Moolenbroek 	[C_SETSOCKOPT_KA]	= {
345*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
346*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
347*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
348*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
349*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
350*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
351*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
352*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
353*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
354*baa5830fSDavid van Moolenbroek 	},
355*baa5830fSDavid van Moolenbroek 	[C_SETSOCKOPT_L]	= {
356*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
357*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
358*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
359*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
360*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
361*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
362*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
363*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
364*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
365*baa5830fSDavid van Moolenbroek 	},
366*baa5830fSDavid van Moolenbroek 	[C_SETSOCKOPT_RA]	= {
367*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
368*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
369*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
370*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
371*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
372*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
373*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
374*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
375*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
376*baa5830fSDavid van Moolenbroek 	},
377*baa5830fSDavid van Moolenbroek 	[C_SHUTDOWN_R]		= {
378*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
379*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
380*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
381*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
382*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
383*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
384*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
385*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
386*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
387*baa5830fSDavid van Moolenbroek 	},
388*baa5830fSDavid van Moolenbroek 	[C_SHUTDOWN_RW]		= {
389*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
390*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
391*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
392*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
393*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
394*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
395*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
396*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
397*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
398*baa5830fSDavid van Moolenbroek 	},
399*baa5830fSDavid van Moolenbroek 	[C_SHUTDOWN_W]		= {
400*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
401*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
402*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
403*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
404*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
405*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
406*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
407*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
408*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
409*baa5830fSDavid van Moolenbroek 	},
410*baa5830fSDavid van Moolenbroek };
411*baa5830fSDavid van Moolenbroek 
412*baa5830fSDavid van Moolenbroek /*
413*baa5830fSDavid van Moolenbroek  * Set up a connection-oriented socket file descriptor in the requested state
414*baa5830fSDavid van Moolenbroek  * and pass it to socklib_sweep_call() along with local and remote addresses
415*baa5830fSDavid van Moolenbroek  * and their length.
416*baa5830fSDavid van Moolenbroek  */
417*baa5830fSDavid van Moolenbroek static int
unix_connect_sweep(int domain,int type,int protocol __unused,enum state state,enum call call)418*baa5830fSDavid van Moolenbroek unix_connect_sweep(int domain, int type, int protocol __unused,
419*baa5830fSDavid van Moolenbroek 	enum state state, enum call call)
420*baa5830fSDavid van Moolenbroek {
421*baa5830fSDavid van Moolenbroek 	struct sockaddr_un sunA, sunB, sunC;
422*baa5830fSDavid van Moolenbroek 	char buf[1];
423*baa5830fSDavid van Moolenbroek 	socklen_t len;
424*baa5830fSDavid van Moolenbroek 	fd_set fds;
425*baa5830fSDavid van Moolenbroek 	int r, fd, fd2, fd3, tmpfd, val, fl;
426*baa5830fSDavid van Moolenbroek 
427*baa5830fSDavid van Moolenbroek 	(void)unlink(SOCK_PATH_A);
428*baa5830fSDavid van Moolenbroek 	(void)unlink(SOCK_PATH_B);
429*baa5830fSDavid van Moolenbroek 	(void)unlink(SOCK_PATH_C);
430*baa5830fSDavid van Moolenbroek 
431*baa5830fSDavid van Moolenbroek 	memset(&sunA, 0, sizeof(sunA));
432*baa5830fSDavid van Moolenbroek 	sunA.sun_family = AF_UNIX;
433*baa5830fSDavid van Moolenbroek 	strlcpy(sunA.sun_path, SOCK_PATH_A, sizeof(sunA.sun_path));
434*baa5830fSDavid van Moolenbroek 
435*baa5830fSDavid van Moolenbroek 	fd = fd3 = -1;
436*baa5830fSDavid van Moolenbroek 
437*baa5830fSDavid van Moolenbroek 	fd2 = get_bound_socket(type | SOCK_NONBLOCK, SOCK_PATH_B, &sunB);
438*baa5830fSDavid van Moolenbroek 
439*baa5830fSDavid van Moolenbroek 	if (listen(fd2, 1) == -1) e(0);
440*baa5830fSDavid van Moolenbroek 
441*baa5830fSDavid van Moolenbroek 	switch (state) {
442*baa5830fSDavid van Moolenbroek 	case S_NEW:
443*baa5830fSDavid van Moolenbroek 	case S_N_SHUT_R:
444*baa5830fSDavid van Moolenbroek 	case S_N_SHUT_W:
445*baa5830fSDavid van Moolenbroek 	case S_N_SHUT_RW:
446*baa5830fSDavid van Moolenbroek 		if ((fd = socket(AF_UNIX, type | SOCK_NONBLOCK, 0)) < 0) e(0);
447*baa5830fSDavid van Moolenbroek 
448*baa5830fSDavid van Moolenbroek 		switch (state) {
449*baa5830fSDavid van Moolenbroek 		case S_N_SHUT_R: if (shutdown(fd, SHUT_RD)) e(0); break;
450*baa5830fSDavid van Moolenbroek 		case S_N_SHUT_W: if (shutdown(fd, SHUT_WR)) e(0); break;
451*baa5830fSDavid van Moolenbroek 		case S_N_SHUT_RW: if (shutdown(fd, SHUT_RDWR)) e(0); break;
452*baa5830fSDavid van Moolenbroek 		default: break;
453*baa5830fSDavid van Moolenbroek 		}
454*baa5830fSDavid van Moolenbroek 
455*baa5830fSDavid van Moolenbroek 		break;
456*baa5830fSDavid van Moolenbroek 
457*baa5830fSDavid van Moolenbroek 	case S_BOUND:
458*baa5830fSDavid van Moolenbroek 	case S_LISTENING:
459*baa5830fSDavid van Moolenbroek 	case S_L_SHUT_R:
460*baa5830fSDavid van Moolenbroek 	case S_L_SHUT_W:
461*baa5830fSDavid van Moolenbroek 	case S_L_SHUT_RW:
462*baa5830fSDavid van Moolenbroek 		fd = get_bound_socket(type | SOCK_NONBLOCK, SOCK_PATH_A,
463*baa5830fSDavid van Moolenbroek 		    &sunA);
464*baa5830fSDavid van Moolenbroek 
465*baa5830fSDavid van Moolenbroek 		if (state == S_BOUND)
466*baa5830fSDavid van Moolenbroek 			break;
467*baa5830fSDavid van Moolenbroek 
468*baa5830fSDavid van Moolenbroek 		if (listen(fd, 1) == -1) e(0);
469*baa5830fSDavid van Moolenbroek 
470*baa5830fSDavid van Moolenbroek 		switch (state) {
471*baa5830fSDavid van Moolenbroek 		case S_L_SHUT_R: if (shutdown(fd, SHUT_RD)) e(0); break;
472*baa5830fSDavid van Moolenbroek 		case S_L_SHUT_W: if (shutdown(fd, SHUT_WR)) e(0); break;
473*baa5830fSDavid van Moolenbroek 		case S_L_SHUT_RW: if (shutdown(fd, SHUT_RDWR)) e(0); break;
474*baa5830fSDavid van Moolenbroek 		default: break;
475*baa5830fSDavid van Moolenbroek 		}
476*baa5830fSDavid van Moolenbroek 
477*baa5830fSDavid van Moolenbroek 		break;
478*baa5830fSDavid van Moolenbroek 
479*baa5830fSDavid van Moolenbroek 	case S_CONNECTING:
480*baa5830fSDavid van Moolenbroek 		/*
481*baa5830fSDavid van Moolenbroek 		 * The following block is nonportable.  On NetBSD, the
482*baa5830fSDavid van Moolenbroek 		 * LOCAL_CONNWAIT socket option is present but seems somewhat..
483*baa5830fSDavid van Moolenbroek 		 * under-tested.  On Linux, it is not possible to put a UNIX
484*baa5830fSDavid van Moolenbroek 		 * domain socket in a connecting state.
485*baa5830fSDavid van Moolenbroek 		 */
486*baa5830fSDavid van Moolenbroek 		if ((fd = socket(AF_UNIX, type | SOCK_NONBLOCK, 0)) < 0) e(0);
487*baa5830fSDavid van Moolenbroek 
488*baa5830fSDavid van Moolenbroek 		val = 1;
489*baa5830fSDavid van Moolenbroek 		if (setsockopt(fd, 0, LOCAL_CONNWAIT, &val, sizeof(val)) != 0)
490*baa5830fSDavid van Moolenbroek 			e(0);
491*baa5830fSDavid van Moolenbroek 
492*baa5830fSDavid van Moolenbroek 		if (connect(fd, (struct sockaddr *)&sunB, sizeof(sunB)) != -1)
493*baa5830fSDavid van Moolenbroek 			e(0);
494*baa5830fSDavid van Moolenbroek 		if (errno != EINPROGRESS) e(0);
495*baa5830fSDavid van Moolenbroek 
496*baa5830fSDavid van Moolenbroek 		break;
497*baa5830fSDavid van Moolenbroek 
498*baa5830fSDavid van Moolenbroek 	case S_CONNECTED:
499*baa5830fSDavid van Moolenbroek 	case S_ACCEPTED:
500*baa5830fSDavid van Moolenbroek 	case S_SHUT_R:
501*baa5830fSDavid van Moolenbroek 	case S_SHUT_W:
502*baa5830fSDavid van Moolenbroek 	case S_SHUT_RW:
503*baa5830fSDavid van Moolenbroek 	case S_RSHUT_R:
504*baa5830fSDavid van Moolenbroek 	case S_RSHUT_W:
505*baa5830fSDavid van Moolenbroek 	case S_RSHUT_RW:
506*baa5830fSDavid van Moolenbroek 	case S_SHUT2_R:
507*baa5830fSDavid van Moolenbroek 	case S_SHUT2_W:
508*baa5830fSDavid van Moolenbroek 	case S_SHUT2_RW:
509*baa5830fSDavid van Moolenbroek 		if ((fd = socket(AF_UNIX, type | SOCK_NONBLOCK, 0)) < 0) e(0);
510*baa5830fSDavid van Moolenbroek 
511*baa5830fSDavid van Moolenbroek 		if (connect(fd, (struct sockaddr *)&sunB, sizeof(sunB)) != 0)
512*baa5830fSDavid van Moolenbroek 			e(0);
513*baa5830fSDavid van Moolenbroek 
514*baa5830fSDavid van Moolenbroek 		len = sizeof(sunC);
515*baa5830fSDavid van Moolenbroek 		if ((fd3 = accept(fd2, (struct sockaddr *)&sunC, &len)) < 0)
516*baa5830fSDavid van Moolenbroek 			e(0);
517*baa5830fSDavid van Moolenbroek 
518*baa5830fSDavid van Moolenbroek 		if ((fl = fcntl(fd3, F_GETFL)) == -1) e(0);
519*baa5830fSDavid van Moolenbroek 		if (fcntl(fd3, F_SETFL, fl | O_NONBLOCK) != 0) e(0);
520*baa5830fSDavid van Moolenbroek 
521*baa5830fSDavid van Moolenbroek 		/* Just to make sure, wait for the socket to be connected. */
522*baa5830fSDavid van Moolenbroek 		FD_ZERO(&fds);
523*baa5830fSDavid van Moolenbroek 		FD_SET(fd, &fds);
524*baa5830fSDavid van Moolenbroek 		if (select(fd + 1, NULL, &fds, NULL, NULL) != 1) e(0);
525*baa5830fSDavid van Moolenbroek 
526*baa5830fSDavid van Moolenbroek 		switch (state) {
527*baa5830fSDavid van Moolenbroek 		case S_SHUT_R:
528*baa5830fSDavid van Moolenbroek 		case S_SHUT2_R: if (shutdown(fd, SHUT_RD)) e(0); break;
529*baa5830fSDavid van Moolenbroek 		case S_SHUT_W:
530*baa5830fSDavid van Moolenbroek 		case S_SHUT2_W: if (shutdown(fd, SHUT_WR)) e(0); break;
531*baa5830fSDavid van Moolenbroek 		case S_SHUT_RW:
532*baa5830fSDavid van Moolenbroek 		case S_SHUT2_RW: if (shutdown(fd, SHUT_RDWR)) e(0); break;
533*baa5830fSDavid van Moolenbroek 		default: break;
534*baa5830fSDavid van Moolenbroek 		}
535*baa5830fSDavid van Moolenbroek 
536*baa5830fSDavid van Moolenbroek 		switch (state) {
537*baa5830fSDavid van Moolenbroek 		case S_RSHUT_R:
538*baa5830fSDavid van Moolenbroek 		case S_SHUT2_R: if (shutdown(fd3, SHUT_RD)) e(0); break;
539*baa5830fSDavid van Moolenbroek 		case S_RSHUT_W:
540*baa5830fSDavid van Moolenbroek 		case S_SHUT2_W: if (shutdown(fd3, SHUT_WR)) e(0); break;
541*baa5830fSDavid van Moolenbroek 		case S_RSHUT_RW:
542*baa5830fSDavid van Moolenbroek 		case S_SHUT2_RW: if (shutdown(fd3, SHUT_RDWR)) e(0); break;
543*baa5830fSDavid van Moolenbroek 		default: break;
544*baa5830fSDavid van Moolenbroek 		}
545*baa5830fSDavid van Moolenbroek 
546*baa5830fSDavid van Moolenbroek 		if (state == S_ACCEPTED) {
547*baa5830fSDavid van Moolenbroek 			tmpfd = fd;
548*baa5830fSDavid van Moolenbroek 			fd = fd3;
549*baa5830fSDavid van Moolenbroek 			fd3 = tmpfd;
550*baa5830fSDavid van Moolenbroek 		}
551*baa5830fSDavid van Moolenbroek 
552*baa5830fSDavid van Moolenbroek 		break;
553*baa5830fSDavid van Moolenbroek 
554*baa5830fSDavid van Moolenbroek 	case S_PRE_EOF:
555*baa5830fSDavid van Moolenbroek 	case S_AT_EOF:
556*baa5830fSDavid van Moolenbroek 	case S_POST_EOF:
557*baa5830fSDavid van Moolenbroek 	case S_PRE_SHUT_R:
558*baa5830fSDavid van Moolenbroek 	case S_EOF_SHUT_R:
559*baa5830fSDavid van Moolenbroek 	case S_POST_SHUT_R:
560*baa5830fSDavid van Moolenbroek 	case S_PRE_SHUT_W:
561*baa5830fSDavid van Moolenbroek 	case S_EOF_SHUT_W:
562*baa5830fSDavid van Moolenbroek 	case S_POST_SHUT_W:
563*baa5830fSDavid van Moolenbroek 	case S_PRE_SHUT_RW:
564*baa5830fSDavid van Moolenbroek 	case S_EOF_SHUT_RW:
565*baa5830fSDavid van Moolenbroek 	case S_POST_SHUT_RW:
566*baa5830fSDavid van Moolenbroek 		if ((fd = socket(AF_UNIX, type | SOCK_NONBLOCK, 0)) < 0) e(0);
567*baa5830fSDavid van Moolenbroek 
568*baa5830fSDavid van Moolenbroek 		if (connect(fd, (struct sockaddr *)&sunB, sizeof(sunB)) != 0)
569*baa5830fSDavid van Moolenbroek 			e(0);
570*baa5830fSDavid van Moolenbroek 
571*baa5830fSDavid van Moolenbroek 		len = sizeof(sunC);
572*baa5830fSDavid van Moolenbroek 		if ((fd3 = accept(fd2, (struct sockaddr *)&sunC, &len)) < 0)
573*baa5830fSDavid van Moolenbroek 			e(0);
574*baa5830fSDavid van Moolenbroek 
575*baa5830fSDavid van Moolenbroek 		if ((fl = fcntl(fd3, F_GETFL)) == -1) e(0);
576*baa5830fSDavid van Moolenbroek 		if (fcntl(fd3, F_SETFL, fl | O_NONBLOCK) != 0) e(0);
577*baa5830fSDavid van Moolenbroek 
578*baa5830fSDavid van Moolenbroek 		if (send(fd3, "", 1, 0) != 1) e(0);
579*baa5830fSDavid van Moolenbroek 
580*baa5830fSDavid van Moolenbroek 		if (close(fd3) != 0) e(0);
581*baa5830fSDavid van Moolenbroek 		fd3 = -1;
582*baa5830fSDavid van Moolenbroek 
583*baa5830fSDavid van Moolenbroek 		FD_ZERO(&fds);
584*baa5830fSDavid van Moolenbroek 		FD_SET(fd, &fds);
585*baa5830fSDavid van Moolenbroek 		if (select(fd + 1, &fds, NULL, NULL, NULL) != 1) e(0);
586*baa5830fSDavid van Moolenbroek 
587*baa5830fSDavid van Moolenbroek 		switch (state) {
588*baa5830fSDavid van Moolenbroek 		case S_AT_EOF:
589*baa5830fSDavid van Moolenbroek 		case S_EOF_SHUT_R:
590*baa5830fSDavid van Moolenbroek 		case S_EOF_SHUT_W:
591*baa5830fSDavid van Moolenbroek 		case S_EOF_SHUT_RW:
592*baa5830fSDavid van Moolenbroek 			if (recv(fd, buf, sizeof(buf), 0) != 1) e(0);
593*baa5830fSDavid van Moolenbroek 			break;
594*baa5830fSDavid van Moolenbroek 		case S_POST_EOF:
595*baa5830fSDavid van Moolenbroek 		case S_POST_SHUT_R:
596*baa5830fSDavid van Moolenbroek 		case S_POST_SHUT_W:
597*baa5830fSDavid van Moolenbroek 		case S_POST_SHUT_RW:
598*baa5830fSDavid van Moolenbroek 			if (recv(fd, buf, sizeof(buf), 0) != 1) e(0);
599*baa5830fSDavid van Moolenbroek 			if (recv(fd, buf, sizeof(buf), 0) != 0) e(0);
600*baa5830fSDavid van Moolenbroek 			break;
601*baa5830fSDavid van Moolenbroek 		default:
602*baa5830fSDavid van Moolenbroek 			break;
603*baa5830fSDavid van Moolenbroek 		}
604*baa5830fSDavid van Moolenbroek 
605*baa5830fSDavid van Moolenbroek 		switch (state) {
606*baa5830fSDavid van Moolenbroek 		case S_PRE_SHUT_R:
607*baa5830fSDavid van Moolenbroek 		case S_EOF_SHUT_R:
608*baa5830fSDavid van Moolenbroek 		case S_POST_SHUT_R: if (shutdown(fd, SHUT_RD)) e(0); break;
609*baa5830fSDavid van Moolenbroek 		case S_PRE_SHUT_W:
610*baa5830fSDavid van Moolenbroek 		case S_EOF_SHUT_W:
611*baa5830fSDavid van Moolenbroek 		case S_POST_SHUT_W: if (shutdown(fd, SHUT_WR)) e(0); break;
612*baa5830fSDavid van Moolenbroek 		case S_PRE_SHUT_RW:
613*baa5830fSDavid van Moolenbroek 		case S_EOF_SHUT_RW:
614*baa5830fSDavid van Moolenbroek 		case S_POST_SHUT_RW: if (shutdown(fd, SHUT_RDWR)) e(0); break;
615*baa5830fSDavid van Moolenbroek 		default: break;
616*baa5830fSDavid van Moolenbroek 		}
617*baa5830fSDavid van Moolenbroek 
618*baa5830fSDavid van Moolenbroek 		break;
619*baa5830fSDavid van Moolenbroek 
620*baa5830fSDavid van Moolenbroek 	case S_AT_RESET:
621*baa5830fSDavid van Moolenbroek 	case S_POST_RESET:
622*baa5830fSDavid van Moolenbroek 		if ((fd = socket(AF_UNIX, type | SOCK_NONBLOCK, 0)) < 0) e(0);
623*baa5830fSDavid van Moolenbroek 
624*baa5830fSDavid van Moolenbroek 		if (connect(fd, (struct sockaddr *)&sunB, sizeof(sunB)) != 0)
625*baa5830fSDavid van Moolenbroek 			e(0);
626*baa5830fSDavid van Moolenbroek 
627*baa5830fSDavid van Moolenbroek 		/*
628*baa5830fSDavid van Moolenbroek 		 * Closing the listening socket before the connection has been
629*baa5830fSDavid van Moolenbroek 		 * accepted should generate ECONNRESET on the connected socket.
630*baa5830fSDavid van Moolenbroek 		 * Well, should.. we choose to do that.  So does Linux.  NetBSD
631*baa5830fSDavid van Moolenbroek 		 * just returns EOF for that case.  There are really no strong
632*baa5830fSDavid van Moolenbroek 		 * arguments for either behavior.
633*baa5830fSDavid van Moolenbroek 		 */
634*baa5830fSDavid van Moolenbroek 		if (close(fd2) != 0) e(0);
635*baa5830fSDavid van Moolenbroek 
636*baa5830fSDavid van Moolenbroek 		if (state == S_POST_RESET)
637*baa5830fSDavid van Moolenbroek 			(void)recv(fd, buf, sizeof(buf), 0);
638*baa5830fSDavid van Moolenbroek 
639*baa5830fSDavid van Moolenbroek 		/* Recreate the listening socket just for consistency. */
640*baa5830fSDavid van Moolenbroek 		fd2 = get_bound_socket(type | SOCK_NONBLOCK, SOCK_PATH_B,
641*baa5830fSDavid van Moolenbroek 		    &sunB);
642*baa5830fSDavid van Moolenbroek 
643*baa5830fSDavid van Moolenbroek 		if (listen(fd2, 1) == -1) e(0);
644*baa5830fSDavid van Moolenbroek 
645*baa5830fSDavid van Moolenbroek 		break;
646*baa5830fSDavid van Moolenbroek 
647*baa5830fSDavid van Moolenbroek 	case S_POST_FAILED:
648*baa5830fSDavid van Moolenbroek 		if ((fd = socket(AF_UNIX, type | SOCK_NONBLOCK, 0)) < 0) e(0);
649*baa5830fSDavid van Moolenbroek 
650*baa5830fSDavid van Moolenbroek 		memset(&sunC, 0, sizeof(sunC));
651*baa5830fSDavid van Moolenbroek 		sunC.sun_family = AF_UNIX;
652*baa5830fSDavid van Moolenbroek 		strlcpy(sunC.sun_path, SOCK_PATH_C, sizeof(sunC.sun_path));
653*baa5830fSDavid van Moolenbroek 
654*baa5830fSDavid van Moolenbroek 		r = connect(fd, (struct sockaddr *)&sunC, sizeof(sunC));
655*baa5830fSDavid van Moolenbroek 		if (r != -1 || errno != ENOENT)
656*baa5830fSDavid van Moolenbroek 			e(0);
657*baa5830fSDavid van Moolenbroek 
658*baa5830fSDavid van Moolenbroek 		break;
659*baa5830fSDavid van Moolenbroek 
660*baa5830fSDavid van Moolenbroek 	default:
661*baa5830fSDavid van Moolenbroek 		e(0);
662*baa5830fSDavid van Moolenbroek 	}
663*baa5830fSDavid van Moolenbroek 
664*baa5830fSDavid van Moolenbroek 	r = socklib_sweep_call(call, fd, (struct sockaddr *)&sunA,
665*baa5830fSDavid van Moolenbroek 	    (struct sockaddr *)&sunB, sizeof(struct sockaddr_un));
666*baa5830fSDavid van Moolenbroek 
667*baa5830fSDavid van Moolenbroek 	if (fd >= 0 && close(fd) != 0) e(0);
668*baa5830fSDavid van Moolenbroek 	if (fd2 >= 0 && close(fd2) != 0) e(0);
669*baa5830fSDavid van Moolenbroek 	if (fd3 >= 0 && close(fd3) != 0) e(0);
670*baa5830fSDavid van Moolenbroek 
671*baa5830fSDavid van Moolenbroek 	(void)unlink(SOCK_PATH_A);
672*baa5830fSDavid van Moolenbroek 	(void)unlink(SOCK_PATH_B);
673*baa5830fSDavid van Moolenbroek 
674*baa5830fSDavid van Moolenbroek 	return r;
675*baa5830fSDavid van Moolenbroek }
676*baa5830fSDavid van Moolenbroek 
677*baa5830fSDavid van Moolenbroek static const enum state unix_dgram_states[] = {
678*baa5830fSDavid van Moolenbroek 		S_NEW,		S_N_SHUT_R,	S_N_SHUT_W,	S_N_SHUT_RW,
679*baa5830fSDavid van Moolenbroek 		S_BOUND,	S_CONNECTED,	S_SHUT_R,	S_SHUT_W,
680*baa5830fSDavid van Moolenbroek 		S_SHUT_RW,	S_RSHUT_R,	S_RSHUT_W,	S_RSHUT_RW,
681*baa5830fSDavid van Moolenbroek 		S_SHUT2_R,	S_SHUT2_W,	S_SHUT2_RW,	S_PRE_RESET,
682*baa5830fSDavid van Moolenbroek 		S_AT_RESET,	S_POST_RESET
683*baa5830fSDavid van Moolenbroek };
684*baa5830fSDavid van Moolenbroek 
685*baa5830fSDavid van Moolenbroek static const int unix_dgram_results[][__arraycount(unix_dgram_states)] = {
686*baa5830fSDavid van Moolenbroek 	[C_ACCEPT]		= {
687*baa5830fSDavid van Moolenbroek 		-EOPNOTSUPP,	-EOPNOTSUPP,	-EOPNOTSUPP,	-EOPNOTSUPP,
688*baa5830fSDavid van Moolenbroek 		-EOPNOTSUPP,	-EOPNOTSUPP,	-EOPNOTSUPP,	-EOPNOTSUPP,
689*baa5830fSDavid van Moolenbroek 		-EOPNOTSUPP,	-EOPNOTSUPP,	-EOPNOTSUPP,	-EOPNOTSUPP,
690*baa5830fSDavid van Moolenbroek 		-EOPNOTSUPP,	-EOPNOTSUPP,	-EOPNOTSUPP,	-EOPNOTSUPP,
691*baa5830fSDavid van Moolenbroek 		-EOPNOTSUPP,	-EOPNOTSUPP,
692*baa5830fSDavid van Moolenbroek 	},
693*baa5830fSDavid van Moolenbroek 	[C_BIND]		= {
694*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
695*baa5830fSDavid van Moolenbroek 		-EINVAL,	-EINVAL,	-EINVAL,	-EINVAL,
696*baa5830fSDavid van Moolenbroek 		-EINVAL,	-EINVAL,	-EINVAL,	-EINVAL,
697*baa5830fSDavid van Moolenbroek 		-EINVAL,	-EINVAL,	-EINVAL,	-EINVAL,
698*baa5830fSDavid van Moolenbroek 		-EINVAL,	-EINVAL,
699*baa5830fSDavid van Moolenbroek 	},
700*baa5830fSDavid van Moolenbroek 	[C_CONNECT]		= {
701*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
702*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
703*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
704*baa5830fSDavid van Moolenbroek 		0,		0,		0,		-ECONNREFUSED,
705*baa5830fSDavid van Moolenbroek 		-ECONNREFUSED,	-ECONNREFUSED,
706*baa5830fSDavid van Moolenbroek 	},
707*baa5830fSDavid van Moolenbroek 	[C_GETPEERNAME]		= {
708*baa5830fSDavid van Moolenbroek 		-ENOTCONN,	-ENOTCONN,	-ENOTCONN,	-ENOTCONN,
709*baa5830fSDavid van Moolenbroek 		-ENOTCONN,	0,		0,		0,
710*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
711*baa5830fSDavid van Moolenbroek 		0,		0,		0,		-ENOTCONN,
712*baa5830fSDavid van Moolenbroek 		-ENOTCONN,	-ENOTCONN,
713*baa5830fSDavid van Moolenbroek 	},
714*baa5830fSDavid van Moolenbroek 	[C_GETSOCKNAME]		= {
715*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
716*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
717*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
718*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
719*baa5830fSDavid van Moolenbroek 		0,		0,
720*baa5830fSDavid van Moolenbroek 	},
721*baa5830fSDavid van Moolenbroek 	[C_GETSOCKOPT_ERR]	= {
722*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
723*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
724*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
725*baa5830fSDavid van Moolenbroek 		0,		0,		0,		-ECONNRESET,
726*baa5830fSDavid van Moolenbroek 		-ECONNRESET,	0,
727*baa5830fSDavid van Moolenbroek 	},
728*baa5830fSDavid van Moolenbroek 	[C_GETSOCKOPT_KA]	= {
729*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
730*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
731*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
732*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
733*baa5830fSDavid van Moolenbroek 		0,		0,
734*baa5830fSDavid van Moolenbroek 	},
735*baa5830fSDavid van Moolenbroek 	[C_GETSOCKOPT_RB]	= {
736*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
737*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
738*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
739*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
740*baa5830fSDavid van Moolenbroek 		0,		0,
741*baa5830fSDavid van Moolenbroek 	},
742*baa5830fSDavid van Moolenbroek 	[C_IOCTL_NREAD]		= {
743*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
744*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
745*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
746*baa5830fSDavid van Moolenbroek 		0,		0,		0,		1,
747*baa5830fSDavid van Moolenbroek 		0,		0,
748*baa5830fSDavid van Moolenbroek 	},
749*baa5830fSDavid van Moolenbroek 	[C_LISTEN]		= {
750*baa5830fSDavid van Moolenbroek 		-EOPNOTSUPP,	-EOPNOTSUPP,	-EOPNOTSUPP,	-EOPNOTSUPP,
751*baa5830fSDavid van Moolenbroek 		-EOPNOTSUPP,	-EOPNOTSUPP,	-EOPNOTSUPP,	-EOPNOTSUPP,
752*baa5830fSDavid van Moolenbroek 		-EOPNOTSUPP,	-EOPNOTSUPP,	-EOPNOTSUPP,	-EOPNOTSUPP,
753*baa5830fSDavid van Moolenbroek 		-EOPNOTSUPP,	-EOPNOTSUPP,	-EOPNOTSUPP,	-EOPNOTSUPP,
754*baa5830fSDavid van Moolenbroek 		-EOPNOTSUPP,	-EOPNOTSUPP,
755*baa5830fSDavid van Moolenbroek 	},
756*baa5830fSDavid van Moolenbroek 	[C_RECV]		= {
757*baa5830fSDavid van Moolenbroek 		-EAGAIN,	0,		-EAGAIN,	0,
758*baa5830fSDavid van Moolenbroek 		-EAGAIN,	-EAGAIN,	0,		-EAGAIN,
759*baa5830fSDavid van Moolenbroek 		0,		-EAGAIN,	-EAGAIN,	-EAGAIN,
760*baa5830fSDavid van Moolenbroek 		0,		-EAGAIN,	0,		1,
761*baa5830fSDavid van Moolenbroek 		-ECONNRESET,	-EAGAIN,
762*baa5830fSDavid van Moolenbroek 	},
763*baa5830fSDavid van Moolenbroek 	[C_RECVFROM]		= {
764*baa5830fSDavid van Moolenbroek 		-EAGAIN,	0,		-EAGAIN,	0,
765*baa5830fSDavid van Moolenbroek 		-EAGAIN,	-EAGAIN,	0,		-EAGAIN,
766*baa5830fSDavid van Moolenbroek 		0,		-EAGAIN,	-EAGAIN,	-EAGAIN,
767*baa5830fSDavid van Moolenbroek 		0,		-EAGAIN,	0,		1,
768*baa5830fSDavid van Moolenbroek 		-ECONNRESET,	-EAGAIN,
769*baa5830fSDavid van Moolenbroek 	},
770*baa5830fSDavid van Moolenbroek 	[C_SEND]		= {
771*baa5830fSDavid van Moolenbroek 		-EDESTADDRREQ,	-EDESTADDRREQ,	-EPIPE,		-EPIPE,
772*baa5830fSDavid van Moolenbroek 		-EDESTADDRREQ,	1,		1,		-EPIPE,
773*baa5830fSDavid van Moolenbroek 		-EPIPE,		-ENOBUFS,	1,		-ENOBUFS,
774*baa5830fSDavid van Moolenbroek 		-ENOBUFS,	-EPIPE,		-EPIPE,		-ECONNRESET,
775*baa5830fSDavid van Moolenbroek 		-ECONNRESET,	-EDESTADDRREQ,
776*baa5830fSDavid van Moolenbroek 	},
777*baa5830fSDavid van Moolenbroek 	[C_SENDTO]		= {
778*baa5830fSDavid van Moolenbroek 		1,		1,		-EPIPE,		-EPIPE,
779*baa5830fSDavid van Moolenbroek 		1,		1,		1,		-EPIPE,
780*baa5830fSDavid van Moolenbroek 		-EPIPE,		-ENOBUFS,	1,		-ENOBUFS,
781*baa5830fSDavid van Moolenbroek 		-ENOBUFS,	-EPIPE,		-EPIPE,		-ECONNRESET,
782*baa5830fSDavid van Moolenbroek 		-ECONNRESET,	-ECONNREFUSED,
783*baa5830fSDavid van Moolenbroek 	},
784*baa5830fSDavid van Moolenbroek 	[C_SELECT_R]		= {
785*baa5830fSDavid van Moolenbroek 		0,		1,		0,		1,
786*baa5830fSDavid van Moolenbroek 		0,		0,		1,		0,
787*baa5830fSDavid van Moolenbroek 		1,		0,		0,		0,
788*baa5830fSDavid van Moolenbroek 		1,		0,		1,		1,
789*baa5830fSDavid van Moolenbroek 		1,		0,
790*baa5830fSDavid van Moolenbroek 	},
791*baa5830fSDavid van Moolenbroek 	[C_SELECT_W]		= {
792*baa5830fSDavid van Moolenbroek 		1,		1,		1,		1,
793*baa5830fSDavid van Moolenbroek 		1,		1,		1,		1,
794*baa5830fSDavid van Moolenbroek 		1,		1,		1,		1,
795*baa5830fSDavid van Moolenbroek 		1,		1,		1,		1,
796*baa5830fSDavid van Moolenbroek 		1,		1,
797*baa5830fSDavid van Moolenbroek 	},
798*baa5830fSDavid van Moolenbroek 	[C_SELECT_X]		= {
799*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
800*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
801*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
802*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
803*baa5830fSDavid van Moolenbroek 		0,		0,
804*baa5830fSDavid van Moolenbroek 	},
805*baa5830fSDavid van Moolenbroek 	[C_SETSOCKOPT_BC]	= {
806*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
807*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
808*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
809*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
810*baa5830fSDavid van Moolenbroek 		0,		0,
811*baa5830fSDavid van Moolenbroek 	},
812*baa5830fSDavid van Moolenbroek 	[C_SETSOCKOPT_KA]	= {
813*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
814*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
815*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
816*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
817*baa5830fSDavid van Moolenbroek 		0,		0,
818*baa5830fSDavid van Moolenbroek 	},
819*baa5830fSDavid van Moolenbroek 	[C_SETSOCKOPT_L]	= {
820*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
821*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
822*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
823*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
824*baa5830fSDavid van Moolenbroek 		0,		0,
825*baa5830fSDavid van Moolenbroek 	},
826*baa5830fSDavid van Moolenbroek 	[C_SETSOCKOPT_RA]	= {
827*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
828*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
829*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
830*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
831*baa5830fSDavid van Moolenbroek 		0,		0,
832*baa5830fSDavid van Moolenbroek 	},
833*baa5830fSDavid van Moolenbroek 	[C_SHUTDOWN_R]		= {
834*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
835*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
836*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
837*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
838*baa5830fSDavid van Moolenbroek 		0,		0,
839*baa5830fSDavid van Moolenbroek 	},
840*baa5830fSDavid van Moolenbroek 	[C_SHUTDOWN_RW]		= {
841*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
842*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
843*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
844*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
845*baa5830fSDavid van Moolenbroek 		0,		0,
846*baa5830fSDavid van Moolenbroek 	},
847*baa5830fSDavid van Moolenbroek 	[C_SHUTDOWN_W]		= {
848*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
849*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
850*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
851*baa5830fSDavid van Moolenbroek 		0,		0,		0,		0,
852*baa5830fSDavid van Moolenbroek 		0,		0,
853*baa5830fSDavid van Moolenbroek 	},
854*baa5830fSDavid van Moolenbroek };
855*baa5830fSDavid van Moolenbroek 
856*baa5830fSDavid van Moolenbroek /*
857*baa5830fSDavid van Moolenbroek  * Set up a datagram socket file descriptor in the requested state and pass it
858*baa5830fSDavid van Moolenbroek  * to socklib_sweep_call() along with local and remote addresses and their
859*baa5830fSDavid van Moolenbroek  * length.
860*baa5830fSDavid van Moolenbroek  */
861*baa5830fSDavid van Moolenbroek static int
unix_dgram_sweep(int domain __unused,int type,int protocol __unused,enum state state,enum call call)862*baa5830fSDavid van Moolenbroek unix_dgram_sweep(int domain __unused, int type, int protocol __unused,
863*baa5830fSDavid van Moolenbroek 	enum state state, enum call call)
864*baa5830fSDavid van Moolenbroek {
865*baa5830fSDavid van Moolenbroek 	struct sockaddr_un sunA, sunB;
866*baa5830fSDavid van Moolenbroek 	char buf[1];
867*baa5830fSDavid van Moolenbroek 	int r, fd, fd2;
868*baa5830fSDavid van Moolenbroek 
869*baa5830fSDavid van Moolenbroek 	(void)unlink(SOCK_PATH_A);
870*baa5830fSDavid van Moolenbroek 	(void)unlink(SOCK_PATH_B);
871*baa5830fSDavid van Moolenbroek 
872*baa5830fSDavid van Moolenbroek 	/* Create a bound remote socket. */
873*baa5830fSDavid van Moolenbroek 	fd2 = get_bound_socket(type | SOCK_NONBLOCK, SOCK_PATH_B, &sunB);
874*baa5830fSDavid van Moolenbroek 
875*baa5830fSDavid van Moolenbroek 	switch (state) {
876*baa5830fSDavid van Moolenbroek 	case S_NEW:
877*baa5830fSDavid van Moolenbroek 	case S_N_SHUT_R:
878*baa5830fSDavid van Moolenbroek 	case S_N_SHUT_W:
879*baa5830fSDavid van Moolenbroek 	case S_N_SHUT_RW:
880*baa5830fSDavid van Moolenbroek 		memset(&sunA, 0, sizeof(sunA));
881*baa5830fSDavid van Moolenbroek 		sunA.sun_family = AF_UNIX;
882*baa5830fSDavid van Moolenbroek 		strlcpy(sunA.sun_path, SOCK_PATH_A, sizeof(sunA.sun_path));
883*baa5830fSDavid van Moolenbroek 
884*baa5830fSDavid van Moolenbroek 		if ((fd = socket(AF_UNIX, type | SOCK_NONBLOCK, 0)) < 0)
885*baa5830fSDavid van Moolenbroek 			e(0);
886*baa5830fSDavid van Moolenbroek 
887*baa5830fSDavid van Moolenbroek 		switch (state) {
888*baa5830fSDavid van Moolenbroek 		case S_N_SHUT_R: if (shutdown(fd, SHUT_RD)) e(0); break;
889*baa5830fSDavid van Moolenbroek 		case S_N_SHUT_W: if (shutdown(fd, SHUT_WR)) e(0); break;
890*baa5830fSDavid van Moolenbroek 		case S_N_SHUT_RW: if (shutdown(fd, SHUT_RDWR)) e(0); break;
891*baa5830fSDavid van Moolenbroek 		default: break;
892*baa5830fSDavid van Moolenbroek 		}
893*baa5830fSDavid van Moolenbroek 
894*baa5830fSDavid van Moolenbroek 		break;
895*baa5830fSDavid van Moolenbroek 
896*baa5830fSDavid van Moolenbroek 	case S_BOUND:
897*baa5830fSDavid van Moolenbroek 	case S_CONNECTED:
898*baa5830fSDavid van Moolenbroek 	case S_SHUT_R:
899*baa5830fSDavid van Moolenbroek 	case S_SHUT_W:
900*baa5830fSDavid van Moolenbroek 	case S_SHUT_RW:
901*baa5830fSDavid van Moolenbroek 	case S_RSHUT_R:
902*baa5830fSDavid van Moolenbroek 	case S_RSHUT_W:
903*baa5830fSDavid van Moolenbroek 	case S_RSHUT_RW:
904*baa5830fSDavid van Moolenbroek 	case S_SHUT2_R:
905*baa5830fSDavid van Moolenbroek 	case S_SHUT2_W:
906*baa5830fSDavid van Moolenbroek 	case S_SHUT2_RW:
907*baa5830fSDavid van Moolenbroek 	case S_PRE_RESET:
908*baa5830fSDavid van Moolenbroek 	case S_AT_RESET:
909*baa5830fSDavid van Moolenbroek 	case S_POST_RESET:
910*baa5830fSDavid van Moolenbroek 		fd = get_bound_socket(type | SOCK_NONBLOCK, SOCK_PATH_A,
911*baa5830fSDavid van Moolenbroek 		    &sunA);
912*baa5830fSDavid van Moolenbroek 
913*baa5830fSDavid van Moolenbroek 		if (state == S_BOUND)
914*baa5830fSDavid van Moolenbroek 			break;
915*baa5830fSDavid van Moolenbroek 
916*baa5830fSDavid van Moolenbroek 		if (connect(fd, (struct sockaddr *)&sunB, sizeof(sunB)) != 0)
917*baa5830fSDavid van Moolenbroek 			e(0);
918*baa5830fSDavid van Moolenbroek 
919*baa5830fSDavid van Moolenbroek 		switch (state) {
920*baa5830fSDavid van Moolenbroek 		case S_SHUT_R:
921*baa5830fSDavid van Moolenbroek 		case S_SHUT2_R: if (shutdown(fd, SHUT_RD)) e(0); break;
922*baa5830fSDavid van Moolenbroek 		case S_SHUT_W:
923*baa5830fSDavid van Moolenbroek 		case S_SHUT2_W: if (shutdown(fd, SHUT_WR)) e(0); break;
924*baa5830fSDavid van Moolenbroek 		case S_SHUT_RW:
925*baa5830fSDavid van Moolenbroek 		case S_SHUT2_RW: if (shutdown(fd, SHUT_RDWR)) e(0); break;
926*baa5830fSDavid van Moolenbroek 		default: break;
927*baa5830fSDavid van Moolenbroek 		}
928*baa5830fSDavid van Moolenbroek 
929*baa5830fSDavid van Moolenbroek 		switch (state) {
930*baa5830fSDavid van Moolenbroek 		case S_RSHUT_R:
931*baa5830fSDavid van Moolenbroek 		case S_SHUT2_R: if (shutdown(fd2, SHUT_RD)) e(0); break;
932*baa5830fSDavid van Moolenbroek 		case S_RSHUT_W:
933*baa5830fSDavid van Moolenbroek 		case S_SHUT2_W: if (shutdown(fd2, SHUT_WR)) e(0); break;
934*baa5830fSDavid van Moolenbroek 		case S_RSHUT_RW:
935*baa5830fSDavid van Moolenbroek 		case S_SHUT2_RW: if (shutdown(fd2, SHUT_RDWR)) e(0); break;
936*baa5830fSDavid van Moolenbroek 		case S_PRE_RESET:
937*baa5830fSDavid van Moolenbroek 		case S_AT_RESET:
938*baa5830fSDavid van Moolenbroek 		case S_POST_RESET:
939*baa5830fSDavid van Moolenbroek 			if (sendto(fd2, "", 1, 0, (struct sockaddr *)&sunA,
940*baa5830fSDavid van Moolenbroek 			    sizeof(sunA)) != 1) e(0);
941*baa5830fSDavid van Moolenbroek 
942*baa5830fSDavid van Moolenbroek 			if (close(fd2) != 0) e(0);
943*baa5830fSDavid van Moolenbroek 			fd2 = -1;
944*baa5830fSDavid van Moolenbroek 
945*baa5830fSDavid van Moolenbroek 			if (state != S_PRE_RESET) {
946*baa5830fSDavid van Moolenbroek 				if (recv(fd, buf, sizeof(buf), 0) != 1) e(0);
947*baa5830fSDavid van Moolenbroek 			}
948*baa5830fSDavid van Moolenbroek 			if (state == S_POST_RESET) {
949*baa5830fSDavid van Moolenbroek 				(void)recv(fd, buf, sizeof(buf), 0);
950*baa5830fSDavid van Moolenbroek 			}
951*baa5830fSDavid van Moolenbroek 		default:
952*baa5830fSDavid van Moolenbroek 			break;
953*baa5830fSDavid van Moolenbroek 		}
954*baa5830fSDavid van Moolenbroek 
955*baa5830fSDavid van Moolenbroek 		break;
956*baa5830fSDavid van Moolenbroek 
957*baa5830fSDavid van Moolenbroek 	default:
958*baa5830fSDavid van Moolenbroek 		fd = -1;
959*baa5830fSDavid van Moolenbroek 		e(0);
960*baa5830fSDavid van Moolenbroek 	}
961*baa5830fSDavid van Moolenbroek 
962*baa5830fSDavid van Moolenbroek 	r = socklib_sweep_call(call, fd, (struct sockaddr *)&sunA,
963*baa5830fSDavid van Moolenbroek 	    (struct sockaddr *)&sunB, sizeof(struct sockaddr_un));
964*baa5830fSDavid van Moolenbroek 
965*baa5830fSDavid van Moolenbroek 	if (close(fd) != 0) e(0);
966*baa5830fSDavid van Moolenbroek 	if (fd2 != -1 && close(fd2) != 0) e(0);
967*baa5830fSDavid van Moolenbroek 
968*baa5830fSDavid van Moolenbroek 	(void)unlink(SOCK_PATH_A);
969*baa5830fSDavid van Moolenbroek 	(void)unlink(SOCK_PATH_B);
970*baa5830fSDavid van Moolenbroek 
971*baa5830fSDavid van Moolenbroek 	return r;
972*baa5830fSDavid van Moolenbroek }
973*baa5830fSDavid van Moolenbroek 
974*baa5830fSDavid van Moolenbroek /*
975*baa5830fSDavid van Moolenbroek  * Sweep test for socket calls versus socket states of all socket types.
976*baa5830fSDavid van Moolenbroek  */
977*baa5830fSDavid van Moolenbroek static void
test90a(void)978*baa5830fSDavid van Moolenbroek test90a(void)
979*baa5830fSDavid van Moolenbroek {
980*baa5830fSDavid van Moolenbroek 
981*baa5830fSDavid van Moolenbroek 	subtest = 1;
982*baa5830fSDavid van Moolenbroek 
983*baa5830fSDavid van Moolenbroek 	socklib_sweep(AF_UNIX, SOCK_STREAM, 0, unix_connect_states,
984*baa5830fSDavid van Moolenbroek 	    __arraycount(unix_connect_states),
985*baa5830fSDavid van Moolenbroek 	    (const int *)unix_connect_results, unix_connect_sweep);
986*baa5830fSDavid van Moolenbroek 
987*baa5830fSDavid van Moolenbroek 	socklib_sweep(AF_UNIX, SOCK_SEQPACKET, 0, unix_connect_states,
988*baa5830fSDavid van Moolenbroek 	    __arraycount(unix_connect_states),
989*baa5830fSDavid van Moolenbroek 	    (const int *)unix_connect_results, unix_connect_sweep);
990*baa5830fSDavid van Moolenbroek 
991*baa5830fSDavid van Moolenbroek 	socklib_sweep(AF_UNIX, SOCK_DGRAM, 0, unix_dgram_states,
992*baa5830fSDavid van Moolenbroek 	    __arraycount(unix_dgram_states), (const int *)unix_dgram_results,
993*baa5830fSDavid van Moolenbroek 	    unix_dgram_sweep);
994*baa5830fSDavid van Moolenbroek 
995*baa5830fSDavid van Moolenbroek }
996*baa5830fSDavid van Moolenbroek 
997*baa5830fSDavid van Moolenbroek /*
998*baa5830fSDavid van Moolenbroek  * Test for large sends and receives with MSG_WAITALL.
999*baa5830fSDavid van Moolenbroek  */
1000*baa5830fSDavid van Moolenbroek static void
test90b(void)1001*baa5830fSDavid van Moolenbroek test90b(void)
1002*baa5830fSDavid van Moolenbroek {
1003*baa5830fSDavid van Moolenbroek 	int fd[2];
1004*baa5830fSDavid van Moolenbroek 
1005*baa5830fSDavid van Moolenbroek 	subtest = 2;
1006*baa5830fSDavid van Moolenbroek 
1007*baa5830fSDavid van Moolenbroek 	if (socketpair(AF_UNIX, SOCK_STREAM, 0, fd) != 0) e(0);
1008*baa5830fSDavid van Moolenbroek 
1009*baa5830fSDavid van Moolenbroek 	socklib_large_transfers(fd);
1010*baa5830fSDavid van Moolenbroek }
1011*baa5830fSDavid van Moolenbroek 
1012*baa5830fSDavid van Moolenbroek /*
1013*baa5830fSDavid van Moolenbroek  * A randomized producer-consumer test for datagram sockets.
1014*baa5830fSDavid van Moolenbroek  */
1015*baa5830fSDavid van Moolenbroek static void
sub90c(int type)1016*baa5830fSDavid van Moolenbroek sub90c(int type)
1017*baa5830fSDavid van Moolenbroek {
1018*baa5830fSDavid van Moolenbroek 	char *buf;
1019*baa5830fSDavid van Moolenbroek 	time_t t;
1020*baa5830fSDavid van Moolenbroek 	socklen_t len, size;
1021*baa5830fSDavid van Moolenbroek 	ssize_t r;
1022*baa5830fSDavid van Moolenbroek 	pid_t pid;
1023*baa5830fSDavid van Moolenbroek 	unsigned int count;
1024*baa5830fSDavid van Moolenbroek 	int i, fd[2], rcvlen, status, exp, flags, num, stat[2] = { 0, 0 };
1025*baa5830fSDavid van Moolenbroek 
1026*baa5830fSDavid van Moolenbroek 	get_socket_pair(type, fd);
1027*baa5830fSDavid van Moolenbroek 
1028*baa5830fSDavid van Moolenbroek 	size = rcvlen = get_rcvbuf_len(fd[0]);
1029*baa5830fSDavid van Moolenbroek 
1030*baa5830fSDavid van Moolenbroek 	if ((buf = malloc(size)) == NULL) e(0);
1031*baa5830fSDavid van Moolenbroek 
1032*baa5830fSDavid van Moolenbroek 	t = time(NULL);
1033*baa5830fSDavid van Moolenbroek 
1034*baa5830fSDavid van Moolenbroek 	/*
1035*baa5830fSDavid van Moolenbroek 	 * We vary small versus large (random) send and receive sizes,
1036*baa5830fSDavid van Moolenbroek 	 * splitting the entire transfer in four phases along those lines.
1037*baa5830fSDavid van Moolenbroek 	 *
1038*baa5830fSDavid van Moolenbroek 	 * In theory, the use of an extra system call and the use of MSG_PEEK
1039*baa5830fSDavid van Moolenbroek 	 * both contribute to the expectation that the consumer side will fall
1040*baa5830fSDavid van Moolenbroek 	 * behind the producer.  In this case, we cannot vary receive sizes to
1041*baa5830fSDavid van Moolenbroek 	 * compensate.  This not appear to be a major problem here, though.
1042*baa5830fSDavid van Moolenbroek 	 */
1043*baa5830fSDavid van Moolenbroek #define NR_PACKETS	(256 * 1024)
1044*baa5830fSDavid van Moolenbroek 
1045*baa5830fSDavid van Moolenbroek 	pid = fork();
1046*baa5830fSDavid van Moolenbroek 	switch (pid) {
1047*baa5830fSDavid van Moolenbroek 	case 0:
1048*baa5830fSDavid van Moolenbroek 		errct = 0;
1049*baa5830fSDavid van Moolenbroek 
1050*baa5830fSDavid van Moolenbroek 		if (close(fd[0]) != 0) e(0);
1051*baa5830fSDavid van Moolenbroek 
1052*baa5830fSDavid van Moolenbroek 		srand48(t + 1);
1053*baa5830fSDavid van Moolenbroek 
1054*baa5830fSDavid van Moolenbroek 		for (count = 0; count < NR_PACKETS; ) {
1055*baa5830fSDavid van Moolenbroek 			if (count < NR_PACKETS / 2)
1056*baa5830fSDavid van Moolenbroek 				len = lrand48() % 64;
1057*baa5830fSDavid van Moolenbroek 			else
1058*baa5830fSDavid van Moolenbroek 				len = lrand48() % size;
1059*baa5830fSDavid van Moolenbroek 
1060*baa5830fSDavid van Moolenbroek 			num = lrand48() % 16;
1061*baa5830fSDavid van Moolenbroek 			flags = 0;
1062*baa5830fSDavid van Moolenbroek 			if (num & 1) flags |= MSG_PEEK;
1063*baa5830fSDavid van Moolenbroek 			if (num & 2) flags |= MSG_WAITALL;
1064*baa5830fSDavid van Moolenbroek 			if (num & 4) flags |= MSG_DONTWAIT;
1065*baa5830fSDavid van Moolenbroek 			if (num & 8) {
1066*baa5830fSDavid van Moolenbroek 				/*
1067*baa5830fSDavid van Moolenbroek 				 * Obviously there are race conditions here but
1068*baa5830fSDavid van Moolenbroek 				 * the returned number should be accurate if
1069*baa5830fSDavid van Moolenbroek 				 * not zero.  Hopefully it's not always zero.
1070*baa5830fSDavid van Moolenbroek 				 */
1071*baa5830fSDavid van Moolenbroek 				if (ioctl(fd[1], FIONREAD, &exp) != 0) e(0);
1072*baa5830fSDavid van Moolenbroek 				if (exp < 0 || exp > rcvlen) e(0);
1073*baa5830fSDavid van Moolenbroek 			} else
1074*baa5830fSDavid van Moolenbroek 				exp = 0;
1075*baa5830fSDavid van Moolenbroek 
1076*baa5830fSDavid van Moolenbroek 			stat[0]++;
1077*baa5830fSDavid van Moolenbroek 
1078*baa5830fSDavid van Moolenbroek 			/*
1079*baa5830fSDavid van Moolenbroek 			 * A lame approach to preventing unbounded spinning on
1080*baa5830fSDavid van Moolenbroek 			 * ENOBUFS on the producer side.
1081*baa5830fSDavid van Moolenbroek 			 */
1082*baa5830fSDavid van Moolenbroek 			if (type == SOCK_DGRAM)
1083*baa5830fSDavid van Moolenbroek 				(void)send(fd[1], "", 1, MSG_DONTWAIT);
1084*baa5830fSDavid van Moolenbroek 
1085*baa5830fSDavid van Moolenbroek 			if ((r = recv(fd[1], buf, len, flags)) == -1) {
1086*baa5830fSDavid van Moolenbroek 				if (errno != EWOULDBLOCK) e(0);
1087*baa5830fSDavid van Moolenbroek 				if (exp > 0) e(0);
1088*baa5830fSDavid van Moolenbroek 
1089*baa5830fSDavid van Moolenbroek 				stat[1]++;
1090*baa5830fSDavid van Moolenbroek 
1091*baa5830fSDavid van Moolenbroek 				continue;
1092*baa5830fSDavid van Moolenbroek 			}
1093*baa5830fSDavid van Moolenbroek 
1094*baa5830fSDavid van Moolenbroek 			if (exp != 0) {
1095*baa5830fSDavid van Moolenbroek 				if (r == len && exp < r) e(0);
1096*baa5830fSDavid van Moolenbroek 				else if (r < len && exp != r) e(0);
1097*baa5830fSDavid van Moolenbroek 			}
1098*baa5830fSDavid van Moolenbroek 
1099*baa5830fSDavid van Moolenbroek 			if (r >= 2 &&
1100*baa5830fSDavid van Moolenbroek 			    r > ((size_t)(unsigned char)buf[0] << 8) +
1101*baa5830fSDavid van Moolenbroek 			    (size_t)(unsigned char)buf[1]) e(0);
1102*baa5830fSDavid van Moolenbroek 
1103*baa5830fSDavid van Moolenbroek 			for (i = 2; i < r; i++)
1104*baa5830fSDavid van Moolenbroek 				if (buf[i] != (char)i) e(0);
1105*baa5830fSDavid van Moolenbroek 
1106*baa5830fSDavid van Moolenbroek 			if (!(flags & MSG_PEEK))
1107*baa5830fSDavid van Moolenbroek 				count++;
1108*baa5830fSDavid van Moolenbroek 		}
1109*baa5830fSDavid van Moolenbroek 
1110*baa5830fSDavid van Moolenbroek #if PRINT_STATS
1111*baa5830fSDavid van Moolenbroek 		/*
1112*baa5830fSDavid van Moolenbroek 		 * The second and third numbers should ideally be a large but
1113*baa5830fSDavid van Moolenbroek 		 * non-dominating fraction of the first one.
1114*baa5830fSDavid van Moolenbroek 		 */
1115*baa5830fSDavid van Moolenbroek 		printf("RECV: total %d again %d\n", stat[0], stat[1]);
1116*baa5830fSDavid van Moolenbroek #endif
1117*baa5830fSDavid van Moolenbroek 
1118*baa5830fSDavid van Moolenbroek 		if (close(fd[1]) != 0) e(0);
1119*baa5830fSDavid van Moolenbroek 		exit(errct);
1120*baa5830fSDavid van Moolenbroek 	case -1:
1121*baa5830fSDavid van Moolenbroek 		e(0);
1122*baa5830fSDavid van Moolenbroek 	}
1123*baa5830fSDavid van Moolenbroek 
1124*baa5830fSDavid van Moolenbroek 	if (close(fd[1]) != 0) e(0);
1125*baa5830fSDavid van Moolenbroek 
1126*baa5830fSDavid van Moolenbroek 	srand48(t);
1127*baa5830fSDavid van Moolenbroek 
1128*baa5830fSDavid van Moolenbroek 	for (count = 0; count < NR_PACKETS; ) {
1129*baa5830fSDavid van Moolenbroek 		if (count < NR_PACKETS / 4 ||
1130*baa5830fSDavid van Moolenbroek 		    (count >= NR_PACKETS / 2 && count < NR_PACKETS * 3 / 4))
1131*baa5830fSDavid van Moolenbroek 			len = lrand48() % 64;
1132*baa5830fSDavid van Moolenbroek 		else
1133*baa5830fSDavid van Moolenbroek 			len = lrand48() % size;
1134*baa5830fSDavid van Moolenbroek 
1135*baa5830fSDavid van Moolenbroek 		buf[0] = (len >> 8) & 0xff;
1136*baa5830fSDavid van Moolenbroek 		buf[1] = len & 0xff;
1137*baa5830fSDavid van Moolenbroek 		for (i = 2; i < len; i++)
1138*baa5830fSDavid van Moolenbroek 			buf[i] = i;
1139*baa5830fSDavid van Moolenbroek 
1140*baa5830fSDavid van Moolenbroek 		flags = (lrand48() % 2) ? MSG_DONTWAIT : 0;
1141*baa5830fSDavid van Moolenbroek 
1142*baa5830fSDavid van Moolenbroek 		r = send(fd[0], buf, len, flags);
1143*baa5830fSDavid van Moolenbroek 
1144*baa5830fSDavid van Moolenbroek 		if (r != len) {
1145*baa5830fSDavid van Moolenbroek 			if (r != -1) e(0);
1146*baa5830fSDavid van Moolenbroek 
1147*baa5830fSDavid van Moolenbroek 			if (errno != EMSGSIZE && errno != EWOULDBLOCK &&
1148*baa5830fSDavid van Moolenbroek 			    errno != ENOBUFS) e(0);
1149*baa5830fSDavid van Moolenbroek 
1150*baa5830fSDavid van Moolenbroek 			if (errno == ENOBUFS || errno == EWOULDBLOCK) {
1151*baa5830fSDavid van Moolenbroek 				/*
1152*baa5830fSDavid van Moolenbroek 				 * As stated above: lame.  Ideally we would
1153*baa5830fSDavid van Moolenbroek 				 * continue only when the receiver side drains
1154*baa5830fSDavid van Moolenbroek 				 * the queue, but it may block once it has done
1155*baa5830fSDavid van Moolenbroek 				 * so.  Instead, by going through consumer
1156*baa5830fSDavid van Moolenbroek 				 * "tokens" we will ultimately block here and
1157*baa5830fSDavid van Moolenbroek 				 * let the receiver catch up.
1158*baa5830fSDavid van Moolenbroek 				 */
1159*baa5830fSDavid van Moolenbroek 				if (type == SOCK_DGRAM && errno == ENOBUFS)
1160*baa5830fSDavid van Moolenbroek 					(void)recv(fd[0], buf, 1, 0);
1161*baa5830fSDavid van Moolenbroek 
1162*baa5830fSDavid van Moolenbroek 				stat[0]++;
1163*baa5830fSDavid van Moolenbroek 				stat[1]++;
1164*baa5830fSDavid van Moolenbroek 			}
1165*baa5830fSDavid van Moolenbroek 			continue;
1166*baa5830fSDavid van Moolenbroek 		} else
1167*baa5830fSDavid van Moolenbroek 			stat[0]++;
1168*baa5830fSDavid van Moolenbroek 
1169*baa5830fSDavid van Moolenbroek 		if (count % (NR_PACKETS / 4) == 0)
1170*baa5830fSDavid van Moolenbroek 			sleep(1);
1171*baa5830fSDavid van Moolenbroek 
1172*baa5830fSDavid van Moolenbroek 		count++;
1173*baa5830fSDavid van Moolenbroek 	}
1174*baa5830fSDavid van Moolenbroek 
1175*baa5830fSDavid van Moolenbroek #if PRINT_STATS
1176*baa5830fSDavid van Moolenbroek 	/*
1177*baa5830fSDavid van Moolenbroek 	 * The second number should ideally be a large but non-dominating
1178*baa5830fSDavid van Moolenbroek 	 * fraction of the first one.
1179*baa5830fSDavid van Moolenbroek 	 */
1180*baa5830fSDavid van Moolenbroek 	printf("SEND: total %d again %d\n", stat[0], stat[1]);
1181*baa5830fSDavid van Moolenbroek #endif
1182*baa5830fSDavid van Moolenbroek 
1183*baa5830fSDavid van Moolenbroek 	free(buf);
1184*baa5830fSDavid van Moolenbroek 
1185*baa5830fSDavid van Moolenbroek 	if (close(fd[0]) != 0) e(0);
1186*baa5830fSDavid van Moolenbroek 
1187*baa5830fSDavid van Moolenbroek 	if (waitpid(pid, &status, 0) != pid) e(0);
1188*baa5830fSDavid van Moolenbroek 	if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) e(0);
1189*baa5830fSDavid van Moolenbroek }
1190*baa5830fSDavid van Moolenbroek 
1191*baa5830fSDavid van Moolenbroek /*
1192*baa5830fSDavid van Moolenbroek  * A randomized producer-consumer test.  As part of this, we also perform very
1193*baa5830fSDavid van Moolenbroek  * basic bulk functionality tests of FIONREAD, MSG_PEEK, MSG_DONTWAIT, and
1194*baa5830fSDavid van Moolenbroek  * MSG_WAITALL.
1195*baa5830fSDavid van Moolenbroek  */
1196*baa5830fSDavid van Moolenbroek static void
test90c(void)1197*baa5830fSDavid van Moolenbroek test90c(void)
1198*baa5830fSDavid van Moolenbroek {
1199*baa5830fSDavid van Moolenbroek 	int fd[2];
1200*baa5830fSDavid van Moolenbroek 
1201*baa5830fSDavid van Moolenbroek 	subtest = 4;
1202*baa5830fSDavid van Moolenbroek 
1203*baa5830fSDavid van Moolenbroek 	if (socketpair(AF_UNIX, SOCK_STREAM, 0, fd) != 0) e(0);
1204*baa5830fSDavid van Moolenbroek 
1205*baa5830fSDavid van Moolenbroek 	socklib_producer_consumer(fd);
1206*baa5830fSDavid van Moolenbroek 
1207*baa5830fSDavid van Moolenbroek 	sub90c(SOCK_SEQPACKET);
1208*baa5830fSDavid van Moolenbroek 
1209*baa5830fSDavid van Moolenbroek 	sub90c(SOCK_DGRAM);
1210*baa5830fSDavid van Moolenbroek }
1211*baa5830fSDavid van Moolenbroek 
1212*baa5830fSDavid van Moolenbroek /*
1213*baa5830fSDavid van Moolenbroek  * Test that immediately accepted non-blocking connect requests to a listening
1214*baa5830fSDavid van Moolenbroek  * socket with LOCAL_CONNWAIT turned on, return OK rather than EINPROGRESS.
1215*baa5830fSDavid van Moolenbroek  * This requires a hack in libsockevent.
1216*baa5830fSDavid van Moolenbroek  */
1217*baa5830fSDavid van Moolenbroek static void
test90d(void)1218*baa5830fSDavid van Moolenbroek test90d(void)
1219*baa5830fSDavid van Moolenbroek {
1220*baa5830fSDavid van Moolenbroek 	struct sockaddr_un sunA, sunB;
1221*baa5830fSDavid van Moolenbroek 	socklen_t len;
1222*baa5830fSDavid van Moolenbroek 	pid_t pid;
1223*baa5830fSDavid van Moolenbroek 	int fd, fd2, fd3, val, status;
1224*baa5830fSDavid van Moolenbroek 
1225*baa5830fSDavid van Moolenbroek 	subtest = 4;
1226*baa5830fSDavid van Moolenbroek 
1227*baa5830fSDavid van Moolenbroek 	/*
1228*baa5830fSDavid van Moolenbroek 	 * First ensure that a non-blocking connect to a listening socket that
1229*baa5830fSDavid van Moolenbroek 	 * does not have a accept call blocked on it, fails with EINPROGRESS.
1230*baa5830fSDavid van Moolenbroek 	 */
1231*baa5830fSDavid van Moolenbroek 	fd = get_bound_socket(SOCK_STREAM, SOCK_PATH_A, &sunA);
1232*baa5830fSDavid van Moolenbroek 
1233*baa5830fSDavid van Moolenbroek 	val = 1;
1234*baa5830fSDavid van Moolenbroek 	if (setsockopt(fd, 0, LOCAL_CONNWAIT, &val, sizeof(val)) != 0) e(0);
1235*baa5830fSDavid van Moolenbroek 
1236*baa5830fSDavid van Moolenbroek 	if (listen(fd, 1) != 0) e(0);
1237*baa5830fSDavid van Moolenbroek 
1238*baa5830fSDavid van Moolenbroek 	if ((fd2 = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0)) < 0) e(0);
1239*baa5830fSDavid van Moolenbroek 
1240*baa5830fSDavid van Moolenbroek 	if (connect(fd2, (struct sockaddr *)&sunA, sizeof(sunA)) != -1) e(0);
1241*baa5830fSDavid van Moolenbroek 	if (errno != EINPROGRESS) e(0);
1242*baa5830fSDavid van Moolenbroek 
1243*baa5830fSDavid van Moolenbroek 	len = sizeof(sunB);
1244*baa5830fSDavid van Moolenbroek 	if ((fd3 = accept(fd, (struct sockaddr *)&sunB, &len)) < 0) e(0);
1245*baa5830fSDavid van Moolenbroek 	check_addr(&sunB, len, NULL);
1246*baa5830fSDavid van Moolenbroek 
1247*baa5830fSDavid van Moolenbroek 	if (close(fd) != 0) e(0);
1248*baa5830fSDavid van Moolenbroek 	if (close(fd2) != 0) e(0);
1249*baa5830fSDavid van Moolenbroek 	if (close(fd3) != 0) e(0);
1250*baa5830fSDavid van Moolenbroek 
1251*baa5830fSDavid van Moolenbroek 	if (unlink(SOCK_PATH_A) != 0) e(0);
1252*baa5830fSDavid van Moolenbroek 
1253*baa5830fSDavid van Moolenbroek 	/*
1254*baa5830fSDavid van Moolenbroek 	 * Second, ensure that a blocking connect eventually does return
1255*baa5830fSDavid van Moolenbroek 	 * success if an accept call is made later on.
1256*baa5830fSDavid van Moolenbroek 	 */
1257*baa5830fSDavid van Moolenbroek 	fd = get_bound_socket(SOCK_STREAM, SOCK_PATH_A, &sunA);
1258*baa5830fSDavid van Moolenbroek 
1259*baa5830fSDavid van Moolenbroek 	val = 1;
1260*baa5830fSDavid van Moolenbroek 	if (setsockopt(fd, 0, LOCAL_CONNWAIT, &val, sizeof(val)) != 0) e(0);
1261*baa5830fSDavid van Moolenbroek 
1262*baa5830fSDavid van Moolenbroek 	if (listen(fd, 1) != 0) e(0);
1263*baa5830fSDavid van Moolenbroek 
1264*baa5830fSDavid van Moolenbroek 	pid = fork();
1265*baa5830fSDavid van Moolenbroek 	switch (pid) {
1266*baa5830fSDavid van Moolenbroek 	case 0:
1267*baa5830fSDavid van Moolenbroek 		errct = 0;
1268*baa5830fSDavid van Moolenbroek 
1269*baa5830fSDavid van Moolenbroek 		sleep(1);
1270*baa5830fSDavid van Moolenbroek 
1271*baa5830fSDavid van Moolenbroek 		len = sizeof(sunB);
1272*baa5830fSDavid van Moolenbroek 		if ((fd2 = accept(fd, (struct sockaddr *)&sunB, &len)) < 0)
1273*baa5830fSDavid van Moolenbroek 			e(0);
1274*baa5830fSDavid van Moolenbroek 		check_addr(&sunB, len, NULL);
1275*baa5830fSDavid van Moolenbroek 
1276*baa5830fSDavid van Moolenbroek 		exit(errct);
1277*baa5830fSDavid van Moolenbroek 	case -1:
1278*baa5830fSDavid van Moolenbroek 		e(0);
1279*baa5830fSDavid van Moolenbroek 	}
1280*baa5830fSDavid van Moolenbroek 
1281*baa5830fSDavid van Moolenbroek 	if (close(fd) != 0) e(0);
1282*baa5830fSDavid van Moolenbroek 
1283*baa5830fSDavid van Moolenbroek 	if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) e(0);
1284*baa5830fSDavid van Moolenbroek 
1285*baa5830fSDavid van Moolenbroek 	if (connect(fd, (struct sockaddr *)&sunA, sizeof(sunA)) != 0) e(0);
1286*baa5830fSDavid van Moolenbroek 
1287*baa5830fSDavid van Moolenbroek 	if (close(fd) != 0) e(0);
1288*baa5830fSDavid van Moolenbroek 
1289*baa5830fSDavid van Moolenbroek 	if (unlink(SOCK_PATH_A) != 0) e(0);
1290*baa5830fSDavid van Moolenbroek 
1291*baa5830fSDavid van Moolenbroek 	if (waitpid(pid, &status, 0) != pid) e(0);
1292*baa5830fSDavid van Moolenbroek 	if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) e(0);
1293*baa5830fSDavid van Moolenbroek 
1294*baa5830fSDavid van Moolenbroek 	/*
1295*baa5830fSDavid van Moolenbroek 	 * Finally, test the most implementation-complex case: a non-blocking
1296*baa5830fSDavid van Moolenbroek 	 * connect should succeed (i.e., yield return code 0) immediately if
1297*baa5830fSDavid van Moolenbroek 	 * there is a accept call blocked on it.
1298*baa5830fSDavid van Moolenbroek 	 */
1299*baa5830fSDavid van Moolenbroek 	fd = get_bound_socket(SOCK_STREAM, SOCK_PATH_A, &sunA);
1300*baa5830fSDavid van Moolenbroek 
1301*baa5830fSDavid van Moolenbroek 	val = 1;
1302*baa5830fSDavid van Moolenbroek 	if (setsockopt(fd, 0, LOCAL_CONNWAIT, &val, sizeof(val)) != 0) e(0);
1303*baa5830fSDavid van Moolenbroek 
1304*baa5830fSDavid van Moolenbroek 	if (listen(fd, 1) != 0) e(0);
1305*baa5830fSDavid van Moolenbroek 
1306*baa5830fSDavid van Moolenbroek 	pid = fork();
1307*baa5830fSDavid van Moolenbroek 	switch (pid) {
1308*baa5830fSDavid van Moolenbroek 	case 0:
1309*baa5830fSDavid van Moolenbroek 		errct = 0;
1310*baa5830fSDavid van Moolenbroek 
1311*baa5830fSDavid van Moolenbroek 		len = sizeof(sunB);
1312*baa5830fSDavid van Moolenbroek 		if ((fd2 = accept(fd, (struct sockaddr *)&sunB, &len)) < 0)
1313*baa5830fSDavid van Moolenbroek 			e(0);
1314*baa5830fSDavid van Moolenbroek 		check_addr(&sunB, len, SOCK_PATH_B);
1315*baa5830fSDavid van Moolenbroek 
1316*baa5830fSDavid van Moolenbroek 		exit(errct);
1317*baa5830fSDavid van Moolenbroek 	case -1:
1318*baa5830fSDavid van Moolenbroek 		e(0);
1319*baa5830fSDavid van Moolenbroek 	}
1320*baa5830fSDavid van Moolenbroek 
1321*baa5830fSDavid van Moolenbroek 	if (close(fd) != 0) e(0);
1322*baa5830fSDavid van Moolenbroek 
1323*baa5830fSDavid van Moolenbroek 	sleep(1);
1324*baa5830fSDavid van Moolenbroek 
1325*baa5830fSDavid van Moolenbroek 	fd = get_bound_socket(SOCK_STREAM | SOCK_NONBLOCK, SOCK_PATH_B, &sunB);
1326*baa5830fSDavid van Moolenbroek 
1327*baa5830fSDavid van Moolenbroek 	if (connect(fd, (struct sockaddr *)&sunA, sizeof(sunA)) != 0) e(0);
1328*baa5830fSDavid van Moolenbroek 
1329*baa5830fSDavid van Moolenbroek 	if (close(fd) != 0) e(0);
1330*baa5830fSDavid van Moolenbroek 
1331*baa5830fSDavid van Moolenbroek 	if (waitpid(pid, &status, 0) != pid) e(0);
1332*baa5830fSDavid van Moolenbroek 	if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) e(0);
1333*baa5830fSDavid van Moolenbroek 
1334*baa5830fSDavid van Moolenbroek 	if (unlink(SOCK_PATH_A) != 0) e(0);
1335*baa5830fSDavid van Moolenbroek 	if (unlink(SOCK_PATH_B) != 0) e(0);
1336*baa5830fSDavid van Moolenbroek }
1337*baa5830fSDavid van Moolenbroek 
1338*baa5830fSDavid van Moolenbroek /*
1339*baa5830fSDavid van Moolenbroek  * Test self-connecting datagram sockets.
1340*baa5830fSDavid van Moolenbroek  */
1341*baa5830fSDavid van Moolenbroek static void
test90e(void)1342*baa5830fSDavid van Moolenbroek test90e(void)
1343*baa5830fSDavid van Moolenbroek {
1344*baa5830fSDavid van Moolenbroek 	struct sockaddr_un sunA, sunB, sunC;
1345*baa5830fSDavid van Moolenbroek 	socklen_t len;
1346*baa5830fSDavid van Moolenbroek 	char buf[3];
1347*baa5830fSDavid van Moolenbroek 	pid_t pid;
1348*baa5830fSDavid van Moolenbroek 	int fdA, fdB, val, status;
1349*baa5830fSDavid van Moolenbroek 
1350*baa5830fSDavid van Moolenbroek 	subtest = 5;
1351*baa5830fSDavid van Moolenbroek 
1352*baa5830fSDavid van Moolenbroek 	fdA = get_bound_socket(SOCK_DGRAM, SOCK_PATH_A, &sunA);
1353*baa5830fSDavid van Moolenbroek 	fdB = get_bound_socket(SOCK_DGRAM, SOCK_PATH_B, &sunB);
1354*baa5830fSDavid van Moolenbroek 
1355*baa5830fSDavid van Moolenbroek 	/* Connect the socket to itself, and attempt to communicate. */
1356*baa5830fSDavid van Moolenbroek 	if (connect(fdA, (struct sockaddr *)&sunA, sizeof(sunA)) != 0) e(0);
1357*baa5830fSDavid van Moolenbroek 
1358*baa5830fSDavid van Moolenbroek 	if (send(fdA, "abc", 3, 0) != 3) e(0);
1359*baa5830fSDavid van Moolenbroek 
1360*baa5830fSDavid van Moolenbroek 	if (recv(fdA, buf, sizeof(buf), 0) != 3) e(0);
1361*baa5830fSDavid van Moolenbroek 	if (strncmp(buf, "abc", 3)) e(0);
1362*baa5830fSDavid van Moolenbroek 
1363*baa5830fSDavid van Moolenbroek 	/* Reconnect the socket to another target. */
1364*baa5830fSDavid van Moolenbroek 	if (connect(fdA, (struct sockaddr *)&sunB, sizeof(sunB)) != 0) e(0);
1365*baa5830fSDavid van Moolenbroek 
1366*baa5830fSDavid van Moolenbroek 	len = sizeof(val);
1367*baa5830fSDavid van Moolenbroek 	if (getsockopt(fdA, SOL_SOCKET, SO_ERROR, &val, &len) != 0) e(0);
1368*baa5830fSDavid van Moolenbroek 	if (val != 0) e(0);
1369*baa5830fSDavid van Moolenbroek 
1370*baa5830fSDavid van Moolenbroek 	if (send(fdA, "def", 3, 0) != 3) e(0);
1371*baa5830fSDavid van Moolenbroek 
1372*baa5830fSDavid van Moolenbroek 	memset(&sunC, 0, sizeof(sunC));
1373*baa5830fSDavid van Moolenbroek 	len = sizeof(sunC);
1374*baa5830fSDavid van Moolenbroek 	if (recvfrom(fdB, buf, sizeof(buf), 0, (struct sockaddr *)&sunC,
1375*baa5830fSDavid van Moolenbroek 	    &len) != 3) e(0);
1376*baa5830fSDavid van Moolenbroek 	check_addr(&sunC, len, SOCK_PATH_A);
1377*baa5830fSDavid van Moolenbroek 	if (strncmp(buf, "def", 3)) e(0);
1378*baa5830fSDavid van Moolenbroek 
1379*baa5830fSDavid van Moolenbroek 	/* Reconnect the socket to itself again. */
1380*baa5830fSDavid van Moolenbroek 	if (connect(fdA, (struct sockaddr *)&sunA, sizeof(sunA)) != 0) e(0);
1381*baa5830fSDavid van Moolenbroek 
1382*baa5830fSDavid van Moolenbroek 	len = sizeof(val);
1383*baa5830fSDavid van Moolenbroek 	if (getsockopt(fdA, SOL_SOCKET, SO_ERROR, &val, &len) != 0) e(0);
1384*baa5830fSDavid van Moolenbroek 	if (val != 0) e(0);
1385*baa5830fSDavid van Moolenbroek 
1386*baa5830fSDavid van Moolenbroek 	pid = fork();
1387*baa5830fSDavid van Moolenbroek 	switch (pid) {
1388*baa5830fSDavid van Moolenbroek 	case 0:
1389*baa5830fSDavid van Moolenbroek 		errct = 0;
1390*baa5830fSDavid van Moolenbroek 
1391*baa5830fSDavid van Moolenbroek 		if (recv(fdA, buf, sizeof(buf), 0) != 3) e(0);
1392*baa5830fSDavid van Moolenbroek 		if (strncmp(buf, "ghi", 3)) e(0);
1393*baa5830fSDavid van Moolenbroek 
1394*baa5830fSDavid van Moolenbroek 		exit(errct);
1395*baa5830fSDavid van Moolenbroek 	case -1:
1396*baa5830fSDavid van Moolenbroek 		e(0);
1397*baa5830fSDavid van Moolenbroek 	}
1398*baa5830fSDavid van Moolenbroek 
1399*baa5830fSDavid van Moolenbroek 	sleep(1);
1400*baa5830fSDavid van Moolenbroek 
1401*baa5830fSDavid van Moolenbroek 	if (send(fdA, "ghi", 3, 0) != 3) e(0);
1402*baa5830fSDavid van Moolenbroek 
1403*baa5830fSDavid van Moolenbroek 	if (waitpid(pid, &status, 0) != pid) e(0);
1404*baa5830fSDavid van Moolenbroek 	if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) e(0);
1405*baa5830fSDavid van Moolenbroek 
1406*baa5830fSDavid van Moolenbroek 	if (close(fdA) != 0) e(0);
1407*baa5830fSDavid van Moolenbroek 	if (close(fdB) != 0) e(0);
1408*baa5830fSDavid van Moolenbroek 
1409*baa5830fSDavid van Moolenbroek 	if (unlink(SOCK_PATH_A) != 0) e(0);
1410*baa5830fSDavid van Moolenbroek 	if (unlink(SOCK_PATH_B) != 0) e(0);
1411*baa5830fSDavid van Moolenbroek }
1412*baa5830fSDavid van Moolenbroek 
1413*baa5830fSDavid van Moolenbroek /*
1414*baa5830fSDavid van Moolenbroek  * Test multiple blocked calls getting resumed (or not) upon connect(2) success
1415*baa5830fSDavid van Moolenbroek  * or failure.  This test uses LOCAL_CONNWAIT.  TODO: rewrite this to use
1416*baa5830fSDavid van Moolenbroek  * interprocess communication rather than the current carefully arranged and
1417*baa5830fSDavid van Moolenbroek  * rather brittle timing approach.
1418*baa5830fSDavid van Moolenbroek  */
1419*baa5830fSDavid van Moolenbroek static void
sub90f(unsigned int test)1420*baa5830fSDavid van Moolenbroek sub90f(unsigned int test)
1421*baa5830fSDavid van Moolenbroek {
1422*baa5830fSDavid van Moolenbroek 	struct sockaddr_un sun;
1423*baa5830fSDavid van Moolenbroek 	pid_t pid[4], apid;
1424*baa5830fSDavid van Moolenbroek 	char buf[1];
1425*baa5830fSDavid van Moolenbroek 	unsigned int i;
1426*baa5830fSDavid van Moolenbroek 	socklen_t len;
1427*baa5830fSDavid van Moolenbroek 	int r, fd, fd2, fl, val, status;
1428*baa5830fSDavid van Moolenbroek 
1429*baa5830fSDavid van Moolenbroek 	fd = get_bound_socket(SOCK_STREAM, SOCK_PATH_A, &sun);
1430*baa5830fSDavid van Moolenbroek 
1431*baa5830fSDavid van Moolenbroek 	val = 1;
1432*baa5830fSDavid van Moolenbroek 	if (setsockopt(fd, 0, LOCAL_CONNWAIT, &val, sizeof(val)) != 0) e(0);
1433*baa5830fSDavid van Moolenbroek 
1434*baa5830fSDavid van Moolenbroek 	if (listen(fd, 1) != 0) e(0);
1435*baa5830fSDavid van Moolenbroek 
1436*baa5830fSDavid van Moolenbroek 	apid = fork();
1437*baa5830fSDavid van Moolenbroek 	switch (apid) {
1438*baa5830fSDavid van Moolenbroek 	case 0:
1439*baa5830fSDavid van Moolenbroek 		errct = 0;
1440*baa5830fSDavid van Moolenbroek 
1441*baa5830fSDavid van Moolenbroek 		sleep(3);
1442*baa5830fSDavid van Moolenbroek 
1443*baa5830fSDavid van Moolenbroek 		if (test < 2) {
1444*baa5830fSDavid van Moolenbroek 			len = sizeof(sun);
1445*baa5830fSDavid van Moolenbroek 			if ((fd2 = accept(fd, (struct sockaddr *)&sun,
1446*baa5830fSDavid van Moolenbroek 			    &len)) < 0) e(0);
1447*baa5830fSDavid van Moolenbroek 
1448*baa5830fSDavid van Moolenbroek 			sleep(2);
1449*baa5830fSDavid van Moolenbroek 
1450*baa5830fSDavid van Moolenbroek 			if (close(fd2) != 0) e(0);
1451*baa5830fSDavid van Moolenbroek 		}
1452*baa5830fSDavid van Moolenbroek 
1453*baa5830fSDavid van Moolenbroek 		if (close(fd) != 0) e(0);
1454*baa5830fSDavid van Moolenbroek 
1455*baa5830fSDavid van Moolenbroek 		exit(errct);
1456*baa5830fSDavid van Moolenbroek 	case -1:
1457*baa5830fSDavid van Moolenbroek 		e(0);
1458*baa5830fSDavid van Moolenbroek 	}
1459*baa5830fSDavid van Moolenbroek 
1460*baa5830fSDavid van Moolenbroek 	if (close(fd) != 0) e(0);
1461*baa5830fSDavid van Moolenbroek 
1462*baa5830fSDavid van Moolenbroek 	if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) e(0);
1463*baa5830fSDavid van Moolenbroek 
1464*baa5830fSDavid van Moolenbroek 	for (i = 0; i < __arraycount(pid); i++) {
1465*baa5830fSDavid van Moolenbroek 		pid[i] = fork();
1466*baa5830fSDavid van Moolenbroek 		switch (pid[i]) {
1467*baa5830fSDavid van Moolenbroek 		case 0:
1468*baa5830fSDavid van Moolenbroek 			errct = 0;
1469*baa5830fSDavid van Moolenbroek 
1470*baa5830fSDavid van Moolenbroek 			sleep((i == 0) ? 1 : 2);
1471*baa5830fSDavid van Moolenbroek 
1472*baa5830fSDavid van Moolenbroek 			if ((i & 1) == 0) {
1473*baa5830fSDavid van Moolenbroek 				r = send(fd, "", 1, 0);
1474*baa5830fSDavid van Moolenbroek 
1475*baa5830fSDavid van Moolenbroek 				switch (test) {
1476*baa5830fSDavid van Moolenbroek 				case 0:
1477*baa5830fSDavid van Moolenbroek 				case 1:
1478*baa5830fSDavid van Moolenbroek 					if (r != 1) e(0);
1479*baa5830fSDavid van Moolenbroek 					break;
1480*baa5830fSDavid van Moolenbroek 				case 3:
1481*baa5830fSDavid van Moolenbroek 					if (i == 0) {
1482*baa5830fSDavid van Moolenbroek 						if (r != -1) e(0);
1483*baa5830fSDavid van Moolenbroek 						if (errno != ECONNRESET) e(0);
1484*baa5830fSDavid van Moolenbroek 						break;
1485*baa5830fSDavid van Moolenbroek 					}
1486*baa5830fSDavid van Moolenbroek 					/* FALLTHROUGH */
1487*baa5830fSDavid van Moolenbroek 				case 2:
1488*baa5830fSDavid van Moolenbroek 					if (r != -1) e(0);
1489*baa5830fSDavid van Moolenbroek 					if (errno != ENOTCONN) e(0);
1490*baa5830fSDavid van Moolenbroek 				}
1491*baa5830fSDavid van Moolenbroek 			} else {
1492*baa5830fSDavid van Moolenbroek 				r = recv(fd, buf, sizeof(buf), 0);
1493*baa5830fSDavid van Moolenbroek 
1494*baa5830fSDavid van Moolenbroek 				if (test >= 2) {
1495*baa5830fSDavid van Moolenbroek 					if (r != -1) e(0);
1496*baa5830fSDavid van Moolenbroek 					if (errno != ENOTCONN) e(0);
1497*baa5830fSDavid van Moolenbroek 				} else
1498*baa5830fSDavid van Moolenbroek 					if (r != 0) e(0);
1499*baa5830fSDavid van Moolenbroek 			}
1500*baa5830fSDavid van Moolenbroek 
1501*baa5830fSDavid van Moolenbroek 			exit(errct);
1502*baa5830fSDavid van Moolenbroek 		case -1:
1503*baa5830fSDavid van Moolenbroek 			e(0);
1504*baa5830fSDavid van Moolenbroek 		}
1505*baa5830fSDavid van Moolenbroek 	}
1506*baa5830fSDavid van Moolenbroek 
1507*baa5830fSDavid van Moolenbroek 	if (test & 1) {
1508*baa5830fSDavid van Moolenbroek 		if ((fl = fcntl(fd, F_GETFL)) == -1) e(0);
1509*baa5830fSDavid van Moolenbroek 		if (fcntl(fd, F_SETFL, fl | O_NONBLOCK) != 0) e(0);
1510*baa5830fSDavid van Moolenbroek 	}
1511*baa5830fSDavid van Moolenbroek 
1512*baa5830fSDavid van Moolenbroek 	r = connect(fd, (struct sockaddr *)&sun, sizeof(sun));
1513*baa5830fSDavid van Moolenbroek 
1514*baa5830fSDavid van Moolenbroek 	if (test & 1) {
1515*baa5830fSDavid van Moolenbroek 		if (r != -1) e(0);
1516*baa5830fSDavid van Moolenbroek 		if (errno != EINPROGRESS) e(0);
1517*baa5830fSDavid van Moolenbroek 
1518*baa5830fSDavid van Moolenbroek 		if (fcntl(fd, F_SETFL, fl) != 0) e(0);
1519*baa5830fSDavid van Moolenbroek 
1520*baa5830fSDavid van Moolenbroek 		sleep(4);
1521*baa5830fSDavid van Moolenbroek 	} else {
1522*baa5830fSDavid van Moolenbroek 		if (test >= 2) {
1523*baa5830fSDavid van Moolenbroek 			if (r != -1) e(0);
1524*baa5830fSDavid van Moolenbroek 			if (errno != ECONNRESET) e(0);
1525*baa5830fSDavid van Moolenbroek 		} else
1526*baa5830fSDavid van Moolenbroek 			if (r != 0) e(0);
1527*baa5830fSDavid van Moolenbroek 
1528*baa5830fSDavid van Moolenbroek 		sleep(1);
1529*baa5830fSDavid van Moolenbroek 	}
1530*baa5830fSDavid van Moolenbroek 
1531*baa5830fSDavid van Moolenbroek 	/*
1532*baa5830fSDavid van Moolenbroek 	 * If the connect failed, collect the senders and receivers.
1533*baa5830fSDavid van Moolenbroek 	 * Otherwise, collect just the senders.
1534*baa5830fSDavid van Moolenbroek 	 */
1535*baa5830fSDavid van Moolenbroek 	for (i = 0; i < __arraycount(pid); i++) {
1536*baa5830fSDavid van Moolenbroek 		r = waitpid(pid[i], &status, WNOHANG);
1537*baa5830fSDavid van Moolenbroek 		if (r == pid[i]) {
1538*baa5830fSDavid van Moolenbroek 			if (test < 2 && (i & 1)) e(0);
1539*baa5830fSDavid van Moolenbroek 			if (!WIFEXITED(status)) e(0);
1540*baa5830fSDavid van Moolenbroek 			if (WEXITSTATUS(status) != 0) e(0);
1541*baa5830fSDavid van Moolenbroek 		} else if (r == 0) {
1542*baa5830fSDavid van Moolenbroek 			if (test >= 2 || !(i & 1)) e(0);
1543*baa5830fSDavid van Moolenbroek 		} else
1544*baa5830fSDavid van Moolenbroek 			e(0);
1545*baa5830fSDavid van Moolenbroek 	}
1546*baa5830fSDavid van Moolenbroek 
1547*baa5830fSDavid van Moolenbroek 	if (close(fd) != 0) e(0);
1548*baa5830fSDavid van Moolenbroek 
1549*baa5830fSDavid van Moolenbroek 	/* Wait for, and collect the accepting child. */
1550*baa5830fSDavid van Moolenbroek 	if (waitpid(apid, &status, 0) != apid) e(0);
1551*baa5830fSDavid van Moolenbroek 	if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) e(0);
1552*baa5830fSDavid van Moolenbroek 
1553*baa5830fSDavid van Moolenbroek 	/*
1554*baa5830fSDavid van Moolenbroek 	 * If the connect succeeded, collect the receivers, which will
1555*baa5830fSDavid van Moolenbroek 	 * terminate once the accepting child closes the accepted socket.
1556*baa5830fSDavid van Moolenbroek 	 */
1557*baa5830fSDavid van Moolenbroek 	if (test < 2) {
1558*baa5830fSDavid van Moolenbroek 		if (waitpid(pid[1], &status, 0) != pid[1]) e(0);
1559*baa5830fSDavid van Moolenbroek 		if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) e(0);
1560*baa5830fSDavid van Moolenbroek 		if (waitpid(pid[3], &status, 0) != pid[3]) e(0);
1561*baa5830fSDavid van Moolenbroek 		if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) e(0);
1562*baa5830fSDavid van Moolenbroek 	}
1563*baa5830fSDavid van Moolenbroek 
1564*baa5830fSDavid van Moolenbroek 	if (unlink(SOCK_PATH_A) != 0) e(0);
1565*baa5830fSDavid van Moolenbroek }
1566*baa5830fSDavid van Moolenbroek 
1567*baa5830fSDavid van Moolenbroek /*
1568*baa5830fSDavid van Moolenbroek  * Test multiple blocked calls getting resumed (or not) upon connect(2) success
1569*baa5830fSDavid van Moolenbroek  * or failure.  In particular, ensure that the error code ends up with the
1570*baa5830fSDavid van Moolenbroek  * right call.
1571*baa5830fSDavid van Moolenbroek  */
1572*baa5830fSDavid van Moolenbroek static void
test90f(void)1573*baa5830fSDavid van Moolenbroek test90f(void)
1574*baa5830fSDavid van Moolenbroek {
1575*baa5830fSDavid van Moolenbroek 
1576*baa5830fSDavid van Moolenbroek 	subtest = 6;
1577*baa5830fSDavid van Moolenbroek 
1578*baa5830fSDavid van Moolenbroek 	/* If a connect succeeds, sends continue but reads block until EOF. */
1579*baa5830fSDavid van Moolenbroek 	sub90f(0);	/* blocking connect */
1580*baa5830fSDavid van Moolenbroek 	sub90f(1);	/* non-blocking connect */
1581*baa5830fSDavid van Moolenbroek 
1582*baa5830fSDavid van Moolenbroek 	/* If a blocking connect fails, the connect call gets the error. */
1583*baa5830fSDavid van Moolenbroek 	sub90f(2);
1584*baa5830fSDavid van Moolenbroek 
1585*baa5830fSDavid van Moolenbroek 	/* If a non-blocking connect fails, the first blocked call gets it. */
1586*baa5830fSDavid van Moolenbroek 	sub90f(3);
1587*baa5830fSDavid van Moolenbroek }
1588*baa5830fSDavid van Moolenbroek 
1589*baa5830fSDavid van Moolenbroek /*
1590*baa5830fSDavid van Moolenbroek  * Test whether various calls all return the same expected error code.
1591*baa5830fSDavid van Moolenbroek  */
1592*baa5830fSDavid van Moolenbroek static void
sub90g(struct sockaddr_un * sun,int err)1593*baa5830fSDavid van Moolenbroek sub90g(struct sockaddr_un * sun, int err)
1594*baa5830fSDavid van Moolenbroek {
1595*baa5830fSDavid van Moolenbroek 	int fd;
1596*baa5830fSDavid van Moolenbroek 
1597*baa5830fSDavid van Moolenbroek 	if ((fd = socket(AF_UNIX, SOCK_SEQPACKET, 0)) < 0) e(0);
1598*baa5830fSDavid van Moolenbroek 
1599*baa5830fSDavid van Moolenbroek 	if (connect(fd, (struct sockaddr *)sun, sizeof(*sun)) != -1) e(0);
1600*baa5830fSDavid van Moolenbroek 	if (errno != err) e(0);
1601*baa5830fSDavid van Moolenbroek 
1602*baa5830fSDavid van Moolenbroek 	if (close(fd) != 0) e(0);
1603*baa5830fSDavid van Moolenbroek 
1604*baa5830fSDavid van Moolenbroek 	if ((fd = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0) e(0);
1605*baa5830fSDavid van Moolenbroek 
1606*baa5830fSDavid van Moolenbroek 	if (sendto(fd, "", 1, 0, (struct sockaddr *)sun, sizeof(*sun)) != -1)
1607*baa5830fSDavid van Moolenbroek 		e(0);
1608*baa5830fSDavid van Moolenbroek 	if (errno != err) e(0);
1609*baa5830fSDavid van Moolenbroek 
1610*baa5830fSDavid van Moolenbroek 	if (connect(fd, (struct sockaddr *)sun, sizeof(*sun)) != -1) e(0);
1611*baa5830fSDavid van Moolenbroek 	if (errno != err) e(0);
1612*baa5830fSDavid van Moolenbroek 
1613*baa5830fSDavid van Moolenbroek 	if (close(fd) != 0) e(0);
1614*baa5830fSDavid van Moolenbroek }
1615*baa5830fSDavid van Moolenbroek 
1616*baa5830fSDavid van Moolenbroek /*
1617*baa5830fSDavid van Moolenbroek  * Test for error codes thrown by connect(2) and sendto(2) with problematic
1618*baa5830fSDavid van Moolenbroek  * destinations.  In particular, we verify that the errors for sendto(2) are
1619*baa5830fSDavid van Moolenbroek  * the same as for connect(2), just like on NetBSD and Linux, even though
1620*baa5830fSDavid van Moolenbroek  * POSIX does not document all of these under sendto(2).
1621*baa5830fSDavid van Moolenbroek  */
1622*baa5830fSDavid van Moolenbroek static void
test90g(void)1623*baa5830fSDavid van Moolenbroek test90g(void)
1624*baa5830fSDavid van Moolenbroek {
1625*baa5830fSDavid van Moolenbroek 	struct sockaddr_un sun;
1626*baa5830fSDavid van Moolenbroek 	int fd;
1627*baa5830fSDavid van Moolenbroek 
1628*baa5830fSDavid van Moolenbroek 	subtest = 7;
1629*baa5830fSDavid van Moolenbroek 
1630*baa5830fSDavid van Moolenbroek 	fd = get_bound_socket(SOCK_STREAM, SOCK_PATH_A, &sun);
1631*baa5830fSDavid van Moolenbroek 
1632*baa5830fSDavid van Moolenbroek 	sub90g(&sun, EPROTOTYPE);
1633*baa5830fSDavid van Moolenbroek 
1634*baa5830fSDavid van Moolenbroek 	if (listen(fd, 1) != 0) e(0);
1635*baa5830fSDavid van Moolenbroek 
1636*baa5830fSDavid van Moolenbroek 	sub90g(&sun, EPROTOTYPE);
1637*baa5830fSDavid van Moolenbroek 
1638*baa5830fSDavid van Moolenbroek 	if (close(fd) != 0) e(0);
1639*baa5830fSDavid van Moolenbroek 
1640*baa5830fSDavid van Moolenbroek 	sub90g(&sun, ECONNREFUSED);
1641*baa5830fSDavid van Moolenbroek 
1642*baa5830fSDavid van Moolenbroek 	if (unlink(SOCK_PATH_A) != 0) e(0);
1643*baa5830fSDavid van Moolenbroek 
1644*baa5830fSDavid van Moolenbroek 	sub90g(&sun, ENOENT);
1645*baa5830fSDavid van Moolenbroek }
1646*baa5830fSDavid van Moolenbroek 
1647*baa5830fSDavid van Moolenbroek /*
1648*baa5830fSDavid van Moolenbroek  * Test addresses returned for unbound connection-type sockets by various
1649*baa5830fSDavid van Moolenbroek  * calls.
1650*baa5830fSDavid van Moolenbroek  */
1651*baa5830fSDavid van Moolenbroek static void
sub90h(int type)1652*baa5830fSDavid van Moolenbroek sub90h(int type)
1653*baa5830fSDavid van Moolenbroek {
1654*baa5830fSDavid van Moolenbroek 	struct sockaddr_un sun;
1655*baa5830fSDavid van Moolenbroek 	socklen_t len;
1656*baa5830fSDavid van Moolenbroek 	char buf[1];
1657*baa5830fSDavid van Moolenbroek 	int fd, fd2, fd3;
1658*baa5830fSDavid van Moolenbroek 
1659*baa5830fSDavid van Moolenbroek 	fd = get_bound_socket(type, SOCK_PATH_A, &sun);
1660*baa5830fSDavid van Moolenbroek 
1661*baa5830fSDavid van Moolenbroek 	if (listen(fd, 5) != 0) e(0);
1662*baa5830fSDavid van Moolenbroek 
1663*baa5830fSDavid van Moolenbroek 	if ((fd2 = socket(AF_UNIX, type, 0)) < 0) e(0);
1664*baa5830fSDavid van Moolenbroek 
1665*baa5830fSDavid van Moolenbroek 	if (connect(fd2, (struct sockaddr *)&sun, sizeof(sun)) != 0) e(0);
1666*baa5830fSDavid van Moolenbroek 
1667*baa5830fSDavid van Moolenbroek 	/* Test for accept(2), which returns an empty address. */
1668*baa5830fSDavid van Moolenbroek 	memset(&sun, 0, sizeof(sun));
1669*baa5830fSDavid van Moolenbroek 	len = sizeof(sun);
1670*baa5830fSDavid van Moolenbroek 	if ((fd3 = accept(fd, (struct sockaddr *)&sun, &len)) < 0) e(0);
1671*baa5830fSDavid van Moolenbroek 	check_addr(&sun, len, NULL);
1672*baa5830fSDavid van Moolenbroek 
1673*baa5830fSDavid van Moolenbroek 	/* Test for recvfrom(2), which ignores the address pointer. */
1674*baa5830fSDavid van Moolenbroek 	if (send(fd2, "", 1, 0) != 1) e(0);
1675*baa5830fSDavid van Moolenbroek 
1676*baa5830fSDavid van Moolenbroek 	memset(&sun, 0, sizeof(sun));
1677*baa5830fSDavid van Moolenbroek 	len = sizeof(sun);
1678*baa5830fSDavid van Moolenbroek 	if (recvfrom(fd3, buf, sizeof(buf), 0, (struct sockaddr *)&sun,
1679*baa5830fSDavid van Moolenbroek 	    &len) != 1) e(0);
1680*baa5830fSDavid van Moolenbroek 	if (len != 0) e(0);
1681*baa5830fSDavid van Moolenbroek 	if (sun.sun_family != 0) e(0);
1682*baa5830fSDavid van Moolenbroek 	if (sun.sun_len != 0) e(0);
1683*baa5830fSDavid van Moolenbroek 
1684*baa5830fSDavid van Moolenbroek 	/* Test for getsockname(2), which returns an empty address. */
1685*baa5830fSDavid van Moolenbroek 	memset(&sun, 0, sizeof(sun));
1686*baa5830fSDavid van Moolenbroek 	len = sizeof(sun);
1687*baa5830fSDavid van Moolenbroek 	if (getsockname(fd2, (struct sockaddr *)&sun, &len) != 0) e(0);
1688*baa5830fSDavid van Moolenbroek 	check_addr(&sun, len, NULL);
1689*baa5830fSDavid van Moolenbroek 
1690*baa5830fSDavid van Moolenbroek 	/* Test for getpeername(2), which returns an empty address. */
1691*baa5830fSDavid van Moolenbroek 	memset(&sun, 0, sizeof(sun));
1692*baa5830fSDavid van Moolenbroek 	len = sizeof(sun);
1693*baa5830fSDavid van Moolenbroek 	if (getpeername(fd3, (struct sockaddr *)&sun, &len) != 0) e(0);
1694*baa5830fSDavid van Moolenbroek 	check_addr(&sun, len, NULL);
1695*baa5830fSDavid van Moolenbroek 
1696*baa5830fSDavid van Moolenbroek 	if (close(fd) != 0) e(0);
1697*baa5830fSDavid van Moolenbroek 	if (close(fd2) != 0) e(0);
1698*baa5830fSDavid van Moolenbroek 	if (close(fd3) != 0) e(0);
1699*baa5830fSDavid van Moolenbroek 
1700*baa5830fSDavid van Moolenbroek 	if (unlink(SOCK_PATH_A) != 0) e(0);
1701*baa5830fSDavid van Moolenbroek }
1702*baa5830fSDavid van Moolenbroek 
1703*baa5830fSDavid van Moolenbroek /*
1704*baa5830fSDavid van Moolenbroek  * Test addresses returned for unbound sockets by various calls.
1705*baa5830fSDavid van Moolenbroek  */
1706*baa5830fSDavid van Moolenbroek static void
test90h(void)1707*baa5830fSDavid van Moolenbroek test90h(void)
1708*baa5830fSDavid van Moolenbroek {
1709*baa5830fSDavid van Moolenbroek 	struct sockaddr_un sun;
1710*baa5830fSDavid van Moolenbroek 	socklen_t len;
1711*baa5830fSDavid van Moolenbroek 	char buf[1];
1712*baa5830fSDavid van Moolenbroek 	int fd, fd2;
1713*baa5830fSDavid van Moolenbroek 
1714*baa5830fSDavid van Moolenbroek 	subtest = 8;
1715*baa5830fSDavid van Moolenbroek 
1716*baa5830fSDavid van Moolenbroek 	/* Connection-type socket tests. */
1717*baa5830fSDavid van Moolenbroek 	sub90h(SOCK_STREAM);
1718*baa5830fSDavid van Moolenbroek 
1719*baa5830fSDavid van Moolenbroek 	sub90h(SOCK_SEQPACKET);
1720*baa5830fSDavid van Moolenbroek 
1721*baa5830fSDavid van Moolenbroek 	/* Datagram socket tests. */
1722*baa5830fSDavid van Moolenbroek 	fd = get_bound_socket(SOCK_DGRAM, SOCK_PATH_A, &sun);
1723*baa5830fSDavid van Moolenbroek 
1724*baa5830fSDavid van Moolenbroek 	if ((fd2 = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0) e(0);
1725*baa5830fSDavid van Moolenbroek 
1726*baa5830fSDavid van Moolenbroek 	if (sendto(fd2, "", 1, 0, (struct sockaddr *)&sun, sizeof(sun)) != 1)
1727*baa5830fSDavid van Moolenbroek 		e(0);
1728*baa5830fSDavid van Moolenbroek 
1729*baa5830fSDavid van Moolenbroek 	/*
1730*baa5830fSDavid van Moolenbroek 	 * Datagram test for recvfrom(2), which returns no address.  This is
1731*baa5830fSDavid van Moolenbroek 	 * the one result in this subtest that is not specified by POSIX and
1732*baa5830fSDavid van Moolenbroek 	 * (not so coincidentally) is different between NetBSD and Linux.
1733*baa5830fSDavid van Moolenbroek 	 * MINIX3 happens to follow Linux behavior for now, but this may be
1734*baa5830fSDavid van Moolenbroek 	 * changed in the future.
1735*baa5830fSDavid van Moolenbroek 	 */
1736*baa5830fSDavid van Moolenbroek 	memset(&sun, 0, sizeof(sun));
1737*baa5830fSDavid van Moolenbroek 	len = sizeof(sun);
1738*baa5830fSDavid van Moolenbroek 	if (recvfrom(fd, buf, sizeof(buf), 0, (struct sockaddr *)&sun,
1739*baa5830fSDavid van Moolenbroek 	    &len) != 1) e(0);
1740*baa5830fSDavid van Moolenbroek 	if (len != 0) e(0);
1741*baa5830fSDavid van Moolenbroek 	if (sun.sun_family != 0) e(0);
1742*baa5830fSDavid van Moolenbroek 	if (sun.sun_len != 0) e(0);
1743*baa5830fSDavid van Moolenbroek 
1744*baa5830fSDavid van Moolenbroek 	/* Datagram test for getsockname(2), which returns an empty address. */
1745*baa5830fSDavid van Moolenbroek 	memset(&sun, 0, sizeof(sun));
1746*baa5830fSDavid van Moolenbroek 	len = sizeof(sun);
1747*baa5830fSDavid van Moolenbroek 	if (getsockname(fd2, (struct sockaddr *)&sun, &len) != 0) e(0);
1748*baa5830fSDavid van Moolenbroek 	check_addr(&sun, len, NULL);
1749*baa5830fSDavid van Moolenbroek 
1750*baa5830fSDavid van Moolenbroek 	if (close(fd) != 0) e(0);
1751*baa5830fSDavid van Moolenbroek 	if (close(fd2) != 0) e(0);
1752*baa5830fSDavid van Moolenbroek 
1753*baa5830fSDavid van Moolenbroek 	if (unlink(SOCK_PATH_A) != 0) e(0);
1754*baa5830fSDavid van Moolenbroek }
1755*baa5830fSDavid van Moolenbroek 
1756*baa5830fSDavid van Moolenbroek #define MAX_FDS 7
1757*baa5830fSDavid van Moolenbroek 
1758*baa5830fSDavid van Moolenbroek /*
1759*baa5830fSDavid van Moolenbroek  * Send anywhere from zero to MAX_FDS file descriptors onto a socket, possibly
1760*baa5830fSDavid van Moolenbroek  * along with regular data.  Return the result of the sendmsg(2) call, with
1761*baa5830fSDavid van Moolenbroek  * errno preserved.  Written to be reusable outside this test set.
1762*baa5830fSDavid van Moolenbroek  */
1763*baa5830fSDavid van Moolenbroek static int
send_fds(int fd,const char * data,size_t len,int flags,struct sockaddr * addr,socklen_t addr_len,int * fds,int nfds)1764*baa5830fSDavid van Moolenbroek send_fds(int fd, const char * data, size_t len, int flags,
1765*baa5830fSDavid van Moolenbroek 	struct sockaddr * addr, socklen_t addr_len, int * fds, int nfds)
1766*baa5830fSDavid van Moolenbroek {
1767*baa5830fSDavid van Moolenbroek 	union {
1768*baa5830fSDavid van Moolenbroek 		char buf[CMSG_SPACE(MAX_FDS * sizeof(int))];
1769*baa5830fSDavid van Moolenbroek 		struct cmsghdr cmsg;
1770*baa5830fSDavid van Moolenbroek 	} control;
1771*baa5830fSDavid van Moolenbroek 	struct msghdr msg;
1772*baa5830fSDavid van Moolenbroek 	struct iovec iov;
1773*baa5830fSDavid van Moolenbroek 
1774*baa5830fSDavid van Moolenbroek 	assert(nfds >= 0 && nfds <= MAX_FDS);
1775*baa5830fSDavid van Moolenbroek 
1776*baa5830fSDavid van Moolenbroek 	iov.iov_base = __UNCONST(data);
1777*baa5830fSDavid van Moolenbroek 	iov.iov_len = len;
1778*baa5830fSDavid van Moolenbroek 
1779*baa5830fSDavid van Moolenbroek 	memset(&control.cmsg, 0, sizeof(control.cmsg));
1780*baa5830fSDavid van Moolenbroek 	control.cmsg.cmsg_len = CMSG_LEN(nfds * sizeof(int));
1781*baa5830fSDavid van Moolenbroek 	control.cmsg.cmsg_level = SOL_SOCKET;
1782*baa5830fSDavid van Moolenbroek 	control.cmsg.cmsg_type = SCM_RIGHTS;
1783*baa5830fSDavid van Moolenbroek 	memcpy(CMSG_DATA(&control.cmsg), fds, nfds * sizeof(int));
1784*baa5830fSDavid van Moolenbroek 
1785*baa5830fSDavid van Moolenbroek 	memset(&msg, 0, sizeof(msg));
1786*baa5830fSDavid van Moolenbroek 	msg.msg_iov = &iov;
1787*baa5830fSDavid van Moolenbroek 	msg.msg_iovlen = 1;
1788*baa5830fSDavid van Moolenbroek 	msg.msg_control = &control;
1789*baa5830fSDavid van Moolenbroek 	msg.msg_controllen = control.cmsg.cmsg_len;
1790*baa5830fSDavid van Moolenbroek 	msg.msg_name = addr;
1791*baa5830fSDavid van Moolenbroek 	msg.msg_namelen = addr_len;
1792*baa5830fSDavid van Moolenbroek 
1793*baa5830fSDavid van Moolenbroek 	return sendmsg(fd, &msg, flags);
1794*baa5830fSDavid van Moolenbroek }
1795*baa5830fSDavid van Moolenbroek 
1796*baa5830fSDavid van Moolenbroek /*
1797*baa5830fSDavid van Moolenbroek  * Receive anywhere from zero to up to MAX_FDS file descriptors from a socket,
1798*baa5830fSDavid van Moolenbroek  * possibly along with regular data.  The 'nfds' parameter must point to the
1799*baa5830fSDavid van Moolenbroek  * maximum number of file descriptors to be received.  Return the result of the
1800*baa5830fSDavid van Moolenbroek  * recvmsg(2) call, with errno preserved.  On success, return the received
1801*baa5830fSDavid van Moolenbroek  * flags in 'rflags', the received file descriptors stored in 'fds' and their
1802*baa5830fSDavid van Moolenbroek  * number stored in 'nfds'.  Written to be (somewhat) reusable.
1803*baa5830fSDavid van Moolenbroek  */
1804*baa5830fSDavid van Moolenbroek static int
recv_fds(int fd,char * buf,size_t size,int flags,int * rflags,int * fds,int * nfds)1805*baa5830fSDavid van Moolenbroek recv_fds(int fd, char * buf, size_t size, int flags, int * rflags, int * fds,
1806*baa5830fSDavid van Moolenbroek 	int * nfds)
1807*baa5830fSDavid van Moolenbroek {
1808*baa5830fSDavid van Moolenbroek 	union {
1809*baa5830fSDavid van Moolenbroek 		char buf[CMSG_SPACE(MAX_FDS * sizeof(int))];
1810*baa5830fSDavid van Moolenbroek 		struct cmsghdr cmsg;
1811*baa5830fSDavid van Moolenbroek 	} control;
1812*baa5830fSDavid van Moolenbroek 	struct msghdr msg;
1813*baa5830fSDavid van Moolenbroek 	struct iovec iov;
1814*baa5830fSDavid van Moolenbroek 	size_t len;
1815*baa5830fSDavid van Moolenbroek 	int r, rnfds;
1816*baa5830fSDavid van Moolenbroek 
1817*baa5830fSDavid van Moolenbroek 	assert(*nfds >= 0 && *nfds <= MAX_FDS);
1818*baa5830fSDavid van Moolenbroek 
1819*baa5830fSDavid van Moolenbroek 	iov.iov_base = buf;
1820*baa5830fSDavid van Moolenbroek 	iov.iov_len = size;
1821*baa5830fSDavid van Moolenbroek 
1822*baa5830fSDavid van Moolenbroek 	memset(&control.cmsg, 0, sizeof(control.cmsg));
1823*baa5830fSDavid van Moolenbroek 	control.cmsg.cmsg_len = CMSG_LEN(*nfds * sizeof(int));
1824*baa5830fSDavid van Moolenbroek 	control.cmsg.cmsg_level = SOL_SOCKET;
1825*baa5830fSDavid van Moolenbroek 	control.cmsg.cmsg_type = SCM_RIGHTS;
1826*baa5830fSDavid van Moolenbroek 
1827*baa5830fSDavid van Moolenbroek 	memset(&msg, 0, sizeof(msg));
1828*baa5830fSDavid van Moolenbroek 	msg.msg_iov = &iov;
1829*baa5830fSDavid van Moolenbroek 	msg.msg_iovlen = 1;
1830*baa5830fSDavid van Moolenbroek 	msg.msg_control = &control;
1831*baa5830fSDavid van Moolenbroek 	msg.msg_controllen = control.cmsg.cmsg_len;
1832*baa5830fSDavid van Moolenbroek 
1833*baa5830fSDavid van Moolenbroek 	if ((r = recvmsg(fd, &msg, flags)) < 0)
1834*baa5830fSDavid van Moolenbroek 		return r;
1835*baa5830fSDavid van Moolenbroek 
1836*baa5830fSDavid van Moolenbroek 	if (msg.msg_controllen > 0) {
1837*baa5830fSDavid van Moolenbroek 		assert(msg.msg_controllen <= sizeof(control));
1838*baa5830fSDavid van Moolenbroek 		assert(msg.msg_controllen >= sizeof(control.cmsg));
1839*baa5830fSDavid van Moolenbroek 		len = control.cmsg.cmsg_len - CMSG_LEN(0);
1840*baa5830fSDavid van Moolenbroek 		assert(len % sizeof(int) == 0);
1841*baa5830fSDavid van Moolenbroek 		rnfds = len / sizeof(int);
1842*baa5830fSDavid van Moolenbroek 		assert(rnfds <= *nfds);
1843*baa5830fSDavid van Moolenbroek 
1844*baa5830fSDavid van Moolenbroek 		memcpy(fds, CMSG_DATA(&control.cmsg), rnfds * sizeof(int));
1845*baa5830fSDavid van Moolenbroek 	} else
1846*baa5830fSDavid van Moolenbroek 		rnfds = 0;
1847*baa5830fSDavid van Moolenbroek 
1848*baa5830fSDavid van Moolenbroek 	*rflags = msg.msg_flags;
1849*baa5830fSDavid van Moolenbroek 	*nfds = rnfds;
1850*baa5830fSDavid van Moolenbroek 	return r;
1851*baa5830fSDavid van Moolenbroek }
1852*baa5830fSDavid van Moolenbroek 
1853*baa5830fSDavid van Moolenbroek /*
1854*baa5830fSDavid van Moolenbroek  * Generate and send zero or more file descriptors onto a socket, possibly
1855*baa5830fSDavid van Moolenbroek  * along with regular data.  Return the result of the sendmsg(2) call, with
1856*baa5830fSDavid van Moolenbroek  * errno preserved.  Also return a set of peer FDs for each of the sent file
1857*baa5830fSDavid van Moolenbroek  * descriptors, which should later be used in a call to close_test_fds().
1858*baa5830fSDavid van Moolenbroek  */
1859*baa5830fSDavid van Moolenbroek static int
send_test_fds(int fd,const char * data,size_t len,int flags,int * peers,int nfds)1860*baa5830fSDavid van Moolenbroek send_test_fds(int fd, const char * data, size_t len, int flags, int * peers,
1861*baa5830fSDavid van Moolenbroek 	int nfds)
1862*baa5830fSDavid van Moolenbroek {
1863*baa5830fSDavid van Moolenbroek 	int i, r, saved_errno, fds[MAX_FDS], pfd[2];
1864*baa5830fSDavid van Moolenbroek 
1865*baa5830fSDavid van Moolenbroek 	if (nfds > MAX_FDS) e(0);
1866*baa5830fSDavid van Moolenbroek 
1867*baa5830fSDavid van Moolenbroek 	for (i = 0; i < nfds; i++) {
1868*baa5830fSDavid van Moolenbroek 		if (pipe2(pfd, O_NONBLOCK) != 0) e(0);
1869*baa5830fSDavid van Moolenbroek 
1870*baa5830fSDavid van Moolenbroek 		peers[i] = pfd[0];
1871*baa5830fSDavid van Moolenbroek 		fds[i] = pfd[1];
1872*baa5830fSDavid van Moolenbroek 	}
1873*baa5830fSDavid van Moolenbroek 
1874*baa5830fSDavid van Moolenbroek 	r = send_fds(fd, data, len, flags, NULL, 0, fds, nfds);
1875*baa5830fSDavid van Moolenbroek 	saved_errno = errno;
1876*baa5830fSDavid van Moolenbroek 
1877*baa5830fSDavid van Moolenbroek 	for (i = 0; i < nfds; i++)
1878*baa5830fSDavid van Moolenbroek 		if (close(fds[i]) != 0) e(0);
1879*baa5830fSDavid van Moolenbroek 
1880*baa5830fSDavid van Moolenbroek 	errno = saved_errno;
1881*baa5830fSDavid van Moolenbroek 	return r;
1882*baa5830fSDavid van Moolenbroek }
1883*baa5830fSDavid van Moolenbroek 
1884*baa5830fSDavid van Moolenbroek /*
1885*baa5830fSDavid van Moolenbroek  * Given an array of peer file descriptors as returned from a call to
1886*baa5830fSDavid van Moolenbroek  * send_test_fds(), test if the original file descriptors have correctly been
1887*baa5830fSDavid van Moolenbroek  * closed, and close all peer file descriptors.  The ultimate goal here is to
1888*baa5830fSDavid van Moolenbroek  * detect any possible file descriptor leaks in the UDS service.
1889*baa5830fSDavid van Moolenbroek  */
1890*baa5830fSDavid van Moolenbroek static void
close_test_fds(int * peers,int nfds)1891*baa5830fSDavid van Moolenbroek close_test_fds(int * peers, int nfds)
1892*baa5830fSDavid van Moolenbroek {
1893*baa5830fSDavid van Moolenbroek 	char buf[1];
1894*baa5830fSDavid van Moolenbroek 	unsigned int i;
1895*baa5830fSDavid van Moolenbroek 	int fd;
1896*baa5830fSDavid van Moolenbroek 
1897*baa5830fSDavid van Moolenbroek 	for (i = 0; i < nfds; i++) {
1898*baa5830fSDavid van Moolenbroek 		fd = peers[i];
1899*baa5830fSDavid van Moolenbroek 
1900*baa5830fSDavid van Moolenbroek 		/* If the other side is still open, we would get EAGAIN. */
1901*baa5830fSDavid van Moolenbroek 		if (read(fd, buf, sizeof(buf)) != 0) e(0);
1902*baa5830fSDavid van Moolenbroek 
1903*baa5830fSDavid van Moolenbroek 		if (close(peers[i]) != 0) e(0);
1904*baa5830fSDavid van Moolenbroek 	}
1905*baa5830fSDavid van Moolenbroek }
1906*baa5830fSDavid van Moolenbroek 
1907*baa5830fSDavid van Moolenbroek /*
1908*baa5830fSDavid van Moolenbroek  * Receive and close zero or more file descriptors from a socket, possibly
1909*baa5830fSDavid van Moolenbroek  * along with regular data.  Return the result of the recvmsg(2) call, with
1910*baa5830fSDavid van Moolenbroek  * errno preserved.
1911*baa5830fSDavid van Moolenbroek  */
1912*baa5830fSDavid van Moolenbroek static int
recv_test_fds(int fd,char * buf,size_t size,int flags,int * rflags,int * nfds)1913*baa5830fSDavid van Moolenbroek recv_test_fds(int fd, char * buf, size_t size, int flags, int * rflags,
1914*baa5830fSDavid van Moolenbroek 	int * nfds)
1915*baa5830fSDavid van Moolenbroek {
1916*baa5830fSDavid van Moolenbroek 	int i, r, saved_errno, fds[MAX_FDS];
1917*baa5830fSDavid van Moolenbroek 
1918*baa5830fSDavid van Moolenbroek 	if (*nfds > MAX_FDS) e(0);
1919*baa5830fSDavid van Moolenbroek 
1920*baa5830fSDavid van Moolenbroek 	if ((r = recv_fds(fd, buf, size, flags, rflags, fds, nfds)) < 0)
1921*baa5830fSDavid van Moolenbroek 		return r;
1922*baa5830fSDavid van Moolenbroek 	saved_errno = errno;
1923*baa5830fSDavid van Moolenbroek 
1924*baa5830fSDavid van Moolenbroek 	for (i = 0; i < *nfds; i++)
1925*baa5830fSDavid van Moolenbroek 		if (close(fds[i]) != 0) e(0);
1926*baa5830fSDavid van Moolenbroek 
1927*baa5830fSDavid van Moolenbroek 	errno = saved_errno;
1928*baa5830fSDavid van Moolenbroek 	return r;
1929*baa5830fSDavid van Moolenbroek }
1930*baa5830fSDavid van Moolenbroek 
1931*baa5830fSDavid van Moolenbroek /*
1932*baa5830fSDavid van Moolenbroek  * Test receive requests on various socket states and in various forms.
1933*baa5830fSDavid van Moolenbroek  * Following this function requires a very close look at what is in the
1934*baa5830fSDavid van Moolenbroek  * receive queue versus what is being received.
1935*baa5830fSDavid van Moolenbroek  */
1936*baa5830fSDavid van Moolenbroek static void
sub90i_recv(int fd,int type,int state,int test,int sub,int sentfds)1937*baa5830fSDavid van Moolenbroek sub90i_recv(int fd, int type, int state, int test, int sub, int sentfds)
1938*baa5830fSDavid van Moolenbroek {
1939*baa5830fSDavid van Moolenbroek 	struct msghdr msg;
1940*baa5830fSDavid van Moolenbroek 	struct iovec iov;
1941*baa5830fSDavid van Moolenbroek 	char data[4];
1942*baa5830fSDavid van Moolenbroek 	unsigned int i;
1943*baa5830fSDavid van Moolenbroek 	int res, err, nfds, rflags;
1944*baa5830fSDavid van Moolenbroek 
1945*baa5830fSDavid van Moolenbroek 	memset(data, 0, sizeof(data));
1946*baa5830fSDavid van Moolenbroek 
1947*baa5830fSDavid van Moolenbroek 	if (sub & 2) {
1948*baa5830fSDavid van Moolenbroek 		rflags = 0;
1949*baa5830fSDavid van Moolenbroek 		nfds = sentfds;
1950*baa5830fSDavid van Moolenbroek 		res = recv_test_fds(fd, data, (sub & 1) ? 0 : sizeof(data), 0,
1951*baa5830fSDavid van Moolenbroek 		    &rflags, &nfds);
1952*baa5830fSDavid van Moolenbroek 		if (rflags & MSG_CTRUNC) e(0);
1953*baa5830fSDavid van Moolenbroek 		if (nfds != 0 && nfds != sentfds) e(0);
1954*baa5830fSDavid van Moolenbroek 		if ((type == SOCK_STREAM) && (rflags & MSG_TRUNC)) e(0);
1955*baa5830fSDavid van Moolenbroek 	} else {
1956*baa5830fSDavid van Moolenbroek 		iov.iov_base = data;
1957*baa5830fSDavid van Moolenbroek 		iov.iov_len = (sub & 1) ? 0 : sizeof(data);
1958*baa5830fSDavid van Moolenbroek 		memset(&msg, 0, sizeof(msg));
1959*baa5830fSDavid van Moolenbroek 		msg.msg_iov = &iov;
1960*baa5830fSDavid van Moolenbroek 		msg.msg_iovlen = 1;
1961*baa5830fSDavid van Moolenbroek 		res = recvmsg(fd, &msg, 0);
1962*baa5830fSDavid van Moolenbroek 		if (res >= 0)
1963*baa5830fSDavid van Moolenbroek 			rflags = msg.msg_flags;
1964*baa5830fSDavid van Moolenbroek 		else
1965*baa5830fSDavid van Moolenbroek 			rflags = 0;
1966*baa5830fSDavid van Moolenbroek 		nfds = 0;
1967*baa5830fSDavid van Moolenbroek 	}
1968*baa5830fSDavid van Moolenbroek 	err = errno;
1969*baa5830fSDavid van Moolenbroek 
1970*baa5830fSDavid van Moolenbroek 	if (res < -1 || res > (int)sizeof(data)) e(0);
1971*baa5830fSDavid van Moolenbroek 
1972*baa5830fSDavid van Moolenbroek 	if (type == SOCK_STREAM) {
1973*baa5830fSDavid van Moolenbroek 		if (sub & 1) {
1974*baa5830fSDavid van Moolenbroek 			/*
1975*baa5830fSDavid van Moolenbroek 			 * Zero-size requests should receive no regular data
1976*baa5830fSDavid van Moolenbroek 			 * and no control data, even if the tail segment is
1977*baa5830fSDavid van Moolenbroek 			 * zero-sized and terminated.  This policy is in place
1978*baa5830fSDavid van Moolenbroek 			 * for simplicity reasons.
1979*baa5830fSDavid van Moolenbroek 			 */
1980*baa5830fSDavid van Moolenbroek 			if (res != 0) e(0);
1981*baa5830fSDavid van Moolenbroek 			if (nfds != 0) e(0);
1982*baa5830fSDavid van Moolenbroek 			if (rflags & MSG_CTRUNC) e(0);
1983*baa5830fSDavid van Moolenbroek 
1984*baa5830fSDavid van Moolenbroek 			/*
1985*baa5830fSDavid van Moolenbroek 			 * Since nothing happened yet, do another, now non-
1986*baa5830fSDavid van Moolenbroek 			 * zero receive call immediately, and continue as if
1987*baa5830fSDavid van Moolenbroek 			 * that was the first call.
1988*baa5830fSDavid van Moolenbroek 			 */
1989*baa5830fSDavid van Moolenbroek 			sub = (sub & ~1) | 2;
1990*baa5830fSDavid van Moolenbroek 			nfds = sentfds;
1991*baa5830fSDavid van Moolenbroek 			rflags = 0;
1992*baa5830fSDavid van Moolenbroek 			res = recv_test_fds(fd, data, sizeof(data), 0, &rflags,
1993*baa5830fSDavid van Moolenbroek 			    &nfds);
1994*baa5830fSDavid van Moolenbroek 			if (rflags & (MSG_TRUNC | MSG_CTRUNC)) e(0);
1995*baa5830fSDavid van Moolenbroek 			if (nfds != 0 && nfds != sentfds) e(0);
1996*baa5830fSDavid van Moolenbroek 			err = errno;
1997*baa5830fSDavid van Moolenbroek 			if (res < -1 || res > (int)sizeof(data)) e(0);
1998*baa5830fSDavid van Moolenbroek 		}
1999*baa5830fSDavid van Moolenbroek 
2000*baa5830fSDavid van Moolenbroek 		if (state == 0 && !(test & 1) && !(sub & 13)) {
2001*baa5830fSDavid van Moolenbroek 			/*
2002*baa5830fSDavid van Moolenbroek 			 * There are no regular data bytes to be received, and
2003*baa5830fSDavid van Moolenbroek 			 * the current segment may still be extended (i.e.,
2004*baa5830fSDavid van Moolenbroek 			 * there is no EOF condition), and we are trying to
2005*baa5830fSDavid van Moolenbroek 			 * receive at least one data byte.  This is the
2006*baa5830fSDavid van Moolenbroek 			 * SO_RCVLOWAT test.
2007*baa5830fSDavid van Moolenbroek 			 */
2008*baa5830fSDavid van Moolenbroek 			if (res != -1) e(0);
2009*baa5830fSDavid van Moolenbroek 			if (err != EWOULDBLOCK) e(0);
2010*baa5830fSDavid van Moolenbroek 			if (test == 4) {
2011*baa5830fSDavid van Moolenbroek 				/*
2012*baa5830fSDavid van Moolenbroek 				 * There are still pending file descriptors but
2013*baa5830fSDavid van Moolenbroek 				 * we cannot get them, due to the SO_RCVLOWAT
2014*baa5830fSDavid van Moolenbroek 				 * test.  This is proper behavior but somewhat
2015*baa5830fSDavid van Moolenbroek 				 * annoying, because we want to see if UDS
2016*baa5830fSDavid van Moolenbroek 				 * forgot to close any file descriptors.  So,
2017*baa5830fSDavid van Moolenbroek 				 * we let it force-close them here.
2018*baa5830fSDavid van Moolenbroek 				 */
2019*baa5830fSDavid van Moolenbroek 				if (shutdown(fd, SHUT_RD) != 0) e(0);
2020*baa5830fSDavid van Moolenbroek 				sub |= 8;
2021*baa5830fSDavid van Moolenbroek 			}
2022*baa5830fSDavid van Moolenbroek 		} else {
2023*baa5830fSDavid van Moolenbroek 			i = 0;
2024*baa5830fSDavid van Moolenbroek 			if (state == 1) {
2025*baa5830fSDavid van Moolenbroek 				if (res < 1) e(0);
2026*baa5830fSDavid van Moolenbroek 				if (data[i] != 'A') e(0);
2027*baa5830fSDavid van Moolenbroek 				i++;
2028*baa5830fSDavid van Moolenbroek 			}
2029*baa5830fSDavid van Moolenbroek 			if ((state == 0 && (test & 1)) ||
2030*baa5830fSDavid van Moolenbroek 			    (state == 1 && (test == 1 || test == 3))) {
2031*baa5830fSDavid van Moolenbroek 				if (res < i + 1) e(0);
2032*baa5830fSDavid van Moolenbroek 				if (data[i] != 'B') e(0);
2033*baa5830fSDavid van Moolenbroek 				i++;
2034*baa5830fSDavid van Moolenbroek 			}
2035*baa5830fSDavid van Moolenbroek 			if ((sub & 4) && (state != 1 || test < 4)) {
2036*baa5830fSDavid van Moolenbroek 				if (res < i + 1) e(0);
2037*baa5830fSDavid van Moolenbroek 				if (data[i] != 'C') e(0);
2038*baa5830fSDavid van Moolenbroek 				i++;
2039*baa5830fSDavid van Moolenbroek 			}
2040*baa5830fSDavid van Moolenbroek 			if (i != res) e(0);
2041*baa5830fSDavid van Moolenbroek 			if (state == 0 && test >= 4) {
2042*baa5830fSDavid van Moolenbroek 				if (sub & 2) {
2043*baa5830fSDavid van Moolenbroek 					if (nfds != sentfds) e(0);
2044*baa5830fSDavid van Moolenbroek 				} else
2045*baa5830fSDavid van Moolenbroek 					if (!(rflags & MSG_CTRUNC)) e(0);
2046*baa5830fSDavid van Moolenbroek 			}
2047*baa5830fSDavid van Moolenbroek 		}
2048*baa5830fSDavid van Moolenbroek 
2049*baa5830fSDavid van Moolenbroek 		if (state == 1 && test >= 4) {
2050*baa5830fSDavid van Moolenbroek 			/*
2051*baa5830fSDavid van Moolenbroek 			 * We just read the first segment, but there is a
2052*baa5830fSDavid van Moolenbroek 			 * second segment with ancillary data.  Read it too.
2053*baa5830fSDavid van Moolenbroek 			 */
2054*baa5830fSDavid van Moolenbroek 			nfds = sentfds;
2055*baa5830fSDavid van Moolenbroek 			rflags = 0;
2056*baa5830fSDavid van Moolenbroek 			res = recv_test_fds(fd, data, sizeof(data), 0, &rflags,
2057*baa5830fSDavid van Moolenbroek 			    &nfds);
2058*baa5830fSDavid van Moolenbroek 			if (rflags & (MSG_TRUNC | MSG_CTRUNC)) e(0);
2059*baa5830fSDavid van Moolenbroek 			if (nfds != sentfds) e(0); /* untouched on failure */
2060*baa5830fSDavid van Moolenbroek 			if (res < -1 || res > (int)sizeof(data)) e(0);
2061*baa5830fSDavid van Moolenbroek 			if (test != 5 && !(sub & 12)) {
2062*baa5830fSDavid van Moolenbroek 				if (res != -1) e(0);
2063*baa5830fSDavid van Moolenbroek 				if (errno != EWOULDBLOCK) e(0);
2064*baa5830fSDavid van Moolenbroek 				/* As above. */
2065*baa5830fSDavid van Moolenbroek 				if (shutdown(fd, SHUT_RD) != 0) e(0);
2066*baa5830fSDavid van Moolenbroek 				sub |= 8;
2067*baa5830fSDavid van Moolenbroek 			} else {
2068*baa5830fSDavid van Moolenbroek 				if (res != (test == 5) + !!(sub & 4)) e(0);
2069*baa5830fSDavid van Moolenbroek 				if (test == 5 && data[0] != 'B') e(0);
2070*baa5830fSDavid van Moolenbroek 				if ((sub & 4) && data[res - 1] != 'C') e(0);
2071*baa5830fSDavid van Moolenbroek 			}
2072*baa5830fSDavid van Moolenbroek 		}
2073*baa5830fSDavid van Moolenbroek 	} else {
2074*baa5830fSDavid van Moolenbroek 		if (res != ((state == 1 || (test & 1)) && !(sub & 1))) e(0);
2075*baa5830fSDavid van Moolenbroek 		if (state == 0 && test >= 4) {
2076*baa5830fSDavid van Moolenbroek 			if (sub & 2) {
2077*baa5830fSDavid van Moolenbroek 				if (nfds != sentfds) e(0);
2078*baa5830fSDavid van Moolenbroek 			} else
2079*baa5830fSDavid van Moolenbroek 				if (!(rflags & MSG_CTRUNC)) e(0);
2080*baa5830fSDavid van Moolenbroek 		}
2081*baa5830fSDavid van Moolenbroek 		if (res > 0 && data[0] != ((state == 1) ? 'A' : 'B')) e(0);
2082*baa5830fSDavid van Moolenbroek 
2083*baa5830fSDavid van Moolenbroek 		if (state == 1) {
2084*baa5830fSDavid van Moolenbroek 			nfds = sentfds;
2085*baa5830fSDavid van Moolenbroek 			rflags = 0;
2086*baa5830fSDavid van Moolenbroek 			res = recv_test_fds(fd, data, sizeof(data), 0, &rflags,
2087*baa5830fSDavid van Moolenbroek 			    &nfds);
2088*baa5830fSDavid van Moolenbroek 			if (res != (test & 1)) e(0);
2089*baa5830fSDavid van Moolenbroek 			if (res > 0 && data[0] != 'B') e(0);
2090*baa5830fSDavid van Moolenbroek 			if (nfds != ((test >= 4) ? sentfds : 0)) e(0);
2091*baa5830fSDavid van Moolenbroek 		}
2092*baa5830fSDavid van Moolenbroek 
2093*baa5830fSDavid van Moolenbroek 		if (sub & 4) {
2094*baa5830fSDavid van Moolenbroek 			nfds = sentfds;
2095*baa5830fSDavid van Moolenbroek 			rflags = 0;
2096*baa5830fSDavid van Moolenbroek 			res = recv_test_fds(fd, data, sizeof(data), 0, &rflags,
2097*baa5830fSDavid van Moolenbroek 			    &nfds);
2098*baa5830fSDavid van Moolenbroek 			if (res != 1) e(0);
2099*baa5830fSDavid van Moolenbroek 			if (data[0] != 'C') e(0);
2100*baa5830fSDavid van Moolenbroek 			if (nfds != 0) e(0);
2101*baa5830fSDavid van Moolenbroek 		}
2102*baa5830fSDavid van Moolenbroek 	}
2103*baa5830fSDavid van Moolenbroek 
2104*baa5830fSDavid van Moolenbroek 	/*
2105*baa5830fSDavid van Moolenbroek 	 * At this point, there is nothing to receive.  Depending on
2106*baa5830fSDavid van Moolenbroek 	 * whether we closed the socket, we expect EOF or EWOULDBLOCK.
2107*baa5830fSDavid van Moolenbroek 	 */
2108*baa5830fSDavid van Moolenbroek 	res = recv(fd, data, sizeof(data), 0);
2109*baa5830fSDavid van Moolenbroek 	if (type == SOCK_DGRAM || !(sub & 8)) {
2110*baa5830fSDavid van Moolenbroek 		if (res != -1) e(0);
2111*baa5830fSDavid van Moolenbroek 		if (errno != EWOULDBLOCK) e(0);
2112*baa5830fSDavid van Moolenbroek 	} else
2113*baa5830fSDavid van Moolenbroek 		if (res != 0) e(0);
2114*baa5830fSDavid van Moolenbroek }
2115*baa5830fSDavid van Moolenbroek 
2116*baa5830fSDavid van Moolenbroek /*
2117*baa5830fSDavid van Moolenbroek  * Test send requests on various socket states and in various forms.
2118*baa5830fSDavid van Moolenbroek  */
2119*baa5830fSDavid van Moolenbroek static void
sub90i_send(int type,int state,int test,int sub)2120*baa5830fSDavid van Moolenbroek sub90i_send(int type, int state, int test, int sub)
2121*baa5830fSDavid van Moolenbroek {
2122*baa5830fSDavid van Moolenbroek 	char *buf;
2123*baa5830fSDavid van Moolenbroek 	int r, res, err, fd[2], peers[2], rcvlen;
2124*baa5830fSDavid van Moolenbroek 
2125*baa5830fSDavid van Moolenbroek 	get_socket_pair(type | SOCK_NONBLOCK, fd);
2126*baa5830fSDavid van Moolenbroek 
2127*baa5830fSDavid van Moolenbroek 	/*
2128*baa5830fSDavid van Moolenbroek 	 * State 0: an empty buffer.
2129*baa5830fSDavid van Moolenbroek 	 * State 1: a non-empty, non-full buffer.
2130*baa5830fSDavid van Moolenbroek 	 * State 2: a full buffer.
2131*baa5830fSDavid van Moolenbroek 	 */
2132*baa5830fSDavid van Moolenbroek 	if (state == 2) {
2133*baa5830fSDavid van Moolenbroek 		if (type == SOCK_STREAM) {
2134*baa5830fSDavid van Moolenbroek 			rcvlen = get_rcvbuf_len(fd[0]);
2135*baa5830fSDavid van Moolenbroek 
2136*baa5830fSDavid van Moolenbroek 			if ((buf = malloc(rcvlen)) == NULL) e(0);
2137*baa5830fSDavid van Moolenbroek 
2138*baa5830fSDavid van Moolenbroek 			memset(buf, 'A', rcvlen);
2139*baa5830fSDavid van Moolenbroek 
2140*baa5830fSDavid van Moolenbroek 			if (send(fd[0], buf, rcvlen, 0) != rcvlen) e(0);
2141*baa5830fSDavid van Moolenbroek 
2142*baa5830fSDavid van Moolenbroek 			free(buf);
2143*baa5830fSDavid van Moolenbroek 		} else {
2144*baa5830fSDavid van Moolenbroek 			while ((r = send(fd[0], "A", 1, 0)) == 1);
2145*baa5830fSDavid van Moolenbroek 			if (r != -1) e(0);
2146*baa5830fSDavid van Moolenbroek 			if (errno !=
2147*baa5830fSDavid van Moolenbroek 			    ((type == SOCK_SEQPACKET) ? EAGAIN : ENOBUFS))
2148*baa5830fSDavid van Moolenbroek 				e(0);
2149*baa5830fSDavid van Moolenbroek 		}
2150*baa5830fSDavid van Moolenbroek 	} else if (state == 1)
2151*baa5830fSDavid van Moolenbroek 		if (send(fd[0], "A", 1, 0) != 1) e(0);
2152*baa5830fSDavid van Moolenbroek 
2153*baa5830fSDavid van Moolenbroek 	/*
2154*baa5830fSDavid van Moolenbroek 	 * Test 0: no data, no control data.
2155*baa5830fSDavid van Moolenbroek 	 * Test 1: data, no control data.
2156*baa5830fSDavid van Moolenbroek 	 * Test 2: no data, empty control data.
2157*baa5830fSDavid van Moolenbroek 	 * Test 3: data, empty control data.
2158*baa5830fSDavid van Moolenbroek 	 * Test 4: no data, control data with a file descriptor.
2159*baa5830fSDavid van Moolenbroek 	 * Test 5: data, control data with a file descriptor.
2160*baa5830fSDavid van Moolenbroek 	 */
2161*baa5830fSDavid van Moolenbroek 	switch (test) {
2162*baa5830fSDavid van Moolenbroek 	case 0:
2163*baa5830fSDavid van Moolenbroek 	case 1:
2164*baa5830fSDavid van Moolenbroek 		res = send(fd[0], "B", test % 2, 0);
2165*baa5830fSDavid van Moolenbroek 		err = errno;
2166*baa5830fSDavid van Moolenbroek 		break;
2167*baa5830fSDavid van Moolenbroek 	case 2:
2168*baa5830fSDavid van Moolenbroek 	case 3:
2169*baa5830fSDavid van Moolenbroek 		res = send_test_fds(fd[0], "B", test % 2, 0, NULL, 0);
2170*baa5830fSDavid van Moolenbroek 		err = errno;
2171*baa5830fSDavid van Moolenbroek 		break;
2172*baa5830fSDavid van Moolenbroek 	case 4:
2173*baa5830fSDavid van Moolenbroek 	case 5:
2174*baa5830fSDavid van Moolenbroek 		res = send_test_fds(fd[0], "B", test % 2, 0, peers,
2175*baa5830fSDavid van Moolenbroek 		    __arraycount(peers));
2176*baa5830fSDavid van Moolenbroek 		err = errno;
2177*baa5830fSDavid van Moolenbroek 		break;
2178*baa5830fSDavid van Moolenbroek 	default:
2179*baa5830fSDavid van Moolenbroek 		res = -1;
2180*baa5830fSDavid van Moolenbroek 		err = EINVAL;
2181*baa5830fSDavid van Moolenbroek 		e(0);
2182*baa5830fSDavid van Moolenbroek 	}
2183*baa5830fSDavid van Moolenbroek 
2184*baa5830fSDavid van Moolenbroek 	if (res < -1 || res > 1) e(0);
2185*baa5830fSDavid van Moolenbroek 
2186*baa5830fSDavid van Moolenbroek 	switch (state) {
2187*baa5830fSDavid van Moolenbroek 	case 0:
2188*baa5830fSDavid van Moolenbroek 	case 1:
2189*baa5830fSDavid van Moolenbroek 		if (res != (test % 2)) e(0);
2190*baa5830fSDavid van Moolenbroek 
2191*baa5830fSDavid van Moolenbroek 		/*
2192*baa5830fSDavid van Moolenbroek 		 * Subtest bit 0x1: try a zero-size receive first.
2193*baa5830fSDavid van Moolenbroek 		 * Subtest bit 0x2: try receiving control data.
2194*baa5830fSDavid van Moolenbroek 		 * Subtest bit 0x4: send an extra segment with no control data.
2195*baa5830fSDavid van Moolenbroek 		 * Subtest bit 0x8: after completing receives, expect EOF.
2196*baa5830fSDavid van Moolenbroek 		 */
2197*baa5830fSDavid van Moolenbroek 		if (sub & 4)
2198*baa5830fSDavid van Moolenbroek 			if (send(fd[0], "C", 1, 0) != 1) e(0);
2199*baa5830fSDavid van Moolenbroek 		if (sub & 8)
2200*baa5830fSDavid van Moolenbroek 			if (shutdown(fd[0], SHUT_WR) != 0) e(0);
2201*baa5830fSDavid van Moolenbroek 
2202*baa5830fSDavid van Moolenbroek 		/*
2203*baa5830fSDavid van Moolenbroek 		 * Assuming (sub&4), which means there is an extra "C"..
2204*baa5830fSDavid van Moolenbroek 		 *
2205*baa5830fSDavid van Moolenbroek 		 * For stream sockets, we should now receive:
2206*baa5830fSDavid van Moolenbroek 		 * - state 0:
2207*baa5830fSDavid van Moolenbroek 		 *   - test 0, 2: "C"
2208*baa5830fSDavid van Moolenbroek 		 *   - test 1, 3: "BC"
2209*baa5830fSDavid van Moolenbroek 		 *   - test 4: "C" (w/fds)
2210*baa5830fSDavid van Moolenbroek 		 *   - test 5: "BC" (w/fds)
2211*baa5830fSDavid van Moolenbroek 		 * - state 1:
2212*baa5830fSDavid van Moolenbroek 		 *   - test 0, 2: "AC"
2213*baa5830fSDavid van Moolenbroek 		 *   - test 1, 3: "ABC"
2214*baa5830fSDavid van Moolenbroek 		 *   - test 4: "A", "C" (w/fds)
2215*baa5830fSDavid van Moolenbroek 		 *   - test 5: "A", "BC" (w/fds)
2216*baa5830fSDavid van Moolenbroek 		 *
2217*baa5830fSDavid van Moolenbroek 		 * For packet sockets, we should now receive:
2218*baa5830fSDavid van Moolenbroek 		 * - state 1:
2219*baa5830fSDavid van Moolenbroek 		 *   - all tests: "A", followed by..
2220*baa5830fSDavid van Moolenbroek 		 * - state 0, 1:
2221*baa5830fSDavid van Moolenbroek 		 *   - test 0, 2: "" (no fds), "C"
2222*baa5830fSDavid van Moolenbroek 		 *   - test 1, 3: "B" (no fds), "C"
2223*baa5830fSDavid van Moolenbroek 		 *   - test 4: "" (w/fds), "C"
2224*baa5830fSDavid van Moolenbroek 		 *   - test 5: "B" (w/fds), "C"
2225*baa5830fSDavid van Moolenbroek 		 */
2226*baa5830fSDavid van Moolenbroek 		sub90i_recv(fd[1], type, state, test, sub,
2227*baa5830fSDavid van Moolenbroek 		    __arraycount(peers));
2228*baa5830fSDavid van Moolenbroek 
2229*baa5830fSDavid van Moolenbroek 		break;
2230*baa5830fSDavid van Moolenbroek 	case 2:
2231*baa5830fSDavid van Moolenbroek 		/*
2232*baa5830fSDavid van Moolenbroek 		 * Alright, the results are a bit tricky to interpret here,
2233*baa5830fSDavid van Moolenbroek 		 * because UDS's current strict send admission control prevents
2234*baa5830fSDavid van Moolenbroek 		 * the receive buffer from being fully utilized.  We therefore
2235*baa5830fSDavid van Moolenbroek 		 * only test the following aspects:
2236*baa5830fSDavid van Moolenbroek 		 *
2237*baa5830fSDavid van Moolenbroek 		 * - if we sent no regular or control data to a stream socket,
2238*baa5830fSDavid van Moolenbroek 		 *   the call should have succeeded (note that the presence of
2239*baa5830fSDavid van Moolenbroek 		 *   empty control data may cause the call to fail);
2240*baa5830fSDavid van Moolenbroek 		 * - if we sent either regular or control data to a stream
2241*baa5830fSDavid van Moolenbroek 		 *   socket, the call should have failed with EWOULDBLOCK;
2242*baa5830fSDavid van Moolenbroek 		 * - if the call failed, the error should have been EWOULDBLOCK
2243*baa5830fSDavid van Moolenbroek 		 *   for connection-type sockets and ENOBUFS for connectionless
2244*baa5830fSDavid van Moolenbroek 		 *   sockets.
2245*baa5830fSDavid van Moolenbroek 		 *
2246*baa5830fSDavid van Moolenbroek 		 * Everything else gets a pass; we can't even be sure that for
2247*baa5830fSDavid van Moolenbroek 		 * packet-oriented sockets we completely filled up the buffer.
2248*baa5830fSDavid van Moolenbroek 		 */
2249*baa5830fSDavid van Moolenbroek 		if (res == -1) {
2250*baa5830fSDavid van Moolenbroek 			if (type == SOCK_STREAM && test == 0) e(0);
2251*baa5830fSDavid van Moolenbroek 
2252*baa5830fSDavid van Moolenbroek 			if (type != SOCK_DGRAM && err != EWOULDBLOCK) e(0);
2253*baa5830fSDavid van Moolenbroek 			if (type == SOCK_DGRAM && err != ENOBUFS) e(0);
2254*baa5830fSDavid van Moolenbroek 		} else
2255*baa5830fSDavid van Moolenbroek 			if (type == SOCK_STREAM && test != 0) e(0);
2256*baa5830fSDavid van Moolenbroek 		break;
2257*baa5830fSDavid van Moolenbroek 	}
2258*baa5830fSDavid van Moolenbroek 
2259*baa5830fSDavid van Moolenbroek 	/*
2260*baa5830fSDavid van Moolenbroek 	 * Make sure there are no more in-flight file descriptors now, even
2261*baa5830fSDavid van Moolenbroek 	 * before closing the socket.
2262*baa5830fSDavid van Moolenbroek 	 */
2263*baa5830fSDavid van Moolenbroek 	if (res >= 0 && test >= 4)
2264*baa5830fSDavid van Moolenbroek 		close_test_fds(peers, __arraycount(peers));
2265*baa5830fSDavid van Moolenbroek 
2266*baa5830fSDavid van Moolenbroek 	close(fd[0]);
2267*baa5830fSDavid van Moolenbroek 	close(fd[1]);
2268*baa5830fSDavid van Moolenbroek }
2269*baa5830fSDavid van Moolenbroek 
2270*baa5830fSDavid van Moolenbroek /*
2271*baa5830fSDavid van Moolenbroek  * Test send and receive requests with regular data, control data, both, or
2272*baa5830fSDavid van Moolenbroek  * neither, and test segment boundaries.
2273*baa5830fSDavid van Moolenbroek  */
2274*baa5830fSDavid van Moolenbroek static void
test90i(void)2275*baa5830fSDavid van Moolenbroek test90i(void)
2276*baa5830fSDavid van Moolenbroek {
2277*baa5830fSDavid van Moolenbroek 	int state, test, sub;
2278*baa5830fSDavid van Moolenbroek 
2279*baa5830fSDavid van Moolenbroek 	subtest = 9;
2280*baa5830fSDavid van Moolenbroek 
2281*baa5830fSDavid van Moolenbroek 	for (state = 0; state < 3; state++) {
2282*baa5830fSDavid van Moolenbroek 		for (test = 0; test < 6; test++) {
2283*baa5830fSDavid van Moolenbroek 			for (sub = 0; sub < ((state < 2) ? 16 : 1); sub++) {
2284*baa5830fSDavid van Moolenbroek 				sub90i_send(SOCK_STREAM, state, test, sub);
2285*baa5830fSDavid van Moolenbroek 
2286*baa5830fSDavid van Moolenbroek 				sub90i_send(SOCK_SEQPACKET, state, test, sub);
2287*baa5830fSDavid van Moolenbroek 
2288*baa5830fSDavid van Moolenbroek 				sub90i_send(SOCK_DGRAM, state, test, sub);
2289*baa5830fSDavid van Moolenbroek 			}
2290*baa5830fSDavid van Moolenbroek 		}
2291*baa5830fSDavid van Moolenbroek 	}
2292*baa5830fSDavid van Moolenbroek }
2293*baa5830fSDavid van Moolenbroek 
2294*baa5830fSDavid van Moolenbroek /*
2295*baa5830fSDavid van Moolenbroek  * Test segmentation of file descriptor transfer on a particular socket type.
2296*baa5830fSDavid van Moolenbroek  */
2297*baa5830fSDavid van Moolenbroek static void
sub90j(int type)2298*baa5830fSDavid van Moolenbroek sub90j(int type)
2299*baa5830fSDavid van Moolenbroek {
2300*baa5830fSDavid van Moolenbroek 	char path[PATH_MAX], buf[2];
2301*baa5830fSDavid van Moolenbroek 	int i, fd[2], out[7], in[7], rflags, nfds;
2302*baa5830fSDavid van Moolenbroek 	ssize_t len;
2303*baa5830fSDavid van Moolenbroek 
2304*baa5830fSDavid van Moolenbroek 	get_socket_pair(type, fd);
2305*baa5830fSDavid van Moolenbroek 
2306*baa5830fSDavid van Moolenbroek 	for (i = 0; i < __arraycount(out); i++) {
2307*baa5830fSDavid van Moolenbroek 		snprintf(path, sizeof(path), "file%d", i);
2308*baa5830fSDavid van Moolenbroek 		out[i] = open(path, O_RDWR | O_CREAT | O_EXCL | O_TRUNC, 0644);
2309*baa5830fSDavid van Moolenbroek 		if (out[i] < 0) e(0);
2310*baa5830fSDavid van Moolenbroek 		if (write(out[i], path, strlen(path)) != strlen(path)) e(0);
2311*baa5830fSDavid van Moolenbroek 		if (lseek(out[i], 0, SEEK_SET) != 0) e(0);
2312*baa5830fSDavid van Moolenbroek 	}
2313*baa5830fSDavid van Moolenbroek 
2314*baa5830fSDavid van Moolenbroek 	if (send_fds(fd[1], "A", 1, 0, NULL, 0, &out[0], 1) != 1) e(0);
2315*baa5830fSDavid van Moolenbroek 	if (send_fds(fd[1], "B", 1, 0, NULL, 0, &out[1], 3) != 1) e(0);
2316*baa5830fSDavid van Moolenbroek 	if (send_fds(fd[1], "C", 1, 0, NULL, 0, &out[4], 2) != 1) e(0);
2317*baa5830fSDavid van Moolenbroek 
2318*baa5830fSDavid van Moolenbroek 	nfds = 2;
2319*baa5830fSDavid van Moolenbroek 	if (recv_fds(fd[0], buf, sizeof(buf), 0, &rflags, &in[0], &nfds) != 1)
2320*baa5830fSDavid van Moolenbroek 		e(0);
2321*baa5830fSDavid van Moolenbroek 	if (buf[0] != 'A') e(0);
2322*baa5830fSDavid van Moolenbroek 	if (rflags != 0) e(0);
2323*baa5830fSDavid van Moolenbroek 	if (nfds != 1) e(0);
2324*baa5830fSDavid van Moolenbroek 
2325*baa5830fSDavid van Moolenbroek 	nfds = 5;
2326*baa5830fSDavid van Moolenbroek 	if (recv_fds(fd[0], buf, sizeof(buf), 0, &rflags, &in[1], &nfds) != 1)
2327*baa5830fSDavid van Moolenbroek 		e(0);
2328*baa5830fSDavid van Moolenbroek 	if (buf[0] != 'B') e(0);
2329*baa5830fSDavid van Moolenbroek 	if (rflags != 0) e(0);
2330*baa5830fSDavid van Moolenbroek 	if (nfds != 3) e(0);
2331*baa5830fSDavid van Moolenbroek 
2332*baa5830fSDavid van Moolenbroek 	if (send_fds(fd[1], "D", 1, 0, NULL, 0, &out[6], 1) != 1) e(0);
2333*baa5830fSDavid van Moolenbroek 
2334*baa5830fSDavid van Moolenbroek 	nfds = 2;
2335*baa5830fSDavid van Moolenbroek 	if (recv_fds(fd[0], buf, sizeof(buf), 0, &rflags, &in[4], &nfds) != 1)
2336*baa5830fSDavid van Moolenbroek 		e(0);
2337*baa5830fSDavid van Moolenbroek 	if (buf[0] != 'C') e(0);
2338*baa5830fSDavid van Moolenbroek 	if (rflags != 0) e(0);
2339*baa5830fSDavid van Moolenbroek 	if (nfds != 2) e(0);
2340*baa5830fSDavid van Moolenbroek 
2341*baa5830fSDavid van Moolenbroek 	nfds = 2;
2342*baa5830fSDavid van Moolenbroek 	if (recv_fds(fd[0], buf, sizeof(buf), 0, &rflags, &in[6], &nfds) != 1)
2343*baa5830fSDavid van Moolenbroek 		e(0);
2344*baa5830fSDavid van Moolenbroek 	if (buf[0] != 'D') e(0);
2345*baa5830fSDavid van Moolenbroek 	if (rflags != 0) e(0);
2346*baa5830fSDavid van Moolenbroek 	if (nfds != 1) e(0);
2347*baa5830fSDavid van Moolenbroek 
2348*baa5830fSDavid van Moolenbroek 	for (i = 0; i < __arraycount(in); i++) {
2349*baa5830fSDavid van Moolenbroek 		len = read(in[i], path, sizeof(path));
2350*baa5830fSDavid van Moolenbroek 		if (len < 5 || len > 7) e(0);
2351*baa5830fSDavid van Moolenbroek 		path[len] = '\0';
2352*baa5830fSDavid van Moolenbroek 		if (strncmp(path, "file", 4) != 0) e(0);
2353*baa5830fSDavid van Moolenbroek 		if (atoi(&path[4]) != i) e(0);
2354*baa5830fSDavid van Moolenbroek 		if (unlink(path) != 0) e(0);
2355*baa5830fSDavid van Moolenbroek 		if (close(in[i]) != 0) e(0);
2356*baa5830fSDavid van Moolenbroek 	}
2357*baa5830fSDavid van Moolenbroek 
2358*baa5830fSDavid van Moolenbroek 	for (i = 0; i < __arraycount(out); i++)
2359*baa5830fSDavid van Moolenbroek 		if (close(out[i]) != 0) e(0);
2360*baa5830fSDavid van Moolenbroek 
2361*baa5830fSDavid van Moolenbroek 	/*
2362*baa5830fSDavid van Moolenbroek 	 * While we're here, see if UDS properly closes any remaining in-flight
2363*baa5830fSDavid van Moolenbroek 	 * file descriptors when the socket is closed.
2364*baa5830fSDavid van Moolenbroek 	 */
2365*baa5830fSDavid van Moolenbroek 	if (send_test_fds(fd[1], "E", 1, 0, out, 7) != 1) e(0);
2366*baa5830fSDavid van Moolenbroek 
2367*baa5830fSDavid van Moolenbroek 	close(fd[0]);
2368*baa5830fSDavid van Moolenbroek 	close(fd[1]);
2369*baa5830fSDavid van Moolenbroek 
2370*baa5830fSDavid van Moolenbroek 	close_test_fds(out, 7);
2371*baa5830fSDavid van Moolenbroek }
2372*baa5830fSDavid van Moolenbroek 
2373*baa5830fSDavid van Moolenbroek /*
2374*baa5830fSDavid van Moolenbroek  * Test segmentation of file descriptor transfer.  That is, there are multiple
2375*baa5830fSDavid van Moolenbroek  * in-flight file descriptors, they must each be associated with their
2376*baa5830fSDavid van Moolenbroek  * respective segments.
2377*baa5830fSDavid van Moolenbroek  */
2378*baa5830fSDavid van Moolenbroek static void
test90j(void)2379*baa5830fSDavid van Moolenbroek test90j(void)
2380*baa5830fSDavid van Moolenbroek {
2381*baa5830fSDavid van Moolenbroek 
2382*baa5830fSDavid van Moolenbroek 	subtest = 10;
2383*baa5830fSDavid van Moolenbroek 
2384*baa5830fSDavid van Moolenbroek 	sub90j(SOCK_STREAM);
2385*baa5830fSDavid van Moolenbroek 
2386*baa5830fSDavid van Moolenbroek 	sub90j(SOCK_SEQPACKET);
2387*baa5830fSDavid van Moolenbroek 
2388*baa5830fSDavid van Moolenbroek 	sub90j(SOCK_DGRAM);
2389*baa5830fSDavid van Moolenbroek }
2390*baa5830fSDavid van Moolenbroek 
2391*baa5830fSDavid van Moolenbroek /*
2392*baa5830fSDavid van Moolenbroek  * Test whether we can deadlock UDS by making it close the last reference to
2393*baa5830fSDavid van Moolenbroek  * an in-flight file descriptor for a UDS socket.  Currently we allow VFS/UDS
2394*baa5830fSDavid van Moolenbroek  * to get away with throwing EDEADLK as a sledgehammer approach to preventing
2395*baa5830fSDavid van Moolenbroek  * problems with in-flight UDS sockets.
2396*baa5830fSDavid van Moolenbroek  */
2397*baa5830fSDavid van Moolenbroek static void
test90k(void)2398*baa5830fSDavid van Moolenbroek test90k(void)
2399*baa5830fSDavid van Moolenbroek {
2400*baa5830fSDavid van Moolenbroek 	int r, fd[2], fd2;
2401*baa5830fSDavid van Moolenbroek 
2402*baa5830fSDavid van Moolenbroek 	subtest = 11;
2403*baa5830fSDavid van Moolenbroek 
2404*baa5830fSDavid van Moolenbroek 	get_socket_pair(SOCK_STREAM, fd);
2405*baa5830fSDavid van Moolenbroek 
2406*baa5830fSDavid van Moolenbroek 	if ((fd2 = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) e(0);
2407*baa5830fSDavid van Moolenbroek 
2408*baa5830fSDavid van Moolenbroek 	if ((r = send_fds(fd[0], "X", 1, 0, NULL, 0, &fd2, 1)) != 1) {
2409*baa5830fSDavid van Moolenbroek 		if (r != -1) e(0);
2410*baa5830fSDavid van Moolenbroek 		if (errno != EDEADLK) e(0); /* whew */
2411*baa5830fSDavid van Moolenbroek 	}
2412*baa5830fSDavid van Moolenbroek 
2413*baa5830fSDavid van Moolenbroek 	if (close(fd2) != 0) e(0);
2414*baa5830fSDavid van Moolenbroek 	if (close(fd[0]) != 0) e(0);
2415*baa5830fSDavid van Moolenbroek 	if (close(fd[1]) != 0) e(0); /* boom */
2416*baa5830fSDavid van Moolenbroek }
2417*baa5830fSDavid van Moolenbroek 
2418*baa5830fSDavid van Moolenbroek /*
2419*baa5830fSDavid van Moolenbroek  * Test whether we can make UDS run out of file descriptors by transferring a
2420*baa5830fSDavid van Moolenbroek  * UDS socket over itself and then closing all other references while it is
2421*baa5830fSDavid van Moolenbroek  * in-flight.  Currently we allow VFS/UDS to get away with throwing EDEADLK as
2422*baa5830fSDavid van Moolenbroek  * a sledgehammer approach to preventing problems with in-flight UDS sockets.
2423*baa5830fSDavid van Moolenbroek  */
2424*baa5830fSDavid van Moolenbroek static void
test90l(void)2425*baa5830fSDavid van Moolenbroek test90l(void)
2426*baa5830fSDavid van Moolenbroek {
2427*baa5830fSDavid van Moolenbroek 	struct sockaddr_un sun;
2428*baa5830fSDavid van Moolenbroek 	int i, r, fd, fd2;
2429*baa5830fSDavid van Moolenbroek 
2430*baa5830fSDavid van Moolenbroek 	subtest = 12;
2431*baa5830fSDavid van Moolenbroek 
2432*baa5830fSDavid van Moolenbroek 	fd = get_bound_socket(SOCK_DGRAM, SOCK_PATH_A, &sun);
2433*baa5830fSDavid van Moolenbroek 
2434*baa5830fSDavid van Moolenbroek 	for (i = 0; i < OPEN_MAX + 1; i++) {
2435*baa5830fSDavid van Moolenbroek 		if ((fd2 = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0) e(0);
2436*baa5830fSDavid van Moolenbroek 
2437*baa5830fSDavid van Moolenbroek 		if ((r = send_fds(fd2, "X", 1, 0, (struct sockaddr *)&sun,
2438*baa5830fSDavid van Moolenbroek 		    sizeof(sun), &fd2, 1)) != 1) {
2439*baa5830fSDavid van Moolenbroek 			if (r != -1) e(0);
2440*baa5830fSDavid van Moolenbroek 			if (errno != EDEADLK) e(0); /* whew */
2441*baa5830fSDavid van Moolenbroek 		}
2442*baa5830fSDavid van Moolenbroek 
2443*baa5830fSDavid van Moolenbroek 		if (close(fd2) != 0) e(0); /* have fun in limbo.. */
2444*baa5830fSDavid van Moolenbroek 	}
2445*baa5830fSDavid van Moolenbroek 
2446*baa5830fSDavid van Moolenbroek 	if (close(fd) != 0) e(0);
2447*baa5830fSDavid van Moolenbroek 	if (unlink(SOCK_PATH_A) != 0) e(0);
2448*baa5830fSDavid van Moolenbroek }
2449*baa5830fSDavid van Moolenbroek 
2450*baa5830fSDavid van Moolenbroek /*
2451*baa5830fSDavid van Moolenbroek  * Receive with credentials.
2452*baa5830fSDavid van Moolenbroek  */
2453*baa5830fSDavid van Moolenbroek static int
recv_creds(int fd,char * buf,size_t size,int flags,int * rflags,struct sockcred * sc,socklen_t * sc_len)2454*baa5830fSDavid van Moolenbroek recv_creds(int fd, char * buf, size_t size, int flags, int * rflags,
2455*baa5830fSDavid van Moolenbroek 	struct sockcred * sc, socklen_t * sc_len)
2456*baa5830fSDavid van Moolenbroek {
2457*baa5830fSDavid van Moolenbroek 	union {
2458*baa5830fSDavid van Moolenbroek 		char buf[CMSG_SPACE(SOCKCREDSIZE(NGROUPS_MAX))];
2459*baa5830fSDavid van Moolenbroek 		struct cmsghdr cmsg;
2460*baa5830fSDavid van Moolenbroek 	} control;
2461*baa5830fSDavid van Moolenbroek 	struct msghdr msg;
2462*baa5830fSDavid van Moolenbroek 	struct iovec iov;
2463*baa5830fSDavid van Moolenbroek 	size_t len;
2464*baa5830fSDavid van Moolenbroek 	int r;
2465*baa5830fSDavid van Moolenbroek 
2466*baa5830fSDavid van Moolenbroek 	iov.iov_base = buf;
2467*baa5830fSDavid van Moolenbroek 	iov.iov_len = size;
2468*baa5830fSDavid van Moolenbroek 
2469*baa5830fSDavid van Moolenbroek 	memset(&control.cmsg, 0, sizeof(control.cmsg));
2470*baa5830fSDavid van Moolenbroek 	control.cmsg.cmsg_len = CMSG_LEN(SOCKCREDSIZE(NGROUPS_MAX));
2471*baa5830fSDavid van Moolenbroek 	control.cmsg.cmsg_level = SOL_SOCKET;
2472*baa5830fSDavid van Moolenbroek 	control.cmsg.cmsg_type = SCM_RIGHTS;
2473*baa5830fSDavid van Moolenbroek 
2474*baa5830fSDavid van Moolenbroek 	memset(&msg, 0, sizeof(msg));
2475*baa5830fSDavid van Moolenbroek 	msg.msg_iov = &iov;
2476*baa5830fSDavid van Moolenbroek 	msg.msg_iovlen = 1;
2477*baa5830fSDavid van Moolenbroek 	msg.msg_control = &control;
2478*baa5830fSDavid van Moolenbroek 	msg.msg_controllen = control.cmsg.cmsg_len;
2479*baa5830fSDavid van Moolenbroek 
2480*baa5830fSDavid van Moolenbroek 	if ((r = recvmsg(fd, &msg, flags)) < 0)
2481*baa5830fSDavid van Moolenbroek 		return r;
2482*baa5830fSDavid van Moolenbroek 
2483*baa5830fSDavid van Moolenbroek 	if (msg.msg_controllen > 0) {
2484*baa5830fSDavid van Moolenbroek 		assert(msg.msg_controllen <= sizeof(control));
2485*baa5830fSDavid van Moolenbroek 		assert(msg.msg_controllen >= sizeof(control.cmsg));
2486*baa5830fSDavid van Moolenbroek 		assert(control.cmsg.cmsg_len <= msg.msg_controllen);
2487*baa5830fSDavid van Moolenbroek 		len = control.cmsg.cmsg_len - CMSG_LEN(0);
2488*baa5830fSDavid van Moolenbroek 		assert(len >= sizeof(struct sockcred));
2489*baa5830fSDavid van Moolenbroek 		assert(len <= SOCKCREDSIZE(NGROUPS_MAX));
2490*baa5830fSDavid van Moolenbroek 		if (*sc_len > len)
2491*baa5830fSDavid van Moolenbroek 			*sc_len = len;
2492*baa5830fSDavid van Moolenbroek 		memcpy(sc, CMSG_DATA(&control.cmsg), *sc_len);
2493*baa5830fSDavid van Moolenbroek 	} else
2494*baa5830fSDavid van Moolenbroek 		*sc_len = 0;
2495*baa5830fSDavid van Moolenbroek 
2496*baa5830fSDavid van Moolenbroek 	*rflags = msg.msg_flags;
2497*baa5830fSDavid van Moolenbroek 	return r;
2498*baa5830fSDavid van Moolenbroek }
2499*baa5830fSDavid van Moolenbroek 
2500*baa5830fSDavid van Moolenbroek /*
2501*baa5830fSDavid van Moolenbroek  * Test basic credentials passing on connection-oriented sockets.
2502*baa5830fSDavid van Moolenbroek  */
2503*baa5830fSDavid van Moolenbroek static void
sub90m(int type)2504*baa5830fSDavid van Moolenbroek sub90m(int type)
2505*baa5830fSDavid van Moolenbroek {
2506*baa5830fSDavid van Moolenbroek 	struct sockaddr_un sun;
2507*baa5830fSDavid van Moolenbroek 	struct sockcred sc;
2508*baa5830fSDavid van Moolenbroek 	struct msghdr msg;
2509*baa5830fSDavid van Moolenbroek 	struct iovec iov;
2510*baa5830fSDavid van Moolenbroek 	socklen_t len;
2511*baa5830fSDavid van Moolenbroek 	char buf[1];
2512*baa5830fSDavid van Moolenbroek 	int fd, fd2, fd3, val, rflags;
2513*baa5830fSDavid van Moolenbroek 
2514*baa5830fSDavid van Moolenbroek 	fd = get_bound_socket(type, SOCK_PATH_A, &sun);
2515*baa5830fSDavid van Moolenbroek 
2516*baa5830fSDavid van Moolenbroek 	val = 1;
2517*baa5830fSDavid van Moolenbroek 	if (setsockopt(fd, 0, LOCAL_CREDS, &val, sizeof(val)) != 0) e(0);
2518*baa5830fSDavid van Moolenbroek 
2519*baa5830fSDavid van Moolenbroek 	if (listen(fd, 1) != 0) e(0);
2520*baa5830fSDavid van Moolenbroek 
2521*baa5830fSDavid van Moolenbroek 	if ((fd2 = socket(AF_UNIX, type | SOCK_NONBLOCK, 0)) < 0) e(0);
2522*baa5830fSDavid van Moolenbroek 
2523*baa5830fSDavid van Moolenbroek 	if (connect(fd2, (struct sockaddr *)&sun, sizeof(sun)) != 0) e(0);
2524*baa5830fSDavid van Moolenbroek 
2525*baa5830fSDavid van Moolenbroek 	len = sizeof(sun);
2526*baa5830fSDavid van Moolenbroek 	if ((fd3 = accept(fd, (struct sockaddr *)&sun, &len)) < 0) e(0);
2527*baa5830fSDavid van Moolenbroek 
2528*baa5830fSDavid van Moolenbroek 	if (send(fd2, "A", 1, 0) != 1) e(0);
2529*baa5830fSDavid van Moolenbroek 	if (send(fd2, "B", 1, 0) != 1) e(0);
2530*baa5830fSDavid van Moolenbroek 
2531*baa5830fSDavid van Moolenbroek 	len = sizeof(sc);
2532*baa5830fSDavid van Moolenbroek 	if (recv_creds(fd3, buf, sizeof(buf), 0, &rflags, &sc, &len) != 1)
2533*baa5830fSDavid van Moolenbroek 		e(0);
2534*baa5830fSDavid van Moolenbroek 	if (buf[0] != 'A') e(0);
2535*baa5830fSDavid van Moolenbroek 	if (rflags != 0) e(0);
2536*baa5830fSDavid van Moolenbroek 	if (len != sizeof(sc)) e(0);
2537*baa5830fSDavid van Moolenbroek 	if (sc.sc_uid != getuid()) e(0);
2538*baa5830fSDavid van Moolenbroek 	if (sc.sc_euid != geteuid()) e(0);
2539*baa5830fSDavid van Moolenbroek 
2540*baa5830fSDavid van Moolenbroek 	len = sizeof(sc);
2541*baa5830fSDavid van Moolenbroek 	if (recv_creds(fd3, buf, sizeof(buf), 0, &rflags, &sc, &len) != 1)
2542*baa5830fSDavid van Moolenbroek 		e(0);
2543*baa5830fSDavid van Moolenbroek 	if (buf[0] != 'B') e(0);
2544*baa5830fSDavid van Moolenbroek 	if (rflags != 0) e(0);
2545*baa5830fSDavid van Moolenbroek 	if (len != 0) e(0);
2546*baa5830fSDavid van Moolenbroek 
2547*baa5830fSDavid van Moolenbroek 	if (send(fd3, "C", 1, 0) != 1) e(0);
2548*baa5830fSDavid van Moolenbroek 
2549*baa5830fSDavid van Moolenbroek 	val = 1;
2550*baa5830fSDavid van Moolenbroek 	if (setsockopt(fd2, 0, LOCAL_CREDS, &val, sizeof(val)) != 0) e(0);
2551*baa5830fSDavid van Moolenbroek 
2552*baa5830fSDavid van Moolenbroek 	if (send(fd3, "D", 1, 0) != 1) e(0);
2553*baa5830fSDavid van Moolenbroek 
2554*baa5830fSDavid van Moolenbroek 	val = 1;
2555*baa5830fSDavid van Moolenbroek 	if (setsockopt(fd2, 0, LOCAL_CREDS, &val, sizeof(val)) != 0) e(0);
2556*baa5830fSDavid van Moolenbroek 
2557*baa5830fSDavid van Moolenbroek 	if (send(fd3, "E", 1, 0) != 1) e(0);
2558*baa5830fSDavid van Moolenbroek 
2559*baa5830fSDavid van Moolenbroek 	len = sizeof(sc);
2560*baa5830fSDavid van Moolenbroek 	if (recv_creds(fd2, buf, sizeof(buf), 0, &rflags, &sc, &len) != 1)
2561*baa5830fSDavid van Moolenbroek 		e(0);
2562*baa5830fSDavid van Moolenbroek 	if (buf[0] != 'C') e(0);
2563*baa5830fSDavid van Moolenbroek 	if (rflags != 0) e(0);
2564*baa5830fSDavid van Moolenbroek 	if (len != 0) e(0);
2565*baa5830fSDavid van Moolenbroek 
2566*baa5830fSDavid van Moolenbroek 	len = sizeof(sc);
2567*baa5830fSDavid van Moolenbroek 	if (recv_creds(fd2, buf, sizeof(buf), 0, &rflags, &sc, &len) != 1)
2568*baa5830fSDavid van Moolenbroek 		e(0);
2569*baa5830fSDavid van Moolenbroek 	if (buf[0] != 'D') e(0);
2570*baa5830fSDavid van Moolenbroek 	if (rflags != 0) e(0);
2571*baa5830fSDavid van Moolenbroek 	if (len != sizeof(sc)) e(0);
2572*baa5830fSDavid van Moolenbroek 	if (sc.sc_uid != getuid()) e(0);
2573*baa5830fSDavid van Moolenbroek 	if (sc.sc_euid != geteuid()) e(0);
2574*baa5830fSDavid van Moolenbroek 
2575*baa5830fSDavid van Moolenbroek 	memset(&msg, 0, sizeof(msg));
2576*baa5830fSDavid van Moolenbroek 	iov.iov_base = buf;
2577*baa5830fSDavid van Moolenbroek 	iov.iov_len = sizeof(buf);
2578*baa5830fSDavid van Moolenbroek 	msg.msg_iov = &iov;
2579*baa5830fSDavid van Moolenbroek 	msg.msg_iovlen = 1;
2580*baa5830fSDavid van Moolenbroek 	if (recvmsg(fd2, &msg, 0) != 1) e(0);
2581*baa5830fSDavid van Moolenbroek 	if (buf[0] != 'E') e(0);
2582*baa5830fSDavid van Moolenbroek 	if (msg.msg_flags != MSG_CTRUNC) e(0);
2583*baa5830fSDavid van Moolenbroek 
2584*baa5830fSDavid van Moolenbroek 	if (close(fd2) != 0) e(0);
2585*baa5830fSDavid van Moolenbroek 	if (close(fd3) != 0) e(0);
2586*baa5830fSDavid van Moolenbroek 
2587*baa5830fSDavid van Moolenbroek 	val = 0;
2588*baa5830fSDavid van Moolenbroek 	if (setsockopt(fd, 0, LOCAL_CREDS, &val, sizeof(val)) != 0) e(0);
2589*baa5830fSDavid van Moolenbroek 
2590*baa5830fSDavid van Moolenbroek 	if ((fd2 = socket(AF_UNIX, type, 0)) < 0) e(0);
2591*baa5830fSDavid van Moolenbroek 
2592*baa5830fSDavid van Moolenbroek 	if (connect(fd2, (struct sockaddr *)&sun, sizeof(sun)) != 0) e(0);
2593*baa5830fSDavid van Moolenbroek 
2594*baa5830fSDavid van Moolenbroek 	len = sizeof(sun);
2595*baa5830fSDavid van Moolenbroek 	if ((fd3 = accept(fd, (struct sockaddr *)&sun, &len)) < 0) e(0);
2596*baa5830fSDavid van Moolenbroek 
2597*baa5830fSDavid van Moolenbroek 	if (send(fd2, "F", 1, 0) != 1) e(0);
2598*baa5830fSDavid van Moolenbroek 
2599*baa5830fSDavid van Moolenbroek 	len = sizeof(sc);
2600*baa5830fSDavid van Moolenbroek 	if (recv_creds(fd3, buf, sizeof(buf), 0, &rflags, &sc, &len) != 1)
2601*baa5830fSDavid van Moolenbroek 		e(0);
2602*baa5830fSDavid van Moolenbroek 	if (buf[0] != 'F') e(0);
2603*baa5830fSDavid van Moolenbroek 	if (rflags != 0) e(0);
2604*baa5830fSDavid van Moolenbroek 	if (len != 0) e(0);
2605*baa5830fSDavid van Moolenbroek 
2606*baa5830fSDavid van Moolenbroek 	if (close(fd) != 0) e(0);
2607*baa5830fSDavid van Moolenbroek 	if (close(fd2) != 0) e(0);
2608*baa5830fSDavid van Moolenbroek 	if (close(fd3) != 0) e(0);
2609*baa5830fSDavid van Moolenbroek 
2610*baa5830fSDavid van Moolenbroek 	if (unlink(SOCK_PATH_A) != 0) e(0);
2611*baa5830fSDavid van Moolenbroek }
2612*baa5830fSDavid van Moolenbroek 
2613*baa5830fSDavid van Moolenbroek /*
2614*baa5830fSDavid van Moolenbroek  * A few tests for credentials passing that matter to some applications:
2615*baa5830fSDavid van Moolenbroek  * the credentials passing setting is inherited by accepted connections from
2616*baa5830fSDavid van Moolenbroek  * their listening socket, and, credentials are passed only once on a
2617*baa5830fSDavid van Moolenbroek  * connection-oriented socket.
2618*baa5830fSDavid van Moolenbroek  */
2619*baa5830fSDavid van Moolenbroek static void
test90m(void)2620*baa5830fSDavid van Moolenbroek test90m(void)
2621*baa5830fSDavid van Moolenbroek {
2622*baa5830fSDavid van Moolenbroek 	struct sockcred sc;
2623*baa5830fSDavid van Moolenbroek 	socklen_t len;
2624*baa5830fSDavid van Moolenbroek 	char buf[1];
2625*baa5830fSDavid van Moolenbroek 	int fd[2], val, rflags;
2626*baa5830fSDavid van Moolenbroek 
2627*baa5830fSDavid van Moolenbroek 	subtest = 13;
2628*baa5830fSDavid van Moolenbroek 
2629*baa5830fSDavid van Moolenbroek 	sub90m(SOCK_STREAM);
2630*baa5830fSDavid van Moolenbroek 
2631*baa5830fSDavid van Moolenbroek 	sub90m(SOCK_SEQPACKET);
2632*baa5830fSDavid van Moolenbroek 
2633*baa5830fSDavid van Moolenbroek 	get_socket_pair(SOCK_DGRAM, fd);
2634*baa5830fSDavid van Moolenbroek 
2635*baa5830fSDavid van Moolenbroek 	val = 1;
2636*baa5830fSDavid van Moolenbroek 	if (setsockopt(fd[0], 0, LOCAL_CREDS, &val, sizeof(val)) != 0) e(0);
2637*baa5830fSDavid van Moolenbroek 
2638*baa5830fSDavid van Moolenbroek 	if (send(fd[1], "A", 1, 0) != 1) e(0);
2639*baa5830fSDavid van Moolenbroek 	if (send(fd[0], "B", 1, 0) != 1) e(0);
2640*baa5830fSDavid van Moolenbroek 	if (send(fd[1], "C", 1, 0) != 1) e(0);
2641*baa5830fSDavid van Moolenbroek 
2642*baa5830fSDavid van Moolenbroek 	len = sizeof(sc);
2643*baa5830fSDavid van Moolenbroek 	if (recv_creds(fd[0], buf, sizeof(buf), 0, &rflags, &sc, &len) != 1)
2644*baa5830fSDavid van Moolenbroek 		e(0);
2645*baa5830fSDavid van Moolenbroek 	if (buf[0] != 'A') e(0);
2646*baa5830fSDavid van Moolenbroek 	if (rflags != 0) e(0);
2647*baa5830fSDavid van Moolenbroek 	if (len != sizeof(sc)) e(0);
2648*baa5830fSDavid van Moolenbroek 	if (sc.sc_uid != getuid()) e(0);
2649*baa5830fSDavid van Moolenbroek 	if (sc.sc_euid != geteuid()) e(0);
2650*baa5830fSDavid van Moolenbroek 
2651*baa5830fSDavid van Moolenbroek 	len = sizeof(sc);
2652*baa5830fSDavid van Moolenbroek 	if (recv_creds(fd[1], buf, sizeof(buf), 0, &rflags, &sc, &len) != 1)
2653*baa5830fSDavid van Moolenbroek 		e(0);
2654*baa5830fSDavid van Moolenbroek 	if (buf[0] != 'B') e(0);
2655*baa5830fSDavid van Moolenbroek 	if (rflags != 0) e(0);
2656*baa5830fSDavid van Moolenbroek 	if (len != 0) e(0);
2657*baa5830fSDavid van Moolenbroek 
2658*baa5830fSDavid van Moolenbroek 	len = sizeof(sc);
2659*baa5830fSDavid van Moolenbroek 	if (recv_creds(fd[0], buf, sizeof(buf), 0, &rflags, &sc, &len) != 1)
2660*baa5830fSDavid van Moolenbroek 		e(0);
2661*baa5830fSDavid van Moolenbroek 	if (buf[0] != 'C') e(0);
2662*baa5830fSDavid van Moolenbroek 	if (rflags != 0) e(0);
2663*baa5830fSDavid van Moolenbroek 	if (len != sizeof(sc)) e(0);
2664*baa5830fSDavid van Moolenbroek 	if (sc.sc_uid != getuid()) e(0);
2665*baa5830fSDavid van Moolenbroek 	if (sc.sc_euid != geteuid()) e(0);
2666*baa5830fSDavid van Moolenbroek 
2667*baa5830fSDavid van Moolenbroek 	if (close(fd[0]) != 0) e(0);
2668*baa5830fSDavid van Moolenbroek 	if (close(fd[1]) != 0) e(0);
2669*baa5830fSDavid van Moolenbroek }
2670*baa5830fSDavid van Moolenbroek 
2671*baa5830fSDavid van Moolenbroek /*
2672*baa5830fSDavid van Moolenbroek  * Test whether MSG_CMSG_CLOEXEC is honored when copying in file descriptors.
2673*baa5830fSDavid van Moolenbroek  * We do not bother to test with execve(2w); obtaining the FD flags suffices.
2674*baa5830fSDavid van Moolenbroek  */
2675*baa5830fSDavid van Moolenbroek static void
test90n(void)2676*baa5830fSDavid van Moolenbroek test90n(void)
2677*baa5830fSDavid van Moolenbroek {
2678*baa5830fSDavid van Moolenbroek 	char buf[1];
2679*baa5830fSDavid van Moolenbroek 	int i, fd[2], sfd, rfd, fl, rflags, nfds;
2680*baa5830fSDavid van Moolenbroek 
2681*baa5830fSDavid van Moolenbroek 	subtest = 14;
2682*baa5830fSDavid van Moolenbroek 
2683*baa5830fSDavid van Moolenbroek 	get_socket_pair(SOCK_STREAM, fd);
2684*baa5830fSDavid van Moolenbroek 
2685*baa5830fSDavid van Moolenbroek 	if ((sfd = open("/dev/null", O_RDONLY)) < 0) e(0);
2686*baa5830fSDavid van Moolenbroek 
2687*baa5830fSDavid van Moolenbroek 	if (send_fds(fd[0], "A", 1, 0, NULL, 0, &sfd, 1) != 1) e(0);
2688*baa5830fSDavid van Moolenbroek 	if (send_fds(fd[0], "B", 1, 0, NULL, 0, &sfd, 1) != 1) e(0);
2689*baa5830fSDavid van Moolenbroek 
2690*baa5830fSDavid van Moolenbroek 	if ((fl = fcntl(sfd, F_GETFD, 0)) < 0) e(0);
2691*baa5830fSDavid van Moolenbroek 	if (fcntl(sfd, F_SETFD, fl | FD_CLOEXEC) != 0) e(0);
2692*baa5830fSDavid van Moolenbroek 
2693*baa5830fSDavid van Moolenbroek 	if (send_fds(fd[0], "C", 1, 0, NULL, 0, &sfd, 1) != 1) e(0);
2694*baa5830fSDavid van Moolenbroek 	if (send_fds(fd[0], "D", 1, 0, NULL, 0, &sfd, 1) != 1) e(0);
2695*baa5830fSDavid van Moolenbroek 
2696*baa5830fSDavid van Moolenbroek 	for (i = 0; i < 4; i++) {
2697*baa5830fSDavid van Moolenbroek 		fl = (i & 1) ? MSG_CMSG_CLOEXEC : 0;
2698*baa5830fSDavid van Moolenbroek 		nfds = 1;
2699*baa5830fSDavid van Moolenbroek 		if (recv_fds(fd[1], buf, sizeof(buf), fl, &rflags, &rfd,
2700*baa5830fSDavid van Moolenbroek 		    &nfds) != 1) e(0);
2701*baa5830fSDavid van Moolenbroek 		if (buf[0] != 'A' + i) e(0);
2702*baa5830fSDavid van Moolenbroek 		if (rflags != 0) e(0);
2703*baa5830fSDavid van Moolenbroek 		if (nfds != 1) e(0);
2704*baa5830fSDavid van Moolenbroek 
2705*baa5830fSDavid van Moolenbroek 		if ((fl = fcntl(rfd, F_GETFD, 0)) < 0) e(0);
2706*baa5830fSDavid van Moolenbroek 		if (!!(fl & FD_CLOEXEC) != (i & 1)) e(0);
2707*baa5830fSDavid van Moolenbroek 
2708*baa5830fSDavid van Moolenbroek 		if (close(rfd) != 0) e(0);
2709*baa5830fSDavid van Moolenbroek 	}
2710*baa5830fSDavid van Moolenbroek 
2711*baa5830fSDavid van Moolenbroek 	if (close(sfd) != 0) e(0);
2712*baa5830fSDavid van Moolenbroek 	if (close(fd[0]) != 0) e(0);
2713*baa5830fSDavid van Moolenbroek 	if (close(fd[1]) != 0) e(0);
2714*baa5830fSDavid van Moolenbroek }
2715*baa5830fSDavid van Moolenbroek 
2716*baa5830fSDavid van Moolenbroek /*
2717*baa5830fSDavid van Moolenbroek  * Test failures sending and receiving sets of file descriptors.
2718*baa5830fSDavid van Moolenbroek  */
2719*baa5830fSDavid van Moolenbroek static void
sub90o(int type)2720*baa5830fSDavid van Moolenbroek sub90o(int type)
2721*baa5830fSDavid van Moolenbroek {
2722*baa5830fSDavid van Moolenbroek 	static int ofd[OPEN_MAX];
2723*baa5830fSDavid van Moolenbroek 	char buf[1];
2724*baa5830fSDavid van Moolenbroek 	int i, fd[2], sfd[2], rfd[2], rflags, nfds;
2725*baa5830fSDavid van Moolenbroek 
2726*baa5830fSDavid van Moolenbroek 	get_socket_pair(type, fd);
2727*baa5830fSDavid van Moolenbroek 
2728*baa5830fSDavid van Moolenbroek 	if ((sfd[0] = open("/dev/null", O_RDONLY)) < 0) e(0);
2729*baa5830fSDavid van Moolenbroek 	sfd[1] = -1;
2730*baa5830fSDavid van Moolenbroek 
2731*baa5830fSDavid van Moolenbroek 	if (send_fds(fd[0], "A", 1, 0, NULL, 0, &sfd[1], 1) != -1) e(0);
2732*baa5830fSDavid van Moolenbroek 	if (errno != EBADF) e(0);
2733*baa5830fSDavid van Moolenbroek 	if (send_fds(fd[0], "B", 1, 0, NULL, 0, &sfd[0], 2) != -1) e(0);
2734*baa5830fSDavid van Moolenbroek 	if (errno != EBADF) e(0);
2735*baa5830fSDavid van Moolenbroek 	if ((sfd[1] = dup(sfd[0])) < 0) e(0);
2736*baa5830fSDavid van Moolenbroek 	if (send_fds(fd[0], "C", 1, 0, NULL, 0, &sfd[0], 2) != 1) e(0);
2737*baa5830fSDavid van Moolenbroek 
2738*baa5830fSDavid van Moolenbroek 	for (i = 0; i < __arraycount(ofd); i++) {
2739*baa5830fSDavid van Moolenbroek 		if ((ofd[i] = dup(sfd[0])) < 0) {
2740*baa5830fSDavid van Moolenbroek 			/* Either will do. */
2741*baa5830fSDavid van Moolenbroek 			if (errno != EMFILE && errno != ENFILE) e(0);
2742*baa5830fSDavid van Moolenbroek 			break;
2743*baa5830fSDavid van Moolenbroek 		}
2744*baa5830fSDavid van Moolenbroek 	}
2745*baa5830fSDavid van Moolenbroek 
2746*baa5830fSDavid van Moolenbroek 	nfds = 2;
2747*baa5830fSDavid van Moolenbroek 	if (recv_fds(fd[1], buf, sizeof(buf), 0, &rflags, rfd, &nfds) != -1)
2748*baa5830fSDavid van Moolenbroek 		e(0);
2749*baa5830fSDavid van Moolenbroek 	if (errno != ENFILE && errno != EMFILE) e(0);
2750*baa5830fSDavid van Moolenbroek 
2751*baa5830fSDavid van Moolenbroek 	if (close(sfd[1]) != 0) e(0);
2752*baa5830fSDavid van Moolenbroek 
2753*baa5830fSDavid van Moolenbroek 	nfds = 2;
2754*baa5830fSDavid van Moolenbroek 	if (recv_fds(fd[1], buf, sizeof(buf), 0, &rflags, rfd, &nfds) != -1)
2755*baa5830fSDavid van Moolenbroek 		e(0);
2756*baa5830fSDavid van Moolenbroek 	if (errno != ENFILE && errno != EMFILE) e(0);
2757*baa5830fSDavid van Moolenbroek 
2758*baa5830fSDavid van Moolenbroek 	if (close(sfd[0]) != 0) e(0);
2759*baa5830fSDavid van Moolenbroek 
2760*baa5830fSDavid van Moolenbroek 	nfds = 2;
2761*baa5830fSDavid van Moolenbroek 	if (recv_fds(fd[1], buf, sizeof(buf), 0, &rflags, rfd, &nfds) != 1)
2762*baa5830fSDavid van Moolenbroek 		e(0);
2763*baa5830fSDavid van Moolenbroek 	if (buf[0] != 'C') e(0);
2764*baa5830fSDavid van Moolenbroek 	if (rflags != 0) e(0);
2765*baa5830fSDavid van Moolenbroek 	if (nfds != 2) e(0);
2766*baa5830fSDavid van Moolenbroek 
2767*baa5830fSDavid van Moolenbroek 	if (close(rfd[1]) != 0) e(0);
2768*baa5830fSDavid van Moolenbroek 	if (close(rfd[0]) != 0) e(0);
2769*baa5830fSDavid van Moolenbroek 	while (i-- > 0)
2770*baa5830fSDavid van Moolenbroek 		if (close(ofd[i]) != 0) e(0);
2771*baa5830fSDavid van Moolenbroek 	if (close(fd[1]) != 0) e(0);
2772*baa5830fSDavid van Moolenbroek 	if (close(fd[0]) != 0) e(0);
2773*baa5830fSDavid van Moolenbroek }
2774*baa5830fSDavid van Moolenbroek 
2775*baa5830fSDavid van Moolenbroek /*
2776*baa5830fSDavid van Moolenbroek  * Test failures sending and receiving sets of file descriptors.
2777*baa5830fSDavid van Moolenbroek  */
2778*baa5830fSDavid van Moolenbroek static void
test90o(void)2779*baa5830fSDavid van Moolenbroek test90o(void)
2780*baa5830fSDavid van Moolenbroek {
2781*baa5830fSDavid van Moolenbroek 	const int types[] = { SOCK_STREAM, SOCK_SEQPACKET, SOCK_DGRAM };
2782*baa5830fSDavid van Moolenbroek 	int i;
2783*baa5830fSDavid van Moolenbroek 
2784*baa5830fSDavid van Moolenbroek 	subtest = 15;
2785*baa5830fSDavid van Moolenbroek 
2786*baa5830fSDavid van Moolenbroek 	for (i = 0; i < OPEN_MAX + 1; i++)
2787*baa5830fSDavid van Moolenbroek 		sub90o(types[i % __arraycount(types)]);
2788*baa5830fSDavid van Moolenbroek }
2789*baa5830fSDavid van Moolenbroek 
2790*baa5830fSDavid van Moolenbroek /*
2791*baa5830fSDavid van Moolenbroek  * Test socket reuse for a particular socket type.
2792*baa5830fSDavid van Moolenbroek  */
2793*baa5830fSDavid van Moolenbroek static void
sub90p(int type)2794*baa5830fSDavid van Moolenbroek sub90p(int type)
2795*baa5830fSDavid van Moolenbroek {
2796*baa5830fSDavid van Moolenbroek 	struct sockaddr_un sunA, sunB, sunC;
2797*baa5830fSDavid van Moolenbroek 	socklen_t len;
2798*baa5830fSDavid van Moolenbroek 	char buf[1];
2799*baa5830fSDavid van Moolenbroek 	uid_t euid;
2800*baa5830fSDavid van Moolenbroek 	gid_t egid;
2801*baa5830fSDavid van Moolenbroek 	int fd, fd2, fd3, val;
2802*baa5830fSDavid van Moolenbroek 
2803*baa5830fSDavid van Moolenbroek 	if ((fd = socket(AF_UNIX, type | SOCK_NONBLOCK, 0)) < 0) e(0);
2804*baa5830fSDavid van Moolenbroek 	/* Unconnected. */
2805*baa5830fSDavid van Moolenbroek 
2806*baa5830fSDavid van Moolenbroek 	if (getpeereid(fd, &euid, &egid) != -1) e(0);
2807*baa5830fSDavid van Moolenbroek 	if (errno != ENOTCONN) e(0);
2808*baa5830fSDavid van Moolenbroek 
2809*baa5830fSDavid van Moolenbroek 	fd2 = get_bound_socket(type, SOCK_PATH_A, &sunA);
2810*baa5830fSDavid van Moolenbroek 
2811*baa5830fSDavid van Moolenbroek 	val = 1;
2812*baa5830fSDavid van Moolenbroek 	if (setsockopt(fd2, 0, LOCAL_CONNWAIT, &val, sizeof(val)) != 0) e(0);
2813*baa5830fSDavid van Moolenbroek 
2814*baa5830fSDavid van Moolenbroek 	if (listen(fd2, 5) != 0) e(0);
2815*baa5830fSDavid van Moolenbroek 
2816*baa5830fSDavid van Moolenbroek 	if (connect(fd, (struct sockaddr *)&sunA, sizeof(sunA)) != -1) e(0);
2817*baa5830fSDavid van Moolenbroek 	if (errno != EINPROGRESS) e(0);
2818*baa5830fSDavid van Moolenbroek 	/* Connecting. */
2819*baa5830fSDavid van Moolenbroek 
2820*baa5830fSDavid van Moolenbroek 	if (getpeereid(fd, &euid, &egid) != -1) e(0);
2821*baa5830fSDavid van Moolenbroek 	if (errno != ENOTCONN) e(0);
2822*baa5830fSDavid van Moolenbroek 
2823*baa5830fSDavid van Moolenbroek 	len = sizeof(sunB);
2824*baa5830fSDavid van Moolenbroek 	if ((fd3 = accept(fd2, (struct sockaddr *)&sunB, &len)) < 0) e(0);
2825*baa5830fSDavid van Moolenbroek 	/* Connected. */
2826*baa5830fSDavid van Moolenbroek 
2827*baa5830fSDavid van Moolenbroek 	len = sizeof(sunC);
2828*baa5830fSDavid van Moolenbroek 	if (getpeername(fd, (struct sockaddr *)&sunC, &len) != 0) e(0);
2829*baa5830fSDavid van Moolenbroek 	check_addr(&sunC, len, SOCK_PATH_A);
2830*baa5830fSDavid van Moolenbroek 
2831*baa5830fSDavid van Moolenbroek 	if (getpeereid(fd, &euid, &egid) != 0) e(0);
2832*baa5830fSDavid van Moolenbroek 	if (euid == -1 || egid == -1) e(0);
2833*baa5830fSDavid van Moolenbroek 
2834*baa5830fSDavid van Moolenbroek 	if (getpeereid(fd3, &euid, &egid) != 0) e(0);
2835*baa5830fSDavid van Moolenbroek 	if (euid == -1 || egid == -1) e(0);
2836*baa5830fSDavid van Moolenbroek 
2837*baa5830fSDavid van Moolenbroek 	if (send(fd3, "A", 1, 0) != 1) e(0);
2838*baa5830fSDavid van Moolenbroek 	if (send(fd3, "B", 1, 0) != 1) e(0);
2839*baa5830fSDavid van Moolenbroek 	if (send(fd3, "C", 1, 0) != 1) e(0);
2840*baa5830fSDavid van Moolenbroek 
2841*baa5830fSDavid van Moolenbroek 	if (close(fd3) != 0) e(0);
2842*baa5830fSDavid van Moolenbroek 	/* Disconnected. */
2843*baa5830fSDavid van Moolenbroek 
2844*baa5830fSDavid van Moolenbroek 	if (getpeereid(fd, &euid, &egid) != -1) e(0);
2845*baa5830fSDavid van Moolenbroek 	if (errno != ENOTCONN) e(0);
2846*baa5830fSDavid van Moolenbroek 
2847*baa5830fSDavid van Moolenbroek 	if (close(fd2) != 0) e(0);
2848*baa5830fSDavid van Moolenbroek 	fd2 = get_bound_socket(type, SOCK_PATH_B, &sunA);
2849*baa5830fSDavid van Moolenbroek 
2850*baa5830fSDavid van Moolenbroek 	if (listen(fd2, 5) != 0) e(0);
2851*baa5830fSDavid van Moolenbroek 
2852*baa5830fSDavid van Moolenbroek 	val = 1;
2853*baa5830fSDavid van Moolenbroek 	if (setsockopt(fd, 0, LOCAL_CONNWAIT, &val, sizeof(val)) != 0) e(0);
2854*baa5830fSDavid van Moolenbroek 
2855*baa5830fSDavid van Moolenbroek 	if (connect(fd, (struct sockaddr *)&sunA, sizeof(sunA)) != -1) e(0);
2856*baa5830fSDavid van Moolenbroek 	if (errno != EINPROGRESS) e(0);
2857*baa5830fSDavid van Moolenbroek 	/* Connecting. */
2858*baa5830fSDavid van Moolenbroek 
2859*baa5830fSDavid van Moolenbroek 	if (getpeereid(fd, &euid, &egid) != -1) e(0);
2860*baa5830fSDavid van Moolenbroek 	if (errno != ENOTCONN) e(0);
2861*baa5830fSDavid van Moolenbroek 
2862*baa5830fSDavid van Moolenbroek 	if (recv(fd, buf, 1, 0) != 1) e(0);
2863*baa5830fSDavid van Moolenbroek 	if (buf[0] != 'A') e(0);
2864*baa5830fSDavid van Moolenbroek 
2865*baa5830fSDavid van Moolenbroek 	len = sizeof(sunB);
2866*baa5830fSDavid van Moolenbroek 	if ((fd3 = accept(fd2, (struct sockaddr *)&sunB, &len)) < 0) e(0);
2867*baa5830fSDavid van Moolenbroek 	/* Connected. */
2868*baa5830fSDavid van Moolenbroek 
2869*baa5830fSDavid van Moolenbroek 	if (send(fd3, "D", 1, 0) != 1) e(0);
2870*baa5830fSDavid van Moolenbroek 	if (send(fd3, "E", 1, 0) != 1) e(0);
2871*baa5830fSDavid van Moolenbroek 
2872*baa5830fSDavid van Moolenbroek 	len = sizeof(sunC);
2873*baa5830fSDavid van Moolenbroek 	if (getpeername(fd, (struct sockaddr *)&sunC, &len) != 0) e(0);
2874*baa5830fSDavid van Moolenbroek 	check_addr(&sunC, len, SOCK_PATH_B);
2875*baa5830fSDavid van Moolenbroek 
2876*baa5830fSDavid van Moolenbroek 	if (getpeereid(fd, &euid, &egid) != 0) e(0);
2877*baa5830fSDavid van Moolenbroek 	if (euid == -1 || egid == -1) e(0);
2878*baa5830fSDavid van Moolenbroek 
2879*baa5830fSDavid van Moolenbroek 	if (close(fd2) != 0) e(0);
2880*baa5830fSDavid van Moolenbroek 	if (unlink(SOCK_PATH_B) != 0) e(0);
2881*baa5830fSDavid van Moolenbroek 
2882*baa5830fSDavid van Moolenbroek 	if (close(fd3) != 0) e(0);
2883*baa5830fSDavid van Moolenbroek 	/* Disconnected. */
2884*baa5830fSDavid van Moolenbroek 
2885*baa5830fSDavid van Moolenbroek 	if (connect(fd, (struct sockaddr *)&sunA, sizeof(sunA)) != -1) e(0);
2886*baa5830fSDavid van Moolenbroek 	if (errno != ENOENT) e(0);
2887*baa5830fSDavid van Moolenbroek 	/* Unconnected. */
2888*baa5830fSDavid van Moolenbroek 
2889*baa5830fSDavid van Moolenbroek 	if (getpeereid(fd, &euid, &egid) != -1) e(0);
2890*baa5830fSDavid van Moolenbroek 	if (errno != ENOTCONN) e(0);
2891*baa5830fSDavid van Moolenbroek 
2892*baa5830fSDavid van Moolenbroek 	if (recv(fd, buf, 1, 0) != 1) e(0);
2893*baa5830fSDavid van Moolenbroek 	if (buf[0] != 'B') e(0);
2894*baa5830fSDavid van Moolenbroek 
2895*baa5830fSDavid van Moolenbroek 	if (unlink(SOCK_PATH_A) != 0) e(0);
2896*baa5830fSDavid van Moolenbroek 
2897*baa5830fSDavid van Moolenbroek 	if (bind(fd, (struct sockaddr *)&sunA, sizeof(sunA)) != 0) e(0);
2898*baa5830fSDavid van Moolenbroek 
2899*baa5830fSDavid van Moolenbroek 	if (recv(fd, buf, 1, 0) != 1) e(0);
2900*baa5830fSDavid van Moolenbroek 	if (buf[0] != 'C') e(0);
2901*baa5830fSDavid van Moolenbroek 
2902*baa5830fSDavid van Moolenbroek 	val = 0;
2903*baa5830fSDavid van Moolenbroek 	if (setsockopt(fd, 0, LOCAL_CONNWAIT, &val, sizeof(val)) != 0) e(0);
2904*baa5830fSDavid van Moolenbroek 
2905*baa5830fSDavid van Moolenbroek 	if (listen(fd, 1) != 0) e(0);
2906*baa5830fSDavid van Moolenbroek 	/* Listening. */
2907*baa5830fSDavid van Moolenbroek 
2908*baa5830fSDavid van Moolenbroek 	if (recv(fd, buf, 1, 0) != 1) e(0);
2909*baa5830fSDavid van Moolenbroek 	if (buf[0] != 'D') e(0);
2910*baa5830fSDavid van Moolenbroek 
2911*baa5830fSDavid van Moolenbroek 	if ((fd2 = socket(AF_UNIX, type, 0)) < 0) e(0);
2912*baa5830fSDavid van Moolenbroek 
2913*baa5830fSDavid van Moolenbroek 	if (connect(fd2, (struct sockaddr *)&sunA, sizeof(sunA)) != 0) e(0);
2914*baa5830fSDavid van Moolenbroek 
2915*baa5830fSDavid van Moolenbroek 	len = sizeof(sunC);
2916*baa5830fSDavid van Moolenbroek 	if ((fd3 = accept(fd, (struct sockaddr *)&sunC, &len)) < 0) e(0);
2917*baa5830fSDavid van Moolenbroek 
2918*baa5830fSDavid van Moolenbroek 	if (send(fd2, "F", 1, 0) != 1) e(0);
2919*baa5830fSDavid van Moolenbroek 
2920*baa5830fSDavid van Moolenbroek 	if (recv(fd3, buf, 1, 0) != 1) e(0);
2921*baa5830fSDavid van Moolenbroek 	if (buf[0] != 'F') e(0);
2922*baa5830fSDavid van Moolenbroek 
2923*baa5830fSDavid van Moolenbroek 	if (recv(fd, buf, 1, 0) != 1) e(0);
2924*baa5830fSDavid van Moolenbroek 	if (buf[0] != 'E') e(0);
2925*baa5830fSDavid van Moolenbroek 
2926*baa5830fSDavid van Moolenbroek 	if (recv(fd, buf, 1, 0) != -1) e(0);
2927*baa5830fSDavid van Moolenbroek 	if (errno != ENOTCONN) e(0);
2928*baa5830fSDavid van Moolenbroek 
2929*baa5830fSDavid van Moolenbroek 	/* It should be possible to obtain peer credentials now. */
2930*baa5830fSDavid van Moolenbroek 	if (getpeereid(fd2, &euid, &egid) != 0) e(0);
2931*baa5830fSDavid van Moolenbroek 	if (euid == -1 || egid == -1) e(0);
2932*baa5830fSDavid van Moolenbroek 
2933*baa5830fSDavid van Moolenbroek 	if (getpeereid(fd3, &euid, &egid) != 0) e(0);
2934*baa5830fSDavid van Moolenbroek 	if (euid == -1 || egid == -1) e(0);
2935*baa5830fSDavid van Moolenbroek 
2936*baa5830fSDavid van Moolenbroek 	if (close(fd3) != 0) e(0);
2937*baa5830fSDavid van Moolenbroek 	if (close(fd2) != 0) e(0);
2938*baa5830fSDavid van Moolenbroek 
2939*baa5830fSDavid van Moolenbroek 	if (close(fd) != 0) e(0);
2940*baa5830fSDavid van Moolenbroek 	/* Closed. */
2941*baa5830fSDavid van Moolenbroek 
2942*baa5830fSDavid van Moolenbroek 	if (unlink(SOCK_PATH_B) != 0) e(0);
2943*baa5830fSDavid van Moolenbroek 
2944*baa5830fSDavid van Moolenbroek 	if ((fd = socket(AF_UNIX, type, 0)) < 0) e(0);
2945*baa5830fSDavid van Moolenbroek 	/* Unconnected. */
2946*baa5830fSDavid van Moolenbroek 
2947*baa5830fSDavid van Moolenbroek 	fd2 = get_bound_socket(type, SOCK_PATH_A, &sunA);
2948*baa5830fSDavid van Moolenbroek 
2949*baa5830fSDavid van Moolenbroek 	if (listen(fd2, 5) != 0) e(0);
2950*baa5830fSDavid van Moolenbroek 
2951*baa5830fSDavid van Moolenbroek 	if (connect(fd, (struct sockaddr *)&sunA, sizeof(sunA)) != 0) e(0);
2952*baa5830fSDavid van Moolenbroek 	/* Connected. */
2953*baa5830fSDavid van Moolenbroek 
2954*baa5830fSDavid van Moolenbroek 	len = sizeof(sunB);
2955*baa5830fSDavid van Moolenbroek 	if ((fd3 = accept(fd2, (struct sockaddr *)&sunB, &len)) < 0) e(0);
2956*baa5830fSDavid van Moolenbroek 
2957*baa5830fSDavid van Moolenbroek 	if (close(fd2) != 0) e(0);
2958*baa5830fSDavid van Moolenbroek 
2959*baa5830fSDavid van Moolenbroek 	memset(&sunB, 0, sizeof(sunB));
2960*baa5830fSDavid van Moolenbroek 	sunB.sun_family = AF_UNIX;
2961*baa5830fSDavid van Moolenbroek 	strlcpy(sunB.sun_path, SOCK_PATH_B, sizeof(sunB.sun_path));
2962*baa5830fSDavid van Moolenbroek 
2963*baa5830fSDavid van Moolenbroek 	if (bind(fd, (struct sockaddr *)&sunB, sizeof(sunB)) != 0) e(0);
2964*baa5830fSDavid van Moolenbroek 
2965*baa5830fSDavid van Moolenbroek 	if (close(fd3) != 0) e(0);
2966*baa5830fSDavid van Moolenbroek 	/* Disconnected. */
2967*baa5830fSDavid van Moolenbroek 
2968*baa5830fSDavid van Moolenbroek 	if (listen(fd, 1) != 0) e(0);
2969*baa5830fSDavid van Moolenbroek 	/* Listening. */
2970*baa5830fSDavid van Moolenbroek 
2971*baa5830fSDavid van Moolenbroek 	if ((fd2 = socket(AF_UNIX, type, 0)) < 0) e(0);
2972*baa5830fSDavid van Moolenbroek 
2973*baa5830fSDavid van Moolenbroek 	if (connect(fd2, (struct sockaddr *)&sunB, sizeof(sunB)) != 0) e(0);
2974*baa5830fSDavid van Moolenbroek 
2975*baa5830fSDavid van Moolenbroek 	len = sizeof(sunC);
2976*baa5830fSDavid van Moolenbroek 	if ((fd3 = accept(fd, (struct sockaddr *)&sunC, &len)) < 0) e(0);
2977*baa5830fSDavid van Moolenbroek 
2978*baa5830fSDavid van Moolenbroek 	/* It should NOT be possible to obtain peer credentials now. */
2979*baa5830fSDavid van Moolenbroek 	if (getpeereid(fd2, &euid, &egid) != -1) e(0);
2980*baa5830fSDavid van Moolenbroek 	if (errno != EINVAL) e(0);
2981*baa5830fSDavid van Moolenbroek 
2982*baa5830fSDavid van Moolenbroek 	if (getpeereid(fd3, &euid, &egid) != 0) e(0);
2983*baa5830fSDavid van Moolenbroek 	if (euid == -1 || egid == -1) e(0);
2984*baa5830fSDavid van Moolenbroek 
2985*baa5830fSDavid van Moolenbroek 	if (close(fd3) != 0) e(0);
2986*baa5830fSDavid van Moolenbroek 	if (close(fd2) != 0) e(0);
2987*baa5830fSDavid van Moolenbroek 
2988*baa5830fSDavid van Moolenbroek 	if (close(fd) != 0) e(0);
2989*baa5830fSDavid van Moolenbroek 	/* Closed. */
2990*baa5830fSDavid van Moolenbroek 
2991*baa5830fSDavid van Moolenbroek 	if (unlink(SOCK_PATH_A) != 0) e(0);
2992*baa5830fSDavid van Moolenbroek 	if (unlink(SOCK_PATH_B) != 0) e(0);
2993*baa5830fSDavid van Moolenbroek }
2994*baa5830fSDavid van Moolenbroek 
2995*baa5830fSDavid van Moolenbroek /*
2996*baa5830fSDavid van Moolenbroek  * Test socket reuse, receiving left-overs in the receive buffer, and the
2997*baa5830fSDavid van Moolenbroek  * (in)ability to obtain peer credentials.
2998*baa5830fSDavid van Moolenbroek  */
2999*baa5830fSDavid van Moolenbroek static void
test90p(void)3000*baa5830fSDavid van Moolenbroek test90p(void)
3001*baa5830fSDavid van Moolenbroek {
3002*baa5830fSDavid van Moolenbroek 
3003*baa5830fSDavid van Moolenbroek 	subtest = 16;
3004*baa5830fSDavid van Moolenbroek 
3005*baa5830fSDavid van Moolenbroek 	sub90p(SOCK_STREAM);
3006*baa5830fSDavid van Moolenbroek 
3007*baa5830fSDavid van Moolenbroek 	sub90p(SOCK_SEQPACKET);
3008*baa5830fSDavid van Moolenbroek }
3009*baa5830fSDavid van Moolenbroek 
3010*baa5830fSDavid van Moolenbroek /*
3011*baa5830fSDavid van Moolenbroek  * Test state changes and errors related to connected datagram sockets.
3012*baa5830fSDavid van Moolenbroek  */
3013*baa5830fSDavid van Moolenbroek static void
test90q(void)3014*baa5830fSDavid van Moolenbroek test90q(void)
3015*baa5830fSDavid van Moolenbroek {
3016*baa5830fSDavid van Moolenbroek 	struct sockaddr_un sunA, sunB, sunC, sunD;
3017*baa5830fSDavid van Moolenbroek 	socklen_t len;
3018*baa5830fSDavid van Moolenbroek 	char buf[1];
3019*baa5830fSDavid van Moolenbroek 	int fd, fd2, fd3, val;
3020*baa5830fSDavid van Moolenbroek 
3021*baa5830fSDavid van Moolenbroek 	subtest = 17;
3022*baa5830fSDavid van Moolenbroek 
3023*baa5830fSDavid van Moolenbroek 	/*
3024*baa5830fSDavid van Moolenbroek 	 * Sending a datagram to a datagram socket connected elsewhere should
3025*baa5830fSDavid van Moolenbroek 	 * fail explicitly (specifically, EPERM).
3026*baa5830fSDavid van Moolenbroek 	 */
3027*baa5830fSDavid van Moolenbroek 	fd = get_bound_socket(SOCK_DGRAM, SOCK_PATH_A, &sunA);
3028*baa5830fSDavid van Moolenbroek 	fd2 = get_bound_socket(SOCK_DGRAM, SOCK_PATH_B, &sunB);
3029*baa5830fSDavid van Moolenbroek 	fd3 = get_bound_socket(SOCK_DGRAM, SOCK_PATH_C, &sunC);
3030*baa5830fSDavid van Moolenbroek 
3031*baa5830fSDavid van Moolenbroek 	if (connect(fd2, (struct sockaddr *)&sunA, sizeof(sunA)) != 0) e(0);
3032*baa5830fSDavid van Moolenbroek 
3033*baa5830fSDavid van Moolenbroek 	if (sendto(fd3, "A", 1, 0, (struct sockaddr *)&sunB,
3034*baa5830fSDavid van Moolenbroek 	    sizeof(sunB)) != -1) e(0);
3035*baa5830fSDavid van Moolenbroek 	if (errno != EPERM) e(0);
3036*baa5830fSDavid van Moolenbroek 
3037*baa5830fSDavid van Moolenbroek 	/* Similarly, connecting to such a socket should fail. */
3038*baa5830fSDavid van Moolenbroek 	if (connect(fd3, (struct sockaddr *)&sunB, sizeof(sunB)) != -1) e(0);
3039*baa5830fSDavid van Moolenbroek 	if (errno != EPERM) e(0);
3040*baa5830fSDavid van Moolenbroek 
3041*baa5830fSDavid van Moolenbroek 	if (send(fd2, "B", 1, 0) != 1) e(0);
3042*baa5830fSDavid van Moolenbroek 
3043*baa5830fSDavid van Moolenbroek 	if (recv(fd, buf, 1, 0) != 1) e(0);
3044*baa5830fSDavid van Moolenbroek 	if (buf[0] != 'B') e(0);
3045*baa5830fSDavid van Moolenbroek 
3046*baa5830fSDavid van Moolenbroek 	/* Reconnection of a socket's target should result in ECONNRESET. */
3047*baa5830fSDavid van Moolenbroek 	if (connect(fd, (struct sockaddr *)&sunC, sizeof(sunC)) != 0) e(0);
3048*baa5830fSDavid van Moolenbroek 
3049*baa5830fSDavid van Moolenbroek 	len = sizeof(val);
3050*baa5830fSDavid van Moolenbroek 	if (getsockopt(fd2, SOL_SOCKET, SO_ERROR, &val, &len) != 0) e(0);
3051*baa5830fSDavid van Moolenbroek 	if (val != ECONNRESET) e(0);
3052*baa5830fSDavid van Moolenbroek 
3053*baa5830fSDavid van Moolenbroek 	if (send(fd2, "C", 1, 0) != -1) e(0);
3054*baa5830fSDavid van Moolenbroek 	if (errno != EDESTADDRREQ) e(0);
3055*baa5830fSDavid van Moolenbroek 
3056*baa5830fSDavid van Moolenbroek 	if (send(fd, "D", 1, 0) != 1) e(0);
3057*baa5830fSDavid van Moolenbroek 
3058*baa5830fSDavid van Moolenbroek 	len = sizeof(sunD);
3059*baa5830fSDavid van Moolenbroek 	if (recvfrom(fd3, buf, 1, 0, (struct sockaddr *)&sunD, &len) != 1)
3060*baa5830fSDavid van Moolenbroek 		e(0);
3061*baa5830fSDavid van Moolenbroek 	if (buf[0] != 'D') e(0);
3062*baa5830fSDavid van Moolenbroek 	check_addr(&sunD, len, SOCK_PATH_A);
3063*baa5830fSDavid van Moolenbroek 
3064*baa5830fSDavid van Moolenbroek 	if (connect(fd2, (struct sockaddr *)&sunC, sizeof(sunC)) != 0) e(0);
3065*baa5830fSDavid van Moolenbroek 
3066*baa5830fSDavid van Moolenbroek 	if (connect(fd3, (struct sockaddr *)&sunA, sizeof(sunA)) != 0) e(0);
3067*baa5830fSDavid van Moolenbroek 
3068*baa5830fSDavid van Moolenbroek 	memset(&sunD, 0, sizeof(sunD));
3069*baa5830fSDavid van Moolenbroek 	sunD.sun_family = AF_UNIX;
3070*baa5830fSDavid van Moolenbroek 	strlcpy(sunD.sun_path, SOCK_PATH_D, sizeof(sunD.sun_path));
3071*baa5830fSDavid van Moolenbroek 
3072*baa5830fSDavid van Moolenbroek 	/* A failed reconnection attempt should not break the previous one. */
3073*baa5830fSDavid van Moolenbroek 	if (connect(fd3, (struct sockaddr *)&sunD, sizeof(sunD)) != -1) e(0);
3074*baa5830fSDavid van Moolenbroek 	if (errno != ENOENT) e(0);
3075*baa5830fSDavid van Moolenbroek 
3076*baa5830fSDavid van Moolenbroek 	/* The destination address should be ignored here. */
3077*baa5830fSDavid van Moolenbroek 	if (sendto(fd3, "E", 1, 0, (struct sockaddr *)&sunB,
3078*baa5830fSDavid van Moolenbroek 	    sizeof(sunB)) != 1) e(0);
3079*baa5830fSDavid van Moolenbroek 
3080*baa5830fSDavid van Moolenbroek 	if (recv(fd2, buf, 1, 0) != -1) e(0);
3081*baa5830fSDavid van Moolenbroek 	if (errno != ECONNRESET) e(0);
3082*baa5830fSDavid van Moolenbroek 
3083*baa5830fSDavid van Moolenbroek 	if (recv(fd, buf, 1, 0) != 1) e(0);
3084*baa5830fSDavid van Moolenbroek 	if (buf[0] != 'E') e(0);
3085*baa5830fSDavid van Moolenbroek 
3086*baa5830fSDavid van Moolenbroek 	if (close(fd3) != 0) e(0);
3087*baa5830fSDavid van Moolenbroek 
3088*baa5830fSDavid van Moolenbroek 	len = sizeof(val);
3089*baa5830fSDavid van Moolenbroek 	if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &val, &len) != 0) e(0);
3090*baa5830fSDavid van Moolenbroek 	if (val != ECONNRESET) e(0);
3091*baa5830fSDavid van Moolenbroek 
3092*baa5830fSDavid van Moolenbroek 	if (close(fd2) != 0) e(0);
3093*baa5830fSDavid van Moolenbroek 
3094*baa5830fSDavid van Moolenbroek 	len = sizeof(val);
3095*baa5830fSDavid van Moolenbroek 	if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &val, &len) != 0) e(0);
3096*baa5830fSDavid van Moolenbroek 	if (val != 0) e(0);
3097*baa5830fSDavid van Moolenbroek 
3098*baa5830fSDavid van Moolenbroek 	if (close(fd) != 0) e(0);
3099*baa5830fSDavid van Moolenbroek 
3100*baa5830fSDavid van Moolenbroek 	if (unlink(SOCK_PATH_A) != 0) e(0);
3101*baa5830fSDavid van Moolenbroek 	if (unlink(SOCK_PATH_B) != 0) e(0);
3102*baa5830fSDavid van Moolenbroek 	if (unlink(SOCK_PATH_C) != 0) e(0);
3103*baa5830fSDavid van Moolenbroek 
3104*baa5830fSDavid van Moolenbroek 	/*
3105*baa5830fSDavid van Moolenbroek 	 * Finally, test unconnecting sockets.
3106*baa5830fSDavid van Moolenbroek 	 */
3107*baa5830fSDavid van Moolenbroek 	fd = get_bound_socket(SOCK_DGRAM, SOCK_PATH_A, &sunA);
3108*baa5830fSDavid van Moolenbroek 	fd2 = get_bound_socket(SOCK_DGRAM, SOCK_PATH_B, &sunB);
3109*baa5830fSDavid van Moolenbroek 
3110*baa5830fSDavid van Moolenbroek 	if (connect(fd, (struct sockaddr *)&sunB, sizeof(sunB)) != 0) e(0);
3111*baa5830fSDavid van Moolenbroek 
3112*baa5830fSDavid van Moolenbroek 	if (connect(fd2, (struct sockaddr *)&sunA, sizeof(sunA)) != 0) e(0);
3113*baa5830fSDavid van Moolenbroek 
3114*baa5830fSDavid van Moolenbroek 	if (sendto(fd2, "F", 1, 0, NULL, 0) != 1) e(0);
3115*baa5830fSDavid van Moolenbroek 
3116*baa5830fSDavid van Moolenbroek 	if (recv(fd, buf, 1, 0) != 1) e(0);
3117*baa5830fSDavid van Moolenbroek 	if (buf[0] != 'F') e(0);
3118*baa5830fSDavid van Moolenbroek 
3119*baa5830fSDavid van Moolenbroek 	memset(&sunC, 0, sizeof(sunC));
3120*baa5830fSDavid van Moolenbroek 	sunC.sun_family = AF_UNSPEC;
3121*baa5830fSDavid van Moolenbroek 	if (connect(fd2, (struct sockaddr *)&sunC, sizeof(sunC)) != 0) e(0);
3122*baa5830fSDavid van Moolenbroek 
3123*baa5830fSDavid van Moolenbroek 	len = sizeof(val);
3124*baa5830fSDavid van Moolenbroek 	if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &val, &len) != 0) e(0);
3125*baa5830fSDavid van Moolenbroek 	if (val != 0) e(0);
3126*baa5830fSDavid van Moolenbroek 
3127*baa5830fSDavid van Moolenbroek 	if (send(fd, "G", 1, 0) != 1) e(0);
3128*baa5830fSDavid van Moolenbroek 
3129*baa5830fSDavid van Moolenbroek 	if (sendto(fd2, "H", 1, 0, NULL, 0) != -1) e(0);
3130*baa5830fSDavid van Moolenbroek 	if (errno != EDESTADDRREQ) e(0);
3131*baa5830fSDavid van Moolenbroek 
3132*baa5830fSDavid van Moolenbroek 	if (sendto(fd2, "I", 1, 0, (struct sockaddr *)&sunA, sizeof(sunA)) != 1)
3133*baa5830fSDavid van Moolenbroek 		e(0);
3134*baa5830fSDavid van Moolenbroek 
3135*baa5830fSDavid van Moolenbroek 	if (connect(fd2, (struct sockaddr *)&sunA, sizeof(sunA)) != 0) e(0);
3136*baa5830fSDavid van Moolenbroek 
3137*baa5830fSDavid van Moolenbroek 	if (sendto(fd2, "J", 1, 0, NULL, 0) != 1) e(0);
3138*baa5830fSDavid van Moolenbroek 
3139*baa5830fSDavid van Moolenbroek 	if (recv(fd, buf, 1, 0) != 1) e(0);
3140*baa5830fSDavid van Moolenbroek 	if (buf[0] != 'I') e(0);
3141*baa5830fSDavid van Moolenbroek 
3142*baa5830fSDavid van Moolenbroek 	if (recv(fd, buf, 1, 0) != 1) e(0);
3143*baa5830fSDavid van Moolenbroek 	if (buf[0] != 'J') e(0);
3144*baa5830fSDavid van Moolenbroek 
3145*baa5830fSDavid van Moolenbroek 	if (recv(fd2, buf, 1, 0) != 1) e(0);
3146*baa5830fSDavid van Moolenbroek 	if (buf[0] != 'G') e(0);
3147*baa5830fSDavid van Moolenbroek 
3148*baa5830fSDavid van Moolenbroek 	if (close(fd) != 0) e(0);
3149*baa5830fSDavid van Moolenbroek 	if (close(fd2) != 0) e(0);
3150*baa5830fSDavid van Moolenbroek 
3151*baa5830fSDavid van Moolenbroek 	if (unlink(SOCK_PATH_A) != 0) e(0);
3152*baa5830fSDavid van Moolenbroek 	if (unlink(SOCK_PATH_B) != 0) e(0);
3153*baa5830fSDavid van Moolenbroek }
3154*baa5830fSDavid van Moolenbroek 
3155*baa5830fSDavid van Moolenbroek /*
3156*baa5830fSDavid van Moolenbroek  * Test socket file name reuse.
3157*baa5830fSDavid van Moolenbroek  */
3158*baa5830fSDavid van Moolenbroek static void
test90r(void)3159*baa5830fSDavid van Moolenbroek test90r(void)
3160*baa5830fSDavid van Moolenbroek {
3161*baa5830fSDavid van Moolenbroek 	struct sockaddr_un sun;
3162*baa5830fSDavid van Moolenbroek 	socklen_t len;
3163*baa5830fSDavid van Moolenbroek 	int fd, fd2, fd3, fd4;
3164*baa5830fSDavid van Moolenbroek 
3165*baa5830fSDavid van Moolenbroek 	subtest = 18;
3166*baa5830fSDavid van Moolenbroek 
3167*baa5830fSDavid van Moolenbroek 	fd = get_bound_socket(SOCK_STREAM | SOCK_NONBLOCK, SOCK_PATH_A, &sun);
3168*baa5830fSDavid van Moolenbroek 
3169*baa5830fSDavid van Moolenbroek 	if (rename(SOCK_PATH_A, SOCK_PATH_B) != 0) e(0);
3170*baa5830fSDavid van Moolenbroek 
3171*baa5830fSDavid van Moolenbroek 	if ((fd3 = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) e(0);
3172*baa5830fSDavid van Moolenbroek 
3173*baa5830fSDavid van Moolenbroek 	if (connect(fd3, (struct sockaddr *)&sun, sizeof(sun)) != -1) e(0);
3174*baa5830fSDavid van Moolenbroek 	if (errno != ENOENT) e(0);
3175*baa5830fSDavid van Moolenbroek 
3176*baa5830fSDavid van Moolenbroek 	if (listen(fd, 1) != 0) e(0);
3177*baa5830fSDavid van Moolenbroek 
3178*baa5830fSDavid van Moolenbroek 	len = sizeof(sun);
3179*baa5830fSDavid van Moolenbroek 	if (getsockname(fd, (struct sockaddr *)&sun, &len) != 0) e(0);
3180*baa5830fSDavid van Moolenbroek 	check_addr(&sun, len, SOCK_PATH_A);
3181*baa5830fSDavid van Moolenbroek 
3182*baa5830fSDavid van Moolenbroek 	fd2 = get_bound_socket(SOCK_STREAM | SOCK_NONBLOCK, SOCK_PATH_A, &sun);
3183*baa5830fSDavid van Moolenbroek 
3184*baa5830fSDavid van Moolenbroek 	if (listen(fd2, 1) != 0) e(0);
3185*baa5830fSDavid van Moolenbroek 
3186*baa5830fSDavid van Moolenbroek 	len = sizeof(sun);
3187*baa5830fSDavid van Moolenbroek 	if (getsockname(fd2, (struct sockaddr *)&sun, &len) != 0) e(0);
3188*baa5830fSDavid van Moolenbroek 	check_addr(&sun, len, SOCK_PATH_A);
3189*baa5830fSDavid van Moolenbroek 
3190*baa5830fSDavid van Moolenbroek 	len = sizeof(sun);
3191*baa5830fSDavid van Moolenbroek 	if (getsockname(fd, (struct sockaddr *)&sun, &len) != 0) e(0);
3192*baa5830fSDavid van Moolenbroek 	check_addr(&sun, len, SOCK_PATH_A);
3193*baa5830fSDavid van Moolenbroek 
3194*baa5830fSDavid van Moolenbroek 	memset(&sun, 0, sizeof(sun));
3195*baa5830fSDavid van Moolenbroek 	sun.sun_family = AF_UNIX;
3196*baa5830fSDavid van Moolenbroek 	strlcpy(sun.sun_path, SOCK_PATH_B, sizeof(sun.sun_path));
3197*baa5830fSDavid van Moolenbroek 	if (connect(fd3, (struct sockaddr *)&sun, sizeof(sun)) != 0) e(0);
3198*baa5830fSDavid van Moolenbroek 
3199*baa5830fSDavid van Moolenbroek 	len = sizeof(sun);
3200*baa5830fSDavid van Moolenbroek 	if ((fd4 = accept(fd2, (struct sockaddr *)&sun, &len)) >= 0) e(0);
3201*baa5830fSDavid van Moolenbroek 	if (errno != EWOULDBLOCK) e(0);
3202*baa5830fSDavid van Moolenbroek 	if ((fd4 = accept(fd, (struct sockaddr *)&sun, &len)) < 0) e(0);
3203*baa5830fSDavid van Moolenbroek 
3204*baa5830fSDavid van Moolenbroek 	len = sizeof(sun);
3205*baa5830fSDavid van Moolenbroek 	if (getpeername(fd3, (struct sockaddr *)&sun, &len) != 0) e(0);
3206*baa5830fSDavid van Moolenbroek 	check_addr(&sun, len, SOCK_PATH_A);
3207*baa5830fSDavid van Moolenbroek 
3208*baa5830fSDavid van Moolenbroek 	if (close(fd) != 0) e(0);
3209*baa5830fSDavid van Moolenbroek 	if (close(fd2) != 0) e(0);
3210*baa5830fSDavid van Moolenbroek 	if (close(fd3) != 0) e(0);
3211*baa5830fSDavid van Moolenbroek 	if (close(fd4) != 0) e(0);
3212*baa5830fSDavid van Moolenbroek 
3213*baa5830fSDavid van Moolenbroek 	if (unlink(SOCK_PATH_A) != 0) e(0);
3214*baa5830fSDavid van Moolenbroek 	if (unlink(SOCK_PATH_B) != 0) e(0);
3215*baa5830fSDavid van Moolenbroek }
3216*baa5830fSDavid van Moolenbroek 
3217*baa5830fSDavid van Moolenbroek /*
3218*baa5830fSDavid van Moolenbroek  * Test that non-canonized path names are accepted and returned.
3219*baa5830fSDavid van Moolenbroek  * Also test datagram send errors on disconnect.
3220*baa5830fSDavid van Moolenbroek  */
3221*baa5830fSDavid van Moolenbroek static void
test90s(void)3222*baa5830fSDavid van Moolenbroek test90s(void)
3223*baa5830fSDavid van Moolenbroek {
3224*baa5830fSDavid van Moolenbroek 	struct sockaddr_un sun;
3225*baa5830fSDavid van Moolenbroek 	socklen_t len;
3226*baa5830fSDavid van Moolenbroek 	int fd, fd2;
3227*baa5830fSDavid van Moolenbroek 
3228*baa5830fSDavid van Moolenbroek 	subtest = 19;
3229*baa5830fSDavid van Moolenbroek 
3230*baa5830fSDavid van Moolenbroek 	fd = get_bound_socket(SOCK_DGRAM, SOCK_PATH_A_X, &sun);
3231*baa5830fSDavid van Moolenbroek 
3232*baa5830fSDavid van Moolenbroek 	if ((fd2 = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0) e(0);
3233*baa5830fSDavid van Moolenbroek 
3234*baa5830fSDavid van Moolenbroek 	memset(&sun, 0, sizeof(sun));
3235*baa5830fSDavid van Moolenbroek 	sun.sun_family = AF_UNIX;
3236*baa5830fSDavid van Moolenbroek 	strlcpy(sun.sun_path, SOCK_PATH_A_Y, sizeof(sun.sun_path));
3237*baa5830fSDavid van Moolenbroek 
3238*baa5830fSDavid van Moolenbroek 	if (connect(fd2, (struct sockaddr *)&sun, sizeof(sun)) != 0) e(0);
3239*baa5830fSDavid van Moolenbroek 
3240*baa5830fSDavid van Moolenbroek 	len = sizeof(sun);
3241*baa5830fSDavid van Moolenbroek 	if (getpeername(fd2, (struct sockaddr *)&sun, &len) != 0) e(0);
3242*baa5830fSDavid van Moolenbroek 	check_addr(&sun, len, SOCK_PATH_A_X);
3243*baa5830fSDavid van Moolenbroek 
3244*baa5830fSDavid van Moolenbroek 	if (send(fd2, "A", 1, 0) != 1) e(0);
3245*baa5830fSDavid van Moolenbroek 
3246*baa5830fSDavid van Moolenbroek 	if (close(fd) != 0) e(0);
3247*baa5830fSDavid van Moolenbroek 
3248*baa5830fSDavid van Moolenbroek 	if (send(fd2, "B", 1, 0) != -1) e(0);
3249*baa5830fSDavid van Moolenbroek 	if (errno != ECONNRESET) e(0);
3250*baa5830fSDavid van Moolenbroek 
3251*baa5830fSDavid van Moolenbroek 	if (send(fd2, "B", 1, 0) != -1) e(0);
3252*baa5830fSDavid van Moolenbroek 	if (errno != EDESTADDRREQ) e(0);
3253*baa5830fSDavid van Moolenbroek 
3254*baa5830fSDavid van Moolenbroek 	if (close(fd2) != 0) e(0);
3255*baa5830fSDavid van Moolenbroek 
3256*baa5830fSDavid van Moolenbroek 	if (unlink(SOCK_PATH_A) != 0) e(0);
3257*baa5830fSDavid van Moolenbroek }
3258*baa5830fSDavid van Moolenbroek 
3259*baa5830fSDavid van Moolenbroek /*
3260*baa5830fSDavid van Moolenbroek  * Test basic sysctl(2) socket enumeration for a specific socket type.
3261*baa5830fSDavid van Moolenbroek  */
3262*baa5830fSDavid van Moolenbroek static void
sub90t(int type,const char * path)3263*baa5830fSDavid van Moolenbroek sub90t(int type, const char * path)
3264*baa5830fSDavid van Moolenbroek {
3265*baa5830fSDavid van Moolenbroek 	struct kinfo_pcb *ki;
3266*baa5830fSDavid van Moolenbroek 	size_t i, len, oldlen;
3267*baa5830fSDavid van Moolenbroek 	int fd, mib[8];
3268*baa5830fSDavid van Moolenbroek 
3269*baa5830fSDavid van Moolenbroek 	if ((fd = socket(AF_UNIX, type, 0)) < 0) e(0);
3270*baa5830fSDavid van Moolenbroek 
3271*baa5830fSDavid van Moolenbroek 	memset(mib, 0, sizeof(mib));
3272*baa5830fSDavid van Moolenbroek 
3273*baa5830fSDavid van Moolenbroek 	len = __arraycount(mib);
3274*baa5830fSDavid van Moolenbroek 	if (sysctlnametomib(path, mib, &len) != 0) e(0);
3275*baa5830fSDavid van Moolenbroek 	if (len != 4) e(0);
3276*baa5830fSDavid van Moolenbroek 
3277*baa5830fSDavid van Moolenbroek 	if (sysctl(mib, __arraycount(mib), NULL, &oldlen, NULL, 0) != 0) e(0);
3278*baa5830fSDavid van Moolenbroek 	if (oldlen == 0) e(0);
3279*baa5830fSDavid van Moolenbroek 	if (oldlen % sizeof(*ki)) e(0);
3280*baa5830fSDavid van Moolenbroek 
3281*baa5830fSDavid van Moolenbroek 	if ((ki = (struct kinfo_pcb *)malloc(oldlen)) == NULL) e(0);
3282*baa5830fSDavid van Moolenbroek 
3283*baa5830fSDavid van Moolenbroek 	if (sysctl(mib, __arraycount(mib), ki, &oldlen, NULL, 0) != 0) e(0);
3284*baa5830fSDavid van Moolenbroek 	if (oldlen == 0) e(0);
3285*baa5830fSDavid van Moolenbroek 	if (oldlen % sizeof(*ki)) e(0);
3286*baa5830fSDavid van Moolenbroek 
3287*baa5830fSDavid van Moolenbroek 	/*
3288*baa5830fSDavid van Moolenbroek 	 * We cannot check a whole lot of things, because we have no way of
3289*baa5830fSDavid van Moolenbroek 	 * knowing which is the socket we created.  Check some basics and leave
3290*baa5830fSDavid van Moolenbroek 	 * it at that.  This subtest is mostly trying to guarantee that
3291*baa5830fSDavid van Moolenbroek 	 * netstat(1) will not show nothing, anyway.
3292*baa5830fSDavid van Moolenbroek 	 */
3293*baa5830fSDavid van Moolenbroek 	for (i = 0; i < oldlen / sizeof(*ki); i++) {
3294*baa5830fSDavid van Moolenbroek 		if (ki[i].ki_pcbaddr == 0) e(0);
3295*baa5830fSDavid van Moolenbroek 		if (ki[i].ki_sockaddr == 0) e(0);
3296*baa5830fSDavid van Moolenbroek 		if (ki[i].ki_family != AF_UNIX) e(0);
3297*baa5830fSDavid van Moolenbroek 		if (ki[i].ki_type != type) e(0);
3298*baa5830fSDavid van Moolenbroek 		if (ki[i].ki_protocol != 0) e(0);
3299*baa5830fSDavid van Moolenbroek 	}
3300*baa5830fSDavid van Moolenbroek 
3301*baa5830fSDavid van Moolenbroek 	free(ki);
3302*baa5830fSDavid van Moolenbroek 
3303*baa5830fSDavid van Moolenbroek 	if (close(fd) != 0) e(0);
3304*baa5830fSDavid van Moolenbroek }
3305*baa5830fSDavid van Moolenbroek 
3306*baa5830fSDavid van Moolenbroek /*
3307*baa5830fSDavid van Moolenbroek  * Test basic sysctl(2) socket enumeration support.
3308*baa5830fSDavid van Moolenbroek  */
3309*baa5830fSDavid van Moolenbroek static void
test90t(void)3310*baa5830fSDavid van Moolenbroek test90t(void)
3311*baa5830fSDavid van Moolenbroek {
3312*baa5830fSDavid van Moolenbroek 
3313*baa5830fSDavid van Moolenbroek 	subtest = 20;
3314*baa5830fSDavid van Moolenbroek 
3315*baa5830fSDavid van Moolenbroek 	/*
3316*baa5830fSDavid van Moolenbroek 	 * We test that for each of the socket types, when we create a socket,
3317*baa5830fSDavid van Moolenbroek 	 * we can find at least one socket of that type in the respective
3318*baa5830fSDavid van Moolenbroek 	 * sysctl(2) out.
3319*baa5830fSDavid van Moolenbroek 	 */
3320*baa5830fSDavid van Moolenbroek 	sub90t(SOCK_STREAM, "net.local.stream.pcblist");
3321*baa5830fSDavid van Moolenbroek 
3322*baa5830fSDavid van Moolenbroek 	sub90t(SOCK_SEQPACKET, "net.local.seqpacket.pcblist");
3323*baa5830fSDavid van Moolenbroek 
3324*baa5830fSDavid van Moolenbroek 	sub90t(SOCK_DGRAM, "net.local.dgram.pcblist");
3325*baa5830fSDavid van Moolenbroek }
3326*baa5830fSDavid van Moolenbroek 
3327*baa5830fSDavid van Moolenbroek /*
3328*baa5830fSDavid van Moolenbroek  * Cause a pending recv() call to return.  Here 'fd' is the file descriptor
3329*baa5830fSDavid van Moolenbroek  * identifying the other end of the socket pair.  If breaking the recv()
3330*baa5830fSDavid van Moolenbroek  * requires sending data, 'data' and 'len' identify the data that should be
3331*baa5830fSDavid van Moolenbroek  * sent.  Return 'fd' if it is still open, or -1 if it is closed.
3332*baa5830fSDavid van Moolenbroek  */
3333*baa5830fSDavid van Moolenbroek static int
break_uds_recv(int fd,const char * data,size_t len)3334*baa5830fSDavid van Moolenbroek break_uds_recv(int fd, const char * data, size_t len)
3335*baa5830fSDavid van Moolenbroek {
3336*baa5830fSDavid van Moolenbroek 	int fd2;
3337*baa5830fSDavid van Moolenbroek 
3338*baa5830fSDavid van Moolenbroek 	/*
3339*baa5830fSDavid van Moolenbroek 	 * This UDS-specific routine makes the recv() in one of two ways
3340*baa5830fSDavid van Moolenbroek 	 * depending on whether the recv() call already made partial progress:
3341*baa5830fSDavid van Moolenbroek 	 * if it did, this send call creates a segment boundary which should
3342*baa5830fSDavid van Moolenbroek 	 * cut short the current receive call.  If it did not, the send call
3343*baa5830fSDavid van Moolenbroek 	 * will simply satisfy the receive call with regular data.
3344*baa5830fSDavid van Moolenbroek 	 */
3345*baa5830fSDavid van Moolenbroek 	if ((fd2 = open("/dev/null", O_RDONLY)) < 0) e(0);
3346*baa5830fSDavid van Moolenbroek 
3347*baa5830fSDavid van Moolenbroek 	if (send_fds(fd, data, len, 0, NULL, 0, &fd2, 1) != len) e(0);
3348*baa5830fSDavid van Moolenbroek 
3349*baa5830fSDavid van Moolenbroek 	if (close(fd2) != 0) e(0);
3350*baa5830fSDavid van Moolenbroek 
3351*baa5830fSDavid van Moolenbroek 	return fd;
3352*baa5830fSDavid van Moolenbroek }
3353*baa5830fSDavid van Moolenbroek 
3354*baa5830fSDavid van Moolenbroek /*
3355*baa5830fSDavid van Moolenbroek  * Test for receiving on stream sockets.  In particular, test SO_RCVLOWAT,
3356*baa5830fSDavid van Moolenbroek  * MSG_PEEK, MSG_DONTWAIT, and MSG_WAITALL.
3357*baa5830fSDavid van Moolenbroek  */
3358*baa5830fSDavid van Moolenbroek static void
test90u(void)3359*baa5830fSDavid van Moolenbroek test90u(void)
3360*baa5830fSDavid van Moolenbroek {
3361*baa5830fSDavid van Moolenbroek 
3362*baa5830fSDavid van Moolenbroek 	subtest = 21;
3363*baa5830fSDavid van Moolenbroek 
3364*baa5830fSDavid van Moolenbroek 	socklib_stream_recv(socketpair, AF_UNIX, SOCK_STREAM, break_uds_recv);
3365*baa5830fSDavid van Moolenbroek }
3366*baa5830fSDavid van Moolenbroek 
3367*baa5830fSDavid van Moolenbroek #define MAX_BYTES	2	/* set to 3 for slightly better(?) testing */
3368*baa5830fSDavid van Moolenbroek #define USLEEP_TIME	250000	/* increase on wimpy platforms if needed */
3369*baa5830fSDavid van Moolenbroek 
3370*baa5830fSDavid van Moolenbroek /*
3371*baa5830fSDavid van Moolenbroek  * Signal handler which just needs to exist, so that invoking it will interrupt
3372*baa5830fSDavid van Moolenbroek  * an ongoing system call.
3373*baa5830fSDavid van Moolenbroek  */
3374*baa5830fSDavid van Moolenbroek static void
test90_got_signal(int sig __unused)3375*baa5830fSDavid van Moolenbroek test90_got_signal(int sig __unused)
3376*baa5830fSDavid van Moolenbroek {
3377*baa5830fSDavid van Moolenbroek 
3378*baa5830fSDavid van Moolenbroek 	/* Nothing. */
3379*baa5830fSDavid van Moolenbroek }
3380*baa5830fSDavid van Moolenbroek 
3381*baa5830fSDavid van Moolenbroek /*
3382*baa5830fSDavid van Moolenbroek  * Test for sending on stream sockets.  The quick summary here is that send()
3383*baa5830fSDavid van Moolenbroek  * should basically act as the mirror of recv(MSG_WAITALL), i.e., it should
3384*baa5830fSDavid van Moolenbroek  * keep suspending until all data is sent (or the call is interrupted or no
3385*baa5830fSDavid van Moolenbroek  * more can possibly be sent), and, SO_SNDLOWAT, mirroring SO_RCVLOWAT, acts as
3386*baa5830fSDavid van Moolenbroek  * an admission test for the send: nothing is sent until there is room in the
3387*baa5830fSDavid van Moolenbroek  * send buffer (i.e., the peer's receive buffer) for at least the low send
3388*baa5830fSDavid van Moolenbroek  * watermark, or the whole send request length, whichever is smaller.  In
3389*baa5830fSDavid van Moolenbroek  * addition, select(2) should use the same threshold.
3390*baa5830fSDavid van Moolenbroek  */
3391*baa5830fSDavid van Moolenbroek static void
sub90v(int iroom,int istate,int slowat,int len,int bits,int act)3392*baa5830fSDavid van Moolenbroek sub90v(int iroom, int istate, int slowat, int len, int bits, int act)
3393*baa5830fSDavid van Moolenbroek {
3394*baa5830fSDavid van Moolenbroek 	const char *data = "ABC";	/* this limits MAX_BYTES to 3 */
3395*baa5830fSDavid van Moolenbroek 	struct sigaction sa;
3396*baa5830fSDavid van Moolenbroek 	struct timeval tv;
3397*baa5830fSDavid van Moolenbroek 	fd_set fds;
3398*baa5830fSDavid van Moolenbroek 	char buf[2], *sndbuf;
3399*baa5830fSDavid van Moolenbroek 	pid_t pid;
3400*baa5830fSDavid van Moolenbroek 	int fd[2], rcvlen, min, flags, res, err;
3401*baa5830fSDavid van Moolenbroek 	int pfd[2], eroom, tstate, fl, status;
3402*baa5830fSDavid van Moolenbroek 
3403*baa5830fSDavid van Moolenbroek 	if (socketpair(AF_UNIX, SOCK_STREAM, 0, fd) != 0) e(0);
3404*baa5830fSDavid van Moolenbroek 
3405*baa5830fSDavid van Moolenbroek 	/*
3406*baa5830fSDavid van Moolenbroek 	 * Set up the initial condition on the sockets.
3407*baa5830fSDavid van Moolenbroek 	 */
3408*baa5830fSDavid van Moolenbroek 	rcvlen = get_rcvbuf_len(fd[1]);
3409*baa5830fSDavid van Moolenbroek 	if (rcvlen <= iroom) e(0);
3410*baa5830fSDavid van Moolenbroek 	rcvlen -= iroom;
3411*baa5830fSDavid van Moolenbroek 
3412*baa5830fSDavid van Moolenbroek 	if ((sndbuf = malloc(rcvlen)) == NULL) e(0);
3413*baa5830fSDavid van Moolenbroek 
3414*baa5830fSDavid van Moolenbroek 	memset(sndbuf, 'X', rcvlen);
3415*baa5830fSDavid van Moolenbroek 	if (send(fd[0], sndbuf, rcvlen, 0) != rcvlen) e(0);
3416*baa5830fSDavid van Moolenbroek 
3417*baa5830fSDavid van Moolenbroek 	free(sndbuf);
3418*baa5830fSDavid van Moolenbroek 
3419*baa5830fSDavid van Moolenbroek 	switch (istate) {
3420*baa5830fSDavid van Moolenbroek 	case 0: break;
3421*baa5830fSDavid van Moolenbroek 	case 1: if (shutdown(fd[0], SHUT_WR) != 0) e(0); break;
3422*baa5830fSDavid van Moolenbroek 	case 2: if (shutdown(fd[1], SHUT_RD) != 0) e(0); break;
3423*baa5830fSDavid van Moolenbroek 	case 3: if (close(fd[1]) != 0) e(0); break;
3424*baa5830fSDavid van Moolenbroek 	}
3425*baa5830fSDavid van Moolenbroek 
3426*baa5830fSDavid van Moolenbroek 	if (setsockopt(fd[0], SOL_SOCKET, SO_SNDLOWAT, &slowat,
3427*baa5830fSDavid van Moolenbroek 	    sizeof(slowat)) != 0) e(0);
3428*baa5830fSDavid van Moolenbroek 
3429*baa5830fSDavid van Moolenbroek 	/* SO_SNDLOWAT is always bounded by the actual send length. */
3430*baa5830fSDavid van Moolenbroek 	min = MIN(len, slowat);
3431*baa5830fSDavid van Moolenbroek 
3432*baa5830fSDavid van Moolenbroek 	flags = MSG_NOSIGNAL;
3433*baa5830fSDavid van Moolenbroek 	if (bits & 1) flags |= MSG_DONTWAIT;
3434*baa5830fSDavid van Moolenbroek 
3435*baa5830fSDavid van Moolenbroek 	/*
3436*baa5830fSDavid van Moolenbroek 	 * Do a quick select test to see if its result indeed matches whether
3437*baa5830fSDavid van Moolenbroek 	 * the available space in the "send" buffer meets the threshold.
3438*baa5830fSDavid van Moolenbroek 	 */
3439*baa5830fSDavid van Moolenbroek 	FD_ZERO(&fds);
3440*baa5830fSDavid van Moolenbroek 	FD_SET(fd[0], &fds);
3441*baa5830fSDavid van Moolenbroek 	tv.tv_sec = 0;
3442*baa5830fSDavid van Moolenbroek 	tv.tv_usec = 0;
3443*baa5830fSDavid van Moolenbroek 	res = select(fd[0] + 1, NULL, &fds, NULL, &tv);
3444*baa5830fSDavid van Moolenbroek 	if (res < 0 || res > 1) e(0);
3445*baa5830fSDavid van Moolenbroek 	if (res != (iroom >= slowat || istate > 0)) e(0);
3446*baa5830fSDavid van Moolenbroek 	if (res == 1 && !FD_ISSET(fd[0], &fds)) e(0);
3447*baa5830fSDavid van Moolenbroek 
3448*baa5830fSDavid van Moolenbroek 	/*
3449*baa5830fSDavid van Moolenbroek 	 * Cut short a whole lot of cases, to avoid the overhead of forking,
3450*baa5830fSDavid van Moolenbroek 	 * namely when we know the call should return immediately.  This is the
3451*baa5830fSDavid van Moolenbroek 	 * case when the socket state disallows further sending, or when all
3452*baa5830fSDavid van Moolenbroek 	 * data could be sent, or when the call was non-blocking.  The low
3453*baa5830fSDavid van Moolenbroek 	 * send watermark only helps determine whether anything was sent here.
3454*baa5830fSDavid van Moolenbroek 	 */
3455*baa5830fSDavid van Moolenbroek 	if (istate > 0 || iroom >= len || (flags & MSG_DONTWAIT)) {
3456*baa5830fSDavid van Moolenbroek 		res = send(fd[0], data, len, flags);
3457*baa5830fSDavid van Moolenbroek 
3458*baa5830fSDavid van Moolenbroek 		if (istate > 0) {
3459*baa5830fSDavid van Moolenbroek 			if (res != -1) e(0);
3460*baa5830fSDavid van Moolenbroek 			if (errno != EPIPE) e(0);
3461*baa5830fSDavid van Moolenbroek 		} else if (iroom >= len) {
3462*baa5830fSDavid van Moolenbroek 			if (res != len) e(0);
3463*baa5830fSDavid van Moolenbroek 		} else if (iroom >= min) {
3464*baa5830fSDavid van Moolenbroek 			if (res != iroom) e(0);
3465*baa5830fSDavid van Moolenbroek 		} else {
3466*baa5830fSDavid van Moolenbroek 			if (res != -1) e(0);
3467*baa5830fSDavid van Moolenbroek 			if (errno != EWOULDBLOCK) e(0);
3468*baa5830fSDavid van Moolenbroek 		}
3469*baa5830fSDavid van Moolenbroek 
3470*baa5830fSDavid van Moolenbroek 		/* Early cleanup and return to avoid even more code clutter. */
3471*baa5830fSDavid van Moolenbroek 		if (istate != 3 && close(fd[1]) != 0) e(0);
3472*baa5830fSDavid van Moolenbroek 		if (close(fd[0]) != 0) e(0);
3473*baa5830fSDavid van Moolenbroek 
3474*baa5830fSDavid van Moolenbroek 		return;
3475*baa5830fSDavid van Moolenbroek 	}
3476*baa5830fSDavid van Moolenbroek 
3477*baa5830fSDavid van Moolenbroek 	/*
3478*baa5830fSDavid van Moolenbroek 	 * Now starts the interesting stuff: the send call should now block,
3479*baa5830fSDavid van Moolenbroek 	 * even though if we add MSG_DONTWAIT it may not return EWOULDBLOCK,
3480*baa5830fSDavid van Moolenbroek 	 * because MSG_DONTWAIT prevents the send from blocking after partial
3481*baa5830fSDavid van Moolenbroek 	 * completion.  As such, we can only test our expectations by letting
3482*baa5830fSDavid van Moolenbroek 	 * the call block, in a child process, and waiting.  We do test as much
3483*baa5830fSDavid van Moolenbroek 	 * of the above assumption as we can for safety right here, but this is
3484*baa5830fSDavid van Moolenbroek 	 * not a substitute for actually blocking even in these cases!
3485*baa5830fSDavid van Moolenbroek 	 */
3486*baa5830fSDavid van Moolenbroek 	if (iroom < min) {
3487*baa5830fSDavid van Moolenbroek 		if (send(fd[0], data, len, flags | MSG_DONTWAIT) != -1) e(0);
3488*baa5830fSDavid van Moolenbroek 		if (errno != EWOULDBLOCK) e(0);
3489*baa5830fSDavid van Moolenbroek 	}
3490*baa5830fSDavid van Moolenbroek 
3491*baa5830fSDavid van Moolenbroek 	/*
3492*baa5830fSDavid van Moolenbroek 	 * If (act < 9), we receive 0, 1, or 2 bytes from the receive queue
3493*baa5830fSDavid van Moolenbroek 	 * before forcing the send call to terminate in one of three ways.
3494*baa5830fSDavid van Moolenbroek 	 *
3495*baa5830fSDavid van Moolenbroek 	 * If (act == 9), we use a signal to interrupt the send call.
3496*baa5830fSDavid van Moolenbroek 	 */
3497*baa5830fSDavid van Moolenbroek 	if (act < 9) {
3498*baa5830fSDavid van Moolenbroek 		eroom = act % 3;
3499*baa5830fSDavid van Moolenbroek 		tstate = act / 3;
3500*baa5830fSDavid van Moolenbroek 	} else
3501*baa5830fSDavid van Moolenbroek 		eroom = tstate = 0;
3502*baa5830fSDavid van Moolenbroek 
3503*baa5830fSDavid van Moolenbroek 	if (pipe2(pfd, O_NONBLOCK) != 0) e(0);
3504*baa5830fSDavid van Moolenbroek 
3505*baa5830fSDavid van Moolenbroek 	pid = fork();
3506*baa5830fSDavid van Moolenbroek 	switch (pid) {
3507*baa5830fSDavid van Moolenbroek 	case 0:
3508*baa5830fSDavid van Moolenbroek 		errct = 0;
3509*baa5830fSDavid van Moolenbroek 
3510*baa5830fSDavid van Moolenbroek 		if (close(fd[1]) != 0) e(0);
3511*baa5830fSDavid van Moolenbroek 		if (close(pfd[0]) != 0) e(0);
3512*baa5830fSDavid van Moolenbroek 
3513*baa5830fSDavid van Moolenbroek 		if (act == 9) {
3514*baa5830fSDavid van Moolenbroek 			memset(&sa, 0, sizeof(sa));
3515*baa5830fSDavid van Moolenbroek 			sa.sa_handler = test90_got_signal;
3516*baa5830fSDavid van Moolenbroek 			if (sigaction(SIGUSR1, &sa, NULL) != 0) e(0);
3517*baa5830fSDavid van Moolenbroek 		}
3518*baa5830fSDavid van Moolenbroek 
3519*baa5830fSDavid van Moolenbroek 		res = send(fd[0], data, len, flags);
3520*baa5830fSDavid van Moolenbroek 		err = errno;
3521*baa5830fSDavid van Moolenbroek 
3522*baa5830fSDavid van Moolenbroek 		if (write(pfd[1], &res, sizeof(res)) != sizeof(res)) e(0);
3523*baa5830fSDavid van Moolenbroek 		if (write(pfd[1], &err, sizeof(err)) != sizeof(err)) e(0);
3524*baa5830fSDavid van Moolenbroek 
3525*baa5830fSDavid van Moolenbroek 		exit(errct);
3526*baa5830fSDavid van Moolenbroek 	case -1:
3527*baa5830fSDavid van Moolenbroek 		e(0);
3528*baa5830fSDavid van Moolenbroek 	}
3529*baa5830fSDavid van Moolenbroek 
3530*baa5830fSDavid van Moolenbroek 	if (close(pfd[1]) != 0) e(0);
3531*baa5830fSDavid van Moolenbroek 
3532*baa5830fSDavid van Moolenbroek 	/*
3533*baa5830fSDavid van Moolenbroek 	 * Allow the child to enter the blocking send(2), and check the pipe
3534*baa5830fSDavid van Moolenbroek 	 * to see if it is really blocked.
3535*baa5830fSDavid van Moolenbroek 	 */
3536*baa5830fSDavid van Moolenbroek 	if (usleep(USLEEP_TIME) != 0) e(0);
3537*baa5830fSDavid van Moolenbroek 
3538*baa5830fSDavid van Moolenbroek 	if (read(pfd[0], &res, sizeof(res)) != -1) e(0);
3539*baa5830fSDavid van Moolenbroek 	if (errno != EAGAIN) e(0);
3540*baa5830fSDavid van Moolenbroek 
3541*baa5830fSDavid van Moolenbroek 	if (eroom > 0) {
3542*baa5830fSDavid van Moolenbroek 		if (recv(fd[1], buf, eroom, 0) != eroom) e(0);
3543*baa5830fSDavid van Moolenbroek 
3544*baa5830fSDavid van Moolenbroek 		/*
3545*baa5830fSDavid van Moolenbroek 		 * The threshold for the send is now met if the entire request
3546*baa5830fSDavid van Moolenbroek 		 * has been satisfied.
3547*baa5830fSDavid van Moolenbroek 		 */
3548*baa5830fSDavid van Moolenbroek 		if (iroom + eroom >= len) {
3549*baa5830fSDavid van Moolenbroek 			if ((fl = fcntl(pfd[0], F_GETFL)) == -1) e(0);
3550*baa5830fSDavid van Moolenbroek 			if (fcntl(pfd[0], F_SETFL, fl & ~O_NONBLOCK) != 0)
3551*baa5830fSDavid van Moolenbroek 				e(0);
3552*baa5830fSDavid van Moolenbroek 
3553*baa5830fSDavid van Moolenbroek 			if (read(pfd[0], &res, sizeof(res)) != sizeof(res))
3554*baa5830fSDavid van Moolenbroek 				e(0);
3555*baa5830fSDavid van Moolenbroek 			if (read(pfd[0], &err, sizeof(err)) != sizeof(err))
3556*baa5830fSDavid van Moolenbroek 				e(0);
3557*baa5830fSDavid van Moolenbroek 
3558*baa5830fSDavid van Moolenbroek 			if (res != len) e(0);
3559*baa5830fSDavid van Moolenbroek 
3560*baa5830fSDavid van Moolenbroek 			/* Bail out. */
3561*baa5830fSDavid van Moolenbroek 			goto cleanup;
3562*baa5830fSDavid van Moolenbroek 		}
3563*baa5830fSDavid van Moolenbroek 	}
3564*baa5830fSDavid van Moolenbroek 
3565*baa5830fSDavid van Moolenbroek 	if (act < 9) {
3566*baa5830fSDavid van Moolenbroek 		/*
3567*baa5830fSDavid van Moolenbroek 		 * Now test various ways to terminate the send call.  Ideally
3568*baa5830fSDavid van Moolenbroek 		 * we would also like to have a case that raises a socket error
3569*baa5830fSDavid van Moolenbroek 		 * here, but with UDS there is currently no way to do that.
3570*baa5830fSDavid van Moolenbroek 		 */
3571*baa5830fSDavid van Moolenbroek 		switch (tstate) {
3572*baa5830fSDavid van Moolenbroek 		case 0: if (shutdown(fd[0], SHUT_WR) != 0) e(0); break;
3573*baa5830fSDavid van Moolenbroek 		case 1: if (shutdown(fd[1], SHUT_RD) != 0) e(0); break;
3574*baa5830fSDavid van Moolenbroek 		case 2: if (close(fd[1]) != 0) e(0); fd[1] = -1; break;
3575*baa5830fSDavid van Moolenbroek 		}
3576*baa5830fSDavid van Moolenbroek 	} else
3577*baa5830fSDavid van Moolenbroek 		if (kill(pid, SIGUSR1) != 0) e(0);
3578*baa5830fSDavid van Moolenbroek 
3579*baa5830fSDavid van Moolenbroek 	if ((fl = fcntl(pfd[0], F_GETFL)) == -1) e(0);
3580*baa5830fSDavid van Moolenbroek 	if (fcntl(pfd[0], F_SETFL, fl & ~O_NONBLOCK) != 0) e(0);
3581*baa5830fSDavid van Moolenbroek 
3582*baa5830fSDavid van Moolenbroek 	if (read(pfd[0], &res, sizeof(res)) != sizeof(res)) e(0);
3583*baa5830fSDavid van Moolenbroek 	if (read(pfd[0], &err, sizeof(err)) != sizeof(err)) e(0);
3584*baa5830fSDavid van Moolenbroek 
3585*baa5830fSDavid van Moolenbroek 	/*
3586*baa5830fSDavid van Moolenbroek 	 * If the send met the threshold before being terminate or interrupted,
3587*baa5830fSDavid van Moolenbroek 	 * we should at least have sent something.  Otherwise, the send was
3588*baa5830fSDavid van Moolenbroek 	 * never admitted and should return EPIPE (if the send was terminated)
3589*baa5830fSDavid van Moolenbroek 	 * or EINTR (if the child was killed).
3590*baa5830fSDavid van Moolenbroek 	 */
3591*baa5830fSDavid van Moolenbroek 	if (iroom + eroom >= min) {
3592*baa5830fSDavid van Moolenbroek 		if (res != MIN(iroom + eroom, len)) e(0);
3593*baa5830fSDavid van Moolenbroek 	} else {
3594*baa5830fSDavid van Moolenbroek 		if (res != -1) e(0);
3595*baa5830fSDavid van Moolenbroek 		if (act < 9) {
3596*baa5830fSDavid van Moolenbroek 			if (err != EPIPE) e(0);
3597*baa5830fSDavid van Moolenbroek 		} else
3598*baa5830fSDavid van Moolenbroek 			if (err != EINTR) e(0);
3599*baa5830fSDavid van Moolenbroek 	}
3600*baa5830fSDavid van Moolenbroek 
3601*baa5830fSDavid van Moolenbroek cleanup:
3602*baa5830fSDavid van Moolenbroek 	if (close(pfd[0]) != 0) e(0);
3603*baa5830fSDavid van Moolenbroek 
3604*baa5830fSDavid van Moolenbroek 	if (wait(&status) != pid) e(0);
3605*baa5830fSDavid van Moolenbroek 	if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) e(0);
3606*baa5830fSDavid van Moolenbroek 
3607*baa5830fSDavid van Moolenbroek 	if (fd[1] != -1 && close(fd[1]) != 0) e(0);
3608*baa5830fSDavid van Moolenbroek 	if (close(fd[0]) != 0) e(0);
3609*baa5830fSDavid van Moolenbroek }
3610*baa5830fSDavid van Moolenbroek 
3611*baa5830fSDavid van Moolenbroek /*
3612*baa5830fSDavid van Moolenbroek  * Test for sending on stream sockets.  In particular, test SO_SNDLOWAT and
3613*baa5830fSDavid van Moolenbroek  * MSG_DONTWAIT.
3614*baa5830fSDavid van Moolenbroek  */
3615*baa5830fSDavid van Moolenbroek static void
test90v(void)3616*baa5830fSDavid van Moolenbroek test90v(void)
3617*baa5830fSDavid van Moolenbroek {
3618*baa5830fSDavid van Moolenbroek 	int iroom, istate, slowat, len, bits, act;
3619*baa5830fSDavid van Moolenbroek 
3620*baa5830fSDavid van Moolenbroek 	subtest = 22;
3621*baa5830fSDavid van Moolenbroek 
3622*baa5830fSDavid van Moolenbroek 	/* Insanity. */
3623*baa5830fSDavid van Moolenbroek 	for (iroom = 0; iroom <= MAX_BYTES; iroom++)
3624*baa5830fSDavid van Moolenbroek 		for (istate = 0; istate <= 3; istate++)
3625*baa5830fSDavid van Moolenbroek 			for (slowat = 1; slowat <= MAX_BYTES; slowat++)
3626*baa5830fSDavid van Moolenbroek 				for (len = 1; len <= MAX_BYTES; len++)
3627*baa5830fSDavid van Moolenbroek 					for (bits = 0; bits < 2; bits++)
3628*baa5830fSDavid van Moolenbroek 						for (act = 0; act <= 9; act++)
3629*baa5830fSDavid van Moolenbroek 							sub90v(iroom, istate,
3630*baa5830fSDavid van Moolenbroek 							    slowat, len, bits,
3631*baa5830fSDavid van Moolenbroek 							    act);
3632*baa5830fSDavid van Moolenbroek }
3633*baa5830fSDavid van Moolenbroek 
3634*baa5830fSDavid van Moolenbroek /*
3635*baa5830fSDavid van Moolenbroek  * Test that SO_RCVLOWAT is limited to the size of the receive buffer.
3636*baa5830fSDavid van Moolenbroek  */
3637*baa5830fSDavid van Moolenbroek static void
sub90w_recv(int fill_delta,int rlowat_delta,int exp_delta)3638*baa5830fSDavid van Moolenbroek sub90w_recv(int fill_delta, int rlowat_delta, int exp_delta)
3639*baa5830fSDavid van Moolenbroek {
3640*baa5830fSDavid van Moolenbroek 	char *buf;
3641*baa5830fSDavid van Moolenbroek 	int fd[2], rcvlen, fill, rlowat, res;
3642*baa5830fSDavid van Moolenbroek 
3643*baa5830fSDavid van Moolenbroek 	if (socketpair(AF_UNIX, SOCK_STREAM, 0, fd) != 0) e(0);
3644*baa5830fSDavid van Moolenbroek 
3645*baa5830fSDavid van Moolenbroek 	rcvlen = get_rcvbuf_len(fd[0]);
3646*baa5830fSDavid van Moolenbroek 
3647*baa5830fSDavid van Moolenbroek 	if ((buf = malloc(rcvlen + 1)) == NULL) e(0);
3648*baa5830fSDavid van Moolenbroek 
3649*baa5830fSDavid van Moolenbroek 	fill = rcvlen + fill_delta;
3650*baa5830fSDavid van Moolenbroek 	rlowat = rcvlen + rlowat_delta;
3651*baa5830fSDavid van Moolenbroek 
3652*baa5830fSDavid van Moolenbroek 	memset(buf, 0, fill);
3653*baa5830fSDavid van Moolenbroek 
3654*baa5830fSDavid van Moolenbroek 	if (send(fd[1], buf, fill, 0) != fill) e(0);
3655*baa5830fSDavid van Moolenbroek 
3656*baa5830fSDavid van Moolenbroek 	if (setsockopt(fd[0], SOL_SOCKET, SO_RCVLOWAT, &rlowat,
3657*baa5830fSDavid van Moolenbroek 	    sizeof(rlowat)) != 0) e(0);
3658*baa5830fSDavid van Moolenbroek 
3659*baa5830fSDavid van Moolenbroek 	res = recv(fd[0], buf, rcvlen + 1, MSG_DONTWAIT);
3660*baa5830fSDavid van Moolenbroek 	if (exp_delta < 0) {
3661*baa5830fSDavid van Moolenbroek 		if (res != -1) e(0);
3662*baa5830fSDavid van Moolenbroek 		if (errno != EWOULDBLOCK) e(0);
3663*baa5830fSDavid van Moolenbroek 	} else
3664*baa5830fSDavid van Moolenbroek 		if (res != rcvlen - exp_delta) e(0);
3665*baa5830fSDavid van Moolenbroek 
3666*baa5830fSDavid van Moolenbroek 	free(buf);
3667*baa5830fSDavid van Moolenbroek 
3668*baa5830fSDavid van Moolenbroek 	if (close(fd[0]) != 0) e(0);
3669*baa5830fSDavid van Moolenbroek 	if (close(fd[1]) != 0) e(0);
3670*baa5830fSDavid van Moolenbroek }
3671*baa5830fSDavid van Moolenbroek 
3672*baa5830fSDavid van Moolenbroek /*
3673*baa5830fSDavid van Moolenbroek  * Test that SO_SNDLOWAT is limited to the size of the "send" buffer.
3674*baa5830fSDavid van Moolenbroek  */
3675*baa5830fSDavid van Moolenbroek static void
sub90w_send(int fill,int slowat_delta,int exp_delta)3676*baa5830fSDavid van Moolenbroek sub90w_send(int fill, int slowat_delta, int exp_delta)
3677*baa5830fSDavid van Moolenbroek {
3678*baa5830fSDavid van Moolenbroek 	char *buf;
3679*baa5830fSDavid van Moolenbroek 	socklen_t len;
3680*baa5830fSDavid van Moolenbroek 	int fd[2], sndlen, slowat, res;
3681*baa5830fSDavid van Moolenbroek 
3682*baa5830fSDavid van Moolenbroek 	if (socketpair(AF_UNIX, SOCK_STREAM, 0, fd) != 0) e(0);
3683*baa5830fSDavid van Moolenbroek 
3684*baa5830fSDavid van Moolenbroek 	len = sizeof(sndlen);
3685*baa5830fSDavid van Moolenbroek 	if (getsockopt(fd[0], SOL_SOCKET, SO_SNDBUF, &sndlen, &len) != 0) e(0);
3686*baa5830fSDavid van Moolenbroek 	if (len != sizeof(sndlen)) e(0);
3687*baa5830fSDavid van Moolenbroek 
3688*baa5830fSDavid van Moolenbroek 	if ((buf = malloc(sndlen + 1)) == NULL) e(0);
3689*baa5830fSDavid van Moolenbroek 
3690*baa5830fSDavid van Moolenbroek 	slowat = sndlen + slowat_delta;
3691*baa5830fSDavid van Moolenbroek 
3692*baa5830fSDavid van Moolenbroek 	if (fill > 0) {
3693*baa5830fSDavid van Moolenbroek 		memset(buf, 0, fill);
3694*baa5830fSDavid van Moolenbroek 
3695*baa5830fSDavid van Moolenbroek 		if (send(fd[0], buf, fill, 0) != fill) e(0);
3696*baa5830fSDavid van Moolenbroek 	}
3697*baa5830fSDavid van Moolenbroek 
3698*baa5830fSDavid van Moolenbroek 	if (setsockopt(fd[0], SOL_SOCKET, SO_SNDLOWAT, &slowat,
3699*baa5830fSDavid van Moolenbroek 	    sizeof(slowat)) != 0) e(0);
3700*baa5830fSDavid van Moolenbroek 
3701*baa5830fSDavid van Moolenbroek 	res = send(fd[0], buf, sndlen + 1, MSG_DONTWAIT);
3702*baa5830fSDavid van Moolenbroek 	if (exp_delta < 0) {
3703*baa5830fSDavid van Moolenbroek 		if (res != -1) e(0);
3704*baa5830fSDavid van Moolenbroek 		if (errno != EWOULDBLOCK) e(0);
3705*baa5830fSDavid van Moolenbroek 	} else
3706*baa5830fSDavid van Moolenbroek 		if (res != sndlen - exp_delta) e(0);
3707*baa5830fSDavid van Moolenbroek 
3708*baa5830fSDavid van Moolenbroek 	free(buf);
3709*baa5830fSDavid van Moolenbroek 
3710*baa5830fSDavid van Moolenbroek 	if (close(fd[0]) != 0) e(0);
3711*baa5830fSDavid van Moolenbroek 	if (close(fd[1]) != 0) e(0);
3712*baa5830fSDavid van Moolenbroek }
3713*baa5830fSDavid van Moolenbroek 
3714*baa5830fSDavid van Moolenbroek /*
3715*baa5830fSDavid van Moolenbroek  * Test that on stream sockets, SO_RCVLOWAT and SO_SNDLOWAT are limited to
3716*baa5830fSDavid van Moolenbroek  * their respective buffer sizes.
3717*baa5830fSDavid van Moolenbroek  */
3718*baa5830fSDavid van Moolenbroek static void
test90w(void)3719*baa5830fSDavid van Moolenbroek test90w(void)
3720*baa5830fSDavid van Moolenbroek {
3721*baa5830fSDavid van Moolenbroek 
3722*baa5830fSDavid van Moolenbroek 	subtest = 23;
3723*baa5830fSDavid van Moolenbroek 
3724*baa5830fSDavid van Moolenbroek 	/*
3725*baa5830fSDavid van Moolenbroek 	 * With the receive buffer filled except for one byte, all data should
3726*baa5830fSDavid van Moolenbroek 	 * be retrieved unless the threshold is not met.
3727*baa5830fSDavid van Moolenbroek 	 */
3728*baa5830fSDavid van Moolenbroek 	sub90w_recv(-1, -1, 1);
3729*baa5830fSDavid van Moolenbroek 	sub90w_recv(-1, 0, -1);
3730*baa5830fSDavid van Moolenbroek 	sub90w_recv(-1, 1, -1);
3731*baa5830fSDavid van Moolenbroek 
3732*baa5830fSDavid van Moolenbroek 	/*
3733*baa5830fSDavid van Moolenbroek 	 * With the receive buffer filled completely, all data should be
3734*baa5830fSDavid van Moolenbroek 	 * retrieved in all cases.
3735*baa5830fSDavid van Moolenbroek 	 */
3736*baa5830fSDavid van Moolenbroek 	sub90w_recv(0, -1, 0);
3737*baa5830fSDavid van Moolenbroek 	sub90w_recv(0, 0, 0);
3738*baa5830fSDavid van Moolenbroek 	sub90w_recv(0, 1, 0);
3739*baa5830fSDavid van Moolenbroek 
3740*baa5830fSDavid van Moolenbroek 	/*
3741*baa5830fSDavid van Moolenbroek 	 * With a "send" buffer that contains one byte, all data should be sent
3742*baa5830fSDavid van Moolenbroek 	 * unless the threshold is not met.
3743*baa5830fSDavid van Moolenbroek 	 */
3744*baa5830fSDavid van Moolenbroek 	sub90w_send(1, -1, 1);
3745*baa5830fSDavid van Moolenbroek 	sub90w_send(1, 0, -1);
3746*baa5830fSDavid van Moolenbroek 	sub90w_send(1, 1, -1);
3747*baa5830fSDavid van Moolenbroek 
3748*baa5830fSDavid van Moolenbroek 	/*
3749*baa5830fSDavid van Moolenbroek 	 * With the "send" buffer filled completely, all data should be sent
3750*baa5830fSDavid van Moolenbroek 	 * in all cases.
3751*baa5830fSDavid van Moolenbroek 	 */
3752*baa5830fSDavid van Moolenbroek 	sub90w_send(0, -1, 0);
3753*baa5830fSDavid van Moolenbroek 	sub90w_send(0, 0, 0);
3754*baa5830fSDavid van Moolenbroek 	sub90w_send(0, 1, 0);
3755*baa5830fSDavid van Moolenbroek }
3756*baa5830fSDavid van Moolenbroek 
3757*baa5830fSDavid van Moolenbroek /*
3758*baa5830fSDavid van Moolenbroek  * Test shutdown on listening sockets.
3759*baa5830fSDavid van Moolenbroek  */
3760*baa5830fSDavid van Moolenbroek static void
sub90x(int type,int how,int connwait)3761*baa5830fSDavid van Moolenbroek sub90x(int type, int how, int connwait)
3762*baa5830fSDavid van Moolenbroek {
3763*baa5830fSDavid van Moolenbroek 	struct sockaddr_un sun;
3764*baa5830fSDavid van Moolenbroek 	socklen_t len;
3765*baa5830fSDavid van Moolenbroek 	char buf[1];
3766*baa5830fSDavid van Moolenbroek 	int fd, fd2, fd3, val, fl;
3767*baa5830fSDavid van Moolenbroek 
3768*baa5830fSDavid van Moolenbroek 	subtest = 24;
3769*baa5830fSDavid van Moolenbroek 
3770*baa5830fSDavid van Moolenbroek 	fd = get_bound_socket(type, SOCK_PATH_A, &sun);
3771*baa5830fSDavid van Moolenbroek 
3772*baa5830fSDavid van Moolenbroek 	if (listen(fd, 5) != 0) e(0);
3773*baa5830fSDavid van Moolenbroek 
3774*baa5830fSDavid van Moolenbroek 	if (!connwait) {
3775*baa5830fSDavid van Moolenbroek 		if ((fd2 = socket(AF_UNIX, type, 0)) < 0) e(0);
3776*baa5830fSDavid van Moolenbroek 
3777*baa5830fSDavid van Moolenbroek 		if (connect(fd2, (struct sockaddr *)&sun, sizeof(sun)) != 0)
3778*baa5830fSDavid van Moolenbroek 			e(0);
3779*baa5830fSDavid van Moolenbroek 	} else {
3780*baa5830fSDavid van Moolenbroek 		val = 1;
3781*baa5830fSDavid van Moolenbroek 		if (setsockopt(fd, 0, LOCAL_CONNWAIT, &val, sizeof(val)) != 0)
3782*baa5830fSDavid van Moolenbroek 			e(0);
3783*baa5830fSDavid van Moolenbroek 
3784*baa5830fSDavid van Moolenbroek 		if ((fd2 = socket(AF_UNIX, type | SOCK_NONBLOCK, 0)) < 0) e(0);
3785*baa5830fSDavid van Moolenbroek 
3786*baa5830fSDavid van Moolenbroek 		if (connect(fd2, (struct sockaddr *)&sun, sizeof(sun)) != -1)
3787*baa5830fSDavid van Moolenbroek 			e(0);
3788*baa5830fSDavid van Moolenbroek 		if (errno != EINPROGRESS) e(0);
3789*baa5830fSDavid van Moolenbroek 	}
3790*baa5830fSDavid van Moolenbroek 
3791*baa5830fSDavid van Moolenbroek 	if (shutdown(fd, how) != 0) e(0);
3792*baa5830fSDavid van Moolenbroek 
3793*baa5830fSDavid van Moolenbroek 	len = sizeof(sun);
3794*baa5830fSDavid van Moolenbroek 	if ((fd3 = accept(fd, (struct sockaddr *)&sun, &len)) < 0) e(0);
3795*baa5830fSDavid van Moolenbroek 
3796*baa5830fSDavid van Moolenbroek 	if (write(fd2, "A", 1) != 1) e(0);
3797*baa5830fSDavid van Moolenbroek 	if (read(fd3, buf, 1) != 1) e(0);
3798*baa5830fSDavid van Moolenbroek 	if (buf[0] != 'A') e(0);
3799*baa5830fSDavid van Moolenbroek 
3800*baa5830fSDavid van Moolenbroek 	if (write(fd3, "B", 1) != 1) e(0);
3801*baa5830fSDavid van Moolenbroek 	if (read(fd2, buf, 1) != 1) e(0);
3802*baa5830fSDavid van Moolenbroek 	if (buf[0] != 'B') e(0);
3803*baa5830fSDavid van Moolenbroek 
3804*baa5830fSDavid van Moolenbroek 	len = sizeof(sun);
3805*baa5830fSDavid van Moolenbroek 	if (accept(fd, (struct sockaddr *)&sun, &len) != -1) e(0);
3806*baa5830fSDavid van Moolenbroek 	if (errno != ECONNABORTED) e(0);
3807*baa5830fSDavid van Moolenbroek 
3808*baa5830fSDavid van Moolenbroek 	/*
3809*baa5830fSDavid van Moolenbroek 	 * Strangely, both NetBSD and Linux (yes, my two reference platforms)
3810*baa5830fSDavid van Moolenbroek 	 * return EWOULDBLOCK from non-blocking accept(2) calls even though
3811*baa5830fSDavid van Moolenbroek 	 * they always return ECONNABORTED when blocking.  For consistency and
3812*baa5830fSDavid van Moolenbroek 	 * select(2), we always return ECONNABORTED.
3813*baa5830fSDavid van Moolenbroek 	 */
3814*baa5830fSDavid van Moolenbroek 	if ((fl = fcntl(fd, F_GETFL)) == -1) e(0);
3815*baa5830fSDavid van Moolenbroek 	if (fcntl(fd, F_SETFL, fl | O_NONBLOCK) != 0) e(0);
3816*baa5830fSDavid van Moolenbroek 
3817*baa5830fSDavid van Moolenbroek 	len = sizeof(sun);
3818*baa5830fSDavid van Moolenbroek 	if (accept(fd, (struct sockaddr *)&sun, &len) != -1) e(0);
3819*baa5830fSDavid van Moolenbroek 	if (errno != ECONNABORTED) e(0);
3820*baa5830fSDavid van Moolenbroek 
3821*baa5830fSDavid van Moolenbroek 	if (fcntl(fd, F_SETFL, fl) != 0) e(0);
3822*baa5830fSDavid van Moolenbroek 
3823*baa5830fSDavid van Moolenbroek 	if (close(fd3) != 0) e(0);
3824*baa5830fSDavid van Moolenbroek 	if (close(fd2) != 0) e(0);
3825*baa5830fSDavid van Moolenbroek 
3826*baa5830fSDavid van Moolenbroek 	if ((fd2 = socket(AF_UNIX, type | SOCK_NONBLOCK, 0)) < 0) e(0);
3827*baa5830fSDavid van Moolenbroek 
3828*baa5830fSDavid van Moolenbroek 	if (connect(fd2, (struct sockaddr *)&sun, sizeof(sun)) != -1) e(0);
3829*baa5830fSDavid van Moolenbroek 	if (errno != ECONNREFUSED) e(0);
3830*baa5830fSDavid van Moolenbroek 
3831*baa5830fSDavid van Moolenbroek 	len = sizeof(sun);
3832*baa5830fSDavid van Moolenbroek 	if (accept(fd, (struct sockaddr *)&sun, &len) != -1) e(0);
3833*baa5830fSDavid van Moolenbroek 	if (errno != ECONNABORTED) e(0);
3834*baa5830fSDavid van Moolenbroek 
3835*baa5830fSDavid van Moolenbroek 	if (close(fd2) != 0) e(0);
3836*baa5830fSDavid van Moolenbroek 	if (close(fd) != 0) e(0);
3837*baa5830fSDavid van Moolenbroek 
3838*baa5830fSDavid van Moolenbroek 	if (unlink(SOCK_PATH_A) != 0) e(0);
3839*baa5830fSDavid van Moolenbroek }
3840*baa5830fSDavid van Moolenbroek 
3841*baa5830fSDavid van Moolenbroek /*
3842*baa5830fSDavid van Moolenbroek  * Test shutdown on listening sockets.  Pending connections should still be
3843*baa5830fSDavid van Moolenbroek  * acceptable (and not inherit the shutdown flags), but new connections must be
3844*baa5830fSDavid van Moolenbroek  * refused, and the accept call must no longer ever block.
3845*baa5830fSDavid van Moolenbroek  */
3846*baa5830fSDavid van Moolenbroek static void
test90x(void)3847*baa5830fSDavid van Moolenbroek test90x(void)
3848*baa5830fSDavid van Moolenbroek {
3849*baa5830fSDavid van Moolenbroek 	const int types[] = { SOCK_STREAM, SOCK_SEQPACKET };
3850*baa5830fSDavid van Moolenbroek 	const int hows[] = { SHUT_RD, SHUT_WR, SHUT_RDWR };
3851*baa5830fSDavid van Moolenbroek 	unsigned int i, j, k;
3852*baa5830fSDavid van Moolenbroek 
3853*baa5830fSDavid van Moolenbroek 	for (i = 0; i < __arraycount(types); i++)
3854*baa5830fSDavid van Moolenbroek 		for (j = 0; j < __arraycount(hows); j++)
3855*baa5830fSDavid van Moolenbroek 			for (k = 0; k <= 1; k++)
3856*baa5830fSDavid van Moolenbroek 				sub90x(types[i], hows[j], k);
3857*baa5830fSDavid van Moolenbroek }
3858*baa5830fSDavid van Moolenbroek 
3859*baa5830fSDavid van Moolenbroek /*
3860*baa5830fSDavid van Moolenbroek  * Test accepting connections without LOCAL_CONNWAIT for the given socket type.
3861*baa5830fSDavid van Moolenbroek  */
3862*baa5830fSDavid van Moolenbroek static void
sub90y(int type)3863*baa5830fSDavid van Moolenbroek sub90y(int type)
3864*baa5830fSDavid van Moolenbroek {
3865*baa5830fSDavid van Moolenbroek 	struct sockaddr_un sunA, sunB, sunC;
3866*baa5830fSDavid van Moolenbroek 	socklen_t len;
3867*baa5830fSDavid van Moolenbroek 	struct timeval tv;
3868*baa5830fSDavid van Moolenbroek 	fd_set fds;
3869*baa5830fSDavid van Moolenbroek 	char buf[7];
3870*baa5830fSDavid van Moolenbroek 	uid_t uid;
3871*baa5830fSDavid van Moolenbroek 	gid_t gid;
3872*baa5830fSDavid van Moolenbroek 	int fd, fd2, fd3, fd4, val;
3873*baa5830fSDavid van Moolenbroek 
3874*baa5830fSDavid van Moolenbroek 	fd = get_bound_socket(type | SOCK_NONBLOCK, SOCK_PATH_A, &sunA);
3875*baa5830fSDavid van Moolenbroek 
3876*baa5830fSDavid van Moolenbroek 	len = sizeof(val);
3877*baa5830fSDavid van Moolenbroek 	if (getsockopt(fd, 0, LOCAL_CONNWAIT, &val, &len) != 0) e(0);
3878*baa5830fSDavid van Moolenbroek 	if (len != sizeof(val)) e(0);
3879*baa5830fSDavid van Moolenbroek 	if (val != 0) e(0);
3880*baa5830fSDavid van Moolenbroek 
3881*baa5830fSDavid van Moolenbroek 	if (listen(fd, 5) != 0) e(0);
3882*baa5830fSDavid van Moolenbroek 
3883*baa5830fSDavid van Moolenbroek 	/*
3884*baa5830fSDavid van Moolenbroek 	 * Any socket options should be inherited from the listening socket at
3885*baa5830fSDavid van Moolenbroek 	 * connect time, and not be re-inherited at accept time.  It does not
3886*baa5830fSDavid van Moolenbroek 	 * really matter what socket option we set here, as long as it is
3887*baa5830fSDavid van Moolenbroek 	 * supposed to be inherited.
3888*baa5830fSDavid van Moolenbroek 	 */
3889*baa5830fSDavid van Moolenbroek 	val = 123;
3890*baa5830fSDavid van Moolenbroek 	if (setsockopt(fd, SOL_SOCKET, SO_SNDLOWAT, &val, sizeof(val)) != 0)
3891*baa5830fSDavid van Moolenbroek 		e(0);
3892*baa5830fSDavid van Moolenbroek 
3893*baa5830fSDavid van Moolenbroek 	fd2 = get_bound_socket(type, SOCK_PATH_B, &sunB);
3894*baa5830fSDavid van Moolenbroek 
3895*baa5830fSDavid van Moolenbroek 	if (connect(fd2, (struct sockaddr *)&sunA, sizeof(sunA)) != 0) e(0);
3896*baa5830fSDavid van Moolenbroek 
3897*baa5830fSDavid van Moolenbroek 	val = 456;
3898*baa5830fSDavid van Moolenbroek 	if (setsockopt(fd, SOL_SOCKET, SO_SNDLOWAT, &val, sizeof(val)) != 0)
3899*baa5830fSDavid van Moolenbroek 		e(0);
3900*baa5830fSDavid van Moolenbroek 
3901*baa5830fSDavid van Moolenbroek 	/*
3902*baa5830fSDavid van Moolenbroek 	 * Obtaining the peer name should work.  As always, the name should be
3903*baa5830fSDavid van Moolenbroek 	 * inherited from the listening socket.
3904*baa5830fSDavid van Moolenbroek 	 */
3905*baa5830fSDavid van Moolenbroek 	len = sizeof(sunC);
3906*baa5830fSDavid van Moolenbroek 	if (getpeername(fd2, (struct sockaddr *)&sunC, &len) != 0) e(0);
3907*baa5830fSDavid van Moolenbroek 	check_addr(&sunC, len, SOCK_PATH_A);
3908*baa5830fSDavid van Moolenbroek 
3909*baa5830fSDavid van Moolenbroek 	/*
3910*baa5830fSDavid van Moolenbroek 	 * Obtaining peer credentials should work.  This is why NetBSD obtains
3911*baa5830fSDavid van Moolenbroek 	 * the peer credentials at bind time, not at accept time.
3912*baa5830fSDavid van Moolenbroek 	 */
3913*baa5830fSDavid van Moolenbroek 	if (getpeereid(fd2, &uid, &gid) != 0) e(0);
3914*baa5830fSDavid van Moolenbroek 	if (uid != geteuid()) e(0);
3915*baa5830fSDavid van Moolenbroek 	if (gid != getegid()) e(0);
3916*baa5830fSDavid van Moolenbroek 
3917*baa5830fSDavid van Moolenbroek 	/*
3918*baa5830fSDavid van Moolenbroek 	 * Sending to the socket should work, and it should be possible to
3919*baa5830fSDavid van Moolenbroek 	 * receive the data from the other side once accepted.
3920*baa5830fSDavid van Moolenbroek 	 */
3921*baa5830fSDavid van Moolenbroek 	if (send(fd2, "Hello, ", 7, 0) != 7) e(0);
3922*baa5830fSDavid van Moolenbroek 	if (send(fd2, "world!", 6, 0) != 6) e(0);
3923*baa5830fSDavid van Moolenbroek 
3924*baa5830fSDavid van Moolenbroek 	/* Shutdown settings should be visible after accepting, too. */
3925*baa5830fSDavid van Moolenbroek 	if (shutdown(fd2, SHUT_RDWR) != 0) e(0);
3926*baa5830fSDavid van Moolenbroek 
3927*baa5830fSDavid van Moolenbroek 	len = sizeof(sunB);
3928*baa5830fSDavid van Moolenbroek 	if ((fd3 = accept(fd, (struct sockaddr *)&sunB, &len)) < 0) e(0);
3929*baa5830fSDavid van Moolenbroek 	check_addr(&sunB, len, SOCK_PATH_B);
3930*baa5830fSDavid van Moolenbroek 
3931*baa5830fSDavid van Moolenbroek 	len = sizeof(val);
3932*baa5830fSDavid van Moolenbroek 	if (getsockopt(fd3, SOL_SOCKET, SO_SNDLOWAT, &val, &len) != 0) e(0);
3933*baa5830fSDavid van Moolenbroek 	if (len != sizeof(val)) e(0);
3934*baa5830fSDavid van Moolenbroek 	if (val != 123) e(0);
3935*baa5830fSDavid van Moolenbroek 
3936*baa5830fSDavid van Moolenbroek 	if (recv(fd3, buf, 7, 0) != 7) e(0);
3937*baa5830fSDavid van Moolenbroek 	if (memcmp(buf, "Hello, ", 7) != 0) e(0);
3938*baa5830fSDavid van Moolenbroek 	if (recv(fd3, buf, 7, 0) != 6) e(0);
3939*baa5830fSDavid van Moolenbroek 	if (memcmp(buf, "world!", 6) != 0) e(0);
3940*baa5830fSDavid van Moolenbroek 
3941*baa5830fSDavid van Moolenbroek 	if (recv(fd3, buf, sizeof(buf), 0) != 0) e(0);
3942*baa5830fSDavid van Moolenbroek 
3943*baa5830fSDavid van Moolenbroek 	if (send(fd3, "X", 1, MSG_NOSIGNAL) != -1) e(0);
3944*baa5830fSDavid van Moolenbroek 	if (errno != EPIPE) e(0);
3945*baa5830fSDavid van Moolenbroek 
3946*baa5830fSDavid van Moolenbroek 	if (close(fd2) != 0) e(0);
3947*baa5830fSDavid van Moolenbroek 	if (close(fd3) != 0) e(0);
3948*baa5830fSDavid van Moolenbroek 
3949*baa5830fSDavid van Moolenbroek 	if (unlink(SOCK_PATH_B) != 0) e(0);
3950*baa5830fSDavid van Moolenbroek 
3951*baa5830fSDavid van Moolenbroek 	/*
3952*baa5830fSDavid van Moolenbroek 	 * If the socket pending acceptance is closed, the listening socket
3953*baa5830fSDavid van Moolenbroek 	 * should pretend as though the connection was never there.
3954*baa5830fSDavid van Moolenbroek 	 */
3955*baa5830fSDavid van Moolenbroek 	if ((fd2 = socket(AF_UNIX, type, 0)) < 0) e(0);
3956*baa5830fSDavid van Moolenbroek 
3957*baa5830fSDavid van Moolenbroek 	if (connect(fd2, (struct sockaddr *)&sunA, sizeof(sunA)) != 0) e(0);
3958*baa5830fSDavid van Moolenbroek 
3959*baa5830fSDavid van Moolenbroek 	FD_ZERO(&fds);
3960*baa5830fSDavid van Moolenbroek 	FD_SET(fd, &fds);
3961*baa5830fSDavid van Moolenbroek 	tv.tv_sec = 0;
3962*baa5830fSDavid van Moolenbroek 	tv.tv_usec = 0;
3963*baa5830fSDavid van Moolenbroek 	if (select(fd + 1, &fds, NULL, NULL, &tv) != 1) e(0);
3964*baa5830fSDavid van Moolenbroek 	if (!FD_ISSET(fd, &fds)) e(0);
3965*baa5830fSDavid van Moolenbroek 
3966*baa5830fSDavid van Moolenbroek 	if (close(fd2) != 0) e(0);
3967*baa5830fSDavid van Moolenbroek 
3968*baa5830fSDavid van Moolenbroek 	if (select(fd + 1, &fds, NULL, NULL, &tv) != 0) e(0);
3969*baa5830fSDavid van Moolenbroek 	if (FD_ISSET(fd, &fds)) e(0);
3970*baa5830fSDavid van Moolenbroek 
3971*baa5830fSDavid van Moolenbroek 	len = sizeof(sunB);
3972*baa5830fSDavid van Moolenbroek 	if (accept(fd, (struct sockaddr *)&sunB, &len) != -1) e(0);
3973*baa5830fSDavid van Moolenbroek 	if (errno != EWOULDBLOCK) e(0);
3974*baa5830fSDavid van Moolenbroek 
3975*baa5830fSDavid van Moolenbroek 	/*
3976*baa5830fSDavid van Moolenbroek 	 * Try the same thing, but now with the connection sandwiched between
3977*baa5830fSDavid van Moolenbroek 	 * two different pending connections, which should be left intact.
3978*baa5830fSDavid van Moolenbroek 	 */
3979*baa5830fSDavid van Moolenbroek 	if ((fd2 = socket(AF_UNIX, type, 0)) < 0) e(0);
3980*baa5830fSDavid van Moolenbroek 
3981*baa5830fSDavid van Moolenbroek 	if (connect(fd2, (struct sockaddr *)&sunA, sizeof(sunA)) != 0) e(0);
3982*baa5830fSDavid van Moolenbroek 
3983*baa5830fSDavid van Moolenbroek 	if (send(fd2, "A", 1, 0) != 1) e(0);
3984*baa5830fSDavid van Moolenbroek 
3985*baa5830fSDavid van Moolenbroek 	if ((fd3 = socket(AF_UNIX, type, 0)) < 0) e(0);
3986*baa5830fSDavid van Moolenbroek 
3987*baa5830fSDavid van Moolenbroek 	if (connect(fd3, (struct sockaddr *)&sunA, sizeof(sunA)) != 0) e(0);
3988*baa5830fSDavid van Moolenbroek 
3989*baa5830fSDavid van Moolenbroek 	if (send(fd3, "B", 1, 0) != 1) e(0);
3990*baa5830fSDavid van Moolenbroek 
3991*baa5830fSDavid van Moolenbroek 	if ((fd4 = socket(AF_UNIX, type, 0)) < 0) e(0);
3992*baa5830fSDavid van Moolenbroek 
3993*baa5830fSDavid van Moolenbroek 	if (connect(fd4, (struct sockaddr *)&sunA, sizeof(sunA)) != 0) e(0);
3994*baa5830fSDavid van Moolenbroek 
3995*baa5830fSDavid van Moolenbroek 	if (send(fd4, "C", 1, 0) != 1) e(0);
3996*baa5830fSDavid van Moolenbroek 
3997*baa5830fSDavid van Moolenbroek 	if (close(fd3) != 0) e(0);
3998*baa5830fSDavid van Moolenbroek 
3999*baa5830fSDavid van Moolenbroek 	len = sizeof(sunB);
4000*baa5830fSDavid van Moolenbroek 	if ((fd3 = accept(fd, (struct sockaddr *)&sunB, &len)) < 0) e(0);
4001*baa5830fSDavid van Moolenbroek 
4002*baa5830fSDavid van Moolenbroek 	if (recv(fd3, buf, sizeof(buf), 0) != 1) e(0);
4003*baa5830fSDavid van Moolenbroek 	if (buf[0] != 'A') e(0);
4004*baa5830fSDavid van Moolenbroek 
4005*baa5830fSDavid van Moolenbroek 	if (close(fd3) != 0) e(0);
4006*baa5830fSDavid van Moolenbroek 	if (close(fd2) != 0) e(0);
4007*baa5830fSDavid van Moolenbroek 
4008*baa5830fSDavid van Moolenbroek 	FD_ZERO(&fds);
4009*baa5830fSDavid van Moolenbroek 	FD_SET(fd, &fds);
4010*baa5830fSDavid van Moolenbroek 	tv.tv_sec = 0;
4011*baa5830fSDavid van Moolenbroek 	tv.tv_usec = 0;
4012*baa5830fSDavid van Moolenbroek 	if (select(fd + 1, &fds, NULL, NULL, &tv) != 1) e(0);
4013*baa5830fSDavid van Moolenbroek 	if (!FD_ISSET(fd, &fds)) e(0);
4014*baa5830fSDavid van Moolenbroek 
4015*baa5830fSDavid van Moolenbroek 	len = sizeof(sunB);
4016*baa5830fSDavid van Moolenbroek 	if ((fd3 = accept(fd, (struct sockaddr *)&sunB, &len)) < 0) e(0);
4017*baa5830fSDavid van Moolenbroek 
4018*baa5830fSDavid van Moolenbroek 	if (recv(fd3, buf, sizeof(buf), 0) != 1) e(0);
4019*baa5830fSDavid van Moolenbroek 	if (buf[0] != 'C') e(0);
4020*baa5830fSDavid van Moolenbroek 
4021*baa5830fSDavid van Moolenbroek 	if (close(fd3) != 0) e(0);
4022*baa5830fSDavid van Moolenbroek 	if (close(fd4) != 0) e(0);
4023*baa5830fSDavid van Moolenbroek 
4024*baa5830fSDavid van Moolenbroek 	if (select(fd + 1, &fds, NULL, NULL, &tv) != 0) e(0);
4025*baa5830fSDavid van Moolenbroek 	if (FD_ISSET(fd, &fds)) e(0);
4026*baa5830fSDavid van Moolenbroek 
4027*baa5830fSDavid van Moolenbroek 	len = sizeof(sunB);
4028*baa5830fSDavid van Moolenbroek 	if (accept(fd, (struct sockaddr *)&sunB, &len) != -1) e(0);
4029*baa5830fSDavid van Moolenbroek 	if (errno != EWOULDBLOCK) e(0);
4030*baa5830fSDavid van Moolenbroek 
4031*baa5830fSDavid van Moolenbroek 	/*
4032*baa5830fSDavid van Moolenbroek 	 * If the listening socket is closed, the socket pending acceptance
4033*baa5830fSDavid van Moolenbroek 	 * should be reset.  We actually rely on this behavior in the sweep
4034*baa5830fSDavid van Moolenbroek 	 * test, but we test this with more than one socket this time.
4035*baa5830fSDavid van Moolenbroek 	 */
4036*baa5830fSDavid van Moolenbroek 	if ((fd2 = socket(AF_UNIX, type, 0)) < 0) e(0);
4037*baa5830fSDavid van Moolenbroek 
4038*baa5830fSDavid van Moolenbroek 	if (connect(fd2, (struct sockaddr *)&sunA, sizeof(sunA)) != 0) e(0);
4039*baa5830fSDavid van Moolenbroek 
4040*baa5830fSDavid van Moolenbroek 	if ((fd3 = socket(AF_UNIX, type, 0)) < 0) e(0);
4041*baa5830fSDavid van Moolenbroek 
4042*baa5830fSDavid van Moolenbroek 	if (connect(fd3, (struct sockaddr *)&sunA, sizeof(sunA)) != 0) e(0);
4043*baa5830fSDavid van Moolenbroek 
4044*baa5830fSDavid van Moolenbroek 	if (close(fd) != 0) e(0);
4045*baa5830fSDavid van Moolenbroek 
4046*baa5830fSDavid van Moolenbroek 	if (recv(fd2, buf, sizeof(buf), 0) != -1) e(0);
4047*baa5830fSDavid van Moolenbroek 	if (errno != ECONNRESET) e(0);
4048*baa5830fSDavid van Moolenbroek 
4049*baa5830fSDavid van Moolenbroek 	if (recv(fd2, buf, sizeof(buf), 0) != 0) e(0);
4050*baa5830fSDavid van Moolenbroek 
4051*baa5830fSDavid van Moolenbroek 	if (recv(fd3, buf, sizeof(buf), 0) != -1) e(0);
4052*baa5830fSDavid van Moolenbroek 	if (errno != ECONNRESET) e(0);
4053*baa5830fSDavid van Moolenbroek 
4054*baa5830fSDavid van Moolenbroek 	if (recv(fd3, buf, sizeof(buf), 0) != 0) e(0);
4055*baa5830fSDavid van Moolenbroek 
4056*baa5830fSDavid van Moolenbroek 	if (close(fd3) != 0) e(0);
4057*baa5830fSDavid van Moolenbroek 
4058*baa5830fSDavid van Moolenbroek 	if (close(fd2) != 0) e(0);
4059*baa5830fSDavid van Moolenbroek 
4060*baa5830fSDavid van Moolenbroek 	if (unlink(SOCK_PATH_A) != 0) e(0);
4061*baa5830fSDavid van Moolenbroek }
4062*baa5830fSDavid van Moolenbroek 
4063*baa5830fSDavid van Moolenbroek /*
4064*baa5830fSDavid van Moolenbroek  * Test accepting connections without LOCAL_CONNWAIT.  Since both the old UDS
4065*baa5830fSDavid van Moolenbroek  * service and the initial version of the new UDS service supported only the
4066*baa5830fSDavid van Moolenbroek  * LOCAL_CONNWAIT behavior, the alternative (which is now the default, as it is
4067*baa5830fSDavid van Moolenbroek  * on other platforms) has been a bit under-tested so far.
4068*baa5830fSDavid van Moolenbroek  */
4069*baa5830fSDavid van Moolenbroek static void
test90y(void)4070*baa5830fSDavid van Moolenbroek test90y(void)
4071*baa5830fSDavid van Moolenbroek {
4072*baa5830fSDavid van Moolenbroek 
4073*baa5830fSDavid van Moolenbroek 	subtest = 25;
4074*baa5830fSDavid van Moolenbroek 
4075*baa5830fSDavid van Moolenbroek 	sub90y(SOCK_STREAM);
4076*baa5830fSDavid van Moolenbroek 
4077*baa5830fSDavid van Moolenbroek 	sub90y(SOCK_SEQPACKET);
4078*baa5830fSDavid van Moolenbroek }
4079*baa5830fSDavid van Moolenbroek 
4080*baa5830fSDavid van Moolenbroek /*
4081*baa5830fSDavid van Moolenbroek  * Test that SO_LINGER has no effect on sockets of the given type.
4082*baa5830fSDavid van Moolenbroek  */
4083*baa5830fSDavid van Moolenbroek static void
sub90z(int type)4084*baa5830fSDavid van Moolenbroek sub90z(int type)
4085*baa5830fSDavid van Moolenbroek {
4086*baa5830fSDavid van Moolenbroek 	struct sockaddr_un sun;
4087*baa5830fSDavid van Moolenbroek 	socklen_t len;
4088*baa5830fSDavid van Moolenbroek 	struct linger l;
4089*baa5830fSDavid van Moolenbroek 	char buf[1];
4090*baa5830fSDavid van Moolenbroek 	int fd, fd2, fd3;
4091*baa5830fSDavid van Moolenbroek 
4092*baa5830fSDavid van Moolenbroek 	fd = get_bound_socket(type, SOCK_PATH_A, &sun);
4093*baa5830fSDavid van Moolenbroek 
4094*baa5830fSDavid van Moolenbroek 	if (listen(fd, 1) != 0) e(0);
4095*baa5830fSDavid van Moolenbroek 
4096*baa5830fSDavid van Moolenbroek 	if ((fd2 = socket(AF_UNIX, type, 0)) < 0) e(0);
4097*baa5830fSDavid van Moolenbroek 
4098*baa5830fSDavid van Moolenbroek 	if (connect(fd2, (struct sockaddr *)&sun, sizeof(sun)) != 0) e(0);
4099*baa5830fSDavid van Moolenbroek 
4100*baa5830fSDavid van Moolenbroek 	len = sizeof(sun);
4101*baa5830fSDavid van Moolenbroek 	if ((fd3 = accept(fd, (struct sockaddr *)&sun, &len)) < 0) e(0);
4102*baa5830fSDavid van Moolenbroek 
4103*baa5830fSDavid van Moolenbroek 	if (close(fd) != 0) e(0);
4104*baa5830fSDavid van Moolenbroek 
4105*baa5830fSDavid van Moolenbroek 	if (send(fd2, "A", 1, 0) != 1) e(0);
4106*baa5830fSDavid van Moolenbroek 
4107*baa5830fSDavid van Moolenbroek 	l.l_onoff = 1;
4108*baa5830fSDavid van Moolenbroek 	l.l_linger = 0;
4109*baa5830fSDavid van Moolenbroek 	if (setsockopt(fd2, SOL_SOCKET, SO_LINGER, &l, sizeof(l)) != 0) e(0);
4110*baa5830fSDavid van Moolenbroek 
4111*baa5830fSDavid van Moolenbroek 	if (close(fd2) != 0) e(0);
4112*baa5830fSDavid van Moolenbroek 
4113*baa5830fSDavid van Moolenbroek 	if (recv(fd3, buf, sizeof(buf), 0) != 1) e(0);
4114*baa5830fSDavid van Moolenbroek 	if (buf[0] != 'A') e(0);
4115*baa5830fSDavid van Moolenbroek 
4116*baa5830fSDavid van Moolenbroek 	/* We should not get ECONNRESET now. */
4117*baa5830fSDavid van Moolenbroek 	if (recv(fd3, buf, sizeof(buf), 0) != 0) e(0);
4118*baa5830fSDavid van Moolenbroek 
4119*baa5830fSDavid van Moolenbroek 	if (close(fd3) != 0) e(0);
4120*baa5830fSDavid van Moolenbroek 
4121*baa5830fSDavid van Moolenbroek 	if (unlink(SOCK_PATH_A) != 0) e(0);
4122*baa5830fSDavid van Moolenbroek }
4123*baa5830fSDavid van Moolenbroek 
4124*baa5830fSDavid van Moolenbroek /*
4125*baa5830fSDavid van Moolenbroek  * Test that SO_LINGER has no effect on UNIX domain sockets.  In particular, a
4126*baa5830fSDavid van Moolenbroek  * timeout of zero does not cause the connection to be reset forcefully.
4127*baa5830fSDavid van Moolenbroek  */
4128*baa5830fSDavid van Moolenbroek static void
test90z(void)4129*baa5830fSDavid van Moolenbroek test90z(void)
4130*baa5830fSDavid van Moolenbroek {
4131*baa5830fSDavid van Moolenbroek 
4132*baa5830fSDavid van Moolenbroek 	subtest = 26;
4133*baa5830fSDavid van Moolenbroek 
4134*baa5830fSDavid van Moolenbroek 	sub90z(SOCK_STREAM);
4135*baa5830fSDavid van Moolenbroek 
4136*baa5830fSDavid van Moolenbroek 	sub90z(SOCK_SEQPACKET);
4137*baa5830fSDavid van Moolenbroek }
4138*baa5830fSDavid van Moolenbroek 
4139*baa5830fSDavid van Moolenbroek /*
4140*baa5830fSDavid van Moolenbroek  * Test program for UDS.
4141*baa5830fSDavid van Moolenbroek  */
4142*baa5830fSDavid van Moolenbroek int
main(int argc,char ** argv)4143*baa5830fSDavid van Moolenbroek main(int argc, char ** argv)
4144*baa5830fSDavid van Moolenbroek {
4145*baa5830fSDavid van Moolenbroek 	int i, m;
4146*baa5830fSDavid van Moolenbroek 
4147*baa5830fSDavid van Moolenbroek 	start(90);
4148*baa5830fSDavid van Moolenbroek 
4149*baa5830fSDavid van Moolenbroek 	if (argc == 2)
4150*baa5830fSDavid van Moolenbroek 		m = atoi(argv[1]);
4151*baa5830fSDavid van Moolenbroek 	else
4152*baa5830fSDavid van Moolenbroek 		m = 0xFFFFFFF;
4153*baa5830fSDavid van Moolenbroek 
4154*baa5830fSDavid van Moolenbroek 	for (i = 0; i < ITERATIONS; i++) {
4155*baa5830fSDavid van Moolenbroek 		if (m & 0x0000001) test90a();
4156*baa5830fSDavid van Moolenbroek 		if (m & 0x0000002) test90b();
4157*baa5830fSDavid van Moolenbroek 		if (m & 0x0000004) test90c();
4158*baa5830fSDavid van Moolenbroek 		if (m & 0x0000008) test90d();
4159*baa5830fSDavid van Moolenbroek 		if (m & 0x0000010) test90e();
4160*baa5830fSDavid van Moolenbroek 		if (m & 0x0000020) test90f();
4161*baa5830fSDavid van Moolenbroek 		if (m & 0x0000040) test90g();
4162*baa5830fSDavid van Moolenbroek 		if (m & 0x0000080) test90h();
4163*baa5830fSDavid van Moolenbroek 		if (m & 0x0000100) test90i();
4164*baa5830fSDavid van Moolenbroek 		if (m & 0x0000200) test90j();
4165*baa5830fSDavid van Moolenbroek 		if (m & 0x0000400) test90k();
4166*baa5830fSDavid van Moolenbroek 		if (m & 0x0000800) test90l();
4167*baa5830fSDavid van Moolenbroek 		if (m & 0x0001000) test90m();
4168*baa5830fSDavid van Moolenbroek 		if (m & 0x0002000) test90n();
4169*baa5830fSDavid van Moolenbroek 		if (m & 0x0004000) test90o();
4170*baa5830fSDavid van Moolenbroek 		if (m & 0x0008000) test90p();
4171*baa5830fSDavid van Moolenbroek 		if (m & 0x0010000) test90q();
4172*baa5830fSDavid van Moolenbroek 		if (m & 0x0020000) test90r();
4173*baa5830fSDavid van Moolenbroek 		if (m & 0x0040000) test90s();
4174*baa5830fSDavid van Moolenbroek 		if (m & 0x0080000) test90t();
4175*baa5830fSDavid van Moolenbroek 		if (m & 0x0100000) test90u();
4176*baa5830fSDavid van Moolenbroek 		if (m & 0x0200000) test90v();
4177*baa5830fSDavid van Moolenbroek 		if (m & 0x0400000) test90w();
4178*baa5830fSDavid van Moolenbroek 		if (m & 0x0800000) test90x();
4179*baa5830fSDavid van Moolenbroek 		if (m & 0x1000000) test90y();
4180*baa5830fSDavid van Moolenbroek 		if (m & 0x2000000) test90z();
4181*baa5830fSDavid van Moolenbroek 	}
4182*baa5830fSDavid van Moolenbroek 
4183*baa5830fSDavid van Moolenbroek 	quit();
4184*baa5830fSDavid van Moolenbroek 	/* NOTREACHED */
4185*baa5830fSDavid van Moolenbroek }
4186