9e927f81d6d81cce6abbc75dc1697d09b1ef3489
[pspp] / tests / test-select.c
1 /* Test of select() substitute.
2    Copyright (C) 2008-2011 Free Software Foundation, Inc.
3
4    This program is free software: you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; either version 3 of the License, or
7    (at your option) any later version.
8
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
16
17 /* Written by Paolo Bonzini, 2008.  */
18
19 #include <config.h>
20
21 #include <sys/select.h>
22
23 #include "signature.h"
24
25 #ifdef TEST_PSELECT
26 SIGNATURE_CHECK (pselect, int,
27                  (int, fd_set *restrict, fd_set *restrict, fd_set *restrict,
28                   struct timespec const *restrict, const sigset_t *restrict));
29 #else
30 SIGNATURE_CHECK (select, int, (int, fd_set *, fd_set *, fd_set *,
31                                struct timeval *));
32 #endif
33
34 /* The following may be macros without underlying functions, so only
35    check signature if they are not macros.  */
36 #ifndef FD_CLR
37 SIGNATURE_CHECK (FD_CLR, void, (int, fd_set *));
38 #endif
39 #ifndef FD_ISSET
40 SIGNATURE_CHECK (FD_ISSET, void, (int, fd_set *));
41 #endif
42 #ifndef FD_SET
43 SIGNATURE_CHECK (FD_SET, int, (int, fd_set *));
44 #endif
45 #ifndef FD_ZERO
46 SIGNATURE_CHECK (FD_ZERO, void, (fd_set *));
47 #endif
48
49 #include <stdio.h>
50 #include <string.h>
51 #include <netinet/in.h>
52 #include <arpa/inet.h>
53 #include <unistd.h>
54 #include <fcntl.h>
55 #include <stdlib.h>
56 #include <stdbool.h>
57 #include <sys/ioctl.h>
58 #include <errno.h>
59
60 #include "macros.h"
61
62 #if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
63 # define WIN32_NATIVE
64 #endif
65
66 #ifdef HAVE_SYS_WAIT_H
67 # include <sys/wait.h>
68 #endif
69
70 #ifndef SO_REUSEPORT
71 # define SO_REUSEPORT    SO_REUSEADDR
72 #endif
73
74 #define TEST_PORT       12345
75
76
77 /* Minimal testing infrastructure.  */
78
79 static int failures;
80
81 static void
82 failed (const char *reason)
83 {
84   if (++failures > 1)
85     printf ("  ");
86   printf ("failed (%s)\n", reason);
87 }
88
89 static int
90 test (void (*fn) (void), const char *msg)
91 {
92   failures = 0;
93   printf ("%s... ", msg);
94   fflush (stdout);
95   fn ();
96
97   if (!failures)
98     printf ("passed\n");
99
100   return failures;
101 }
102
103
104 /* Funny socket code.  */
105
106 static int
107 open_server_socket (void)
108 {
109   int s, x;
110   struct sockaddr_in ia;
111
112   s = socket (AF_INET, SOCK_STREAM, 0);
113
114   memset (&ia, 0, sizeof (ia));
115   ia.sin_family = AF_INET;
116   inet_pton (AF_INET, "127.0.0.1", &ia.sin_addr);
117   ia.sin_port = htons (TEST_PORT);
118   if (bind (s, (struct sockaddr *) &ia, sizeof (ia)) < 0)
119     {
120       perror ("bind");
121       exit (77);
122     }
123
124   x = 1;
125   setsockopt (s, SOL_SOCKET, SO_REUSEPORT, &x, sizeof (x));
126
127   if (listen (s, 1) < 0)
128     {
129       perror ("listen");
130       exit (77);
131     }
132
133   return s;
134 }
135
136 static int
137 connect_to_socket (bool blocking)
138 {
139   int s;
140   struct sockaddr_in ia;
141
142   s = socket (AF_INET, SOCK_STREAM, 0);
143
144   memset (&ia, 0, sizeof (ia));
145   ia.sin_family = AF_INET;
146   inet_pton (AF_INET, "127.0.0.1", &ia.sin_addr);
147   ia.sin_port = htons (TEST_PORT);
148
149   if (!blocking)
150     {
151 #ifdef WIN32_NATIVE
152       unsigned long iMode = 1;
153       ioctl (s, FIONBIO, (char *) &iMode);
154
155 #elif defined F_GETFL
156       int oldflags = fcntl (s, F_GETFL, NULL);
157
158       if (!(oldflags & O_NONBLOCK))
159         fcntl (s, F_SETFL, oldflags | O_NONBLOCK);
160 #endif
161     }
162
163   if (connect (s, (struct sockaddr *) &ia, sizeof (ia)) < 0
164       && (blocking || errno != EINPROGRESS))
165     {
166       perror ("connect");
167       exit (77);
168     }
169
170   return s;
171 }
172
173
174 /* A slightly more convenient interface to select(2).
175    Waits until a specific event occurs on a file descriptor FD.
176    EV is a bit mask of events to look for:
177      SEL_IN - input can be polled without blocking,
178      SEL_OUT - output can be provided without blocking,
179      SEL_EXC - an exception occurred,
180    A maximum wait time is specified by TIMEOUT.
181    *TIMEOUT = { 0, 0 } means to return immediately,
182    TIMEOUT = NULL means to wait indefinitely.  */
183
184 enum { SEL_IN = 1, SEL_OUT = 2, SEL_EXC = 4 };
185
186 static int
187 do_select (int fd, int ev, struct timeval *timeout)
188 {
189   fd_set rfds, wfds, xfds;
190   int r, rev;
191
192   FD_ZERO (&rfds);
193   FD_ZERO (&wfds);
194   FD_ZERO (&xfds);
195   if (ev & SEL_IN)
196     FD_SET (fd, &rfds);
197   if (ev & SEL_OUT)
198     FD_SET (fd, &wfds);
199   if (ev & SEL_EXC)
200     FD_SET (fd, &xfds);
201 #ifdef TEST_PSELECT
202   {
203     struct timespec ts, *pts = NULL;
204     if (timeout)
205       {
206         ts.tv_sec = timeout->tv_sec;
207         ts.tv_nsec = timeout->tv_usec * 1000;
208         pts = &ts;
209       }
210     r = pselect (fd + 1, &rfds, &wfds, &xfds, pts, NULL);
211   }
212 #else
213   r = select (fd + 1, &rfds, &wfds, &xfds, timeout);
214 #endif
215   if (r < 0)
216     return r;
217
218   rev = 0;
219   if (FD_ISSET (fd, &rfds))
220     rev |= SEL_IN;
221   if (FD_ISSET (fd, &wfds))
222     rev |= SEL_OUT;
223   if (FD_ISSET (fd, &xfds))
224     rev |= SEL_EXC;
225   if (rev && r == 0)
226     failed ("select returned 0");
227   if (rev & ~ev)
228     failed ("select returned unrequested events");
229
230   return rev;
231 }
232
233 static int
234 do_select_nowait (int fd, int ev)
235 {
236   struct timeval tv0;
237   tv0.tv_sec = 0;
238   tv0.tv_usec = 0;
239   return do_select (fd, ev, &tv0);
240 }
241
242 static int
243 do_select_wait (int fd, int ev)
244 {
245   return do_select (fd, ev, NULL);
246 }
247
248
249 /* Test select(2) for TTYs.  */
250
251 #ifdef INTERACTIVE
252 static void
253 test_tty (void)
254 {
255   if (do_select_nowait (0, SEL_IN) != 0)
256     failed ("can read");
257   if (do_select_nowait (0, SEL_OUT) == 0)
258     failed ("cannot write");
259
260   if (do_select_wait (0, SEL_IN) == 0)
261     failed ("return with infinite timeout");
262
263   getchar ();
264   if (do_select_nowait (0, SEL_IN) != 0)
265     failed ("can read after getc");
266 }
267 #endif
268
269
270 /* Test select(2) for unconnected nonblocking sockets.  */
271
272 static void
273 test_connect_first (void)
274 {
275   int s = open_server_socket ();
276   struct sockaddr_in ia;
277   socklen_t addrlen;
278
279   int c1, c2;
280
281   if (do_select_nowait (s, SEL_IN | SEL_EXC) != 0)
282     failed ("can read, socket not connected");
283
284   c1 = connect_to_socket (false);
285
286   if (do_select_wait (s, SEL_IN | SEL_EXC) != SEL_IN)
287     failed ("expecting readability on passive socket");
288   if (do_select_nowait (s, SEL_IN | SEL_EXC) != SEL_IN)
289     failed ("expecting readability on passive socket");
290
291   addrlen = sizeof (ia);
292   c2 = accept (s, (struct sockaddr *) &ia, &addrlen);
293   ASSERT (close (s) == 0);
294   ASSERT (close (c1) == 0);
295   ASSERT (close (c2) == 0);
296 }
297
298
299 /* Test select(2) for unconnected blocking sockets.  */
300
301 static void
302 test_accept_first (void)
303 {
304 #ifndef WIN32_NATIVE
305   int s = open_server_socket ();
306   struct sockaddr_in ia;
307   socklen_t addrlen;
308   char buf[3];
309   int c, pid;
310
311   pid = fork ();
312   if (pid < 0)
313     return;
314
315   if (pid == 0)
316     {
317       addrlen = sizeof (ia);
318       c = accept (s, (struct sockaddr *) &ia, &addrlen);
319       ASSERT (close (s) == 0);
320       ASSERT (write (c, "foo", 3) == 3);
321       ASSERT (read (c, buf, 3) == 3);
322       shutdown (c, SHUT_RD);
323       ASSERT (close (c) == 0);
324       exit (0);
325     }
326   else
327     {
328       ASSERT (close (s) == 0);
329       c = connect_to_socket (true);
330       if (do_select_nowait (c, SEL_OUT) != SEL_OUT)
331         failed ("cannot write after blocking connect");
332       ASSERT (write (c, "foo", 3) == 3);
333       wait (&pid);
334       if (do_select_wait (c, SEL_IN) != SEL_IN)
335         failed ("cannot read data left in the socket by closed process");
336       ASSERT (read (c, buf, 3) == 3);
337       ASSERT (write (c, "foo", 3) == 3);
338       (void) close (c); /* may fail with errno = ECONNRESET */
339     }
340 #endif
341 }
342
343
344 /* Common code for pipes and connected sockets.  */
345
346 static void
347 test_pair (int rd, int wd)
348 {
349   char buf[3];
350   if (do_select_wait (wd, SEL_IN | SEL_OUT | SEL_EXC) != SEL_OUT)
351     failed ("expecting writability before writing");
352   if (do_select_nowait (wd, SEL_IN | SEL_OUT | SEL_EXC) != SEL_OUT)
353     failed ("expecting writability before writing");
354
355   ASSERT (write (wd, "foo", 3) == 3);
356   if (do_select_wait (rd, SEL_IN) != SEL_IN)
357     failed ("expecting readability after writing");
358   if (do_select_nowait (rd, SEL_IN) != SEL_IN)
359     failed ("expecting readability after writing");
360
361   ASSERT (read (rd, buf, 3) == 3);
362 }
363
364
365 /* Test select(2) on connected sockets.  */
366
367 static void
368 test_socket_pair (void)
369 {
370   struct sockaddr_in ia;
371
372   socklen_t addrlen = sizeof (ia);
373   int s = open_server_socket ();
374   int c1 = connect_to_socket (false);
375   int c2 = accept (s, (struct sockaddr *) &ia, &addrlen);
376
377   ASSERT (close (s) == 0);
378
379   test_pair (c1, c2);
380   ASSERT (close (c1) == 0);
381   ASSERT (write (c2, "foo", 3) == 3);
382   (void) close (c2); /* may fail with errno = ECONNRESET */
383 }
384
385
386 /* Test select(2) on pipes.  */
387
388 static void
389 test_pipe (void)
390 {
391   int fd[2];
392
393   ASSERT (pipe (fd) == 0);
394   test_pair (fd[0], fd[1]);
395   ASSERT (close (fd[0]) == 0);
396   ASSERT (close (fd[1]) == 0);
397 }
398
399
400 /* Do them all.  */
401
402 int
403 main (void)
404 {
405   int result;
406
407 #ifdef INTERACTIVE
408   printf ("Please press Enter\n");
409   test (test_tty, "TTY");
410 #endif
411
412   result = test (test_connect_first, "Unconnected socket test");
413   result += test (test_socket_pair, "Connected sockets test");
414   result += test (test_accept_first, "General socket test with fork");
415   result += test (test_pipe, "Pipe test");
416
417   exit (result);
418 }