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