5 * Select works on regular files, (pseudo) terminal devices, streams-based
6 * files, FIFOs, pipes, and sockets. This test verifies selecting for sockets.
8 * This test is part of a bigger select test. It expects as argument which sub-
11 * Specific rules for sockets:
12 * If a socket has a pending error, it shall be considered to have an
13 * exceptional condition pending. Otherwise, what constitutes an exceptional
14 * condition is file type-specific. For a file descriptor for use with a
15 * socket, it is protocol-specific except as noted below. For other file types
16 * it is implementation-defined. If the operation is meaningless for a
17 * particular file type, pselect() or select() shall indicate that the
18 * descriptor is ready for read or write operations, and shall indicate that
19 * the descriptor has no exceptional condition pending.
21 * [1] If a descriptor refers to a socket, the implied input function is the
22 * recvmsg()function with parameters requesting normal and ancillary data, such
23 * that the presence of either type shall cause the socket to be marked as
24 * readable. The presence of out-of-band data shall be checked if the socket
25 * option SO_OOBINLINE has been enabled, as out-of-band data is enqueued with
26 * normal data. If the socket is currently listening, then it shall be marked
27 * as readable if an incoming connection request has been received, and a call
28 * to the accept() function shall complete without blocking.
30 * [2] If a descriptor refers to a socket, the implied output function is the
31 * sendmsg() function supplying an amount of normal data equal to the current
32 * value of the SO_SNDLOWAT option for the socket. If a non-blocking call to
33 * the connect() function has been made for a socket, and the connection
34 * attempt has either succeeded or failed leaving a pending error, the socket
35 * shall be marked as writable.
37 * [3] A socket shall be considered to have an exceptional condition pending if
38 * a receive operation with O_NONBLOCK clear for the open file description and
39 * with the MSG_OOB flag set would return out-of-band data without blocking.
40 * (It is protocol-specific whether the MSG_OOB flag would be used to read
41 * out-of-band data.) A socket shall also be considered to have an exceptional
42 * condition pending if an out-of-band data mark is present in the receive
43 * queue. Other circumstances under which a socket may be considered to have an
44 * exceptional condition pending are protocol-specific and
45 * implementation-defined.
51 #include <sys/types.h>
54 #include <sys/select.h>
55 #include <sys/socket.h>
56 #include <netinet/in.h>
57 #include <arpa/inet.h>
65 #define DO_HANDLEDATA 1
72 int errct
= 0, subtest
= -1;
75 void e(int n
, char *s
) {
76 printf("Subtest %d, error %d, %s\n", subtest
, n
, s
);
78 if (errct
++ > MAX_ERROR
) {
79 printf("Too many errors; test aborted\n");
84 /* All *_fds routines are helping routines. They intentionally use FD_* macros
85 in order to prevent making assumptions on how the macros are implemented.*/
87 int count_fds(int nfds
, fd_set
*fds
) {
88 /* Return number of bits set in fds */
90 assert(fds
!= NULL
&& nfds
> 0);
91 for(i
= 0; i
< nfds
; i
++) {
92 if(FD_ISSET(i
, fds
)) result
++;
97 int empty_fds(int nfds
, fd_set
*fds
) {
98 /* Returns nonzero if the first bits up to nfds in fds are not set */
100 assert(fds
!= NULL
&& nfds
> 0);
101 for(i
= 0; i
< nfds
; i
++) if(FD_ISSET(i
, fds
)) return 0;
105 int compare_fds(int nfds
, fd_set
*lh
, fd_set
*rh
) {
106 /* Returns nonzero if lh equals rh up to nfds bits */
108 assert(lh
!= NULL
&& rh
!= NULL
&& nfds
> 0);
109 for(i
= 0; i
< nfds
; i
++) {
110 if((FD_ISSET(i
, lh
) && !FD_ISSET(i
, rh
)) ||
111 (!FD_ISSET(i
, lh
) && FD_ISSET(i
, rh
))) {
118 void dump_fds(int nfds
, fd_set
*fds
) {
119 /* Print a graphical representation of bits in fds */
121 if(fds
!= NULL
&& nfds
> 0) {
122 for(i
= 0; i
< nfds
; i
++) printf("%d ", (FD_ISSET(i
, fds
) ? 1 : 0));
127 void do_child(int childno
) {
131 fd_set fds_read
, fds_write
, fds_error
;
132 fd_set fds_compare_write
;
135 struct sockaddr_in server
;
138 if((fd_sock
= socket(PF_INET
, SOCK_STREAM
, 0)) < 0) {
139 perror("Error getting socket\n");
143 if((he
= gethostbyname("127.0.0.1")) == NULL
){/*"localhost" might be unknown*/
144 perror("Error resolving");
148 /* Child 4 connects to the wrong port. See Actual testing description below.*/
149 port
= (childno
== 3 ? MYPORT
+ 1 : MYPORT
);
151 memcpy(&server
.sin_addr
, he
->h_addr_list
[0], he
->h_length
);
152 server
.sin_family
= AF_INET
;
153 server
.sin_port
= htons(port
);
156 printf("Going to connect to: %s:%d\n", inet_ntoa(server
.sin_addr
),
157 ntohs(server
.sin_port
));
160 /* Normally we'd zerofill sin_zero, but there is no such thing on Minix */
162 memset(server
.sin_zero
, '\0', sizeof server
.sin_zero
);
165 /* Wait for parent to set up connection */
166 tv
.tv_sec
= (childno
<= 1 ? DO_PAUSE
: DO_TIMEOUT
);
168 retval
= select(0, NULL
, NULL
, NULL
, &tv
);
170 /* All set, let's do some testing */
171 /* Children 3 and 4 do a non-blocking connect */
172 if(childno
== 2 || childno
== 3)
173 fcntl(fd_sock
, F_SETFL
, fcntl(fd_sock
, F_GETFL
, 0) | O_NONBLOCK
);
175 if(connect(fd_sock
, (struct sockaddr
*) &server
, sizeof(server
)) < 0) {
176 /* Well, we don't actually care. The connect is non-blocking and is
177 supposed to "in progress" at this point. */
180 if(childno
== 2 || childno
== 3) { /* Children 3 and 4 */
181 /* Open Group: "If a non-blocking call to the connect() function has been
182 made for a socket, and the connection attempt has either succeeded or
183 failed leaving a pending error, the socket shall be marked as writable.
185 A socket shall be considered to have an exceptional condition pending if
186 a receive operation with O_NONBLOCK clear for the open file description
187 and with the MSG_OOB flag set would return out-of-band data without
188 blocking. (It is protocol-specific whether the MSG_OOB flag would be used
189 to read out-of-band data.) A socket shall also be considered to have an
190 exceptional condition pending if an out-of-band data mark is present in
191 the receive queue. Other circumstances under which a socket may be
192 considered to have an exceptional condition pending are protocol-specific
193 and implementation-defined."
195 In other words, it only makes sense for us to check the write set as the
196 read set is not expected to be set, but is allowed to be set (i.e.,
197 unspecified) and whether the error set is set is implementation-defined.
199 FD_ZERO(&fds_read
); FD_ZERO(&fds_write
); FD_ZERO(&fds_error
);
200 FD_SET(fd_sock
, &fds_write
);
201 tv
.tv_sec
= DO_TIMEOUT
;
203 retval
= select(fd_sock
+1, NULL
, &fds_write
, NULL
, &tv
);
206 if(retval
<= 0) e(6, "expected one fd to be ready");
208 FD_ZERO(&fds_compare_write
); FD_SET(fd_sock
, &fds_compare_write
);
209 if(!compare_fds(fd_sock
+1, &fds_compare_write
, &fds_compare_write
))
210 e(7, "write should be set");
213 if(close(fd_sock
) < 0) {
214 perror("Error disconnecting");
221 void do_parent(void) {
225 int fd_sock
, fd_new
, exitstatus
;
226 int sockets
[NUMCHILDREN
], i
;
227 fd_set fds_read
, fds_write
, fds_error
;
228 fd_set fds_compare_read
, fds_compare_write
;
230 int retval
, childresults
= 0;
232 struct sockaddr_in my_addr
;
233 struct sockaddr_in other_addr
;
234 socklen_t other_size
;
236 if((fd_sock
= socket(PF_INET
, SOCK_STREAM
, 0)) < 0) {
237 perror("Error getting socket\n");
241 my_addr
.sin_family
= AF_INET
;
242 my_addr
.sin_port
= htons(MYPORT
); /* Short, network byte order */
243 my_addr
.sin_addr
.s_addr
= INADDR_ANY
;
244 /* Normally we'd zerofill sin_zero, but there is no such thing on Minix */
246 memset(my_addr
.sin_zero
, '\0', sizeof my_addr
.sin_zero
);
249 /* Reuse port number. Not implemented in Minix. */
251 if(setsockopt(fd_sock
, SOL_SOCKET
, SO_REUSEADDR
, &yes
, sizeof(int)) < 0) {
252 perror("Error setting port reuse option");
258 if(bind(fd_sock
, (struct sockaddr
*) &my_addr
, sizeof my_addr
) < 0) {
259 perror("Error binding to port");
263 /* Mark socket to be used for incoming connections */
264 if(listen(fd_sock
, 20) < 0) {
270 /* While sockets resemble file descriptors, they are not the same at all.
271 We can read/write from/to and close file descriptors, but we cannot open
272 them O_RDONLY or O_WRONLY; they are always O_RDWR (other flags do not make
273 sense regarding sockets). As such, we cannot provide wrong file descriptors
274 to select, except for descriptors that are not in use.
275 We will test standard behavior and what is described in [2]. [1] and [3]
276 are not possible to test on Minix, as Minix does not support OOB data. That
277 is, the TCP layer can handle it, but there is no socket interface for it.
278 Our test consists of waiting for input from the first two children and
279 waiting to write output [standard usage]. Then the first child closes its
280 connection we select for reading. This should fail with error set. Then we
281 close child number two on our side and select for reading. This should fail
282 with EBADF. Child number three shall then do a non-blocking connect (after
283 waiting for DO_PAUSE seconds) and do a select, resulting in being marked
284 ready for writing. Subsequently child number four also does a non-blocking
285 connect to loclhost on MYPORT+1 (causing the connect to fail) and then does
286 a select. This should result in write and error being set (error because of
290 /* Accept and store connections from the first two children */
291 other_size
= sizeof(other_addr
);
292 for(i
= 0; i
< 2; i
++) {
293 fd_new
= accept(fd_sock
, (struct sockaddr
*) &other_addr
, &other_size
);
294 if(fd_new
< 0) break;
298 /* If we break out of the for loop, we ran across an error and want to exit.
299 Check whether we broke out. */
301 perror("Error accepting connection");
305 /* Select error condition checking */
306 for(childresults
= 0; childresults
< 2; childresults
++) {
307 FD_ZERO(&fds_read
); FD_ZERO(&fds_write
); FD_ZERO(&fds_error
);
308 FD_SET(sockets
[childresults
], &fds_read
);
309 FD_SET(sockets
[childresults
], &fds_write
);
310 FD_SET(sockets
[childresults
], &fds_error
);
311 tv
.tv_sec
= DO_TIMEOUT
;
314 retval
= select(sockets
[childresults
]+1, &fds_read
, &fds_write
, &fds_error
,
318 snprintf(errbuf
, sizeof(errbuf
),
319 "two fds should be set%s", (retval
== 0 ? " (TIMEOUT)" : ""));
323 FD_ZERO(&fds_compare_read
); FD_ZERO(&fds_compare_write
);
324 FD_SET(sockets
[childresults
], &fds_compare_write
);
326 /* We can't say much about being ready for reading at this point or not. It
327 is not specified and the other side might have data ready for us to read
329 if(!compare_fds(sockets
[childresults
]+1, &fds_compare_write
, &fds_write
))
330 e(2, "write should be set");
332 if(!empty_fds(sockets
[childresults
]+1, &fds_error
))
333 e(3, "no error should be set");
337 /* We continue by accepting a connection of child 3 */
338 fd_new
= accept(fd_sock
, (struct sockaddr
*) &other_addr
, &other_size
);
340 perror("Error accepting connection\n");
345 /* Child 4 will never connect */
347 /* Child 5 is still pending to be accepted. Open Group: "If the socket is
348 currently listening, then it shall be marked as readable if an incoming
349 connection request has been received, and a call to the accept() function
350 shall complete without blocking."*/
352 FD_SET(fd_sock
, &fds_read
);
353 tv
.tv_sec
= DO_TIMEOUT
;
355 retval
= select(fd_sock
+1, &fds_read
, NULL
, NULL
, &tv
);
357 snprintf(errbuf
, sizeof(errbuf
),
358 "one fd should be set%s", (retval
== 0 ? " (TIMEOUT)" : ""));
362 /* Check read bit is set */
363 FD_ZERO(&fds_compare_read
); FD_SET(fd_sock
, &fds_compare_read
);
364 if(!compare_fds(fd_sock
+1, &fds_compare_read
, &fds_read
))
365 e(5, "read should be set");
368 /* Accept incoming connection to unblock child 5 */
369 fd_new
= accept(fd_sock
, (struct sockaddr
*) &other_addr
, &other_size
);
371 perror("Error accepting connection\n");
377 /* We're done, let's wait a second to synchronize children and parent. */
378 tv
.tv_sec
= DO_HANDLEDATA
;
380 select(0, NULL
, NULL
, NULL
, &tv
);
382 /* Close connection with children. */
383 for(i
= 0; i
< NUMCHILDREN
; i
++) {
384 if(i
== 3) /* No need to disconnect child 4 that failed to connect. */
387 if(close(sockets
[i
]) < 0) {
392 /* Close listening socket */
393 if(close(fd_sock
) < 0) {
394 perror("Closing listening socket");
398 for(i
= 0; i
< NUMCHILDREN
; i
++) {
399 wait(&exitstatus
); /* Wait for children */
401 errct
+= WEXITSTATUS(exitstatus
); /* and count their errors, too. */
407 int main(int argc
, char **argv
) {
410 /* Get subtest number */
412 printf("Usage: %s subtest_no\n", argv
[0]);
414 } else if(sscanf(argv
[1], "%d", &subtest
) != 1) {
415 printf("Usage: %s subtest_no\n", argv
[0]);
419 /* Fork off a bunch of children */
420 for(i
= 0; i
< NUMCHILDREN
; i
++) {
422 if(forkres
== 0) do_child(i
);
423 else if(forkres
< 0) {
424 perror("Unable to fork");
428 /* do_child always calls exit(), so when we end up here, we're the parent. */
431 exit(-2); /* We're not supposed to get here. Both do_* routines should exit.*/