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