1294d1590SErik van der Kouwe #include <assert.h>
2294d1590SErik van der Kouwe #include <ctype.h>
3294d1590SErik van der Kouwe #include <errno.h>
4294d1590SErik van der Kouwe #include <fcntl.h>
5294d1590SErik van der Kouwe #include <signal.h>
6294d1590SErik van der Kouwe #include <stdio.h>
7294d1590SErik van der Kouwe #include <stdlib.h>
8294d1590SErik van der Kouwe #include <string.h>
9294d1590SErik van der Kouwe #include <sys/socket.h>
10294d1590SErik van der Kouwe #include <sys/stat.h>
11294d1590SErik van der Kouwe #include <sys/wait.h>
12294d1590SErik van der Kouwe #include <time.h>
13294d1590SErik van der Kouwe #include <unistd.h>
14294d1590SErik van der Kouwe
15294d1590SErik van der Kouwe #include "common.h"
16294d1590SErik van der Kouwe #include "common-socket.h"
17294d1590SErik van der Kouwe
18294d1590SErik van der Kouwe #define ISO8601_FORMAT "%Y-%m-%dT%H:%M:%S"
19294d1590SErik van der Kouwe
20294d1590SErik van der Kouwe /* timestamps for debug and error logs */
get_timestamp(void)21294d1590SErik van der Kouwe static char *get_timestamp(void)
22294d1590SErik van der Kouwe {
23294d1590SErik van der Kouwe struct tm *tm;
24294d1590SErik van der Kouwe time_t t;
25294d1590SErik van der Kouwe size_t len;
26294d1590SErik van der Kouwe char *s;
27294d1590SErik van der Kouwe
28294d1590SErik van der Kouwe len = sizeof(char) * 32;
29294d1590SErik van der Kouwe
30294d1590SErik van der Kouwe t = time(NULL);
31294d1590SErik van der Kouwe if (t == -1) {
32294d1590SErik van der Kouwe return NULL;
33294d1590SErik van der Kouwe }
34294d1590SErik van der Kouwe tm = gmtime(&t);
35294d1590SErik van der Kouwe if (tm == NULL) {
36294d1590SErik van der Kouwe return NULL;
37294d1590SErik van der Kouwe }
38294d1590SErik van der Kouwe
39294d1590SErik van der Kouwe s = (char *) malloc(len);
40294d1590SErik van der Kouwe if (!s) {
41294d1590SErik van der Kouwe perror("malloc");
42294d1590SErik van der Kouwe return NULL;
43294d1590SErik van der Kouwe }
44294d1590SErik van der Kouwe memset(s, '\0', len);
45294d1590SErik van der Kouwe
46294d1590SErik van der Kouwe strftime(s, len - 1, ISO8601_FORMAT, tm);
47294d1590SErik van der Kouwe return s;
48294d1590SErik van der Kouwe }
49294d1590SErik van der Kouwe
test_fail_fl(char * msg,char * file,int line)50294d1590SErik van der Kouwe void test_fail_fl(char *msg, char *file, int line)
51294d1590SErik van der Kouwe {
52294d1590SErik van der Kouwe char *timestamp;
5327852ebeSDavid van Moolenbroek int e;
5427852ebeSDavid van Moolenbroek e = errno;
55294d1590SErik van der Kouwe timestamp = get_timestamp();
56294d1590SErik van der Kouwe if (errct == 0) fprintf(stderr, "\n");
5727852ebeSDavid van Moolenbroek errno = e;
58294d1590SErik van der Kouwe fprintf(stderr, "[ERROR][%s] (%s Line %d) %s [pid=%d:errno=%d:%s]\n",
5927852ebeSDavid van Moolenbroek timestamp, file, line, msg, getpid(), errno, strerror(errno));
60294d1590SErik van der Kouwe fflush(stderr);
61294d1590SErik van der Kouwe if (timestamp != NULL) {
62294d1590SErik van der Kouwe free(timestamp);
63294d1590SErik van der Kouwe timestamp = NULL;
64294d1590SErik van der Kouwe }
6527852ebeSDavid van Moolenbroek errno = e;
66294d1590SErik van der Kouwe e(7);
67294d1590SErik van der Kouwe }
68294d1590SErik van der Kouwe
69294d1590SErik van der Kouwe #if DEBUG == 1
debug_fl(char * msg,char * file,int line)70294d1590SErik van der Kouwe void debug_fl(char *msg, char *file, int line)
71294d1590SErik van der Kouwe {
72294d1590SErik van der Kouwe char *timestamp;
73294d1590SErik van der Kouwe timestamp = get_timestamp();
74294d1590SErik van der Kouwe fprintf(stdout,"[DEBUG][%s] (%s:%d) %s [pid=%d]\n",
75294d1590SErik van der Kouwe timestamp, __FILE__, __LINE__, msg, getpid());
76294d1590SErik van der Kouwe fflush(stdout);
77294d1590SErik van der Kouwe if (timestamp != NULL) {
78294d1590SErik van der Kouwe free(timestamp);
79294d1590SErik van der Kouwe timestamp = NULL;
80294d1590SErik van der Kouwe }
81294d1590SErik van der Kouwe }
82294d1590SErik van der Kouwe #endif
83294d1590SErik van der Kouwe
test_socket(const struct socket_test_info * info)84294d1590SErik van der Kouwe void test_socket(const struct socket_test_info *info)
85294d1590SErik van der Kouwe {
86294d1590SErik van der Kouwe struct stat statbuf, statbuf2;
87294d1590SErik van der Kouwe int sd, sd2;
88294d1590SErik van der Kouwe int rc;
89294d1590SErik van der Kouwe int i;
90294d1590SErik van der Kouwe
91294d1590SErik van der Kouwe debug("entering test_socket()");
92294d1590SErik van der Kouwe
93294d1590SErik van der Kouwe debug("Test socket() with an unsupported address family");
94294d1590SErik van der Kouwe
95294d1590SErik van der Kouwe errno = 0;
96294d1590SErik van der Kouwe sd = socket(-1, info->type, 0);
97294d1590SErik van der Kouwe if (!(sd == -1 && errno == EAFNOSUPPORT)) {
98294d1590SErik van der Kouwe test_fail("socket");
99294d1590SErik van der Kouwe if (sd != -1) {
100294d1590SErik van der Kouwe CLOSE(sd);
101294d1590SErik van der Kouwe }
102294d1590SErik van der Kouwe }
103294d1590SErik van der Kouwe
104294d1590SErik van der Kouwe debug("Test socket() with all available FDs open by this process");
105294d1590SErik van der Kouwe
106294d1590SErik van der Kouwe for (i = 3; i < getdtablesize(); i++) {
107294d1590SErik van der Kouwe rc = open("/dev/null", O_RDONLY);
108294d1590SErik van der Kouwe if (rc == -1) {
109294d1590SErik van der Kouwe test_fail("we couldn't open /dev/null for read");
110294d1590SErik van der Kouwe }
111294d1590SErik van der Kouwe }
112294d1590SErik van der Kouwe
113294d1590SErik van der Kouwe errno = 0;
114294d1590SErik van der Kouwe sd = socket(info->domain, info->type, 0);
115294d1590SErik van der Kouwe if (!(sd == -1 && errno == EMFILE)) {
116294d1590SErik van der Kouwe test_fail("socket() call with all fds open should fail");
117294d1590SErik van der Kouwe if (sd != -1) {
118294d1590SErik van der Kouwe CLOSE(sd);
119294d1590SErik van der Kouwe }
120294d1590SErik van der Kouwe }
121294d1590SErik van der Kouwe
122294d1590SErik van der Kouwe for (i = 3; i < getdtablesize(); i++) {
123294d1590SErik van der Kouwe CLOSE(i);
124294d1590SErik van der Kouwe }
125294d1590SErik van der Kouwe
126294d1590SErik van der Kouwe debug("Test socket() with an mismatched protocol");
127294d1590SErik van der Kouwe
128294d1590SErik van der Kouwe errno = 0;
129294d1590SErik van der Kouwe sd = socket(info->domain, info->type, 4);
130294d1590SErik van der Kouwe if (!(sd == -1 && errno == EPROTONOSUPPORT)) {
131294d1590SErik van der Kouwe test_fail("socket() should fail with errno = EPROTONOSUPPORT");
132294d1590SErik van der Kouwe if (sd != -1) {
133294d1590SErik van der Kouwe CLOSE(sd);
134294d1590SErik van der Kouwe }
135294d1590SErik van der Kouwe }
136294d1590SErik van der Kouwe
137294d1590SErik van der Kouwe debug("Test socket() success");
138294d1590SErik van der Kouwe
139294d1590SErik van der Kouwe /*
140294d1590SErik van der Kouwe * open 2 sockets at once and *then* close them.
141294d1590SErik van der Kouwe * This will test that /dev/uds is cloning properly.
142294d1590SErik van der Kouwe */
143294d1590SErik van der Kouwe
144294d1590SErik van der Kouwe SOCKET(sd, info->domain, info->type, 0);
145294d1590SErik van der Kouwe SOCKET(sd2, info->domain, info->type, 0);
146294d1590SErik van der Kouwe
147294d1590SErik van der Kouwe rc = fstat(sd, &statbuf);
148294d1590SErik van der Kouwe if (rc == -1) {
149294d1590SErik van der Kouwe test_fail("fstat failed on sd");
150294d1590SErik van der Kouwe }
151294d1590SErik van der Kouwe
152294d1590SErik van der Kouwe rc = fstat(sd2, &statbuf2);
153294d1590SErik van der Kouwe if (rc == -1) {
154294d1590SErik van der Kouwe test_fail("fstat failed on sd2");
155294d1590SErik van der Kouwe }
156294d1590SErik van der Kouwe
157294d1590SErik van der Kouwe
158294d1590SErik van der Kouwe if (statbuf.st_dev == statbuf2.st_dev) {
159294d1590SErik van der Kouwe test_fail("/dev/uds isn't being cloned");
160294d1590SErik van der Kouwe }
161294d1590SErik van der Kouwe
162294d1590SErik van der Kouwe CLOSE(sd2);
163294d1590SErik van der Kouwe CLOSE(sd);
164294d1590SErik van der Kouwe
165294d1590SErik van der Kouwe debug("leaving test_socket()");
166294d1590SErik van der Kouwe }
167294d1590SErik van der Kouwe
test_getsockname(const struct socket_test_info * info)168294d1590SErik van der Kouwe void test_getsockname(const struct socket_test_info *info)
169294d1590SErik van der Kouwe {
170294d1590SErik van der Kouwe int sd;
171294d1590SErik van der Kouwe int rc;
172*ad920fc4SDavid van Moolenbroek int on;
173294d1590SErik van der Kouwe struct sockaddr_storage sock_addr;
174294d1590SErik van der Kouwe socklen_t sock_addr_len;
175294d1590SErik van der Kouwe
176294d1590SErik van der Kouwe SOCKET(sd, info->domain, info->type, 0);
177*ad920fc4SDavid van Moolenbroek
178*ad920fc4SDavid van Moolenbroek on = 1;
179*ad920fc4SDavid van Moolenbroek (void)setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
180*ad920fc4SDavid van Moolenbroek
181294d1590SErik van der Kouwe rc = bind(sd, info->serveraddr, info->serveraddrlen);
182294d1590SErik van der Kouwe if (rc == -1) {
183294d1590SErik van der Kouwe test_fail("bind() should have worked");
184294d1590SErik van der Kouwe }
185294d1590SErik van der Kouwe
186294d1590SErik van der Kouwe debug("Test getsockname() success");
187294d1590SErik van der Kouwe
188294d1590SErik van der Kouwe memset(&sock_addr, '\0', sizeof(sock_addr));
189294d1590SErik van der Kouwe sock_addr_len = sizeof(sock_addr);
190294d1590SErik van der Kouwe
191294d1590SErik van der Kouwe rc = getsockname(sd, (struct sockaddr *) &sock_addr, &sock_addr_len);
192294d1590SErik van der Kouwe if (rc == -1) {
193294d1590SErik van der Kouwe test_fail("getsockname() should have worked");
194294d1590SErik van der Kouwe }
195294d1590SErik van der Kouwe
196294d1590SErik van der Kouwe info->callback_check_sockaddr((struct sockaddr *) &sock_addr,
197294d1590SErik van der Kouwe sock_addr_len, "getsockname", 1);
198294d1590SErik van der Kouwe
199294d1590SErik van der Kouwe CLOSE(sd);
200294d1590SErik van der Kouwe }
201294d1590SErik van der Kouwe
test_bind(const struct socket_test_info * info)202294d1590SErik van der Kouwe void test_bind(const struct socket_test_info *info)
203294d1590SErik van der Kouwe {
204294d1590SErik van der Kouwe struct sockaddr_storage sock_addr;
205294d1590SErik van der Kouwe socklen_t sock_addr_len;
206294d1590SErik van der Kouwe int sd;
207294d1590SErik van der Kouwe int sd2;
208294d1590SErik van der Kouwe int rc;
209*ad920fc4SDavid van Moolenbroek int on;
210294d1590SErik van der Kouwe
211294d1590SErik van der Kouwe debug("entering test_bind()");
212294d1590SErik van der Kouwe info->callback_cleanup();
213294d1590SErik van der Kouwe
214294d1590SErik van der Kouwe debug("Test bind() success");
215294d1590SErik van der Kouwe
216294d1590SErik van der Kouwe SOCKET(sd, info->domain, info->type, 0);
217*ad920fc4SDavid van Moolenbroek
218*ad920fc4SDavid van Moolenbroek on = 1;
219*ad920fc4SDavid van Moolenbroek (void)setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
220*ad920fc4SDavid van Moolenbroek
221294d1590SErik van der Kouwe rc = bind(sd, info->serveraddr, info->serveraddrlen);
222294d1590SErik van der Kouwe if (rc == -1) {
223294d1590SErik van der Kouwe test_fail("bind() should have worked");
224294d1590SErik van der Kouwe }
225294d1590SErik van der Kouwe
226294d1590SErik van der Kouwe debug("Test getsockname() success");
227294d1590SErik van der Kouwe
228294d1590SErik van der Kouwe memset(&sock_addr, '\0', sizeof(sock_addr));
229294d1590SErik van der Kouwe sock_addr_len = sizeof(sock_addr);
230294d1590SErik van der Kouwe
231294d1590SErik van der Kouwe rc = getsockname(sd, (struct sockaddr *) &sock_addr, &sock_addr_len);
232294d1590SErik van der Kouwe if (rc == -1) {
233294d1590SErik van der Kouwe test_fail("getsockname() should have worked");
234294d1590SErik van der Kouwe }
235294d1590SErik van der Kouwe
236294d1590SErik van der Kouwe info->callback_check_sockaddr((struct sockaddr *) &sock_addr,
237294d1590SErik van der Kouwe sock_addr_len, "getsockname", 1);
238294d1590SErik van der Kouwe
239294d1590SErik van der Kouwe debug("Test bind() with a address that has already been bind()'d");
240294d1590SErik van der Kouwe
241294d1590SErik van der Kouwe SOCKET(sd2, info->domain, info->type, 0);
242294d1590SErik van der Kouwe errno = 0;
243294d1590SErik van der Kouwe rc = bind(sd2, info->serveraddr, info->serveraddrlen);
244*ad920fc4SDavid van Moolenbroek if (!((rc == -1) && (errno == EADDRINUSE))) {
245294d1590SErik van der Kouwe test_fail("bind() should have failed with EADDRINUSE");
246294d1590SErik van der Kouwe }
247294d1590SErik van der Kouwe CLOSE(sd2);
248294d1590SErik van der Kouwe CLOSE(sd);
249294d1590SErik van der Kouwe info->callback_cleanup();
250294d1590SErik van der Kouwe
251294d1590SErik van der Kouwe debug("Test bind() with a NULL address");
252294d1590SErik van der Kouwe
253294d1590SErik van der Kouwe SOCKET(sd, info->domain, info->type, 0);
254294d1590SErik van der Kouwe errno = 0;
255294d1590SErik van der Kouwe rc = bind(sd, (struct sockaddr *) NULL,
256294d1590SErik van der Kouwe sizeof(struct sockaddr_storage));
257294d1590SErik van der Kouwe if (!((rc == -1) && (errno == EFAULT))) {
258294d1590SErik van der Kouwe test_fail("bind() should have failed with EFAULT");
259294d1590SErik van der Kouwe }
260294d1590SErik van der Kouwe CLOSE(sd);
261294d1590SErik van der Kouwe
262294d1590SErik van der Kouwe debug("leaving test_bind()");
263294d1590SErik van der Kouwe }
264294d1590SErik van der Kouwe
test_listen(const struct socket_test_info * info)265294d1590SErik van der Kouwe void test_listen(const struct socket_test_info *info)
266294d1590SErik van der Kouwe {
267294d1590SErik van der Kouwe int rc;
268294d1590SErik van der Kouwe
269294d1590SErik van der Kouwe debug("entering test_listen()");
270294d1590SErik van der Kouwe
271294d1590SErik van der Kouwe debug("Test listen() with a bad file descriptor");
272294d1590SErik van der Kouwe
273294d1590SErik van der Kouwe errno = 0;
274294d1590SErik van der Kouwe rc = listen(-1, 0);
275294d1590SErik van der Kouwe if (!(rc == -1 && errno == EBADF)) {
276294d1590SErik van der Kouwe test_fail("listen(-1, 0) should have failed");
277294d1590SErik van der Kouwe }
278294d1590SErik van der Kouwe
279294d1590SErik van der Kouwe debug("Test listen() with a non-socket file descriptor");
280294d1590SErik van der Kouwe
281294d1590SErik van der Kouwe errno = 0;
282294d1590SErik van der Kouwe rc = listen(0, 0);
283294d1590SErik van der Kouwe /* Test on errno disabled here: there's currently no telling what this
284294d1590SErik van der Kouwe * will return. POSIX says it should be ENOTSOCK, MINIX3 libc returns
285294d1590SErik van der Kouwe * ENOSYS, and we used to test for ENOTTY here..
286294d1590SErik van der Kouwe */
287294d1590SErik van der Kouwe if (!(rc == -1)) {
288294d1590SErik van der Kouwe test_fail("listen(0, 0) should have failed");
289294d1590SErik van der Kouwe }
290294d1590SErik van der Kouwe
291294d1590SErik van der Kouwe debug("leaving test_listen()");
292294d1590SErik van der Kouwe }
293294d1590SErik van der Kouwe
test_shutdown(const struct socket_test_info * info)294294d1590SErik van der Kouwe void test_shutdown(const struct socket_test_info *info)
295294d1590SErik van der Kouwe {
296294d1590SErik van der Kouwe int how[3] = { SHUT_RD, SHUT_WR, SHUT_RDWR };
297294d1590SErik van der Kouwe int sd;
298294d1590SErik van der Kouwe int rc;
299294d1590SErik van der Kouwe int i;
300294d1590SErik van der Kouwe
301294d1590SErik van der Kouwe debug("entering test_shutdown()");
302294d1590SErik van der Kouwe
303294d1590SErik van der Kouwe /* test for each direction (read, write, read-write) */
304294d1590SErik van der Kouwe for (i = 0; i < 3; i++) {
305294d1590SErik van der Kouwe
306294d1590SErik van der Kouwe debug("test shutdown() with an invalid descriptor");
307294d1590SErik van der Kouwe
308294d1590SErik van der Kouwe errno = 0;
309294d1590SErik van der Kouwe rc = shutdown(-1, how[i]);
310*ad920fc4SDavid van Moolenbroek if (!(rc == -1 && errno == EBADF)) {
311294d1590SErik van der Kouwe test_fail("shutdown(-1, how[i]) should have failed");
312294d1590SErik van der Kouwe }
313294d1590SErik van der Kouwe
314294d1590SErik van der Kouwe debug("test shutdown() with a non-socket descriptor");
315294d1590SErik van der Kouwe
316294d1590SErik van der Kouwe errno = 0;
317294d1590SErik van der Kouwe rc = shutdown(0, how[i]);
318*ad920fc4SDavid van Moolenbroek if (!(rc == -1 && errno == ENOTSOCK)) {
319c38dbb97SDavid van Moolenbroek test_fail("shutdown() should have failed with "
320c38dbb97SDavid van Moolenbroek "ENOTSOCK");
321294d1590SErik van der Kouwe }
322294d1590SErik van der Kouwe
323294d1590SErik van der Kouwe debug("test shutdown() with a socket that is not connected");
324294d1590SErik van der Kouwe
325294d1590SErik van der Kouwe SOCKET(sd, info->domain, info->type, 0);
326294d1590SErik van der Kouwe errno = 0;
327294d1590SErik van der Kouwe rc = shutdown(sd, how[i]);
328*ad920fc4SDavid van Moolenbroek if (rc != 0 && !(rc == -1 && errno == ENOTCONN)) {
329294d1590SErik van der Kouwe test_fail("shutdown() should have failed");
330294d1590SErik van der Kouwe }
331294d1590SErik van der Kouwe CLOSE(sd);
332294d1590SErik van der Kouwe }
333294d1590SErik van der Kouwe
334294d1590SErik van der Kouwe SOCKET(sd, info->domain, info->type, 0);
335294d1590SErik van der Kouwe errno = 0;
336294d1590SErik van der Kouwe rc = shutdown(sd, -1);
337*ad920fc4SDavid van Moolenbroek if (!(rc == -1 && errno == EINVAL)) {
33827852ebeSDavid van Moolenbroek test_fail("shutdown(sd, -1) should have failed with EINVAL");
339294d1590SErik van der Kouwe }
340294d1590SErik van der Kouwe CLOSE(sd);
341294d1590SErik van der Kouwe
342294d1590SErik van der Kouwe debug("leaving test_shutdown()");
343294d1590SErik van der Kouwe }
344294d1590SErik van der Kouwe
test_close(const struct socket_test_info * info)345294d1590SErik van der Kouwe void test_close(const struct socket_test_info *info)
346294d1590SErik van der Kouwe {
347294d1590SErik van der Kouwe int sd, sd2;
348*ad920fc4SDavid van Moolenbroek int rc, i, on;
349294d1590SErik van der Kouwe
350294d1590SErik van der Kouwe debug("entering test_close()");
351294d1590SErik van der Kouwe
352294d1590SErik van der Kouwe info->callback_cleanup();
353294d1590SErik van der Kouwe
354294d1590SErik van der Kouwe debug("Test close() success");
355294d1590SErik van der Kouwe
356294d1590SErik van der Kouwe SOCKET(sd, info->domain, info->type, 0);
357*ad920fc4SDavid van Moolenbroek
358*ad920fc4SDavid van Moolenbroek on = 1;
359*ad920fc4SDavid van Moolenbroek (void)setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
360*ad920fc4SDavid van Moolenbroek
361294d1590SErik van der Kouwe rc = bind(sd, info->serveraddr, info->serveraddrlen);
362294d1590SErik van der Kouwe if (rc != 0) {
363294d1590SErik van der Kouwe test_fail("bind() should have worked");
364294d1590SErik van der Kouwe }
365294d1590SErik van der Kouwe
366294d1590SErik van der Kouwe CLOSE(sd);
367294d1590SErik van der Kouwe
368294d1590SErik van der Kouwe debug("Close an already closed file descriptor");
369294d1590SErik van der Kouwe
370294d1590SErik van der Kouwe errno = 0;
371294d1590SErik van der Kouwe rc = close(sd);
372294d1590SErik van der Kouwe if (!(rc == -1 && errno == EBADF)) {
373294d1590SErik van der Kouwe test_fail("close(sd) should have failed with EBADF");
374294d1590SErik van der Kouwe }
375294d1590SErik van der Kouwe
376294d1590SErik van der Kouwe info->callback_cleanup();
377294d1590SErik van der Kouwe
378294d1590SErik van der Kouwe debug("dup()'ing a file descriptor and closing both should work");
379294d1590SErik van der Kouwe
380294d1590SErik van der Kouwe SOCKET(sd, info->domain, info->type, 0);
381*ad920fc4SDavid van Moolenbroek
382*ad920fc4SDavid van Moolenbroek on = 1;
383*ad920fc4SDavid van Moolenbroek (void)setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
384*ad920fc4SDavid van Moolenbroek
385294d1590SErik van der Kouwe rc = bind(sd, info->serveraddr, info->serveraddrlen);
386294d1590SErik van der Kouwe if (rc != 0) {
387294d1590SErik van der Kouwe test_fail("bind() should have worked");
388294d1590SErik van der Kouwe }
389294d1590SErik van der Kouwe
390294d1590SErik van der Kouwe errno = 0;
391294d1590SErik van der Kouwe sd2 = dup(sd);
392294d1590SErik van der Kouwe if (sd2 == -1) {
393294d1590SErik van der Kouwe test_fail("dup(sd) should have worked");
394294d1590SErik van der Kouwe } else {
395294d1590SErik van der Kouwe CLOSE(sd2);
396294d1590SErik van der Kouwe CLOSE(sd);
397294d1590SErik van der Kouwe }
398294d1590SErik van der Kouwe
399294d1590SErik van der Kouwe info->callback_cleanup();
400294d1590SErik van der Kouwe
401294d1590SErik van der Kouwe /* Create and close a socket a bunch of times.
402294d1590SErik van der Kouwe * If the implementation doesn't properly free the
403294d1590SErik van der Kouwe * socket during close(), eventually socket() will
404294d1590SErik van der Kouwe * fail when the internal descriptor table is full.
405294d1590SErik van der Kouwe */
406294d1590SErik van der Kouwe for (i = 0; i < 1024; i++) {
407294d1590SErik van der Kouwe SOCKET(sd, info->domain, info->type, 0);
408294d1590SErik van der Kouwe CLOSE(sd);
409294d1590SErik van der Kouwe }
410294d1590SErik van der Kouwe
411294d1590SErik van der Kouwe debug("leaving test_close()");
412294d1590SErik van der Kouwe }
413294d1590SErik van der Kouwe
test_sockopts(const struct socket_test_info * info)414294d1590SErik van der Kouwe void test_sockopts(const struct socket_test_info *info)
415294d1590SErik van der Kouwe {
416294d1590SErik van der Kouwe int i;
417294d1590SErik van der Kouwe int rc;
418294d1590SErik van der Kouwe int sd;
419294d1590SErik van der Kouwe int option_value;
420294d1590SErik van der Kouwe socklen_t option_len;
421294d1590SErik van der Kouwe
422294d1590SErik van der Kouwe debug("entering test_sockopts()");
423294d1590SErik van der Kouwe
424294d1590SErik van der Kouwe for (i = 0; i < info->typecount; i++) {
425294d1590SErik van der Kouwe
426294d1590SErik van der Kouwe SOCKET(sd, info->domain, info->types[i], 0);
427294d1590SErik van der Kouwe
428294d1590SErik van der Kouwe debug("Test setsockopt() works");
429294d1590SErik van der Kouwe
430294d1590SErik van der Kouwe option_value = 0;
431294d1590SErik van der Kouwe option_len = sizeof(option_value);
432294d1590SErik van der Kouwe errno = 0;
433294d1590SErik van der Kouwe rc = getsockopt(sd, SOL_SOCKET, SO_TYPE, &option_value,
434294d1590SErik van der Kouwe &option_len);
435294d1590SErik van der Kouwe if (rc != 0) {
436294d1590SErik van der Kouwe test_fail("setsockopt() should have worked");
437294d1590SErik van der Kouwe }
438294d1590SErik van der Kouwe
439294d1590SErik van der Kouwe if (option_value != info->types[i]) {
440294d1590SErik van der Kouwe test_fail("SO_TYPE didn't seem to work.");
441294d1590SErik van der Kouwe }
442294d1590SErik van der Kouwe
443294d1590SErik van der Kouwe CLOSE(sd);
444294d1590SErik van der Kouwe }
445294d1590SErik van der Kouwe
446294d1590SErik van der Kouwe SOCKET(sd, info->domain, info->type, 0);
447294d1590SErik van der Kouwe
448294d1590SErik van der Kouwe debug("Test setsockopt() works");
449294d1590SErik van der Kouwe
450294d1590SErik van der Kouwe option_value = 0;
451294d1590SErik van der Kouwe option_len = sizeof(option_value);
452294d1590SErik van der Kouwe errno = 0;
453294d1590SErik van der Kouwe rc = getsockopt(sd, SOL_SOCKET, SO_SNDBUF, &option_value, &option_len);
454294d1590SErik van der Kouwe
455294d1590SErik van der Kouwe if (info->expected_sndbuf >= 0 &&
456*ad920fc4SDavid van Moolenbroek option_value != info->expected_sndbuf) {
457294d1590SErik van der Kouwe test_fail("SO_SNDBUF didn't seem to work.");
458294d1590SErik van der Kouwe }
459294d1590SErik van der Kouwe
460294d1590SErik van der Kouwe CLOSE(sd);
461294d1590SErik van der Kouwe
462294d1590SErik van der Kouwe
463294d1590SErik van der Kouwe SOCKET(sd, info->domain, info->type, 0);
464294d1590SErik van der Kouwe
465294d1590SErik van der Kouwe debug("Test setsockopt() works");
466294d1590SErik van der Kouwe
467294d1590SErik van der Kouwe option_value = 0;
468294d1590SErik van der Kouwe option_len = sizeof(option_value);
469294d1590SErik van der Kouwe errno = 0;
470294d1590SErik van der Kouwe rc = getsockopt(sd, SOL_SOCKET, SO_RCVBUF, &option_value, &option_len);
471*ad920fc4SDavid van Moolenbroek if (rc != 0) {
472294d1590SErik van der Kouwe test_fail("getsockopt() should have worked");
473294d1590SErik van der Kouwe }
474294d1590SErik van der Kouwe
475294d1590SErik van der Kouwe if (info->expected_rcvbuf >= 0 &&
476*ad920fc4SDavid van Moolenbroek option_value != info->expected_rcvbuf) {
477294d1590SErik van der Kouwe test_fail("SO_RCVBUF didn't seem to work.");
478294d1590SErik van der Kouwe }
479294d1590SErik van der Kouwe
480294d1590SErik van der Kouwe CLOSE(sd);
481294d1590SErik van der Kouwe
482294d1590SErik van der Kouwe
483294d1590SErik van der Kouwe debug("leaving test_sockopts()");
484294d1590SErik van der Kouwe }
485294d1590SErik van der Kouwe
test_read(const struct socket_test_info * info)486294d1590SErik van der Kouwe void test_read(const struct socket_test_info *info)
487294d1590SErik van der Kouwe {
488294d1590SErik van der Kouwe int rc;
489294d1590SErik van der Kouwe int fd;
490294d1590SErik van der Kouwe char buf[BUFSIZE];
491294d1590SErik van der Kouwe
492294d1590SErik van der Kouwe debug("entering test_read()");
493294d1590SErik van der Kouwe
494294d1590SErik van der Kouwe errno = 0;
495294d1590SErik van der Kouwe rc = read(-1, buf, sizeof(buf));
496294d1590SErik van der Kouwe if (!(rc == -1 && errno == EBADF)) {
497294d1590SErik van der Kouwe test_fail("read() should have failed with EBADF");
498294d1590SErik van der Kouwe }
499294d1590SErik van der Kouwe
500294d1590SErik van der Kouwe fd = open("/tmp", O_RDONLY);
501294d1590SErik van der Kouwe if (fd == -1) {
502294d1590SErik van der Kouwe test_fail("open(\"/tmp\", O_RDONLY) should have worked");
503294d1590SErik van der Kouwe }
504294d1590SErik van der Kouwe
505294d1590SErik van der Kouwe CLOSE(fd);
506294d1590SErik van der Kouwe
507294d1590SErik van der Kouwe debug("leaving test_read()");
508294d1590SErik van der Kouwe }
509294d1590SErik van der Kouwe
test_write(const struct socket_test_info * info)510294d1590SErik van der Kouwe void test_write(const struct socket_test_info *info)
511294d1590SErik van der Kouwe {
512294d1590SErik van der Kouwe int rc;
513294d1590SErik van der Kouwe char buf[BUFSIZE];
514294d1590SErik van der Kouwe
515294d1590SErik van der Kouwe debug("entering test_write()");
516294d1590SErik van der Kouwe
517294d1590SErik van der Kouwe errno = 0;
518294d1590SErik van der Kouwe rc = write(-1, buf, sizeof(buf));
519294d1590SErik van der Kouwe if (!(rc == -1 && errno == EBADF)) {
520294d1590SErik van der Kouwe test_fail("write() should have failed with EBADF");
521294d1590SErik van der Kouwe }
522294d1590SErik van der Kouwe
523294d1590SErik van der Kouwe debug("leaving test_write()");
524294d1590SErik van der Kouwe }
525294d1590SErik van der Kouwe
test_dup(const struct socket_test_info * info)526294d1590SErik van der Kouwe void test_dup(const struct socket_test_info *info)
527294d1590SErik van der Kouwe {
528294d1590SErik van der Kouwe struct stat info1;
529294d1590SErik van der Kouwe struct stat info2;
530294d1590SErik van der Kouwe int sd, sd2;
531294d1590SErik van der Kouwe int rc;
532*ad920fc4SDavid van Moolenbroek int i, on;
533294d1590SErik van der Kouwe
534294d1590SErik van der Kouwe debug("entering test_dup()");
535294d1590SErik van der Kouwe
536294d1590SErik van der Kouwe info->callback_cleanup();
537294d1590SErik van der Kouwe
538294d1590SErik van der Kouwe debug("Test dup()");
539294d1590SErik van der Kouwe
540294d1590SErik van der Kouwe SOCKET(sd, info->domain, info->type, 0);
541*ad920fc4SDavid van Moolenbroek
542*ad920fc4SDavid van Moolenbroek on = 1;
543*ad920fc4SDavid van Moolenbroek (void)setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
544*ad920fc4SDavid van Moolenbroek
545294d1590SErik van der Kouwe rc = bind(sd, info->serveraddr, info->serveraddrlen);
546294d1590SErik van der Kouwe if (rc != 0) {
547294d1590SErik van der Kouwe test_fail("bind() should have worked");
548294d1590SErik van der Kouwe }
549294d1590SErik van der Kouwe
550294d1590SErik van der Kouwe errno = 0;
551294d1590SErik van der Kouwe sd2 = dup(sd);
552294d1590SErik van der Kouwe if (sd2 == -1) {
553294d1590SErik van der Kouwe test_fail("dup(sd) should have worked");
554294d1590SErik van der Kouwe }
555294d1590SErik van der Kouwe
556294d1590SErik van der Kouwe rc = fstat(sd, &info1);
557294d1590SErik van der Kouwe if (rc == -1) {
558294d1590SErik van der Kouwe test_fail("fstat(fd, &info1) failed");
559294d1590SErik van der Kouwe }
560294d1590SErik van der Kouwe
561294d1590SErik van der Kouwe rc = fstat(sd2, &info2);
562294d1590SErik van der Kouwe if (rc == -1) {
563294d1590SErik van der Kouwe test_fail("fstat(sd, &info2) failed");
564294d1590SErik van der Kouwe }
565294d1590SErik van der Kouwe
566294d1590SErik van der Kouwe if (info1.st_ino != info2.st_ino) {
567294d1590SErik van der Kouwe test_fail("dup() failed info1.st_ino != info2.st_ino");
568294d1590SErik van der Kouwe }
569294d1590SErik van der Kouwe
570294d1590SErik van der Kouwe CLOSE(sd);
571294d1590SErik van der Kouwe CLOSE(sd2);
572294d1590SErik van der Kouwe
573294d1590SErik van der Kouwe debug("Test dup() with a closed socket");
574294d1590SErik van der Kouwe
575294d1590SErik van der Kouwe errno = 0;
576294d1590SErik van der Kouwe rc = dup(sd);
577294d1590SErik van der Kouwe if (!(rc == -1 && errno == EBADF)) {
578294d1590SErik van der Kouwe test_fail("dup(sd) on a closed socket shouldn't have worked");
579294d1590SErik van der Kouwe }
580294d1590SErik van der Kouwe
581294d1590SErik van der Kouwe debug("Test dup() with socket descriptor of -1");
582294d1590SErik van der Kouwe
583294d1590SErik van der Kouwe errno = 0;
584294d1590SErik van der Kouwe rc = dup(-1);
585294d1590SErik van der Kouwe if (!(rc == -1 && errno == EBADF)) {
586294d1590SErik van der Kouwe test_fail("dup(-1) shouldn't have worked");
587294d1590SErik van der Kouwe }
588294d1590SErik van der Kouwe
589294d1590SErik van der Kouwe debug("Test dup() when all of the file descriptors are taken");
590294d1590SErik van der Kouwe
591294d1590SErik van der Kouwe SOCKET(sd, info->domain, info->type, 0);
592294d1590SErik van der Kouwe
593294d1590SErik van der Kouwe for (i = 4; i < getdtablesize(); i++) {
594294d1590SErik van der Kouwe rc = open("/dev/null", O_RDONLY);
595294d1590SErik van der Kouwe if (rc == -1) {
596294d1590SErik van der Kouwe test_fail("we couldn't open /dev/null for read");
597294d1590SErik van der Kouwe }
598294d1590SErik van der Kouwe }
599294d1590SErik van der Kouwe
600294d1590SErik van der Kouwe errno = 0;
601294d1590SErik van der Kouwe sd2 = dup(sd);
602294d1590SErik van der Kouwe if (!(sd2 == -1 && errno == EMFILE)) {
603294d1590SErik van der Kouwe test_fail("dup(sd) should have failed with errno = EMFILE");
604294d1590SErik van der Kouwe }
605294d1590SErik van der Kouwe
606294d1590SErik van der Kouwe for (i = 3; i < getdtablesize(); i++) {
607294d1590SErik van der Kouwe CLOSE(i);
608294d1590SErik van der Kouwe }
609294d1590SErik van der Kouwe
610294d1590SErik van der Kouwe info->callback_cleanup();
611294d1590SErik van der Kouwe
612294d1590SErik van der Kouwe debug("leaving test_dup()");
613294d1590SErik van der Kouwe }
614294d1590SErik van der Kouwe
test_dup2(const struct socket_test_info * info)615294d1590SErik van der Kouwe void test_dup2(const struct socket_test_info *info)
616294d1590SErik van der Kouwe {
617294d1590SErik van der Kouwe struct stat info1;
618294d1590SErik van der Kouwe struct stat info2;
619294d1590SErik van der Kouwe int sd;
620294d1590SErik van der Kouwe int fd;
621294d1590SErik van der Kouwe int rc;
622*ad920fc4SDavid van Moolenbroek int on;
623294d1590SErik van der Kouwe
624294d1590SErik van der Kouwe debug("entering test_dup2()");
625294d1590SErik van der Kouwe info->callback_cleanup();
626294d1590SErik van der Kouwe
627294d1590SErik van der Kouwe SOCKET(sd, info->domain, info->type, 0);
628294d1590SErik van der Kouwe
629*ad920fc4SDavid van Moolenbroek on = 1;
630*ad920fc4SDavid van Moolenbroek (void)setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
631*ad920fc4SDavid van Moolenbroek
632294d1590SErik van der Kouwe rc = bind(sd, info->serveraddr, info->serveraddrlen);
633294d1590SErik van der Kouwe if (rc != 0) {
634294d1590SErik van der Kouwe test_fail("bind() should have worked");
635294d1590SErik van der Kouwe }
636294d1590SErik van der Kouwe
637294d1590SErik van der Kouwe fd = open("/dev/null", O_RDONLY);
638294d1590SErik van der Kouwe if (fd == -1) {
639294d1590SErik van der Kouwe test_fail("open(\"/dev/null\", O_RDONLY) failed");
640294d1590SErik van der Kouwe }
641294d1590SErik van der Kouwe
642294d1590SErik van der Kouwe fd = dup2(sd, fd);
643294d1590SErik van der Kouwe if (fd == -1) {
644294d1590SErik van der Kouwe test_fail("dup2(sd, fd) failed.");
645294d1590SErik van der Kouwe }
646294d1590SErik van der Kouwe
647294d1590SErik van der Kouwe memset(&info1, '\0', sizeof(struct stat));
648294d1590SErik van der Kouwe memset(&info2, '\0', sizeof(struct stat));
649294d1590SErik van der Kouwe
650294d1590SErik van der Kouwe rc = fstat(fd, &info1);
651294d1590SErik van der Kouwe if (rc == -1) {
652294d1590SErik van der Kouwe test_fail("fstat(fd, &info1) failed");
653294d1590SErik van der Kouwe }
654294d1590SErik van der Kouwe
655294d1590SErik van der Kouwe rc = fstat(sd, &info2);
656294d1590SErik van der Kouwe if (rc == -1) {
657294d1590SErik van der Kouwe test_fail("fstat(sd, &info2) failed");
658294d1590SErik van der Kouwe }
659294d1590SErik van der Kouwe
660294d1590SErik van der Kouwe if (!(info1.st_ino == info2.st_ino &&
661294d1590SErik van der Kouwe major(info1.st_dev) == major(info2.st_dev) &&
662294d1590SErik van der Kouwe minor(info1.st_dev) == minor(info2.st_dev))) {
663294d1590SErik van der Kouwe
664294d1590SErik van der Kouwe test_fail("dup2() failed");
665294d1590SErik van der Kouwe }
666294d1590SErik van der Kouwe
667294d1590SErik van der Kouwe CLOSE(fd);
668294d1590SErik van der Kouwe CLOSE(sd);
669294d1590SErik van der Kouwe
670294d1590SErik van der Kouwe info->callback_cleanup();
671294d1590SErik van der Kouwe debug("leaving test_dup2()");
672294d1590SErik van der Kouwe
673294d1590SErik van der Kouwe }
674294d1590SErik van der Kouwe
675294d1590SErik van der Kouwe /*
676294d1590SErik van der Kouwe * A toupper() server. This toy server converts a string to upper case.
677294d1590SErik van der Kouwe */
test_xfer_server(const struct socket_test_info * info,pid_t pid)678294d1590SErik van der Kouwe static void test_xfer_server(const struct socket_test_info *info, pid_t pid)
679294d1590SErik van der Kouwe {
680294d1590SErik van der Kouwe int i;
681294d1590SErik van der Kouwe struct timeval tv;
682294d1590SErik van der Kouwe fd_set readfds;
683294d1590SErik van der Kouwe int status;
684294d1590SErik van der Kouwe int rc;
685294d1590SErik van der Kouwe int sd;
686*ad920fc4SDavid van Moolenbroek int on;
687294d1590SErik van der Kouwe unsigned char buf[BUFSIZE];
688294d1590SErik van der Kouwe socklen_t client_addr_size;
689294d1590SErik van der Kouwe int client_sd;
690294d1590SErik van der Kouwe struct sockaddr_storage client_addr;
691294d1590SErik van der Kouwe
692294d1590SErik van der Kouwe status = 0;
693294d1590SErik van der Kouwe rc = 0;
694294d1590SErik van der Kouwe sd = 0;
695294d1590SErik van der Kouwe client_sd = 0;
696294d1590SErik van der Kouwe client_addr_size = sizeof(struct sockaddr_storage);
697294d1590SErik van der Kouwe
698294d1590SErik van der Kouwe memset(&buf, '\0', sizeof(buf));
699294d1590SErik van der Kouwe memset(&client_addr, '\0', sizeof(client_addr));
700294d1590SErik van der Kouwe
701294d1590SErik van der Kouwe SOCKET(sd, info->domain, info->type, 0);
702294d1590SErik van der Kouwe
703*ad920fc4SDavid van Moolenbroek on = 1;
704*ad920fc4SDavid van Moolenbroek (void)setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
705*ad920fc4SDavid van Moolenbroek
706294d1590SErik van der Kouwe rc = bind(sd, info->serveraddr, info->serveraddrlen);
707294d1590SErik van der Kouwe if (rc == -1) {
708294d1590SErik van der Kouwe test_fail("bind() should have worked");
709294d1590SErik van der Kouwe }
710294d1590SErik van der Kouwe
711294d1590SErik van der Kouwe rc = listen(sd, 8);
712294d1590SErik van der Kouwe if (rc == -1) {
713294d1590SErik van der Kouwe test_fail("listen(sd, 8) should have worked");
714294d1590SErik van der Kouwe }
715294d1590SErik van der Kouwe
716294d1590SErik van der Kouwe /* we're ready for connections, time to tell the client to start
717294d1590SErik van der Kouwe * the test
718294d1590SErik van der Kouwe */
719294d1590SErik van der Kouwe kill(pid, SIGUSR1);
720294d1590SErik van der Kouwe
721294d1590SErik van der Kouwe tv.tv_sec = 10;
722294d1590SErik van der Kouwe tv.tv_usec = 0;
723294d1590SErik van der Kouwe
724294d1590SErik van der Kouwe FD_ZERO(&readfds);
725294d1590SErik van der Kouwe FD_SET(sd, &readfds);
726294d1590SErik van der Kouwe
727294d1590SErik van der Kouwe /* use select() in case the client is really broken and never
728294d1590SErik van der Kouwe * attempts to connect (we don't want to block on accept()
729294d1590SErik van der Kouwe * forever).
730294d1590SErik van der Kouwe */
731294d1590SErik van der Kouwe rc = select(sd + 1, &readfds, NULL, NULL, &tv);
732294d1590SErik van der Kouwe if (rc == -1) {
733294d1590SErik van der Kouwe test_fail("[server] select() should not have failed");
734294d1590SErik van der Kouwe }
735294d1590SErik van der Kouwe
736294d1590SErik van der Kouwe if (rc != 1) {
737294d1590SErik van der Kouwe test_fail("[server] select() should have returned 1");
738294d1590SErik van der Kouwe printf("[server] select returned %d\n", rc);
739294d1590SErik van der Kouwe }
740294d1590SErik van der Kouwe
741294d1590SErik van der Kouwe if (!(FD_ISSET(sd, &readfds))) {
742294d1590SErik van der Kouwe test_fail("[server] client didn't connect within 10 seconds");
743294d1590SErik van der Kouwe kill(pid, SIGKILL);
744294d1590SErik van der Kouwe return;
745294d1590SErik van der Kouwe }
746294d1590SErik van der Kouwe
747294d1590SErik van der Kouwe client_sd = accept(sd, (struct sockaddr *) &client_addr,
748294d1590SErik van der Kouwe &client_addr_size);
749294d1590SErik van der Kouwe
750294d1590SErik van der Kouwe if (client_sd == -1) {
751294d1590SErik van der Kouwe test_fail("accept() should have worked");
752294d1590SErik van der Kouwe kill(pid, SIGKILL);
753294d1590SErik van der Kouwe return;
754294d1590SErik van der Kouwe } else {
755294d1590SErik van der Kouwe debug("[server] client accept()'d");
756294d1590SErik van der Kouwe }
757294d1590SErik van der Kouwe
758294d1590SErik van der Kouwe debug("[server] Reading message");
759294d1590SErik van der Kouwe rc = read(client_sd, buf, sizeof(buf));
760294d1590SErik van der Kouwe if (rc == -1) {
761294d1590SErik van der Kouwe test_fail("read() failed unexpectedly");
762294d1590SErik van der Kouwe kill(pid, SIGKILL);
763294d1590SErik van der Kouwe return;
764294d1590SErik van der Kouwe }
765294d1590SErik van der Kouwe debug("[server] we got the following message:");
766294d1590SErik van der Kouwe debug(buf);
767294d1590SErik van der Kouwe
768294d1590SErik van der Kouwe for (i = 0; i < rc && i < 127; i++) {
769294d1590SErik van der Kouwe buf[i] = toupper(buf[i]);
770294d1590SErik van der Kouwe }
771294d1590SErik van der Kouwe
772294d1590SErik van der Kouwe debug("[server] Writing message...");
773294d1590SErik van der Kouwe rc = write(client_sd, buf, sizeof(buf));
774294d1590SErik van der Kouwe if (rc == -1) {
775294d1590SErik van der Kouwe test_fail("write(client_sd, buf, sizeof(buf)) failed");
776294d1590SErik van der Kouwe kill(pid, SIGKILL);
777294d1590SErik van der Kouwe return;
778294d1590SErik van der Kouwe }
779294d1590SErik van der Kouwe
7807c48de6cSDavid van Moolenbroek if (rc < strlen((char *)buf)) {
781294d1590SErik van der Kouwe test_fail("[server] write didn't write all the bytes");
782294d1590SErik van der Kouwe }
783294d1590SErik van der Kouwe
784294d1590SErik van der Kouwe memset(&buf, '\0', sizeof(buf));
785294d1590SErik van der Kouwe
786294d1590SErik van der Kouwe debug("[server] Recv message");
787294d1590SErik van der Kouwe rc = recv(client_sd, buf, sizeof(buf), 0);
788294d1590SErik van der Kouwe if (rc == -1) {
789294d1590SErik van der Kouwe test_fail("recv() failed unexpectedly");
790294d1590SErik van der Kouwe kill(pid, SIGKILL);
791294d1590SErik van der Kouwe return;
792294d1590SErik van der Kouwe }
793294d1590SErik van der Kouwe debug("[server] we got the following message:");
794294d1590SErik van der Kouwe debug(buf);
795294d1590SErik van der Kouwe
796294d1590SErik van der Kouwe for (i = 0; i < rc && i < 127; i++) {
797294d1590SErik van der Kouwe buf[i] = toupper(buf[i]);
798294d1590SErik van der Kouwe }
799294d1590SErik van der Kouwe
800294d1590SErik van der Kouwe debug("[server] Sending message...");
801294d1590SErik van der Kouwe rc = send(client_sd, buf, sizeof(buf), 0);
802294d1590SErik van der Kouwe if (rc == -1) {
803294d1590SErik van der Kouwe test_fail("send(client_sd, buf, sizeof(buf), 0) failed");
804294d1590SErik van der Kouwe kill(pid, SIGKILL);
805294d1590SErik van der Kouwe return;
806294d1590SErik van der Kouwe }
807294d1590SErik van der Kouwe
8087c48de6cSDavid van Moolenbroek if (rc < strlen((char *)buf)) {
809294d1590SErik van der Kouwe test_fail("[server] write didn't write all the bytes");
810294d1590SErik van der Kouwe }
811294d1590SErik van der Kouwe
812294d1590SErik van der Kouwe memset(&buf, '\0', sizeof(buf));
813294d1590SErik van der Kouwe
814294d1590SErik van der Kouwe debug("[server] Recvfrom message");
815294d1590SErik van der Kouwe rc = recvfrom(client_sd, buf, sizeof(buf), 0, NULL, 0);
816294d1590SErik van der Kouwe if (rc == -1) {
817294d1590SErik van der Kouwe test_fail("recvfrom() failed unexpectedly");
818294d1590SErik van der Kouwe kill(pid, SIGKILL);
819294d1590SErik van der Kouwe return;
820294d1590SErik van der Kouwe }
821294d1590SErik van der Kouwe debug("[server] we got the following message:");
822294d1590SErik van der Kouwe debug(buf);
823294d1590SErik van der Kouwe
824294d1590SErik van der Kouwe for (i = 0; i < rc && i < 127; i++) {
825294d1590SErik van der Kouwe buf[i] = toupper(buf[i]);
826294d1590SErik van der Kouwe }
827294d1590SErik van der Kouwe
828294d1590SErik van der Kouwe debug("[server] Sendto message...");
829294d1590SErik van der Kouwe rc = sendto(client_sd, buf, sizeof(buf), 0, NULL, 0);
830294d1590SErik van der Kouwe if (rc == -1) {
831294d1590SErik van der Kouwe test_fail("sendto() failed");
832294d1590SErik van der Kouwe kill(pid, SIGKILL);
833294d1590SErik van der Kouwe return;
834294d1590SErik van der Kouwe }
835294d1590SErik van der Kouwe
8367c48de6cSDavid van Moolenbroek if (rc < strlen((char *)buf)) {
837294d1590SErik van der Kouwe test_fail("[server] write didn't write all the bytes");
838294d1590SErik van der Kouwe }
839294d1590SErik van der Kouwe
840294d1590SErik van der Kouwe shutdown(client_sd, SHUT_RDWR);
841294d1590SErik van der Kouwe CLOSE(client_sd);
842294d1590SErik van der Kouwe
843294d1590SErik van der Kouwe shutdown(sd, SHUT_RDWR);
844294d1590SErik van der Kouwe CLOSE(sd);
845294d1590SErik van der Kouwe
846294d1590SErik van der Kouwe /* wait for client to exit */
847294d1590SErik van der Kouwe do {
848294d1590SErik van der Kouwe errno = 0;
849294d1590SErik van der Kouwe rc = waitpid(pid, &status, 0);
850294d1590SErik van der Kouwe } while (rc == -1 && errno == EINTR);
851294d1590SErik van der Kouwe
852294d1590SErik van der Kouwe /* we use the exit status to get its error count */
853294d1590SErik van der Kouwe errct += WEXITSTATUS(status);
854294d1590SErik van der Kouwe }
855294d1590SErik van der Kouwe
856294d1590SErik van der Kouwe int server_ready = 0;
857294d1590SErik van der Kouwe
858294d1590SErik van der Kouwe /* signal handler for the client */
test_xfer_sighdlr(int sig)859294d1590SErik van der Kouwe void test_xfer_sighdlr(int sig)
860294d1590SErik van der Kouwe {
861294d1590SErik van der Kouwe debug("entering signal handler");
862294d1590SErik van der Kouwe switch (sig) {
863294d1590SErik van der Kouwe /* the server will send SIGUSR1 when it is time for us
864294d1590SErik van der Kouwe * to start the tests
865294d1590SErik van der Kouwe */
866294d1590SErik van der Kouwe case SIGUSR1:
867294d1590SErik van der Kouwe server_ready = 1;
868294d1590SErik van der Kouwe debug("got SIGUSR1, the server is ready for the client");
869294d1590SErik van der Kouwe break;
870294d1590SErik van der Kouwe default:
871294d1590SErik van der Kouwe debug("didn't get SIGUSR1");
872294d1590SErik van der Kouwe }
873294d1590SErik van der Kouwe debug("leaving signal handler");
874294d1590SErik van der Kouwe }
875294d1590SErik van der Kouwe
876294d1590SErik van der Kouwe /*
877294d1590SErik van der Kouwe * A toupper() client.
878294d1590SErik van der Kouwe */
test_xfer_client(const struct socket_test_info * info)879294d1590SErik van der Kouwe static void test_xfer_client(const struct socket_test_info *info)
880294d1590SErik van der Kouwe {
881294d1590SErik van der Kouwe struct timeval tv;
882294d1590SErik van der Kouwe fd_set readfds;
883294d1590SErik van der Kouwe struct sockaddr_storage peer_addr;
884294d1590SErik van der Kouwe socklen_t peer_addr_len;
885294d1590SErik van der Kouwe int sd;
886294d1590SErik van der Kouwe int rc;
887294d1590SErik van der Kouwe char buf[BUFSIZE];
888294d1590SErik van der Kouwe
889294d1590SErik van der Kouwe debug("[client] entering test_xfer_client()");
890294d1590SErik van der Kouwe errct = 0; /* reset error count */
891294d1590SErik van der Kouwe memset(&buf, '\0', sizeof(buf));
892294d1590SErik van der Kouwe
893294d1590SErik van der Kouwe while (server_ready == 0) {
894294d1590SErik van der Kouwe debug("[client] waiting for the server to signal");
895294d1590SErik van der Kouwe sleep(1);
896294d1590SErik van der Kouwe }
897294d1590SErik van der Kouwe
898294d1590SErik van der Kouwe peer_addr_len = sizeof(peer_addr);
899294d1590SErik van der Kouwe
900294d1590SErik van der Kouwe
901294d1590SErik van der Kouwe if (info->callback_xfer_prepclient) info->callback_xfer_prepclient();
902294d1590SErik van der Kouwe
903294d1590SErik van der Kouwe debug("[client] creating client socket");
904294d1590SErik van der Kouwe SOCKET(sd, info->domain, info->type, 0);
905294d1590SErik van der Kouwe
906294d1590SErik van der Kouwe debug("[client] connecting to server through the symlink");
907294d1590SErik van der Kouwe rc = connect(sd, info->clientaddrsym, info->clientaddrsymlen);
908294d1590SErik van der Kouwe if (rc == -1) {
909294d1590SErik van der Kouwe test_fail("[client] connect() should have worked");
910294d1590SErik van der Kouwe } else {
911294d1590SErik van der Kouwe debug("[client] connected");
912294d1590SErik van der Kouwe }
913294d1590SErik van der Kouwe
914294d1590SErik van der Kouwe debug("[client] testing getpeername()");
915294d1590SErik van der Kouwe memset(&peer_addr, '\0', sizeof(peer_addr));
916294d1590SErik van der Kouwe rc = getpeername(sd, (struct sockaddr *) &peer_addr, &peer_addr_len);
917294d1590SErik van der Kouwe if (rc == -1) {
918294d1590SErik van der Kouwe test_fail("[client] getpeername() should have worked");
919294d1590SErik van der Kouwe }
920294d1590SErik van der Kouwe
921294d1590SErik van der Kouwe
922294d1590SErik van der Kouwe info->callback_check_sockaddr((struct sockaddr *) &peer_addr,
923294d1590SErik van der Kouwe peer_addr_len, "getpeername", 1);
924294d1590SErik van der Kouwe
925294d1590SErik van der Kouwe strncpy(buf, "Hello, World!", sizeof(buf) - 1);
926294d1590SErik van der Kouwe debug("[client] send to server");
927294d1590SErik van der Kouwe rc = write(sd, buf, sizeof(buf));
928294d1590SErik van der Kouwe if (rc == -1) {
929294d1590SErik van der Kouwe test_fail("[client] write() failed unexpectedly");
930294d1590SErik van der Kouwe }
931294d1590SErik van der Kouwe
932294d1590SErik van der Kouwe memset(buf, '\0', sizeof(buf));
933294d1590SErik van der Kouwe debug("[client] read from server");
934294d1590SErik van der Kouwe rc = read(sd, buf, sizeof(buf));
935294d1590SErik van der Kouwe if (rc == -1) {
936294d1590SErik van der Kouwe test_fail("[client] read() failed unexpectedly");
937294d1590SErik van der Kouwe } else {
938294d1590SErik van der Kouwe debug("[client] we got the following message:");
939294d1590SErik van der Kouwe debug(buf);
940294d1590SErik van der Kouwe }
941294d1590SErik van der Kouwe
942294d1590SErik van der Kouwe if (strncmp(buf, "HELLO, WORLD!", sizeof(buf)) != 0) {
943294d1590SErik van der Kouwe test_fail("[client] We didn't get the correct response");
944294d1590SErik van der Kouwe }
945294d1590SErik van der Kouwe
946294d1590SErik van der Kouwe memset(&buf, '\0', sizeof(buf));
947294d1590SErik van der Kouwe strncpy(buf, "Bonjour!", sizeof(buf) - 1);
948294d1590SErik van der Kouwe
949294d1590SErik van der Kouwe debug("[client] send to server");
950294d1590SErik van der Kouwe rc = send(sd, buf, sizeof(buf), 0);
951294d1590SErik van der Kouwe if (rc == -1) {
952294d1590SErik van der Kouwe test_fail("[client] send() failed unexpectedly");
953294d1590SErik van der Kouwe }
954294d1590SErik van der Kouwe
955294d1590SErik van der Kouwe if (info->callback_xfer_peercred) info->callback_xfer_peercred(sd);
956294d1590SErik van der Kouwe
957294d1590SErik van der Kouwe debug("Testing select()");
958294d1590SErik van der Kouwe
959294d1590SErik van der Kouwe tv.tv_sec = 2;
960294d1590SErik van der Kouwe tv.tv_usec = 500000;
961294d1590SErik van der Kouwe
962294d1590SErik van der Kouwe FD_ZERO(&readfds);
963294d1590SErik van der Kouwe FD_SET(sd, &readfds);
964294d1590SErik van der Kouwe
965294d1590SErik van der Kouwe rc = select(sd + 1, &readfds, NULL, NULL, &tv);
966294d1590SErik van der Kouwe if (rc == -1) {
967294d1590SErik van der Kouwe test_fail("[client] select() should not have failed");
968294d1590SErik van der Kouwe }
969294d1590SErik van der Kouwe
970294d1590SErik van der Kouwe if (rc != 1) {
971294d1590SErik van der Kouwe test_fail("[client] select() should have returned 1");
972294d1590SErik van der Kouwe }
973294d1590SErik van der Kouwe
974294d1590SErik van der Kouwe if (!(FD_ISSET(sd, &readfds))) {
975294d1590SErik van der Kouwe test_fail("The server didn't respond within 2.5 seconds");
976294d1590SErik van der Kouwe }
977294d1590SErik van der Kouwe
978294d1590SErik van der Kouwe memset(buf, '\0', sizeof(buf));
979294d1590SErik van der Kouwe debug("[client] recv from server");
980294d1590SErik van der Kouwe rc = recv(sd, buf, sizeof(buf), 0);
981294d1590SErik van der Kouwe if (rc == -1) {
982294d1590SErik van der Kouwe test_fail("[client] recv() failed unexpectedly");
983294d1590SErik van der Kouwe } else {
984294d1590SErik van der Kouwe debug("[client] we got the following message:");
985294d1590SErik van der Kouwe debug(buf);
986294d1590SErik van der Kouwe }
987294d1590SErik van der Kouwe
988294d1590SErik van der Kouwe if (strncmp(buf, "BONJOUR!", sizeof(buf)) != 0) {
989294d1590SErik van der Kouwe test_fail("[client] We didn't get the right response.");
990294d1590SErik van der Kouwe }
991294d1590SErik van der Kouwe
992294d1590SErik van der Kouwe memset(&buf, '\0', sizeof(buf));
993294d1590SErik van der Kouwe strncpy(buf, "Hola!", sizeof(buf) - 1);
994294d1590SErik van der Kouwe
995294d1590SErik van der Kouwe debug("[client] sendto to server");
996294d1590SErik van der Kouwe rc = sendto(sd, buf, sizeof(buf), 0, NULL, 0);
997294d1590SErik van der Kouwe if (rc == -1) {
998294d1590SErik van der Kouwe test_fail("[client] sendto() failed");
999294d1590SErik van der Kouwe }
1000294d1590SErik van der Kouwe
1001294d1590SErik van der Kouwe debug("Testing select()");
1002294d1590SErik van der Kouwe
1003294d1590SErik van der Kouwe tv.tv_sec = 2;
1004294d1590SErik van der Kouwe tv.tv_usec = 500000;
1005294d1590SErik van der Kouwe
1006294d1590SErik van der Kouwe FD_ZERO(&readfds);
1007294d1590SErik van der Kouwe FD_SET(sd, &readfds);
1008294d1590SErik van der Kouwe
1009294d1590SErik van der Kouwe rc = select(sd + 1, &readfds, NULL, NULL, &tv);
1010294d1590SErik van der Kouwe if (rc == -1) {
1011294d1590SErik van der Kouwe test_fail("[client] select() should not have failed");
1012294d1590SErik van der Kouwe }
1013294d1590SErik van der Kouwe
1014294d1590SErik van der Kouwe if (rc != 1) {
1015294d1590SErik van der Kouwe test_fail("[client] select() should have returned 1");
1016294d1590SErik van der Kouwe }
1017294d1590SErik van der Kouwe
1018294d1590SErik van der Kouwe if (!(FD_ISSET(sd, &readfds))) {
1019294d1590SErik van der Kouwe test_fail("[client] The server didn't respond in 2.5 seconds");
1020294d1590SErik van der Kouwe }
1021294d1590SErik van der Kouwe
1022294d1590SErik van der Kouwe memset(buf, '\0', sizeof(buf));
1023294d1590SErik van der Kouwe debug("[client] recvfrom from server");
1024294d1590SErik van der Kouwe rc = recvfrom(sd, buf, sizeof(buf), 0, NULL, 0);
1025294d1590SErik van der Kouwe if (rc == -1) {
1026294d1590SErik van der Kouwe test_fail("[cleint] recvfrom() failed unexpectedly");
1027294d1590SErik van der Kouwe } else {
1028294d1590SErik van der Kouwe debug("[client] we got the following message:");
1029294d1590SErik van der Kouwe debug(buf);
1030294d1590SErik van der Kouwe }
1031294d1590SErik van der Kouwe
1032294d1590SErik van der Kouwe if (strncmp(buf, "HOLA!", sizeof(buf)) != 0) {
1033294d1590SErik van der Kouwe test_fail("[client] We didn't get the right response.");
1034294d1590SErik van der Kouwe }
1035294d1590SErik van der Kouwe
1036294d1590SErik van der Kouwe debug("[client] closing socket");
1037294d1590SErik van der Kouwe CLOSE(sd);
1038294d1590SErik van der Kouwe
1039294d1590SErik van der Kouwe debug("[client] leaving test_xfer_client()");
1040294d1590SErik van der Kouwe exit(errct);
1041294d1590SErik van der Kouwe }
1042294d1590SErik van der Kouwe
test_xfer(const struct socket_test_info * info)1043294d1590SErik van der Kouwe void test_xfer(const struct socket_test_info *info)
1044294d1590SErik van der Kouwe {
1045294d1590SErik van der Kouwe pid_t pid;
1046294d1590SErik van der Kouwe
1047294d1590SErik van der Kouwe debug("entering test_xfer()");
1048294d1590SErik van der Kouwe info->callback_cleanup();
1049294d1590SErik van der Kouwe
1050294d1590SErik van der Kouwe /* the signal handler is only used by the client, but we have to
1051294d1590SErik van der Kouwe * install it now. if we don't the server may signal the client
1052294d1590SErik van der Kouwe * before the handler is installed.
1053294d1590SErik van der Kouwe */
1054294d1590SErik van der Kouwe debug("installing signal handler");
1055294d1590SErik van der Kouwe if (signal(SIGUSR1, test_xfer_sighdlr) == SIG_ERR) {
1056294d1590SErik van der Kouwe test_fail("signal(SIGUSR1, test_xfer_sighdlr) failed");
1057294d1590SErik van der Kouwe }
1058294d1590SErik van der Kouwe
1059294d1590SErik van der Kouwe debug("signal handler installed");
1060294d1590SErik van der Kouwe
1061294d1590SErik van der Kouwe server_ready = 0;
1062294d1590SErik van der Kouwe
1063294d1590SErik van der Kouwe pid = fork();
1064294d1590SErik van der Kouwe if (pid == -1) {
1065294d1590SErik van der Kouwe test_fail("fork() failed");
1066294d1590SErik van der Kouwe return;
1067294d1590SErik van der Kouwe } else if (pid == 0) {
1068294d1590SErik van der Kouwe debug("child");
1069294d1590SErik van der Kouwe errct = 0;
1070294d1590SErik van der Kouwe test_xfer_client(info);
1071294d1590SErik van der Kouwe test_fail("we should never get here");
1072294d1590SErik van der Kouwe exit(1);
1073294d1590SErik van der Kouwe } else {
1074294d1590SErik van der Kouwe debug("parent");
1075294d1590SErik van der Kouwe test_xfer_server(info, pid);
1076294d1590SErik van der Kouwe debug("parent done");
1077294d1590SErik van der Kouwe }
1078294d1590SErik van der Kouwe
1079294d1590SErik van der Kouwe info->callback_cleanup();
1080294d1590SErik van der Kouwe debug("leaving test_xfer()");
1081294d1590SErik van der Kouwe }
1082294d1590SErik van der Kouwe
test_simple_client(const struct socket_test_info * info,int type)1083294d1590SErik van der Kouwe static void test_simple_client(const struct socket_test_info *info, int type)
1084294d1590SErik van der Kouwe {
1085294d1590SErik van der Kouwe char buf[BUFSIZE];
1086294d1590SErik van der Kouwe int sd, rc;
1087294d1590SErik van der Kouwe
1088294d1590SErik van der Kouwe sd = socket(info->domain, type, 0);
1089294d1590SErik van der Kouwe if (sd == -1) {
1090294d1590SErik van der Kouwe test_fail("socket");
1091294d1590SErik van der Kouwe exit(errct);
1092294d1590SErik van der Kouwe }
1093294d1590SErik van der Kouwe
1094294d1590SErik van der Kouwe while (server_ready == 0) {
1095294d1590SErik van der Kouwe debug("[client] waiting for the server");
1096294d1590SErik van der Kouwe sleep(1);
1097294d1590SErik van der Kouwe }
1098294d1590SErik van der Kouwe
1099294d1590SErik van der Kouwe bzero(buf, BUFSIZE);
1100294d1590SErik van der Kouwe snprintf(buf, BUFSIZE-1, "Hello, My Name is Client.");
1101294d1590SErik van der Kouwe
1102294d1590SErik van der Kouwe if (type == SOCK_DGRAM) {
1103294d1590SErik van der Kouwe
1104294d1590SErik van der Kouwe rc = sendto(sd, buf, strlen(buf) + 1, 0,
1105294d1590SErik van der Kouwe info->clientaddr, info->clientaddrlen);
1106294d1590SErik van der Kouwe if (rc == -1) {
1107294d1590SErik van der Kouwe test_fail("sendto");
1108294d1590SErik van der Kouwe exit(errct);
1109294d1590SErik van der Kouwe }
1110294d1590SErik van der Kouwe
1111294d1590SErik van der Kouwe } else {
1112294d1590SErik van der Kouwe
1113294d1590SErik van der Kouwe rc = connect(sd, info->clientaddr, info->clientaddrlen);
1114294d1590SErik van der Kouwe if (rc == -1) {
1115294d1590SErik van der Kouwe test_fail("connect");
1116294d1590SErik van der Kouwe exit(errct);
1117294d1590SErik van der Kouwe }
1118294d1590SErik van der Kouwe
1119294d1590SErik van der Kouwe rc = write(sd, buf, strlen(buf) + 1);
1120294d1590SErik van der Kouwe
1121294d1590SErik van der Kouwe if (rc == -1) {
1122294d1590SErik van der Kouwe test_fail("write");
1123294d1590SErik van der Kouwe }
1124294d1590SErik van der Kouwe
1125294d1590SErik van der Kouwe memset(buf, '\0', BUFSIZE);
1126294d1590SErik van der Kouwe rc = read(sd, buf, BUFSIZE);
1127294d1590SErik van der Kouwe if (rc == -1) {
1128294d1590SErik van der Kouwe test_fail("read");
1129294d1590SErik van der Kouwe }
1130294d1590SErik van der Kouwe
1131294d1590SErik van der Kouwe if (strcmp("Hello, My Name is Server.", buf) != 0) {
1132294d1590SErik van der Kouwe test_fail("didn't read the correct string");
1133294d1590SErik van der Kouwe }
1134294d1590SErik van der Kouwe }
1135294d1590SErik van der Kouwe
1136294d1590SErik van der Kouwe rc = close(sd);
1137294d1590SErik van der Kouwe if (rc == -1) {
1138294d1590SErik van der Kouwe test_fail("close");
1139294d1590SErik van der Kouwe }
1140294d1590SErik van der Kouwe
1141294d1590SErik van der Kouwe exit(errct);
1142294d1590SErik van der Kouwe }
1143294d1590SErik van der Kouwe
test_simple_server(const struct socket_test_info * info,int type,pid_t pid)1144294d1590SErik van der Kouwe static void test_simple_server(const struct socket_test_info *info, int type,
1145294d1590SErik van der Kouwe pid_t pid)
1146294d1590SErik van der Kouwe {
1147294d1590SErik van der Kouwe char buf[BUFSIZE];
1148*ad920fc4SDavid van Moolenbroek int sd, rc, client_sd, status, on;
1149294d1590SErik van der Kouwe struct sockaddr_storage addr;
1150294d1590SErik van der Kouwe socklen_t addr_len;
1151294d1590SErik van der Kouwe
1152294d1590SErik van der Kouwe addr_len = info->clientaddrlen;
1153294d1590SErik van der Kouwe
1154294d1590SErik van der Kouwe sd = socket(info->domain, type, 0);
1155294d1590SErik van der Kouwe if (sd == -1) {
1156294d1590SErik van der Kouwe test_fail("socket");
1157294d1590SErik van der Kouwe }
1158294d1590SErik van der Kouwe
1159*ad920fc4SDavid van Moolenbroek on = 1;
1160*ad920fc4SDavid van Moolenbroek (void)setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
1161*ad920fc4SDavid van Moolenbroek
1162294d1590SErik van der Kouwe assert(info->clientaddrlen <= sizeof(addr));
1163294d1590SErik van der Kouwe memcpy(&addr, info->clientaddr, info->clientaddrlen);
1164294d1590SErik van der Kouwe
1165294d1590SErik van der Kouwe rc = bind(sd, info->serveraddr, info->serveraddrlen);
1166294d1590SErik van der Kouwe if (rc == -1) {
1167294d1590SErik van der Kouwe test_fail("bind");
1168294d1590SErik van der Kouwe }
1169294d1590SErik van der Kouwe
1170294d1590SErik van der Kouwe if (type == SOCK_DGRAM) {
1171294d1590SErik van der Kouwe
1172294d1590SErik van der Kouwe /* ready for client */
1173294d1590SErik van der Kouwe kill(pid, SIGUSR1);
1174294d1590SErik van der Kouwe
1175294d1590SErik van der Kouwe rc = recvfrom(sd, buf, BUFSIZE, 0,
1176294d1590SErik van der Kouwe (struct sockaddr *) &addr, &addr_len);
1177294d1590SErik van der Kouwe if (rc == -1) {
1178294d1590SErik van der Kouwe test_fail("recvfrom");
1179294d1590SErik van der Kouwe }
1180294d1590SErik van der Kouwe
1181294d1590SErik van der Kouwe } else {
1182294d1590SErik van der Kouwe
1183294d1590SErik van der Kouwe rc = listen(sd, 5);
1184294d1590SErik van der Kouwe if (rc == -1) {
1185294d1590SErik van der Kouwe test_fail("listen");
1186294d1590SErik van der Kouwe }
1187294d1590SErik van der Kouwe
1188294d1590SErik van der Kouwe /* we're ready for connections, time to tell the client
1189294d1590SErik van der Kouwe * to start the test
1190294d1590SErik van der Kouwe */
1191294d1590SErik van der Kouwe kill(pid, SIGUSR1);
1192294d1590SErik van der Kouwe
1193294d1590SErik van der Kouwe client_sd = accept(sd, (struct sockaddr *) &addr, &addr_len);
1194294d1590SErik van der Kouwe if (client_sd == -1) {
1195294d1590SErik van der Kouwe test_fail("accept");
1196294d1590SErik van der Kouwe }
1197294d1590SErik van der Kouwe
1198294d1590SErik van der Kouwe memset(buf, '\0', BUFSIZE);
1199294d1590SErik van der Kouwe rc = read(client_sd, buf, BUFSIZE);
1200294d1590SErik van der Kouwe if (rc == -1) {
1201294d1590SErik van der Kouwe test_fail("read");
1202294d1590SErik van der Kouwe }
1203294d1590SErik van der Kouwe
1204294d1590SErik van der Kouwe if (strcmp("Hello, My Name is Client.", buf) != 0) {
1205294d1590SErik van der Kouwe test_fail("didn't read the correct string");
1206294d1590SErik van der Kouwe }
1207294d1590SErik van der Kouwe
1208294d1590SErik van der Kouwe /* added for extra fun to make the client block on read() */
1209294d1590SErik van der Kouwe sleep(1);
1210294d1590SErik van der Kouwe
1211294d1590SErik van der Kouwe bzero(buf, BUFSIZE);
1212294d1590SErik van der Kouwe snprintf(buf, BUFSIZE-1, "Hello, My Name is Server.");
1213294d1590SErik van der Kouwe
1214294d1590SErik van der Kouwe rc = write(client_sd, buf, strlen(buf) + 1);
1215294d1590SErik van der Kouwe if (rc == -1) {
1216294d1590SErik van der Kouwe test_fail("write");
1217294d1590SErik van der Kouwe }
1218294d1590SErik van der Kouwe rc = close(client_sd);
1219294d1590SErik van der Kouwe if (rc == -1) {
1220294d1590SErik van der Kouwe test_fail("close");
1221294d1590SErik van der Kouwe }
1222294d1590SErik van der Kouwe }
1223294d1590SErik van der Kouwe
1224294d1590SErik van der Kouwe rc = close(sd);
1225294d1590SErik van der Kouwe if (rc == -1) {
1226294d1590SErik van der Kouwe test_fail("close");
1227294d1590SErik van der Kouwe }
1228294d1590SErik van der Kouwe
1229294d1590SErik van der Kouwe /* wait for client to exit */
1230294d1590SErik van der Kouwe do {
1231294d1590SErik van der Kouwe errno = 0;
1232294d1590SErik van der Kouwe rc = waitpid(pid, &status, 0);
1233294d1590SErik van der Kouwe } while (rc == -1 && errno == EINTR);
1234294d1590SErik van der Kouwe
1235294d1590SErik van der Kouwe /* we use the exit status to get its error count */
1236294d1590SErik van der Kouwe errct += WEXITSTATUS(status);
1237294d1590SErik van der Kouwe }
1238294d1590SErik van der Kouwe
1239294d1590SErik van der Kouwe static void test_abort_client(const struct socket_test_info *info,
1240294d1590SErik van der Kouwe int abort_type);
1241294d1590SErik van der Kouwe static void test_abort_server(const struct socket_test_info *info,
1242294d1590SErik van der Kouwe pid_t pid, int abort_type);
1243294d1590SErik van der Kouwe
test_abort_client_server(const struct socket_test_info * info,int abort_type)1244294d1590SErik van der Kouwe void test_abort_client_server(const struct socket_test_info *info,
1245294d1590SErik van der Kouwe int abort_type)
1246294d1590SErik van der Kouwe {
1247294d1590SErik van der Kouwe pid_t pid;
1248294d1590SErik van der Kouwe
1249294d1590SErik van der Kouwe debug("test_simple_client_server()");
1250294d1590SErik van der Kouwe
1251294d1590SErik van der Kouwe info->callback_cleanup();
1252294d1590SErik van der Kouwe
1253294d1590SErik van der Kouwe /* the signal handler is only used by the client, but we have to
1254294d1590SErik van der Kouwe * install it now. if we don't the server may signal the client
1255294d1590SErik van der Kouwe * before the handler is installed.
1256294d1590SErik van der Kouwe */
1257294d1590SErik van der Kouwe debug("installing signal handler");
1258294d1590SErik van der Kouwe if (signal(SIGUSR1, test_xfer_sighdlr) == SIG_ERR) {
1259294d1590SErik van der Kouwe test_fail("signal(SIGUSR1, test_xfer_sighdlr) failed");
1260294d1590SErik van der Kouwe }
1261294d1590SErik van der Kouwe
1262294d1590SErik van der Kouwe debug("signal handler installed");
1263294d1590SErik van der Kouwe
1264294d1590SErik van der Kouwe server_ready = 0;
1265294d1590SErik van der Kouwe
1266294d1590SErik van der Kouwe pid = fork();
1267294d1590SErik van der Kouwe if (pid == -1) {
1268294d1590SErik van der Kouwe test_fail("fork() failed");
1269294d1590SErik van der Kouwe return;
1270294d1590SErik van der Kouwe } else if (pid == 0) {
1271294d1590SErik van der Kouwe debug("child");
1272294d1590SErik van der Kouwe errct = 0;
1273294d1590SErik van der Kouwe test_abort_client(info, abort_type);
1274294d1590SErik van der Kouwe test_fail("we should never get here");
1275294d1590SErik van der Kouwe exit(1);
1276294d1590SErik van der Kouwe } else {
1277294d1590SErik van der Kouwe debug("parent");
1278294d1590SErik van der Kouwe test_abort_server(info, pid, abort_type);
1279294d1590SErik van der Kouwe debug("parent done");
1280294d1590SErik van der Kouwe }
1281294d1590SErik van der Kouwe
1282294d1590SErik van der Kouwe info->callback_cleanup();
1283294d1590SErik van der Kouwe }
1284294d1590SErik van der Kouwe
test_abort_client(const struct socket_test_info * info,int abort_type)1285294d1590SErik van der Kouwe static void test_abort_client(const struct socket_test_info *info,
1286294d1590SErik van der Kouwe int abort_type)
1287294d1590SErik van der Kouwe {
1288294d1590SErik van der Kouwe char buf[BUFSIZE];
1289294d1590SErik van der Kouwe int sd, rc;
1290294d1590SErik van der Kouwe
1291294d1590SErik van der Kouwe sd = socket(info->domain, info->type, 0);
1292294d1590SErik van der Kouwe if (sd == -1) {
1293294d1590SErik van der Kouwe test_fail("socket");
1294294d1590SErik van der Kouwe exit(errct);
1295294d1590SErik van der Kouwe }
1296294d1590SErik van der Kouwe
1297294d1590SErik van der Kouwe while (server_ready == 0) {
1298294d1590SErik van der Kouwe debug("[client] waiting for the server");
1299294d1590SErik van der Kouwe sleep(1);
1300294d1590SErik van der Kouwe }
1301294d1590SErik van der Kouwe
1302294d1590SErik van der Kouwe bzero(buf, BUFSIZE);
1303294d1590SErik van der Kouwe snprintf(buf, BUFSIZE-1, "Hello, My Name is Client.");
1304294d1590SErik van der Kouwe
1305294d1590SErik van der Kouwe rc = connect(sd, info->clientaddr, info->clientaddrlen);
1306294d1590SErik van der Kouwe if (rc == -1) {
1307294d1590SErik van der Kouwe test_fail("connect");
1308294d1590SErik van der Kouwe exit(errct);
1309294d1590SErik van der Kouwe }
1310294d1590SErik van der Kouwe
1311294d1590SErik van der Kouwe if (abort_type == 2) {
1312294d1590SErik van der Kouwe /* Give server a chance to close connection */
1313294d1590SErik van der Kouwe sleep(2);
1314294d1590SErik van der Kouwe rc = write(sd, buf, strlen(buf) + 1);
1315294d1590SErik van der Kouwe if (rc != -1) {
1316294d1590SErik van der Kouwe if (!info->ignore_write_conn_reset) {
1317294d1590SErik van der Kouwe test_fail("write should have failed\n");
1318294d1590SErik van der Kouwe }
131927852ebeSDavid van Moolenbroek } else if (errno != EPIPE && errno != ECONNRESET) {
132027852ebeSDavid van Moolenbroek test_fail("errno should've been EPIPE/ECONNRESET\n");
1321294d1590SErik van der Kouwe }
1322294d1590SErik van der Kouwe }
1323294d1590SErik van der Kouwe
1324294d1590SErik van der Kouwe rc = close(sd);
1325294d1590SErik van der Kouwe if (rc == -1) {
1326294d1590SErik van der Kouwe test_fail("close");
1327294d1590SErik van der Kouwe }
1328294d1590SErik van der Kouwe
1329294d1590SErik van der Kouwe exit(errct);
1330294d1590SErik van der Kouwe }
1331294d1590SErik van der Kouwe
test_abort_server(const struct socket_test_info * info,pid_t pid,int abort_type)1332294d1590SErik van der Kouwe static void test_abort_server(const struct socket_test_info *info,
1333294d1590SErik van der Kouwe pid_t pid, int abort_type)
1334294d1590SErik van der Kouwe {
1335294d1590SErik van der Kouwe char buf[BUFSIZE];
1336*ad920fc4SDavid van Moolenbroek int sd, rc, client_sd, status, on;
1337294d1590SErik van der Kouwe struct sockaddr_storage addr;
1338294d1590SErik van der Kouwe socklen_t addr_len;
1339294d1590SErik van der Kouwe
1340294d1590SErik van der Kouwe addr_len = info->clientaddrlen;
1341294d1590SErik van der Kouwe
1342294d1590SErik van der Kouwe sd = socket(info->domain, info->type, 0);
1343294d1590SErik van der Kouwe if (sd == -1) {
1344294d1590SErik van der Kouwe test_fail("socket");
1345294d1590SErik van der Kouwe }
1346294d1590SErik van der Kouwe
1347*ad920fc4SDavid van Moolenbroek on = 1;
1348*ad920fc4SDavid van Moolenbroek (void)setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
1349*ad920fc4SDavid van Moolenbroek
1350294d1590SErik van der Kouwe assert(sizeof(addr) >= info->clientaddrlen);
1351294d1590SErik van der Kouwe memcpy(&addr, info->clientaddr, info->clientaddrlen);
1352294d1590SErik van der Kouwe
1353294d1590SErik van der Kouwe rc = bind(sd, info->serveraddr, info->serveraddrlen);
1354294d1590SErik van der Kouwe if (rc == -1) {
1355294d1590SErik van der Kouwe test_fail("bind");
1356294d1590SErik van der Kouwe }
1357294d1590SErik van der Kouwe
1358294d1590SErik van der Kouwe rc = listen(sd, 5);
1359294d1590SErik van der Kouwe if (rc == -1) {
1360294d1590SErik van der Kouwe test_fail("listen");
1361294d1590SErik van der Kouwe }
1362294d1590SErik van der Kouwe
1363294d1590SErik van der Kouwe /* we're ready for connections, time to tell the client
1364294d1590SErik van der Kouwe * to start the test
1365294d1590SErik van der Kouwe */
1366294d1590SErik van der Kouwe kill(pid, SIGUSR1);
1367294d1590SErik van der Kouwe
1368294d1590SErik van der Kouwe client_sd = accept(sd, (struct sockaddr *) &addr, &addr_len);
1369294d1590SErik van der Kouwe if (client_sd == -1) {
1370294d1590SErik van der Kouwe test_fail("accept");
1371294d1590SErik van der Kouwe }
1372294d1590SErik van der Kouwe
1373294d1590SErik van der Kouwe if (abort_type == 1) {
1374294d1590SErik van der Kouwe memset(buf, '\0', BUFSIZE);
1375294d1590SErik van der Kouwe rc = read(client_sd, buf, BUFSIZE);
137627852ebeSDavid van Moolenbroek if (rc != 0 && rc != -1) {
1377294d1590SErik van der Kouwe test_fail("read should've failed or returned zero\n");
1378294d1590SErik van der Kouwe }
1379294d1590SErik van der Kouwe if (rc != 0 && errno != ECONNRESET) {
1380294d1590SErik van der Kouwe test_fail("errno should've been ECONNRESET\n");
1381294d1590SErik van der Kouwe }
1382294d1590SErik van der Kouwe } /* else if (abort_type == 2) { */
1383294d1590SErik van der Kouwe rc = close(client_sd);
1384294d1590SErik van der Kouwe if (rc == -1) {
1385294d1590SErik van der Kouwe test_fail("close");
1386294d1590SErik van der Kouwe }
1387294d1590SErik van der Kouwe /* } */
1388294d1590SErik van der Kouwe
1389294d1590SErik van der Kouwe rc = close(sd);
1390294d1590SErik van der Kouwe if (rc == -1) {
1391294d1590SErik van der Kouwe test_fail("close");
1392294d1590SErik van der Kouwe }
1393294d1590SErik van der Kouwe
1394294d1590SErik van der Kouwe /* wait for client to exit */
1395294d1590SErik van der Kouwe do {
1396294d1590SErik van der Kouwe errno = 0;
1397294d1590SErik van der Kouwe rc = waitpid(pid, &status, 0);
1398294d1590SErik van der Kouwe } while (rc == -1 && errno == EINTR);
1399294d1590SErik van der Kouwe
1400294d1590SErik van der Kouwe /* we use the exit status to get its error count */
1401294d1590SErik van der Kouwe errct += WEXITSTATUS(status);
1402294d1590SErik van der Kouwe }
1403294d1590SErik van der Kouwe
test_simple_client_server(const struct socket_test_info * info,int type)1404294d1590SErik van der Kouwe void test_simple_client_server(const struct socket_test_info *info, int type)
1405294d1590SErik van der Kouwe {
1406294d1590SErik van der Kouwe pid_t pid;
1407294d1590SErik van der Kouwe
1408294d1590SErik van der Kouwe debug("entering test_simple_client_server()");
1409294d1590SErik van der Kouwe
1410294d1590SErik van der Kouwe info->callback_cleanup();
1411294d1590SErik van der Kouwe
1412294d1590SErik van der Kouwe /* the signal handler is only used by the client, but we have to
1413294d1590SErik van der Kouwe * install it now. if we don't the server may signal the client
1414294d1590SErik van der Kouwe * before the handler is installed.
1415294d1590SErik van der Kouwe */
1416294d1590SErik van der Kouwe debug("installing signal handler");
1417294d1590SErik van der Kouwe if (signal(SIGUSR1, test_xfer_sighdlr) == SIG_ERR) {
1418294d1590SErik van der Kouwe test_fail("signal(SIGUSR1, test_xfer_sighdlr) failed");
1419294d1590SErik van der Kouwe }
1420294d1590SErik van der Kouwe
1421294d1590SErik van der Kouwe debug("signal handler installed");
1422294d1590SErik van der Kouwe
1423294d1590SErik van der Kouwe server_ready = 0;
1424294d1590SErik van der Kouwe
1425294d1590SErik van der Kouwe pid = fork();
1426294d1590SErik van der Kouwe if (pid == -1) {
1427294d1590SErik van der Kouwe test_fail("fork() failed");
1428294d1590SErik van der Kouwe return;
1429294d1590SErik van der Kouwe } else if (pid == 0) {
1430294d1590SErik van der Kouwe debug("child");
1431294d1590SErik van der Kouwe errct = 0;
1432294d1590SErik van der Kouwe test_simple_client(info, type);
1433294d1590SErik van der Kouwe test_fail("we should never get here");
1434294d1590SErik van der Kouwe exit(1);
1435294d1590SErik van der Kouwe } else {
1436294d1590SErik van der Kouwe debug("parent");
1437294d1590SErik van der Kouwe test_simple_server(info, type, pid);
1438294d1590SErik van der Kouwe debug("parent done");
1439294d1590SErik van der Kouwe }
1440294d1590SErik van der Kouwe
1441294d1590SErik van der Kouwe info->callback_cleanup();
1442294d1590SErik van der Kouwe debug("leaving test_simple_client_server()");
1443294d1590SErik van der Kouwe }
1444294d1590SErik van der Kouwe
test_msg_dgram(const struct socket_test_info * info)1445294d1590SErik van der Kouwe void test_msg_dgram(const struct socket_test_info *info)
1446294d1590SErik van der Kouwe {
1447294d1590SErik van der Kouwe int rc;
1448294d1590SErik van der Kouwe int src;
1449294d1590SErik van der Kouwe int dst;
1450294d1590SErik van der Kouwe struct sockaddr_storage addr;
1451294d1590SErik van der Kouwe struct iovec iov[3];
1452294d1590SErik van der Kouwe struct msghdr msg1;
1453294d1590SErik van der Kouwe struct msghdr msg2;
1454294d1590SErik van der Kouwe char buf1[BUFSIZE];
1455294d1590SErik van der Kouwe char buf2[BUFSIZE];
1456294d1590SErik van der Kouwe char buf3[BUFSIZE];
1457294d1590SErik van der Kouwe
1458294d1590SErik van der Kouwe debug("entering test_msg_dgram");
1459294d1590SErik van der Kouwe
1460294d1590SErik van der Kouwe info->callback_cleanup();
1461294d1590SErik van der Kouwe
1462294d1590SErik van der Kouwe src = socket(info->domain, SOCK_DGRAM, 0);
1463294d1590SErik van der Kouwe if (src == -1) {
1464294d1590SErik van der Kouwe test_fail("socket");
1465294d1590SErik van der Kouwe }
1466294d1590SErik van der Kouwe
1467294d1590SErik van der Kouwe dst = socket(info->domain, SOCK_DGRAM, 0);
1468294d1590SErik van der Kouwe if (dst == -1) {
1469294d1590SErik van der Kouwe test_fail("socket");
1470294d1590SErik van der Kouwe }
1471294d1590SErik van der Kouwe
1472294d1590SErik van der Kouwe rc = bind(src, info->serveraddr2, info->serveraddr2len);
1473294d1590SErik van der Kouwe if (rc == -1) {
1474294d1590SErik van der Kouwe test_fail("bind");
1475294d1590SErik van der Kouwe }
1476294d1590SErik van der Kouwe
1477294d1590SErik van der Kouwe assert(info->clientaddrlen <= sizeof(addr));
1478294d1590SErik van der Kouwe memcpy(&addr, info->clientaddr, info->clientaddrlen);
1479294d1590SErik van der Kouwe
1480294d1590SErik van der Kouwe rc = bind(dst, info->serveraddr, info->serveraddrlen);
1481294d1590SErik van der Kouwe if (rc == -1) {
1482294d1590SErik van der Kouwe test_fail("bind");
1483294d1590SErik van der Kouwe }
1484294d1590SErik van der Kouwe
1485294d1590SErik van der Kouwe memset(&buf1, '\0', BUFSIZE);
1486294d1590SErik van der Kouwe memset(&buf2, '\0', BUFSIZE);
1487294d1590SErik van der Kouwe memset(&buf3, '\0', BUFSIZE);
1488294d1590SErik van der Kouwe
1489294d1590SErik van der Kouwe strncpy(buf1, "Minix ", BUFSIZE-1);
1490294d1590SErik van der Kouwe strncpy(buf2, "is ", BUFSIZE-1);
1491294d1590SErik van der Kouwe strncpy(buf3, "great!", BUFSIZE-1);
1492294d1590SErik van der Kouwe
1493294d1590SErik van der Kouwe iov[0].iov_base = buf1;
1494294d1590SErik van der Kouwe iov[0].iov_len = 6;
1495294d1590SErik van der Kouwe iov[1].iov_base = buf2;
1496294d1590SErik van der Kouwe iov[1].iov_len = 3;
1497294d1590SErik van der Kouwe iov[2].iov_base = buf3;
1498294d1590SErik van der Kouwe iov[2].iov_len = 32;
1499294d1590SErik van der Kouwe
1500294d1590SErik van der Kouwe memset(&msg1, '\0', sizeof(struct msghdr));
1501294d1590SErik van der Kouwe msg1.msg_name = &addr;
1502294d1590SErik van der Kouwe msg1.msg_namelen = info->clientaddrlen;
1503294d1590SErik van der Kouwe msg1.msg_iov = iov;
1504294d1590SErik van der Kouwe msg1.msg_iovlen = 3;
1505294d1590SErik van der Kouwe msg1.msg_control = NULL;
1506294d1590SErik van der Kouwe msg1.msg_controllen = 0;
1507294d1590SErik van der Kouwe msg1.msg_flags = 0;
1508294d1590SErik van der Kouwe
1509294d1590SErik van der Kouwe rc = sendmsg(src, &msg1, 0);
1510294d1590SErik van der Kouwe if (rc == -1) {
1511294d1590SErik van der Kouwe test_fail("sendmsg");
1512294d1590SErik van der Kouwe }
1513294d1590SErik van der Kouwe
1514294d1590SErik van der Kouwe memset(&buf1, '\0', BUFSIZE);
1515294d1590SErik van der Kouwe memset(&buf2, '\0', BUFSIZE);
1516294d1590SErik van der Kouwe
1517294d1590SErik van der Kouwe iov[0].iov_base = buf1;
1518294d1590SErik van der Kouwe iov[0].iov_len = 9;
1519294d1590SErik van der Kouwe iov[1].iov_base = buf2;
1520294d1590SErik van der Kouwe iov[1].iov_len = 32;
1521294d1590SErik van der Kouwe
1522294d1590SErik van der Kouwe memset(&addr, '\0', sizeof(addr));
1523294d1590SErik van der Kouwe memset(&msg2, '\0', sizeof(struct msghdr));
1524294d1590SErik van der Kouwe msg2.msg_name = &addr;
1525294d1590SErik van der Kouwe msg2.msg_namelen = sizeof(addr);
1526294d1590SErik van der Kouwe msg2.msg_iov = iov;
1527294d1590SErik van der Kouwe msg2.msg_iovlen = 2;
1528294d1590SErik van der Kouwe msg2.msg_control = NULL;
1529294d1590SErik van der Kouwe msg2.msg_controllen = 0;
1530294d1590SErik van der Kouwe msg2.msg_flags = 0;
1531294d1590SErik van der Kouwe
1532294d1590SErik van der Kouwe rc = recvmsg(dst, &msg2, 0);
1533294d1590SErik van der Kouwe if (rc == -1) {
1534294d1590SErik van der Kouwe test_fail("recvmsg");
1535294d1590SErik van der Kouwe }
1536294d1590SErik van der Kouwe
1537294d1590SErik van der Kouwe if (strncmp(buf1, "Minix is ", 9) || strncmp(buf2, "great!", 6)) {
1538294d1590SErik van der Kouwe test_fail("recvmsg");
1539294d1590SErik van der Kouwe }
1540294d1590SErik van der Kouwe
1541294d1590SErik van der Kouwe info->callback_check_sockaddr((struct sockaddr *) &addr,
1542294d1590SErik van der Kouwe msg2.msg_namelen, "recvmsg", 2);
1543294d1590SErik van der Kouwe
1544294d1590SErik van der Kouwe rc = close(dst);
1545294d1590SErik van der Kouwe if (rc == -1) {
1546294d1590SErik van der Kouwe test_fail("close");
1547294d1590SErik van der Kouwe }
1548294d1590SErik van der Kouwe
1549294d1590SErik van der Kouwe rc = close(src);
1550294d1590SErik van der Kouwe if (rc == -1) {
1551294d1590SErik van der Kouwe test_fail("close");
1552294d1590SErik van der Kouwe }
1553294d1590SErik van der Kouwe
1554294d1590SErik van der Kouwe info->callback_cleanup();
1555294d1590SErik van der Kouwe debug("leaving test_msg_dgram");
1556294d1590SErik van der Kouwe }
1557294d1590SErik van der Kouwe
1558294d1590SErik van der Kouwe #define check_select(sd, rd, wr, block) \
1559294d1590SErik van der Kouwe check_select_internal(sd, rd, wr, block, 1, __LINE__)
1560294d1590SErik van der Kouwe #define check_select_cond(sd, rd, wr, block, allchecks) \
1561294d1590SErik van der Kouwe check_select_internal(sd, rd, wr, block, allchecks, __LINE__)
1562294d1590SErik van der Kouwe
1563294d1590SErik van der Kouwe static void
check_select_internal(int sd,int rd,int wr,int block,int allchecks,int line)1564294d1590SErik van der Kouwe check_select_internal(int sd, int rd, int wr, int block, int allchecks, int line)
1565294d1590SErik van der Kouwe {
1566294d1590SErik van der Kouwe fd_set read_set, write_set;
1567294d1590SErik van der Kouwe struct timeval tv;
1568294d1590SErik van der Kouwe
1569294d1590SErik van der Kouwe FD_ZERO(&read_set);
1570294d1590SErik van der Kouwe if (rd != -1)
1571294d1590SErik van der Kouwe FD_SET(sd, &read_set);
1572294d1590SErik van der Kouwe
1573294d1590SErik van der Kouwe FD_ZERO(&write_set);
1574294d1590SErik van der Kouwe if (wr != -1)
1575294d1590SErik van der Kouwe FD_SET(sd, &write_set);
1576294d1590SErik van der Kouwe
1577294d1590SErik van der Kouwe tv.tv_sec = block ? 2 : 0;
1578294d1590SErik van der Kouwe tv.tv_usec = 0;
1579294d1590SErik van der Kouwe
1580294d1590SErik van der Kouwe errno = 0;
1581294d1590SErik van der Kouwe if (select(sd + 1, &read_set, &write_set, NULL, &tv) < 0)
1582294d1590SErik van der Kouwe test_fail_fl("select() failed unexpectedly", __FILE__, line);
1583294d1590SErik van der Kouwe
1584294d1590SErik van der Kouwe if (rd != -1 && !!FD_ISSET(sd, &read_set) != rd && allchecks)
1585294d1590SErik van der Kouwe test_fail_fl("select() mismatch on read operation",
1586294d1590SErik van der Kouwe __FILE__, line);
1587294d1590SErik van der Kouwe
1588294d1590SErik van der Kouwe if (wr != -1 && !!FD_ISSET(sd, &write_set) != wr && allchecks)
1589294d1590SErik van der Kouwe test_fail_fl("select() mismatch on write operation",
1590294d1590SErik van der Kouwe __FILE__, line);
1591294d1590SErik van der Kouwe }
1592294d1590SErik van der Kouwe
1593294d1590SErik van der Kouwe /*
1594294d1590SErik van der Kouwe * Verify that:
1595294d1590SErik van der Kouwe * - a nonblocking connecting socket for which there is no accepter, will
1596294d1590SErik van der Kouwe * return EINPROGRESS and complete in the background later;
1597294d1590SErik van der Kouwe * - a nonblocking listening socket will return EAGAIN on accept;
1598294d1590SErik van der Kouwe * - connecting a connecting socket yields EALREADY;
1599294d1590SErik van der Kouwe * - connecting a connected socket yields EISCONN;
1600294d1590SErik van der Kouwe * - selecting for read and write on a connecting socket will only satisfy the
1601294d1590SErik van der Kouwe * write only once it is connected;
1602294d1590SErik van der Kouwe * - doing a nonblocking write on a connecting socket yields EAGAIN;
1603294d1590SErik van der Kouwe * - doing a nonblocking read on a connected socket with no pending data yields
1604294d1590SErik van der Kouwe * EAGAIN.
1605294d1590SErik van der Kouwe */
1606294d1590SErik van der Kouwe void
test_nonblock(const struct socket_test_info * info)1607294d1590SErik van der Kouwe test_nonblock(const struct socket_test_info *info)
1608294d1590SErik van der Kouwe {
1609294d1590SErik van der Kouwe char buf[BUFSIZE];
1610294d1590SErik van der Kouwe socklen_t len;
1611294d1590SErik van der Kouwe int server_sd, client_sd;
1612294d1590SErik van der Kouwe struct sockaddr_storage addr;
1613*ad920fc4SDavid van Moolenbroek int status, on;
1614294d1590SErik van der Kouwe
1615294d1590SErik van der Kouwe debug("entering test_nonblock()");
1616294d1590SErik van der Kouwe memset(buf, 0, sizeof(buf));
1617294d1590SErik van der Kouwe
1618294d1590SErik van der Kouwe SOCKET(server_sd, info->domain, info->type, 0);
1619294d1590SErik van der Kouwe
1620*ad920fc4SDavid van Moolenbroek on = 1;
1621*ad920fc4SDavid van Moolenbroek (void)setsockopt(server_sd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
1622*ad920fc4SDavid van Moolenbroek
1623294d1590SErik van der Kouwe if (bind(server_sd, info->serveraddr, info->serveraddrlen) == -1)
1624294d1590SErik van der Kouwe test_fail("bind() should have worked");
1625294d1590SErik van der Kouwe
162627852ebeSDavid van Moolenbroek if (info->callback_set_listen_opt != NULL)
162727852ebeSDavid van Moolenbroek info->callback_set_listen_opt(server_sd);
162827852ebeSDavid van Moolenbroek
1629294d1590SErik van der Kouwe if (listen(server_sd, 8) == -1)
1630294d1590SErik van der Kouwe test_fail("listen() should have worked");
1631294d1590SErik van der Kouwe
1632294d1590SErik van der Kouwe fcntl(server_sd, F_SETFL, fcntl(server_sd, F_GETFL) | O_NONBLOCK);
1633294d1590SErik van der Kouwe
1634294d1590SErik van der Kouwe check_select(server_sd, 0 /*read*/, 1 /*write*/, 0 /*block*/);
1635294d1590SErik van der Kouwe
1636294d1590SErik van der Kouwe len = sizeof(addr);
1637294d1590SErik van der Kouwe if (accept(server_sd, (struct sockaddr *) &addr, &len) != -1 ||
1638294d1590SErik van der Kouwe errno != EAGAIN)
1639294d1590SErik van der Kouwe test_fail("accept() should have yielded EAGAIN");
1640294d1590SErik van der Kouwe
1641294d1590SErik van der Kouwe SOCKET(client_sd, info->domain, info->type, 0);
1642294d1590SErik van der Kouwe
1643294d1590SErik van der Kouwe fcntl(client_sd, F_SETFL, fcntl(client_sd, F_GETFL) | O_NONBLOCK);
1644294d1590SErik van der Kouwe
1645294d1590SErik van der Kouwe if (connect(client_sd, info->clientaddr, info->clientaddrlen) != -1) {
1646294d1590SErik van der Kouwe test_fail("connect() should have failed");
1647294d1590SErik van der Kouwe } else if (errno != EINPROGRESS) {
1648294d1590SErik van der Kouwe test_fail("connect() should have yielded EINPROGRESS");
1649294d1590SErik van der Kouwe }
1650294d1590SErik van der Kouwe
1651294d1590SErik van der Kouwe check_select_cond(client_sd, 0 /*read*/, 0 /*write*/, 0 /*block*/,
1652294d1590SErik van der Kouwe !info->ignore_select_delay);
1653294d1590SErik van der Kouwe
1654294d1590SErik van der Kouwe if (connect(client_sd, info->clientaddr, info->clientaddrlen) != -1) {
1655294d1590SErik van der Kouwe test_fail("connect() should have failed");
1656294d1590SErik van der Kouwe } else if (errno != EALREADY && errno != EISCONN) {
1657294d1590SErik van der Kouwe test_fail("connect() should have yielded EALREADY");
1658294d1590SErik van der Kouwe }
1659294d1590SErik van der Kouwe
1660294d1590SErik van der Kouwe if (recv(client_sd, buf, sizeof(buf), 0) != -1 || errno != EAGAIN)
1661294d1590SErik van der Kouwe test_fail("recv() should have yielded EAGAIN");
1662294d1590SErik van der Kouwe
1663294d1590SErik van der Kouwe /* This may be an implementation aspect, or even plain wrong (?). */
1664294d1590SErik van der Kouwe if (!info->ignore_send_waiting) {
16654f5713ccSDavid van Moolenbroek if (send(client_sd, buf, sizeof(buf), 0) != -1) {
1666294d1590SErik van der Kouwe test_fail("send() should have failed");
1667294d1590SErik van der Kouwe } else if (errno != EAGAIN) {
1668294d1590SErik van der Kouwe test_fail("send() should have yielded EAGAIN");
1669294d1590SErik van der Kouwe }
16704f5713ccSDavid van Moolenbroek }
1671294d1590SErik van der Kouwe
1672294d1590SErik van der Kouwe switch (fork()) {
1673294d1590SErik van der Kouwe case 0:
1674294d1590SErik van der Kouwe errct = 0;
1675294d1590SErik van der Kouwe close(client_sd);
1676294d1590SErik van der Kouwe
1677294d1590SErik van der Kouwe check_select(server_sd, 1 /*read*/, 1 /*write*/, 0 /*block*/);
1678294d1590SErik van der Kouwe
1679294d1590SErik van der Kouwe len = sizeof(addr);
1680294d1590SErik van der Kouwe client_sd = accept(server_sd, (struct sockaddr *) &addr, &len);
1681294d1590SErik van der Kouwe if (client_sd == -1)
1682294d1590SErik van der Kouwe test_fail("accept() should have succeeded");
1683294d1590SErik van der Kouwe
1684294d1590SErik van der Kouwe check_select(server_sd, 0 /*read*/, 1 /*write*/, 0 /*block*/);
1685294d1590SErik van der Kouwe
1686294d1590SErik van der Kouwe close(server_sd);
1687294d1590SErik van der Kouwe
1688294d1590SErik van der Kouwe /* Let the socket become writable in the parent process. */
1689294d1590SErik van der Kouwe sleep(1);
1690294d1590SErik van der Kouwe
1691294d1590SErik van der Kouwe if (write(client_sd, buf, 1) != 1)
1692294d1590SErik van der Kouwe test_fail("write() should have succeeded");
1693294d1590SErik van der Kouwe
1694294d1590SErik van der Kouwe /* Wait for the client side to close. */
1695294d1590SErik van der Kouwe check_select_cond(client_sd, 0 /*read*/, 1 /*write*/,
1696294d1590SErik van der Kouwe 0 /*block*/, !info->ignore_select_delay /*allchecks*/);
1697294d1590SErik van der Kouwe check_select(client_sd, 1 /*read*/, -1 /*write*/, 1 /*block*/);
1698294d1590SErik van der Kouwe check_select(client_sd, 1 /*read*/, 1 /*write*/, 0 /*block*/);
1699294d1590SErik van der Kouwe
1700294d1590SErik van der Kouwe exit(errct);
1701294d1590SErik van der Kouwe case -1:
1702294d1590SErik van der Kouwe test_fail("can't fork");
1703294d1590SErik van der Kouwe default:
1704294d1590SErik van der Kouwe break;
1705294d1590SErik van der Kouwe }
1706294d1590SErik van der Kouwe
1707294d1590SErik van der Kouwe close(server_sd);
1708294d1590SErik van der Kouwe
1709294d1590SErik van der Kouwe check_select(client_sd, 0 /*read*/, 1 /*write*/, 1 /*block*/);
1710294d1590SErik van der Kouwe check_select(client_sd, 0 /*read*/, 1 /*write*/, 0 /*block*/);
1711294d1590SErik van der Kouwe
1712294d1590SErik van der Kouwe if (connect(client_sd, info->clientaddr, info->clientaddrlen) != -1 ||
1713294d1590SErik van der Kouwe errno != EISCONN)
1714294d1590SErik van der Kouwe test_fail("connect() should have yielded EISCONN");
1715294d1590SErik van der Kouwe
1716294d1590SErik van der Kouwe check_select(client_sd, 1 /*read*/, -1 /*write*/, 1 /*block*/);
1717294d1590SErik van der Kouwe check_select(client_sd, 1 /*read*/, 1 /*write*/, 0 /*block*/);
1718294d1590SErik van der Kouwe
1719294d1590SErik van der Kouwe if (read(client_sd, buf, 1) != 1)
1720294d1590SErik van der Kouwe test_fail("read() should have succeeded");
1721294d1590SErik van der Kouwe
1722294d1590SErik van der Kouwe check_select(client_sd, 0 /*read*/, 1 /*write*/, 0 /*block*/);
1723294d1590SErik van der Kouwe
1724294d1590SErik van der Kouwe if (read(client_sd, buf, 1) != -1 || errno != EAGAIN)
1725294d1590SErik van der Kouwe test_fail("read() should have yielded EAGAIN");
1726294d1590SErik van der Kouwe
1727294d1590SErik van der Kouwe /* Let the child process block on the select waiting for the close. */
1728294d1590SErik van der Kouwe sleep(1);
1729294d1590SErik van der Kouwe
1730294d1590SErik van der Kouwe close(client_sd);
1731294d1590SErik van der Kouwe
1732294d1590SErik van der Kouwe errno = 0;
1733294d1590SErik van der Kouwe if (wait(&status) <= 0)
1734294d1590SErik van der Kouwe test_fail("wait() should have succeeded");
1735294d1590SErik van der Kouwe if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
1736294d1590SErik van der Kouwe test_fail("child process failed the test");
1737294d1590SErik van der Kouwe
1738294d1590SErik van der Kouwe info->callback_cleanup();
1739294d1590SErik van der Kouwe debug("leaving test_nonblock()");
1740294d1590SErik van der Kouwe }
1741294d1590SErik van der Kouwe
1742294d1590SErik van der Kouwe /*
1743294d1590SErik van der Kouwe * Verify that a nonblocking connect for which there is an accepter, succeeds
1744294d1590SErik van der Kouwe * immediately. A pretty lame test, only here for completeness.
1745294d1590SErik van der Kouwe */
1746294d1590SErik van der Kouwe void
test_connect_nb(const struct socket_test_info * info)1747294d1590SErik van der Kouwe test_connect_nb(const struct socket_test_info *info)
1748294d1590SErik van der Kouwe {
1749294d1590SErik van der Kouwe socklen_t len;
1750294d1590SErik van der Kouwe int server_sd, client_sd;
1751294d1590SErik van der Kouwe struct sockaddr_storage addr;
1752*ad920fc4SDavid van Moolenbroek int status, on;
1753294d1590SErik van der Kouwe
1754294d1590SErik van der Kouwe debug("entering test_connect_nb()");
1755294d1590SErik van der Kouwe SOCKET(server_sd, info->domain, info->type, 0);
1756294d1590SErik van der Kouwe
1757*ad920fc4SDavid van Moolenbroek on = 1;
1758*ad920fc4SDavid van Moolenbroek (void)setsockopt(server_sd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
1759*ad920fc4SDavid van Moolenbroek
1760294d1590SErik van der Kouwe if (bind(server_sd, info->serveraddr, info->serveraddrlen) == -1)
1761294d1590SErik van der Kouwe test_fail("bind() should have worked");
1762294d1590SErik van der Kouwe
1763294d1590SErik van der Kouwe if (listen(server_sd, 8) == -1)
1764294d1590SErik van der Kouwe test_fail("listen() should have worked");
1765294d1590SErik van der Kouwe
1766294d1590SErik van der Kouwe switch (fork()) {
1767294d1590SErik van der Kouwe case 0:
1768294d1590SErik van der Kouwe errct = 0;
1769294d1590SErik van der Kouwe len = sizeof(addr);
1770294d1590SErik van der Kouwe if (accept(server_sd, (struct sockaddr *) &addr, &len) == -1)
1771294d1590SErik van der Kouwe test_fail("accept() should have succeeded");
1772294d1590SErik van der Kouwe
1773294d1590SErik van der Kouwe exit(errct);
1774294d1590SErik van der Kouwe case -1:
1775294d1590SErik van der Kouwe test_fail("can't fork");
1776294d1590SErik van der Kouwe default:
1777294d1590SErik van der Kouwe break;
1778294d1590SErik van der Kouwe }
1779294d1590SErik van der Kouwe
1780294d1590SErik van der Kouwe close(server_sd);
1781294d1590SErik van der Kouwe
1782294d1590SErik van der Kouwe sleep(1);
1783294d1590SErik van der Kouwe
1784294d1590SErik van der Kouwe SOCKET(client_sd, info->domain, info->type, 0);
1785294d1590SErik van der Kouwe
1786294d1590SErik van der Kouwe fcntl(client_sd, F_SETFL, fcntl(client_sd, F_GETFL) | O_NONBLOCK);
1787294d1590SErik van der Kouwe
1788294d1590SErik van der Kouwe if (connect(client_sd, info->clientaddr, info->clientaddrlen) != 0) {
1789294d1590SErik van der Kouwe if (!info->ignore_connect_delay) {
1790294d1590SErik van der Kouwe test_fail("connect() should have succeeded");
1791294d1590SErik van der Kouwe } else if (errno != EINPROGRESS) {
1792294d1590SErik van der Kouwe test_fail("connect() should have succeeded or "
1793294d1590SErik van der Kouwe "failed with EINPROGRESS");
1794294d1590SErik van der Kouwe }
1795294d1590SErik van der Kouwe }
1796294d1590SErik van der Kouwe
1797294d1590SErik van der Kouwe close(client_sd);
1798294d1590SErik van der Kouwe
1799294d1590SErik van der Kouwe if (wait(&status) <= 0)
1800294d1590SErik van der Kouwe test_fail("wait() should have succeeded");
1801294d1590SErik van der Kouwe if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
1802294d1590SErik van der Kouwe test_fail("child process failed the test");
1803294d1590SErik van der Kouwe
1804294d1590SErik van der Kouwe info->callback_cleanup();
1805294d1590SErik van der Kouwe debug("leaving test_connect_nb()");
1806294d1590SErik van der Kouwe }
1807294d1590SErik van der Kouwe
1808294d1590SErik van der Kouwe static void
dummy_handler(int sig)1809294d1590SErik van der Kouwe dummy_handler(int sig)
1810294d1590SErik van der Kouwe {
1811294d1590SErik van der Kouwe /* Nothing. */
1812294d1590SErik van der Kouwe }
1813294d1590SErik van der Kouwe
1814294d1590SErik van der Kouwe /*
1815294d1590SErik van der Kouwe * Verify that:
1816294d1590SErik van der Kouwe * - interrupting a blocking connect will return EINTR but complete in the
1817294d1590SErik van der Kouwe * background later;
1818294d1590SErik van der Kouwe * - doing a blocking write on an asynchronously connecting socket succeeds
1819294d1590SErik van der Kouwe * once the socket is connected.
1820294d1590SErik van der Kouwe * - doing a nonblocking write on a connected socket with lots of pending data
1821294d1590SErik van der Kouwe * yields EAGAIN.
1822294d1590SErik van der Kouwe */
1823294d1590SErik van der Kouwe void
test_intr(const struct socket_test_info * info)1824294d1590SErik van der Kouwe test_intr(const struct socket_test_info *info)
1825294d1590SErik van der Kouwe {
1826294d1590SErik van der Kouwe struct sigaction act, oact;
1827294d1590SErik van der Kouwe char buf[BUFSIZE];
1828294d1590SErik van der Kouwe int isconn;
1829294d1590SErik van der Kouwe socklen_t len;
1830294d1590SErik van der Kouwe int server_sd, client_sd;
1831294d1590SErik van der Kouwe struct sockaddr_storage addr;
1832*ad920fc4SDavid van Moolenbroek int r, status, on;
1833294d1590SErik van der Kouwe
1834294d1590SErik van der Kouwe debug("entering test_intr()");
1835294d1590SErik van der Kouwe memset(buf, 0, sizeof(buf));
1836294d1590SErik van der Kouwe
1837294d1590SErik van der Kouwe SOCKET(server_sd, info->domain, info->type, 0);
1838294d1590SErik van der Kouwe
1839*ad920fc4SDavid van Moolenbroek on = 1;
1840*ad920fc4SDavid van Moolenbroek (void)setsockopt(server_sd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
1841*ad920fc4SDavid van Moolenbroek
1842294d1590SErik van der Kouwe if (bind(server_sd, info->serveraddr, info->serveraddrlen) == -1)
1843294d1590SErik van der Kouwe test_fail("bind() should have worked");
1844294d1590SErik van der Kouwe
184527852ebeSDavid van Moolenbroek if (info->callback_set_listen_opt != NULL)
184627852ebeSDavid van Moolenbroek info->callback_set_listen_opt(server_sd);
184727852ebeSDavid van Moolenbroek
1848294d1590SErik van der Kouwe if (listen(server_sd, 8) == -1)
1849294d1590SErik van der Kouwe test_fail("listen() should have worked");
1850294d1590SErik van der Kouwe
1851294d1590SErik van der Kouwe SOCKET(client_sd, info->domain, info->type, 0);
1852294d1590SErik van der Kouwe
1853294d1590SErik van der Kouwe memset(&act, 0, sizeof(act));
1854294d1590SErik van der Kouwe act.sa_handler = dummy_handler;
1855294d1590SErik van der Kouwe if (sigaction(SIGALRM, &act, &oact) == -1)
1856294d1590SErik van der Kouwe test_fail("sigaction() should have succeeded");
1857294d1590SErik van der Kouwe
1858294d1590SErik van der Kouwe if (info->domain != PF_INET) alarm(1);
1859294d1590SErik van der Kouwe
1860294d1590SErik van der Kouwe isconn = 0;
1861294d1590SErik van der Kouwe if (connect(client_sd, info->clientaddr, info->clientaddrlen) != -1) {
1862294d1590SErik van der Kouwe if (!info->ignore_connect_unaccepted) {
1863294d1590SErik van der Kouwe test_fail("connect() should have failed");
1864294d1590SErik van der Kouwe }
1865294d1590SErik van der Kouwe isconn = 1;
1866294d1590SErik van der Kouwe } else if (errno != EINTR) {
1867294d1590SErik van der Kouwe test_fail("connect() should have yielded EINTR");
1868294d1590SErik van der Kouwe }
1869294d1590SErik van der Kouwe
1870294d1590SErik van der Kouwe alarm(0);
1871294d1590SErik van der Kouwe
1872294d1590SErik van der Kouwe check_select(client_sd, 0 /*read*/, isconn /*write*/, 0 /*block*/);
1873294d1590SErik van der Kouwe
1874294d1590SErik van der Kouwe switch (fork()) {
1875294d1590SErik van der Kouwe case 0:
1876294d1590SErik van der Kouwe errct = 0;
1877294d1590SErik van der Kouwe close(client_sd);
1878294d1590SErik van der Kouwe
187927852ebeSDavid van Moolenbroek /* Ensure that the parent is blocked on the send(). */
188027852ebeSDavid van Moolenbroek sleep(1);
188127852ebeSDavid van Moolenbroek
1882294d1590SErik van der Kouwe check_select(server_sd, 1 /*read*/, 1 /*write*/, 0 /*block*/);
1883294d1590SErik van der Kouwe
1884294d1590SErik van der Kouwe len = sizeof(addr);
1885294d1590SErik van der Kouwe client_sd = accept(server_sd, (struct sockaddr *) &addr, &len);
1886294d1590SErik van der Kouwe if (client_sd == -1)
1887294d1590SErik van der Kouwe test_fail("accept() should have succeeded");
1888294d1590SErik van der Kouwe
1889294d1590SErik van der Kouwe check_select(server_sd, 0 /*read*/, 1 /*write*/, 0 /*block*/);
1890294d1590SErik van der Kouwe
1891294d1590SErik van der Kouwe close(server_sd);
1892294d1590SErik van der Kouwe
1893294d1590SErik van der Kouwe check_select(client_sd, 1 /*read*/, -1 /*write*/, 1 /*block*/);
1894294d1590SErik van der Kouwe check_select(client_sd, 1 /*read*/, 1 /*write*/, 0 /*block*/);
1895294d1590SErik van der Kouwe
1896294d1590SErik van der Kouwe if (recv(client_sd, buf, sizeof(buf), 0) != sizeof(buf))
1897294d1590SErik van der Kouwe test_fail("recv() should have yielded bytes");
1898294d1590SErik van der Kouwe
1899294d1590SErik van der Kouwe /* No partial transfers should be happening. */
1900294d1590SErik van der Kouwe check_select(client_sd, 0 /*read*/, 1 /*write*/, 0 /*block*/);
1901294d1590SErik van der Kouwe
1902294d1590SErik van der Kouwe sleep(1);
1903294d1590SErik van der Kouwe
1904294d1590SErik van der Kouwe fcntl(client_sd, F_SETFL, fcntl(client_sd, F_GETFL) |
1905294d1590SErik van der Kouwe O_NONBLOCK);
1906294d1590SErik van der Kouwe
1907294d1590SErik van der Kouwe /* We can only test nonblocking writes by filling the pipe. */
1908294d1590SErik van der Kouwe while ((r = write(client_sd, buf, sizeof(buf))) > 0);
1909294d1590SErik van der Kouwe
1910294d1590SErik van der Kouwe if (r != -1) {
1911294d1590SErik van der Kouwe test_fail("write() should have failed");
1912294d1590SErik van der Kouwe } else if (errno != EAGAIN) {
1913294d1590SErik van der Kouwe test_fail("write() should have yielded EAGAIN");
1914294d1590SErik van der Kouwe }
1915294d1590SErik van der Kouwe
1916294d1590SErik van der Kouwe check_select(client_sd, 0 /*read*/, 0 /*write*/, 0 /*block*/);
1917294d1590SErik van der Kouwe
1918294d1590SErik van der Kouwe if (write(client_sd, buf, 1) != -1) {
1919294d1590SErik van der Kouwe test_fail("write() should have failed");
1920294d1590SErik van der Kouwe } else if (errno != EAGAIN) {
1921294d1590SErik van der Kouwe test_fail("write() should have yielded EAGAIN");
1922294d1590SErik van der Kouwe }
1923294d1590SErik van der Kouwe
1924294d1590SErik van der Kouwe exit(errct);
1925294d1590SErik van der Kouwe case -1:
1926294d1590SErik van der Kouwe test_fail("can't fork");
1927294d1590SErik van der Kouwe default:
1928294d1590SErik van der Kouwe break;
1929294d1590SErik van der Kouwe }
1930294d1590SErik van der Kouwe
1931294d1590SErik van der Kouwe close(server_sd);
1932294d1590SErik van der Kouwe
1933294d1590SErik van der Kouwe if (send(client_sd, buf, sizeof(buf), 0) != sizeof(buf))
1934294d1590SErik van der Kouwe test_fail("send() should have succeded");
1935294d1590SErik van der Kouwe
1936294d1590SErik van der Kouwe check_select(client_sd, 0 /*read*/, 1 /*write*/, 0 /*block*/);
1937294d1590SErik van der Kouwe
1938294d1590SErik van der Kouwe if (wait(&status) <= 0)
1939294d1590SErik van der Kouwe test_fail("wait() should have succeeded");
1940294d1590SErik van der Kouwe if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
1941294d1590SErik van der Kouwe test_fail("child process failed the test");
1942294d1590SErik van der Kouwe
1943294d1590SErik van der Kouwe check_select(client_sd, 1 /*read*/, 1 /*write*/, 0 /*block*/);
1944294d1590SErik van der Kouwe
1945294d1590SErik van der Kouwe close(client_sd);
1946294d1590SErik van der Kouwe
1947294d1590SErik van der Kouwe sigaction(SIGALRM, &oact, NULL);
1948294d1590SErik van der Kouwe
1949294d1590SErik van der Kouwe info->callback_cleanup();
1950294d1590SErik van der Kouwe debug("leaving test_intr()");
1951294d1590SErik van der Kouwe }
1952294d1590SErik van der Kouwe
1953294d1590SErik van der Kouwe /*
1954294d1590SErik van der Kouwe * Verify that closing a connecting socket before it is accepted will result in
1955294d1590SErik van der Kouwe * no activity on the accepting side later.
1956294d1590SErik van der Kouwe */
1957294d1590SErik van der Kouwe void
test_connect_close(const struct socket_test_info * info)1958294d1590SErik van der Kouwe test_connect_close(const struct socket_test_info *info)
1959294d1590SErik van der Kouwe {
1960*ad920fc4SDavid van Moolenbroek int server_sd, client_sd, sd, on;
1961294d1590SErik van der Kouwe struct sockaddr_storage addr;
1962294d1590SErik van der Kouwe socklen_t len;
1963294d1590SErik van der Kouwe
1964294d1590SErik van der Kouwe debug("entering test_connect_close()");
1965294d1590SErik van der Kouwe SOCKET(server_sd, info->domain, info->type, 0);
1966294d1590SErik van der Kouwe
1967*ad920fc4SDavid van Moolenbroek on = 1;
1968*ad920fc4SDavid van Moolenbroek (void)setsockopt(server_sd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
1969*ad920fc4SDavid van Moolenbroek
1970294d1590SErik van der Kouwe if (bind(server_sd, info->serveraddr, info->serveraddrlen) == -1)
1971294d1590SErik van der Kouwe test_fail("bind() should have worked");
1972294d1590SErik van der Kouwe
197327852ebeSDavid van Moolenbroek if (info->callback_set_listen_opt != NULL)
197427852ebeSDavid van Moolenbroek info->callback_set_listen_opt(server_sd);
197527852ebeSDavid van Moolenbroek
1976294d1590SErik van der Kouwe if (listen(server_sd, 8) == -1)
1977294d1590SErik van der Kouwe test_fail("listen() should have worked");
1978294d1590SErik van der Kouwe
1979294d1590SErik van der Kouwe fcntl(server_sd, F_SETFL, fcntl(server_sd, F_GETFL) | O_NONBLOCK);
1980294d1590SErik van der Kouwe
1981294d1590SErik van der Kouwe check_select(server_sd, 0 /*read*/, 1 /*write*/, 0 /*block*/);
1982294d1590SErik van der Kouwe
1983294d1590SErik van der Kouwe SOCKET(client_sd, info->domain, info->type, 0);
1984294d1590SErik van der Kouwe
1985294d1590SErik van der Kouwe fcntl(client_sd, F_SETFL, fcntl(client_sd, F_GETFL) | O_NONBLOCK);
1986294d1590SErik van der Kouwe
1987294d1590SErik van der Kouwe if (connect(client_sd, info->clientaddr, info->clientaddrlen) != -1 ||
1988294d1590SErik van der Kouwe errno != EINPROGRESS)
1989294d1590SErik van der Kouwe test_fail("connect() should have yielded EINPROGRESS");
1990294d1590SErik van der Kouwe
1991294d1590SErik van der Kouwe check_select_cond(client_sd, 0 /*read*/, 0 /*write*/, 0 /*block*/,
1992294d1590SErik van der Kouwe !info->ignore_select_delay);
1993294d1590SErik van der Kouwe check_select_cond(server_sd, 1 /*read*/, 1 /*write*/, 0 /*block*/,
1994294d1590SErik van der Kouwe !info->ignore_select_delay);
1995294d1590SErik van der Kouwe
1996294d1590SErik van der Kouwe close(client_sd);
1997294d1590SErik van der Kouwe
1998294d1590SErik van der Kouwe check_select_cond(server_sd, 0 /*read*/, 1 /*write*/, 0 /*block*/,
1999294d1590SErik van der Kouwe !info->ignore_select_delay);
2000294d1590SErik van der Kouwe
2001294d1590SErik van der Kouwe len = sizeof(addr);
2002294d1590SErik van der Kouwe errno = 0;
2003*ad920fc4SDavid van Moolenbroek if ((sd = accept(server_sd, (struct sockaddr *) &addr, &len)) != -1) {
2004294d1590SErik van der Kouwe if (!info->ignore_accept_delay) {
2005294d1590SErik van der Kouwe test_fail("accept() should have failed");
2006294d1590SErik van der Kouwe }
2007*ad920fc4SDavid van Moolenbroek close(sd);
2008294d1590SErik van der Kouwe } else if (errno != EAGAIN) {
2009294d1590SErik van der Kouwe test_fail("accept() should have yielded EAGAIN");
2010294d1590SErik van der Kouwe }
2011294d1590SErik van der Kouwe close(server_sd);
2012294d1590SErik van der Kouwe
2013294d1590SErik van der Kouwe info->callback_cleanup();
2014294d1590SErik van der Kouwe debug("leaving test_connect_close()");
2015294d1590SErik van der Kouwe }
2016294d1590SErik van der Kouwe
2017294d1590SErik van der Kouwe /*
2018294d1590SErik van der Kouwe * Verify that closing a listening socket will cause a blocking connect to fail
2019*ad920fc4SDavid van Moolenbroek * with ECONNRESET, and that a subsequent write will yield EPIPE. This test
2020*ad920fc4SDavid van Moolenbroek * works only if the connect(2) does not succeed before accept(2) is called at
2021*ad920fc4SDavid van Moolenbroek * all, which means it is limited to UDS with LOCAL_CONNWAIT right now.
2022294d1590SErik van der Kouwe */
2023294d1590SErik van der Kouwe void
test_listen_close(const struct socket_test_info * info)2024294d1590SErik van der Kouwe test_listen_close(const struct socket_test_info *info)
2025294d1590SErik van der Kouwe {
2026294d1590SErik van der Kouwe int server_sd, client_sd;
2027*ad920fc4SDavid van Moolenbroek int status, on;
2028294d1590SErik van der Kouwe char byte;
2029294d1590SErik van der Kouwe
2030294d1590SErik van der Kouwe debug("entering test_listen_close()");
2031294d1590SErik van der Kouwe SOCKET(server_sd, info->domain, info->type, 0);
2032294d1590SErik van der Kouwe
2033*ad920fc4SDavid van Moolenbroek on = 1;
2034*ad920fc4SDavid van Moolenbroek (void)setsockopt(server_sd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
2035*ad920fc4SDavid van Moolenbroek
2036294d1590SErik van der Kouwe if (bind(server_sd, info->serveraddr, info->serveraddrlen) == -1)
2037294d1590SErik van der Kouwe test_fail("bind() should have worked");
2038294d1590SErik van der Kouwe
203927852ebeSDavid van Moolenbroek if (info->callback_set_listen_opt != NULL)
204027852ebeSDavid van Moolenbroek info->callback_set_listen_opt(server_sd);
204127852ebeSDavid van Moolenbroek
2042294d1590SErik van der Kouwe if (listen(server_sd, 8) == -1)
2043294d1590SErik van der Kouwe test_fail("listen() should have worked");
2044294d1590SErik van der Kouwe
2045294d1590SErik van der Kouwe switch (fork()) {
2046294d1590SErik van der Kouwe case 0:
2047294d1590SErik van der Kouwe sleep(1);
2048294d1590SErik van der Kouwe
2049294d1590SErik van der Kouwe exit(0);
2050294d1590SErik van der Kouwe case -1:
2051294d1590SErik van der Kouwe test_fail("can't fork");
2052294d1590SErik van der Kouwe default:
2053294d1590SErik van der Kouwe break;
2054294d1590SErik van der Kouwe }
2055294d1590SErik van der Kouwe
2056294d1590SErik van der Kouwe close(server_sd);
2057294d1590SErik van der Kouwe
2058294d1590SErik van der Kouwe SOCKET(client_sd, info->domain, info->type, 0);
2059294d1590SErik van der Kouwe
2060294d1590SErik van der Kouwe byte = 0;
2061294d1590SErik van der Kouwe if (write(client_sd, &byte, 1) != -1 || errno != ENOTCONN)
2062294d1590SErik van der Kouwe test_fail("write() should have yielded ENOTCONN");
2063294d1590SErik van der Kouwe
2064294d1590SErik van der Kouwe if (connect(client_sd, info->clientaddr, info->clientaddrlen) != -1) {
2065294d1590SErik van der Kouwe test_fail("connect() should have failed");
2066294d1590SErik van der Kouwe } else if (errno != ECONNRESET) {
2067294d1590SErik van der Kouwe test_fail("connect() should have yielded ECONNRESET");
2068294d1590SErik van der Kouwe }
2069294d1590SErik van der Kouwe
2070294d1590SErik van der Kouwe /*
207127852ebeSDavid van Moolenbroek * The error we get on the next write() depends on whether the socket
2072*ad920fc4SDavid van Moolenbroek * may be reused after a failed connect. For UDS, it may be, so we get
2073*ad920fc4SDavid van Moolenbroek * ENOTCONN. Otherwise we would expect EPIPE.
2074294d1590SErik van der Kouwe */
2075*ad920fc4SDavid van Moolenbroek if (write(client_sd, &byte, 1) != -1 || errno != ENOTCONN)
2076*ad920fc4SDavid van Moolenbroek test_fail("write() should have yielded ENOTCONN");
2077294d1590SErik van der Kouwe
2078294d1590SErik van der Kouwe close(client_sd);
2079294d1590SErik van der Kouwe
2080294d1590SErik van der Kouwe if (wait(&status) <= 0)
2081294d1590SErik van der Kouwe test_fail("wait() should have succeeded");
2082294d1590SErik van der Kouwe if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
2083294d1590SErik van der Kouwe test_fail("child process failed the test");
2084294d1590SErik van der Kouwe
2085294d1590SErik van der Kouwe info->callback_cleanup();
2086294d1590SErik van der Kouwe debug("leaving test_listen_close()");
2087294d1590SErik van der Kouwe }
2088294d1590SErik van der Kouwe
2089294d1590SErik van der Kouwe /*
2090294d1590SErik van der Kouwe * Verify that closing a listening socket will cause a nonblocking connect to
2091294d1590SErik van der Kouwe * result in the socket becoming readable and writable, and yielding ECONNRESET
2092294d1590SErik van der Kouwe * and EPIPE on the next two writes, respectively.
2093294d1590SErik van der Kouwe */
2094294d1590SErik van der Kouwe void
test_listen_close_nb(const struct socket_test_info * info)2095294d1590SErik van der Kouwe test_listen_close_nb(const struct socket_test_info *info)
2096294d1590SErik van der Kouwe {
2097294d1590SErik van der Kouwe int server_sd, client_sd;
2098*ad920fc4SDavid van Moolenbroek int status, on;
2099294d1590SErik van der Kouwe char byte;
2100294d1590SErik van der Kouwe
2101294d1590SErik van der Kouwe debug("entering test_listen_close_nb()");
2102294d1590SErik van der Kouwe SOCKET(server_sd, info->domain, info->type, 0);
2103294d1590SErik van der Kouwe
2104*ad920fc4SDavid van Moolenbroek on = 1;
2105*ad920fc4SDavid van Moolenbroek (void)setsockopt(server_sd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
2106*ad920fc4SDavid van Moolenbroek
2107294d1590SErik van der Kouwe if (bind(server_sd, info->serveraddr, info->serveraddrlen) == -1)
2108294d1590SErik van der Kouwe test_fail("bind() should have worked");
2109294d1590SErik van der Kouwe
211027852ebeSDavid van Moolenbroek if (info->callback_set_listen_opt != NULL)
211127852ebeSDavid van Moolenbroek info->callback_set_listen_opt(server_sd);
211227852ebeSDavid van Moolenbroek
2113294d1590SErik van der Kouwe if (listen(server_sd, 8) == -1)
2114294d1590SErik van der Kouwe test_fail("listen() should have worked");
2115294d1590SErik van der Kouwe
2116294d1590SErik van der Kouwe switch (fork()) {
2117294d1590SErik van der Kouwe case 0:
2118294d1590SErik van der Kouwe sleep(1);
2119294d1590SErik van der Kouwe
2120294d1590SErik van der Kouwe exit(0);
2121294d1590SErik van der Kouwe case -1:
2122294d1590SErik van der Kouwe test_fail("can't fork");
2123294d1590SErik van der Kouwe default:
2124294d1590SErik van der Kouwe break;
2125294d1590SErik van der Kouwe }
2126294d1590SErik van der Kouwe
2127294d1590SErik van der Kouwe close(server_sd);
2128294d1590SErik van der Kouwe
2129294d1590SErik van der Kouwe SOCKET(client_sd, info->domain, info->type, 0);
2130294d1590SErik van der Kouwe
2131294d1590SErik van der Kouwe fcntl(client_sd, F_SETFL, fcntl(client_sd, F_GETFL) | O_NONBLOCK);
2132294d1590SErik van der Kouwe
2133294d1590SErik van der Kouwe if (connect(client_sd, info->clientaddr, info->clientaddrlen) != -1 ||
2134294d1590SErik van der Kouwe errno != EINPROGRESS)
2135294d1590SErik van der Kouwe test_fail("connect() should have yielded EINPROGRESS");
2136294d1590SErik van der Kouwe
2137294d1590SErik van der Kouwe check_select_cond(client_sd, 0 /*read*/, 0 /*write*/, 0 /*block*/,
2138294d1590SErik van der Kouwe !info->ignore_select_delay);
2139294d1590SErik van der Kouwe check_select_cond(client_sd, 1 /*read*/, 1 /*write*/, 1 /*block*/,
2140294d1590SErik van der Kouwe !info->ignore_select_delay);
2141294d1590SErik van der Kouwe
2142294d1590SErik van der Kouwe byte = 0;
2143294d1590SErik van der Kouwe if (write(client_sd, &byte, 1) != -1) {
2144294d1590SErik van der Kouwe if (!info->ignore_write_conn_reset) {
2145294d1590SErik van der Kouwe test_fail("write() should have failed");
2146294d1590SErik van der Kouwe }
2147294d1590SErik van der Kouwe } else if (errno != ECONNRESET) {
2148294d1590SErik van der Kouwe test_fail("write() should have yielded ECONNRESET");
2149294d1590SErik van der Kouwe }
2150294d1590SErik van der Kouwe
2151294d1590SErik van der Kouwe check_select_cond(client_sd, 1 /*read*/, 1 /*write*/, 0 /*block*/,
2152294d1590SErik van der Kouwe !info->ignore_select_delay);
2153294d1590SErik van der Kouwe
2154294d1590SErik van der Kouwe close(client_sd);
2155294d1590SErik van der Kouwe
2156294d1590SErik van der Kouwe if (wait(&status) <= 0)
2157294d1590SErik van der Kouwe test_fail("wait() should have succeeded");
2158294d1590SErik van der Kouwe if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
2159294d1590SErik van der Kouwe test_fail("child process failed the test");
2160294d1590SErik van der Kouwe
2161294d1590SErik van der Kouwe info->callback_cleanup();
2162294d1590SErik van der Kouwe debug("leaving test_listen_close_nb()");
2163294d1590SErik van der Kouwe }
2164