1 *433d6423SLionel Sambuc /* t40e.c
2 *433d6423SLionel Sambuc *
3 *433d6423SLionel Sambuc * Test sockets
4 *433d6423SLionel Sambuc *
5 *433d6423SLionel Sambuc * Select works on regular files, (pseudo) terminal devices, streams-based
6 *433d6423SLionel Sambuc * files, FIFOs, pipes, and sockets. This test verifies selecting for sockets.
7 *433d6423SLionel Sambuc *
8 *433d6423SLionel Sambuc * This test is part of a bigger select test. It expects as argument which sub-
9 *433d6423SLionel Sambuc * test it is.
10 *433d6423SLionel Sambuc *
11 *433d6423SLionel Sambuc * Specific rules for sockets:
12 *433d6423SLionel Sambuc * If a socket has a pending error, it shall be considered to have an
13 *433d6423SLionel Sambuc * exceptional condition pending. Otherwise, what constitutes an exceptional
14 *433d6423SLionel Sambuc * condition is file type-specific. For a file descriptor for use with a
15 *433d6423SLionel Sambuc * socket, it is protocol-specific except as noted below. For other file types
16 *433d6423SLionel Sambuc * it is implementation-defined. If the operation is meaningless for a
17 *433d6423SLionel Sambuc * particular file type, pselect() or select() shall indicate that the
18 *433d6423SLionel Sambuc * descriptor is ready for read or write operations, and shall indicate that
19 *433d6423SLionel Sambuc * the descriptor has no exceptional condition pending.
20 *433d6423SLionel Sambuc *
21 *433d6423SLionel Sambuc * [1] If a descriptor refers to a socket, the implied input function is the
22 *433d6423SLionel Sambuc * recvmsg()function with parameters requesting normal and ancillary data, such
23 *433d6423SLionel Sambuc * that the presence of either type shall cause the socket to be marked as
24 *433d6423SLionel Sambuc * readable. The presence of out-of-band data shall be checked if the socket
25 *433d6423SLionel Sambuc * option SO_OOBINLINE has been enabled, as out-of-band data is enqueued with
26 *433d6423SLionel Sambuc * normal data. If the socket is currently listening, then it shall be marked
27 *433d6423SLionel Sambuc * as readable if an incoming connection request has been received, and a call
28 *433d6423SLionel Sambuc * to the accept() function shall complete without blocking.
29 *433d6423SLionel Sambuc *
30 *433d6423SLionel Sambuc * [2] If a descriptor refers to a socket, the implied output function is the
31 *433d6423SLionel Sambuc * sendmsg() function supplying an amount of normal data equal to the current
32 *433d6423SLionel Sambuc * value of the SO_SNDLOWAT option for the socket. If a non-blocking call to
33 *433d6423SLionel Sambuc * the connect() function has been made for a socket, and the connection
34 *433d6423SLionel Sambuc * attempt has either succeeded or failed leaving a pending error, the socket
35 *433d6423SLionel Sambuc * shall be marked as writable.
36 *433d6423SLionel Sambuc *
37 *433d6423SLionel Sambuc * [3] A socket shall be considered to have an exceptional condition pending if
38 *433d6423SLionel Sambuc * a receive operation with O_NONBLOCK clear for the open file description and
39 *433d6423SLionel Sambuc * with the MSG_OOB flag set would return out-of-band data without blocking.
40 *433d6423SLionel Sambuc * (It is protocol-specific whether the MSG_OOB flag would be used to read
41 *433d6423SLionel Sambuc * out-of-band data.) A socket shall also be considered to have an exceptional
42 *433d6423SLionel Sambuc * condition pending if an out-of-band data mark is present in the receive
43 *433d6423SLionel Sambuc * queue. Other circumstances under which a socket may be considered to have an
44 *433d6423SLionel Sambuc * exceptional condition pending are protocol-specific and
45 *433d6423SLionel Sambuc * implementation-defined.
46 *433d6423SLionel Sambuc */
47 *433d6423SLionel Sambuc
48 *433d6423SLionel Sambuc #include <stdio.h>
49 *433d6423SLionel Sambuc #include <stdlib.h>
50 *433d6423SLionel Sambuc #include <unistd.h>
51 *433d6423SLionel Sambuc #include <sys/types.h>
52 *433d6423SLionel Sambuc #include <sys/stat.h>
53 *433d6423SLionel Sambuc #include <sys/wait.h>
54 *433d6423SLionel Sambuc #include <sys/select.h>
55 *433d6423SLionel Sambuc #include <sys/socket.h>
56 *433d6423SLionel Sambuc #include <netinet/in.h>
57 *433d6423SLionel Sambuc #include <arpa/inet.h>
58 *433d6423SLionel Sambuc #include <fcntl.h>
59 *433d6423SLionel Sambuc #include <errno.h>
60 *433d6423SLionel Sambuc #include <string.h>
61 *433d6423SLionel Sambuc #include <time.h>
62 *433d6423SLionel Sambuc #include <assert.h>
63 *433d6423SLionel Sambuc #include <netdb.h>
64 *433d6423SLionel Sambuc
65 *433d6423SLionel Sambuc #include "common.h"
66 *433d6423SLionel Sambuc
67 *433d6423SLionel Sambuc #define DO_HANDLEDATA 1
68 *433d6423SLionel Sambuc #define DO_PAUSE 3
69 *433d6423SLionel Sambuc #define DO_TIMEOUT 7
70 *433d6423SLionel Sambuc #define MYPORT 3490
71 *433d6423SLionel Sambuc #define NUMCHILDREN 5
72 *433d6423SLionel Sambuc #define MAX_ERROR 10
73 *433d6423SLionel Sambuc
74 *433d6423SLionel Sambuc char errbuf[1000];
75 *433d6423SLionel Sambuc
76 *433d6423SLionel Sambuc /* All *_fds routines are helping routines. They intentionally use FD_* macros
77 *433d6423SLionel Sambuc in order to prevent making assumptions on how the macros are implemented.*/
78 *433d6423SLionel Sambuc
79 *433d6423SLionel Sambuc #if 0
80 *433d6423SLionel Sambuc static int count_fds(int nfds, fd_set *fds) {
81 *433d6423SLionel Sambuc /* Return number of bits set in fds */
82 *433d6423SLionel Sambuc int i, result = 0;
83 *433d6423SLionel Sambuc assert(fds != NULL && nfds > 0);
84 *433d6423SLionel Sambuc for(i = 0; i < nfds; i++) {
85 *433d6423SLionel Sambuc if(FD_ISSET(i, fds)) result++;
86 *433d6423SLionel Sambuc }
87 *433d6423SLionel Sambuc return result;
88 *433d6423SLionel Sambuc }
89 *433d6423SLionel Sambuc #endif
90 *433d6423SLionel Sambuc
empty_fds(int nfds,fd_set * fds)91 *433d6423SLionel Sambuc static int empty_fds(int nfds, fd_set *fds) {
92 *433d6423SLionel Sambuc /* Returns nonzero if the first bits up to nfds in fds are not set */
93 *433d6423SLionel Sambuc int i;
94 *433d6423SLionel Sambuc assert(fds != NULL && nfds > 0);
95 *433d6423SLionel Sambuc for(i = 0; i < nfds; i++) if(FD_ISSET(i, fds)) return 0;
96 *433d6423SLionel Sambuc return 1;
97 *433d6423SLionel Sambuc }
98 *433d6423SLionel Sambuc
compare_fds(int nfds,fd_set * lh,fd_set * rh)99 *433d6423SLionel Sambuc static int compare_fds(int nfds, fd_set *lh, fd_set *rh) {
100 *433d6423SLionel Sambuc /* Returns nonzero if lh equals rh up to nfds bits */
101 *433d6423SLionel Sambuc int i;
102 *433d6423SLionel Sambuc assert(lh != NULL && rh != NULL && nfds > 0);
103 *433d6423SLionel Sambuc for(i = 0; i < nfds; i++) {
104 *433d6423SLionel Sambuc if((FD_ISSET(i, lh) && !FD_ISSET(i, rh)) ||
105 *433d6423SLionel Sambuc (!FD_ISSET(i, lh) && FD_ISSET(i, rh))) {
106 *433d6423SLionel Sambuc return 0;
107 *433d6423SLionel Sambuc }
108 *433d6423SLionel Sambuc }
109 *433d6423SLionel Sambuc return 1;
110 *433d6423SLionel Sambuc }
111 *433d6423SLionel Sambuc
112 *433d6423SLionel Sambuc #if 0
113 *433d6423SLionel Sambuc static void dump_fds(int nfds, fd_set *fds) {
114 *433d6423SLionel Sambuc /* Print a graphical representation of bits in fds */
115 *433d6423SLionel Sambuc int i;
116 *433d6423SLionel Sambuc if(fds != NULL && nfds > 0) {
117 *433d6423SLionel Sambuc for(i = 0; i < nfds; i++) printf("%d ", (FD_ISSET(i, fds) ? 1 : 0));
118 *433d6423SLionel Sambuc printf("\n");
119 *433d6423SLionel Sambuc }
120 *433d6423SLionel Sambuc }
121 *433d6423SLionel Sambuc #endif
122 *433d6423SLionel Sambuc
do_child(int childno)123 *433d6423SLionel Sambuc static void do_child(int childno) {
124 *433d6423SLionel Sambuc int fd_sock, port;
125 *433d6423SLionel Sambuc int retval;
126 *433d6423SLionel Sambuc
127 *433d6423SLionel Sambuc fd_set fds_read, fds_write, fds_error;
128 *433d6423SLionel Sambuc fd_set fds_compare_write;
129 *433d6423SLionel Sambuc
130 *433d6423SLionel Sambuc struct hostent *he;
131 *433d6423SLionel Sambuc struct sockaddr_in server;
132 *433d6423SLionel Sambuc struct timeval tv;
133 *433d6423SLionel Sambuc
134 *433d6423SLionel Sambuc if((fd_sock = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
135 *433d6423SLionel Sambuc perror("Error getting socket\n");
136 *433d6423SLionel Sambuc exit(-1);
137 *433d6423SLionel Sambuc }
138 *433d6423SLionel Sambuc
139 *433d6423SLionel Sambuc if((he = gethostbyname("127.0.0.1")) == NULL){/*"localhost" might be unknown*/
140 *433d6423SLionel Sambuc perror("Error resolving");
141 *433d6423SLionel Sambuc exit(-1);
142 *433d6423SLionel Sambuc }
143 *433d6423SLionel Sambuc
144 *433d6423SLionel Sambuc /* Child 4 connects to the wrong port. See Actual testing description below.*/
145 *433d6423SLionel Sambuc port = (childno == 3 ? MYPORT + 1 : MYPORT);
146 *433d6423SLionel Sambuc
147 *433d6423SLionel Sambuc memcpy(&server.sin_addr, he->h_addr_list[0], he->h_length);
148 *433d6423SLionel Sambuc server.sin_family = AF_INET;
149 *433d6423SLionel Sambuc server.sin_port = htons(port);
150 *433d6423SLionel Sambuc
151 *433d6423SLionel Sambuc #if 0
152 *433d6423SLionel Sambuc printf("Going to connect to: %s:%d\n", inet_ntoa(server.sin_addr),
153 *433d6423SLionel Sambuc ntohs(server.sin_port));
154 *433d6423SLionel Sambuc #endif
155 *433d6423SLionel Sambuc
156 *433d6423SLionel Sambuc /* Normally we'd zerofill sin_zero, but there is no such thing on Minix */
157 *433d6423SLionel Sambuc #if !defined(__minix)
158 *433d6423SLionel Sambuc memset(server.sin_zero, '\0', sizeof server.sin_zero);
159 *433d6423SLionel Sambuc #endif
160 *433d6423SLionel Sambuc
161 *433d6423SLionel Sambuc /* Wait for parent to set up connection */
162 *433d6423SLionel Sambuc tv.tv_sec = (childno <= 1 ? DO_PAUSE : DO_TIMEOUT);
163 *433d6423SLionel Sambuc tv.tv_usec = 0;
164 *433d6423SLionel Sambuc retval = select(0, NULL, NULL, NULL, &tv);
165 *433d6423SLionel Sambuc
166 *433d6423SLionel Sambuc /* All set, let's do some testing */
167 *433d6423SLionel Sambuc /* Children 3 and 4 do a non-blocking connect */
168 *433d6423SLionel Sambuc if(childno == 2 || childno == 3)
169 *433d6423SLionel Sambuc fcntl(fd_sock, F_SETFL, fcntl(fd_sock, F_GETFL, 0) | O_NONBLOCK);
170 *433d6423SLionel Sambuc
171 *433d6423SLionel Sambuc if(connect(fd_sock, (struct sockaddr *) &server, sizeof(server)) < 0) {
172 *433d6423SLionel Sambuc /* Well, we don't actually care. The connect is non-blocking and is
173 *433d6423SLionel Sambuc supposed to "in progress" at this point. */
174 *433d6423SLionel Sambuc }
175 *433d6423SLionel Sambuc
176 *433d6423SLionel Sambuc if(childno == 2 || childno == 3) { /* Children 3 and 4 */
177 *433d6423SLionel Sambuc /* Open Group: "If a non-blocking call to the connect() function has been
178 *433d6423SLionel Sambuc made for a socket, and the connection attempt has either succeeded or
179 *433d6423SLionel Sambuc failed leaving a pending error, the socket shall be marked as writable.
180 *433d6423SLionel Sambuc ...
181 *433d6423SLionel Sambuc A socket shall be considered to have an exceptional condition pending if
182 *433d6423SLionel Sambuc a receive operation with O_NONBLOCK clear for the open file description
183 *433d6423SLionel Sambuc and with the MSG_OOB flag set would return out-of-band data without
184 *433d6423SLionel Sambuc blocking. (It is protocol-specific whether the MSG_OOB flag would be used
185 *433d6423SLionel Sambuc to read out-of-band data.) A socket shall also be considered to have an
186 *433d6423SLionel Sambuc exceptional condition pending if an out-of-band data mark is present in
187 *433d6423SLionel Sambuc the receive queue. Other circumstances under which a socket may be
188 *433d6423SLionel Sambuc considered to have an exceptional condition pending are protocol-specific
189 *433d6423SLionel Sambuc and implementation-defined."
190 *433d6423SLionel Sambuc
191 *433d6423SLionel Sambuc In other words, it only makes sense for us to check the write set as the
192 *433d6423SLionel Sambuc read set is not expected to be set, but is allowed to be set (i.e.,
193 *433d6423SLionel Sambuc unspecified) and whether the error set is set is implementation-defined.
194 *433d6423SLionel Sambuc */
195 *433d6423SLionel Sambuc FD_ZERO(&fds_read); FD_ZERO(&fds_write); FD_ZERO(&fds_error);
196 *433d6423SLionel Sambuc FD_SET(fd_sock, &fds_write);
197 *433d6423SLionel Sambuc tv.tv_sec = DO_TIMEOUT;
198 *433d6423SLionel Sambuc tv.tv_usec = 0;
199 *433d6423SLionel Sambuc retval = select(fd_sock+1, NULL, &fds_write, NULL, &tv);
200 *433d6423SLionel Sambuc
201 *433d6423SLionel Sambuc
202 *433d6423SLionel Sambuc if(retval <= 0) em(6, "expected one fd to be ready");
203 *433d6423SLionel Sambuc
204 *433d6423SLionel Sambuc FD_ZERO(&fds_compare_write); FD_SET(fd_sock, &fds_compare_write);
205 *433d6423SLionel Sambuc if(!compare_fds(fd_sock+1, &fds_compare_write, &fds_compare_write))
206 *433d6423SLionel Sambuc em(7, "write should be set");
207 *433d6423SLionel Sambuc }
208 *433d6423SLionel Sambuc
209 *433d6423SLionel Sambuc if(close(fd_sock) < 0) {
210 *433d6423SLionel Sambuc perror("Error disconnecting");
211 *433d6423SLionel Sambuc exit(-1);
212 *433d6423SLionel Sambuc }
213 *433d6423SLionel Sambuc
214 *433d6423SLionel Sambuc exit(errct);
215 *433d6423SLionel Sambuc }
216 *433d6423SLionel Sambuc
do_parent(void)217 *433d6423SLionel Sambuc static void do_parent(void) {
218 *433d6423SLionel Sambuc #if !defined(__minix)
219 *433d6423SLionel Sambuc int yes = 1;
220 *433d6423SLionel Sambuc #endif
221 *433d6423SLionel Sambuc int fd_sock, fd_new, exitstatus;
222 *433d6423SLionel Sambuc int sockets[NUMCHILDREN], i;
223 *433d6423SLionel Sambuc fd_set fds_read, fds_write, fds_error;
224 *433d6423SLionel Sambuc fd_set fds_compare_read, fds_compare_write;
225 *433d6423SLionel Sambuc struct timeval tv;
226 *433d6423SLionel Sambuc int retval, childresults = 0;
227 *433d6423SLionel Sambuc
228 *433d6423SLionel Sambuc struct sockaddr_in my_addr;
229 *433d6423SLionel Sambuc struct sockaddr_in other_addr;
230 *433d6423SLionel Sambuc socklen_t other_size;
231 *433d6423SLionel Sambuc
232 *433d6423SLionel Sambuc if((fd_sock = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
233 *433d6423SLionel Sambuc perror("Error getting socket\n");
234 *433d6423SLionel Sambuc exit(-1);
235 *433d6423SLionel Sambuc }
236 *433d6423SLionel Sambuc
237 *433d6423SLionel Sambuc my_addr.sin_family = AF_INET;
238 *433d6423SLionel Sambuc my_addr.sin_port = htons(MYPORT); /* Short, network byte order */
239 *433d6423SLionel Sambuc my_addr.sin_addr.s_addr = INADDR_ANY;
240 *433d6423SLionel Sambuc /* Normally we'd zerofill sin_zero, but there is no such thing on Minix */
241 *433d6423SLionel Sambuc #if !defined(__minix)
242 *433d6423SLionel Sambuc memset(my_addr.sin_zero, '\0', sizeof my_addr.sin_zero);
243 *433d6423SLionel Sambuc #endif
244 *433d6423SLionel Sambuc
245 *433d6423SLionel Sambuc /* Reuse port number. Not implemented in Minix. */
246 *433d6423SLionel Sambuc #if !defined(__minix)
247 *433d6423SLionel Sambuc if(setsockopt(fd_sock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) < 0) {
248 *433d6423SLionel Sambuc perror("Error setting port reuse option");
249 *433d6423SLionel Sambuc exit(-1);
250 *433d6423SLionel Sambuc }
251 *433d6423SLionel Sambuc #endif
252 *433d6423SLionel Sambuc
253 *433d6423SLionel Sambuc /* Bind to port */
254 *433d6423SLionel Sambuc if(bind(fd_sock, (struct sockaddr *) &my_addr, sizeof my_addr) < 0) {
255 *433d6423SLionel Sambuc perror("Error binding to port");
256 *433d6423SLionel Sambuc exit(-1);
257 *433d6423SLionel Sambuc }
258 *433d6423SLionel Sambuc
259 *433d6423SLionel Sambuc /* Mark socket to be used for incoming connections */
260 *433d6423SLionel Sambuc if(listen(fd_sock, 20) < 0) {
261 *433d6423SLionel Sambuc perror("Listen");
262 *433d6423SLionel Sambuc exit(-1);
263 *433d6423SLionel Sambuc }
264 *433d6423SLionel Sambuc
265 *433d6423SLionel Sambuc /* Actual testing */
266 *433d6423SLionel Sambuc /* While sockets resemble file descriptors, they are not the same at all.
267 *433d6423SLionel Sambuc We can read/write from/to and close file descriptors, but we cannot open
268 *433d6423SLionel Sambuc them O_RDONLY or O_WRONLY; they are always O_RDWR (other flags do not make
269 *433d6423SLionel Sambuc sense regarding sockets). As such, we cannot provide wrong file descriptors
270 *433d6423SLionel Sambuc to select, except for descriptors that are not in use.
271 *433d6423SLionel Sambuc We will test standard behavior and what is described in [2]. [1] and [3]
272 *433d6423SLionel Sambuc are not possible to test on Minix, as Minix does not support OOB data. That
273 *433d6423SLionel Sambuc is, the TCP layer can handle it, but there is no socket interface for it.
274 *433d6423SLionel Sambuc Our test consists of waiting for input from the first two children and
275 *433d6423SLionel Sambuc waiting to write output [standard usage]. Then the first child closes its
276 *433d6423SLionel Sambuc connection we select for reading. This should fail with error set. Then we
277 *433d6423SLionel Sambuc close child number two on our side and select for reading. This should fail
278 *433d6423SLionel Sambuc with EBADF. Child number three shall then do a non-blocking connect (after
279 *433d6423SLionel Sambuc waiting for DO_PAUSE seconds) and do a select, resulting in being marked
280 *433d6423SLionel Sambuc ready for writing. Subsequently child number four also does a non-blocking
281 *433d6423SLionel Sambuc connect to loclhost on MYPORT+1 (causing the connect to fail) and then does
282 *433d6423SLionel Sambuc a select. This should result in write and error being set (error because of
283 *433d6423SLionel Sambuc pending error).
284 *433d6423SLionel Sambuc */
285 *433d6423SLionel Sambuc
286 *433d6423SLionel Sambuc /* Accept and store connections from the first two children */
287 *433d6423SLionel Sambuc other_size = sizeof(other_addr);
288 *433d6423SLionel Sambuc for(i = 0; i < 2; i++) {
289 *433d6423SLionel Sambuc fd_new = accept(fd_sock, (struct sockaddr *) &other_addr, &other_size);
290 *433d6423SLionel Sambuc if(fd_new < 0) break;
291 *433d6423SLionel Sambuc sockets[i] = fd_new;
292 *433d6423SLionel Sambuc }
293 *433d6423SLionel Sambuc
294 *433d6423SLionel Sambuc /* If we break out of the for loop, we ran across an error and want to exit.
295 *433d6423SLionel Sambuc Check whether we broke out. */
296 *433d6423SLionel Sambuc if(fd_new < 0) {
297 *433d6423SLionel Sambuc perror("Error accepting connection");
298 *433d6423SLionel Sambuc exit(-1);
299 *433d6423SLionel Sambuc }
300 *433d6423SLionel Sambuc
301 *433d6423SLionel Sambuc /* Select error condition checking */
302 *433d6423SLionel Sambuc for(childresults = 0; childresults < 2; childresults++) {
303 *433d6423SLionel Sambuc FD_ZERO(&fds_read); FD_ZERO(&fds_write); FD_ZERO(&fds_error);
304 *433d6423SLionel Sambuc FD_SET(sockets[childresults], &fds_read);
305 *433d6423SLionel Sambuc FD_SET(sockets[childresults], &fds_write);
306 *433d6423SLionel Sambuc FD_SET(sockets[childresults], &fds_error);
307 *433d6423SLionel Sambuc tv.tv_sec = DO_TIMEOUT;
308 *433d6423SLionel Sambuc tv.tv_usec = 0;
309 *433d6423SLionel Sambuc
310 *433d6423SLionel Sambuc retval = select(sockets[childresults]+1, &fds_read, &fds_write, &fds_error,
311 *433d6423SLionel Sambuc &tv);
312 *433d6423SLionel Sambuc
313 *433d6423SLionel Sambuc if(retval <= 0) {
314 *433d6423SLionel Sambuc snprintf(errbuf, sizeof(errbuf),
315 *433d6423SLionel Sambuc "two fds should be set%s", (retval == 0 ? " (TIMEOUT)" : ""));
316 *433d6423SLionel Sambuc em(1, errbuf);
317 *433d6423SLionel Sambuc }
318 *433d6423SLionel Sambuc
319 *433d6423SLionel Sambuc FD_ZERO(&fds_compare_read); FD_ZERO(&fds_compare_write);
320 *433d6423SLionel Sambuc FD_SET(sockets[childresults], &fds_compare_write);
321 *433d6423SLionel Sambuc
322 *433d6423SLionel Sambuc /* We can't say much about being ready for reading at this point or not. It
323 *433d6423SLionel Sambuc is not specified and the other side might have data ready for us to read
324 *433d6423SLionel Sambuc */
325 *433d6423SLionel Sambuc if(!compare_fds(sockets[childresults]+1, &fds_compare_write, &fds_write))
326 *433d6423SLionel Sambuc em(2, "write should be set");
327 *433d6423SLionel Sambuc
328 *433d6423SLionel Sambuc if(!empty_fds(sockets[childresults]+1, &fds_error))
329 *433d6423SLionel Sambuc em(3, "no error should be set");
330 *433d6423SLionel Sambuc }
331 *433d6423SLionel Sambuc
332 *433d6423SLionel Sambuc
333 *433d6423SLionel Sambuc /* We continue by accepting a connection of child 3 */
334 *433d6423SLionel Sambuc fd_new = accept(fd_sock, (struct sockaddr *) &other_addr, &other_size);
335 *433d6423SLionel Sambuc if(fd_new < 0) {
336 *433d6423SLionel Sambuc perror("Error accepting connection\n");
337 *433d6423SLionel Sambuc exit(-1);
338 *433d6423SLionel Sambuc }
339 *433d6423SLionel Sambuc sockets[2] = fd_new;
340 *433d6423SLionel Sambuc
341 *433d6423SLionel Sambuc /* Child 4 will never connect */
342 *433d6423SLionel Sambuc
343 *433d6423SLionel Sambuc /* Child 5 is still pending to be accepted. Open Group: "If the socket is
344 *433d6423SLionel Sambuc currently listening, then it shall be marked as readable if an incoming
345 *433d6423SLionel Sambuc connection request has been received, and a call to the accept() function
346 *433d6423SLionel Sambuc shall complete without blocking."*/
347 *433d6423SLionel Sambuc FD_ZERO(&fds_read);
348 *433d6423SLionel Sambuc FD_SET(fd_sock, &fds_read);
349 *433d6423SLionel Sambuc tv.tv_sec = DO_TIMEOUT;
350 *433d6423SLionel Sambuc tv.tv_usec = 0;
351 *433d6423SLionel Sambuc retval = select(fd_sock+1, &fds_read, NULL, NULL, &tv);
352 *433d6423SLionel Sambuc if(retval <= 0) {
353 *433d6423SLionel Sambuc snprintf(errbuf, sizeof(errbuf),
354 *433d6423SLionel Sambuc "one fd should be set%s", (retval == 0 ? " (TIMEOUT)" : ""));
355 *433d6423SLionel Sambuc em(4, errbuf);
356 *433d6423SLionel Sambuc }
357 *433d6423SLionel Sambuc
358 *433d6423SLionel Sambuc /* Check read bit is set */
359 *433d6423SLionel Sambuc FD_ZERO(&fds_compare_read); FD_SET(fd_sock, &fds_compare_read);
360 *433d6423SLionel Sambuc if(!compare_fds(fd_sock+1, &fds_compare_read, &fds_read))
361 *433d6423SLionel Sambuc em(5, "read should be set");
362 *433d6423SLionel Sambuc
363 *433d6423SLionel Sambuc
364 *433d6423SLionel Sambuc /* Accept incoming connection to unblock child 5 */
365 *433d6423SLionel Sambuc fd_new = accept(fd_sock, (struct sockaddr *) &other_addr, &other_size);
366 *433d6423SLionel Sambuc if(fd_new < 0) {
367 *433d6423SLionel Sambuc perror("Error accepting connection\n");
368 *433d6423SLionel Sambuc exit(-1);
369 *433d6423SLionel Sambuc }
370 *433d6423SLionel Sambuc sockets[4] = fd_new;
371 *433d6423SLionel Sambuc
372 *433d6423SLionel Sambuc
373 *433d6423SLionel Sambuc /* We're done, let's wait a second to synchronize children and parent. */
374 *433d6423SLionel Sambuc tv.tv_sec = DO_HANDLEDATA;
375 *433d6423SLionel Sambuc tv.tv_usec = 0;
376 *433d6423SLionel Sambuc select(0, NULL, NULL, NULL, &tv);
377 *433d6423SLionel Sambuc
378 *433d6423SLionel Sambuc /* Close connection with children. */
379 *433d6423SLionel Sambuc for(i = 0; i < NUMCHILDREN; i++) {
380 *433d6423SLionel Sambuc if(i == 3) /* No need to disconnect child 4 that failed to connect. */
381 *433d6423SLionel Sambuc continue;
382 *433d6423SLionel Sambuc
383 *433d6423SLionel Sambuc if(close(sockets[i]) < 0) {
384 *433d6423SLionel Sambuc perror(NULL);
385 *433d6423SLionel Sambuc }
386 *433d6423SLionel Sambuc }
387 *433d6423SLionel Sambuc
388 *433d6423SLionel Sambuc /* Close listening socket */
389 *433d6423SLionel Sambuc if(close(fd_sock) < 0) {
390 *433d6423SLionel Sambuc perror("Closing listening socket");
391 *433d6423SLionel Sambuc errct++;
392 *433d6423SLionel Sambuc }
393 *433d6423SLionel Sambuc
394 *433d6423SLionel Sambuc for(i = 0; i < NUMCHILDREN; i++) {
395 *433d6423SLionel Sambuc wait(&exitstatus); /* Wait for children */
396 *433d6423SLionel Sambuc if(exitstatus > 0)
397 *433d6423SLionel Sambuc errct += WEXITSTATUS(exitstatus); /* and count their errors, too. */
398 *433d6423SLionel Sambuc }
399 *433d6423SLionel Sambuc
400 *433d6423SLionel Sambuc exit(errct);
401 *433d6423SLionel Sambuc }
402 *433d6423SLionel Sambuc
main(int argc,char ** argv)403 *433d6423SLionel Sambuc int main(int argc, char **argv) {
404 *433d6423SLionel Sambuc int forkres, i;
405 *433d6423SLionel Sambuc
406 *433d6423SLionel Sambuc /* Get subtest number */
407 *433d6423SLionel Sambuc if(argc != 2) {
408 *433d6423SLionel Sambuc printf("Usage: %s subtest_no\n", argv[0]);
409 *433d6423SLionel Sambuc exit(-2);
410 *433d6423SLionel Sambuc } else if(sscanf(argv[1], "%d", &subtest) != 1) {
411 *433d6423SLionel Sambuc printf("Usage: %s subtest_no\n", argv[0]);
412 *433d6423SLionel Sambuc exit(-2);
413 *433d6423SLionel Sambuc }
414 *433d6423SLionel Sambuc
415 *433d6423SLionel Sambuc /* Fork off a bunch of children */
416 *433d6423SLionel Sambuc for(i = 0; i < NUMCHILDREN; i++) {
417 *433d6423SLionel Sambuc forkres = fork();
418 *433d6423SLionel Sambuc if(forkres == 0) do_child(i);
419 *433d6423SLionel Sambuc else if(forkres < 0) {
420 *433d6423SLionel Sambuc perror("Unable to fork");
421 *433d6423SLionel Sambuc exit(-1);
422 *433d6423SLionel Sambuc }
423 *433d6423SLionel Sambuc }
424 *433d6423SLionel Sambuc /* do_child always calls exit(), so when we end up here, we're the parent. */
425 *433d6423SLionel Sambuc do_parent();
426 *433d6423SLionel Sambuc
427 *433d6423SLionel Sambuc exit(-2); /* We're not supposed to get here. Both do_* routines should exit.*/
428 *433d6423SLionel Sambuc }
429