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