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