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) {
222 int fd_sock
, fd_new
, yes
= 1, exitstatus
;
223 int sockets
[NUMCHILDREN
], i
;
224 fd_set fds_read
, fds_write
, fds_error
;
225 fd_set fds_compare_read
, fds_compare_write
;
227 int retval
, childresults
= 0;
229 struct sockaddr_in my_addr
;
230 struct sockaddr_in other_addr
;
231 socklen_t other_size
;
233 if((fd_sock
= socket(PF_INET
, SOCK_STREAM
, 0)) < 0) {
234 perror("Error getting socket\n");
238 my_addr
.sin_family
= AF_INET
;
239 my_addr
.sin_port
= htons(MYPORT
); /* Short, network byte order */
240 my_addr
.sin_addr
.s_addr
= INADDR_ANY
;
241 /* Normally we'd zerofill sin_zero, but there is no such thing on Minix */
243 memset(my_addr
.sin_zero
, '\0', sizeof my_addr
.sin_zero
);
246 /* Reuse port number. Not implemented in Minix. */
248 if(setsockopt(fd_sock
, SOL_SOCKET
, SO_REUSEADDR
, &yes
, sizeof(int)) < 0) {
249 perror("Error setting port reuse option");
255 if(bind(fd_sock
, (struct sockaddr
*) &my_addr
, sizeof my_addr
) < 0) {
256 perror("Error binding to port");
260 /* Mark socket to be used for incoming connections */
261 if(listen(fd_sock
, 20) < 0) {
267 /* While sockets resemble file descriptors, they are not the same at all.
268 We can read/write from/to and close file descriptors, but we cannot open
269 them O_RDONLY or O_WRONLY; they are always O_RDWR (other flags do not make
270 sense regarding sockets). As such, we cannot provide wrong file descriptors
271 to select, except for descriptors that are not in use.
272 We will test standard behavior and what is described in [2]. [1] and [3]
273 are not possible to test on Minix, as Minix does not support OOB data. That
274 is, the TCP layer can handle it, but there is no socket interface for it.
275 Our test consists of waiting for input from the first two children and
276 waiting to write output [standard usage]. Then the first child closes its
277 connection we select for reading. This should fail with error set. Then we
278 close child number two on our side and select for reading. This should fail
279 with EBADF. Child number three shall then do a non-blocking connect (after
280 waiting for DO_PAUSE seconds) and do a select, resulting in being marked
281 ready for writing. Subsequently child number four also does a non-blocking
282 connect to loclhost on MYPORT+1 (causing the connect to fail) and then does
283 a select. This should result in write and error being set (error because of
287 /* Accept and store connections from the first two children */
288 other_size
= sizeof(other_addr
);
289 for(i
= 0; i
< 2; i
++) {
290 fd_new
= accept(fd_sock
, (struct sockaddr
*) &other_addr
, &other_size
);
291 if(fd_new
< 0) break;
295 /* If we break out of the for loop, we ran across an error and want to exit.
296 Check whether we broke out. */
298 perror("Error accepting connection");
302 /* Select error condition checking */
303 for(childresults
= 0; childresults
< 2; childresults
++) {
304 FD_ZERO(&fds_read
); FD_ZERO(&fds_write
); FD_ZERO(&fds_error
);
305 FD_SET(sockets
[childresults
], &fds_read
);
306 FD_SET(sockets
[childresults
], &fds_write
);
307 FD_SET(sockets
[childresults
], &fds_error
);
308 tv
.tv_sec
= DO_TIMEOUT
;
311 retval
= select(sockets
[childresults
]+1, &fds_read
, &fds_write
, &fds_error
,
315 snprintf(errbuf
, sizeof(errbuf
),
316 "two fds should be set%s", (retval
== 0 ? " (TIMEOUT)" : ""));
320 FD_ZERO(&fds_compare_read
); FD_ZERO(&fds_compare_write
);
321 FD_SET(sockets
[childresults
], &fds_compare_write
);
323 /* We can't say much about being ready for reading at this point or not. It
324 is not specified and the other side might have data ready for us to read
326 if(!compare_fds(sockets
[childresults
]+1, &fds_compare_write
, &fds_write
))
327 e(2, "write should be set");
329 if(!empty_fds(sockets
[childresults
]+1, &fds_error
))
330 e(3, "no error should be set");
334 /* We continue by accepting a connection of child 3 */
335 fd_new
= accept(fd_sock
, (struct sockaddr
*) &other_addr
, &other_size
);
337 perror("Error accepting connection\n");
342 /* Child 4 will never connect */
344 /* Child 5 is still pending to be accepted. Open Group: "If the socket is
345 currently listening, then it shall be marked as readable if an incoming
346 connection request has been received, and a call to the accept() function
347 shall complete without blocking."*/
349 FD_SET(fd_sock
, &fds_read
);
350 tv
.tv_sec
= DO_TIMEOUT
;
352 retval
= select(fd_sock
+1, &fds_read
, NULL
, NULL
, &tv
);
354 snprintf(errbuf
, sizeof(errbuf
),
355 "one fd should be set%s", (retval
== 0 ? " (TIMEOUT)" : ""));
359 /* Check read bit is set */
360 FD_ZERO(&fds_compare_read
); FD_SET(fd_sock
, &fds_compare_read
);
361 if(!compare_fds(fd_sock
+1, &fds_compare_read
, &fds_read
))
362 e(5, "read should be set");
365 /* Accept incoming connection to unblock child 5 */
366 fd_new
= accept(fd_sock
, (struct sockaddr
*) &other_addr
, &other_size
);
368 perror("Error accepting connection\n");
374 /* We're done, let's wait a second to synchronize children and parent. */
375 tv
.tv_sec
= DO_HANDLEDATA
;
377 select(0, NULL
, NULL
, NULL
, &tv
);
379 /* Close connection with children. */
380 for(i
= 0; i
< NUMCHILDREN
; i
++) {
381 if(i
== 3) /* No need to disconnect child 4 that failed to connect. */
384 if(close(sockets
[i
]) < 0) {
389 /* Close listening socket */
390 if(close(fd_sock
) < 0) {
391 perror("Closing listening socket");
395 for(i
= 0; i
< NUMCHILDREN
; i
++) {
396 wait(&exitstatus
); /* Wait for children */
398 errct
+= WEXITSTATUS(exitstatus
); /* and count their errors, too. */
404 int main(int argc
, char **argv
) {
407 /* Get subtest number */
409 printf("Usage: %s subtest_no\n", argv
[0]);
411 } else if(sscanf(argv
[1], "%d", &subtest
) != 1) {
412 printf("Usage: %s subtest_no\n", argv
[0]);
416 /* Fork off a bunch of children */
417 for(i
= 0; i
< NUMCHILDREN
; i
++) {
419 if(forkres
== 0) do_child(i
);
420 else if(forkres
< 0) {
421 perror("Unable to fork");
425 /* do_child always calls exit(), so when we end up here, we're the parent. */
428 exit(-2); /* We're not supposed to get here. Both do_* routines should exit.*/