2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
10 /* selserver.c tests the IOMGR_Select interface. Specifically it verifies
11 * that the read/write/exception lists work correctly with file descriptors
12 * larger than 31. Generally, the calls to IOMGR_Select pass in all the
13 * read, write and exception fd_sets. When handling is complete, the file
14 * descriptor is cleared from the set. Then if fd_set is checked to make sure
15 * there are no other bits set. The fd_sets which should have had nothing set
18 * The client can send one of the following:
19 * -end - shoots the selserver.
20 * -delay n - The selserver thread handling this request should sleep for
21 * n seconds before accepting data. Used in conjuction with -write
22 * so that the write STREAM can fill. This tests the IOMGR_Select
24 * -write n - writes n bytes to the selserver. If -delay is not set, a default
25 * of 5 seconds is used.
26 * -soob - Send an out-of-band message to selserver. Tests the exception
30 /* Typical test scanario:
31 * selclient -soob : used to test exception fd's on selserver.
32 * selclient -delay 20 -write 150000 : used to test read/write fd's.
33 * Adjust delay to 40 seconds if running loopback. Times and sizes derived
34 * on IRIX 6.2 and 6.4.
42 #include <sys/select.h>
43 #include <sys/types.h>
44 #include <sys/socket.h>
47 #include <netinet/in.h>
50 #include <sys/ioctl.h>
54 #include <afs/param.h>
55 #include <afsconfig.h>
63 extern int IOMGR_Select(int, fd_set *, fd_set *, fd_set *, struct timeval *);
66 void sendTest(int, int, int);
67 void handleRequest(char *);
78 struct sockaddr_in ch_addr;
79 fd_set ch_read, ch_write, ch_except;
83 void handleWrite(clientHandle_t *, selcmd_t *);
85 clientHandle_t clientHandles[MAX_THREADS];
87 clientHandle_t *getClientHandle()
90 for (i=0; i<MAX_THREADS; i++) {
91 if (clientHandles[i].ch_state == CH_FREE) {
92 clientHandles[i].ch_state = CH_INUSE;
94 return &clientHandles[i];
97 Die(1, "No free client handles!\n");
99 return (clientHandle_t*)NULL; /* quiet compiler. */
111 printf("Usage: selserver [-fd n] [-syssel] port\n");
112 printf("\t-fd n\tUse file descriptor n for socket.\n");
118 main(int ac, char **av)
122 short port = -1; /* host order. */
124 struct sockaddr_in saddr;
126 clientHandle_t *clientHandle;
130 fd_set *rfds, *wfds, *efds;
140 signal(SIGIO, sigIO);
143 for (i=1; i<ac; i++) {
144 if (!strcmp("-fd", av[i])) {
146 printf("Missing number for -fd option.\n");
151 printf("%d: file descriptor must be at least 3.\n", setFD);
159 printf("%s: port must be at least 1\n", av[i]);
164 printf("%s: Unknown argument.\n", av[i]);
170 printf("Missing port.\n");
176 printf("Using default socket of %d.\n", setFD);
183 /* Setup server processes */
184 for (i=0; i<MAX_THREADS; i++) {
185 if (LWP_CreateProcess(handleRequest, 32768,
187 (char*)&clientHandles[i],
188 "HandleRequestThread",
190 printf("%s: Failed to start all LWP's\n", program);
193 clientHandles[i].ch_pid = pid;
197 sockFD = socket(AF_INET, SOCK_STREAM, 0);
202 Log("Using socket at file descriptor %d.\n", sockFD);
204 if (setsockopt(sockFD, SOL_SOCKET, SO_REUSEADDR, (char *) &on,
206 perror("setsockopt: ");
210 memset((void*)&saddr, 0, sizeof(saddr));
212 saddr.sin_family = AF_INET;
213 saddr.sin_port = ntohs(port);
214 saddr.sin_addr.s_addr = htonl(INADDR_ANY);
216 if (bind(sockFD, (struct sockaddr*)&saddr, sizeof(saddr))<0) {
222 rfds = IOMGR_AllocFDSet();
223 wfds = IOMGR_AllocFDSet();
224 efds = IOMGR_AllocFDSet();
225 if (!rfds || !wfds || !efds) {
226 printf("main: Could not alloc fd_set's.\n");
230 listen(sockFD, 100) ;
234 FD_ZERO(rfds); FD_ZERO(wfds); FD_ZERO(efds);
235 FD_SET(sockFD, rfds); FD_SET(sockFD, efds);
237 Log("Main - going to select.\n");
238 code = IOMGR_Select(sockFD+1, rfds, wfds, efds, (struct timeval*)0);
240 case 0: /* Timer, can't happen here. */
243 Log("Oops! select returns %d!\n", code);
246 if (FD_ISSET(sockFD, efds)) {
248 assertNullFDSet(sockFD, rfds);
249 assertNullFDSet(-1, wfds);
250 assertNullFDSet(sockFD, efds);
252 if (FD_ISSET(sockFD, rfds)) {
253 while (nThreads > MAX_THREADS) {
257 clientHandle = getClientHandle();
259 addr_len = sizeof(clientHandle->ch_addr);
260 clientHandle->ch_fd = accept(sockFD,
261 (struct sockaddr*)&clientHandle->ch_addr,
263 if (clientHandle->ch_fd < 0) {
268 Log("Main - signalling LWP 0x%x\n", &clientHandle->ch_state);
269 LWP_NoYieldSignal(&clientHandle->ch_state);
270 assertNullFDSet(sockFD, rfds);
271 assertNullFDSet(-1, wfds);
272 assertNullFDSet(-1, efds);
275 Die(1, "(main) No data to read.\n");
280 void handleRequest(char *arg)
282 clientHandle_t *ch = (clientHandle_t*)arg;
289 Log("(handleRequest) going to sleep on 0x%x\n",
291 LWP_WaitProcess(&ch->ch_state);
292 assert(ch->ch_state == CH_INUSE);
294 FD_ZERO(&(ch->ch_read));
295 FD_ZERO(&(ch->ch_write));
296 FD_ZERO(&(ch->ch_except));
297 FD_SET(ch->ch_fd, &(ch->ch_read));
298 FD_SET(ch->ch_fd, &(ch->ch_except));
299 code = IOMGR_Select(ch->ch_fd + 1, &(ch->ch_read), &(ch->ch_write),
300 &(ch->ch_except), (struct timeval *)NULL);
301 if (FD_ISSET(ch->ch_fd, &(ch->ch_except))) {
302 Log("Received expception. Read fd_set shows %d\n",
303 FD_ISSET(ch->ch_fd, &(ch->ch_read)));
304 assertNullFDSet(ch->ch_fd, &(ch->ch_read));
305 assertNullFDSet(-1, &(ch->ch_write));
306 assertNullFDSet(ch->ch_fd, &(ch->ch_except));
311 if (read(ch->ch_fd, (char*)&sc, sizeof(sc))!=sizeof(sc)) {
312 Die(1, "(handleRequest) read command");
315 Log("(handleRequest)cmd=%d\n", sc.sc_cmd);
320 Log("Probed from client at %s\n",
321 inet_ntoa(ch->ch_addr.sin_addr));
327 ch->ch_state = CH_FREE;
331 handleWrite(ch, &sc);
334 Log("Ending ungracefully in server.\n");
337 Log("%d: bad command to handleRequest.\n", sc.sc_cmd);
342 /* We're done now, so we can be re-used. */
346 ch->ch_state = CH_FREE;
351 void handleWrite(clientHandle_t *ch, selcmd_t *sc)
354 fd_set *rfds, *wfds, *efds;
361 rfds = IOMGR_AllocFDSet();
362 wfds = IOMGR_AllocFDSet();
363 efds = IOMGR_AllocFDSet();
364 assert(rfds && wfds && efds);
366 if (sc->sc_delay>0) {
367 IOMGR_Sleep(sc->sc_delay);
370 Log("(handleWrite 0x%x) waking after %d second sleep.\n",
371 ch->ch_pid, sc->sc_delay);
373 if (sc->sc_flags & SC_WAIT_OOB)
376 buf = (char*)malloc(sc->sc_info);
381 FD_ZERO(rfds); FD_SET(ch->ch_fd, rfds);
382 FD_ZERO(efds); FD_SET(ch->ch_fd, efds);
384 scode = IOMGR_Select(ch->ch_fd+1, rfds, wfds, efds,
388 if (FD_ISSET(ch->ch_fd, rfds)) {
390 assert(i<sc->sc_info);
392 code = read(ch->ch_fd, &buf[i], 1);
396 Log("code =%d\n", code);
400 /* Test for valid fds */
401 assertNullFDSet(ch->ch_fd, rfds);
402 assertNullFDSet(-1, wfds);
403 assertNullFDSet(-1, efds);
404 if (c == END_DATA || i >= sc->sc_info) {
409 Log("Read %d bytes of data.\n", sc->sc_info);
410 nbytes = write(ch->ch_fd, buf, sc->sc_info);
411 assert(nbytes == sc->sc_info);
412 Log("Wrote data back to client.\n");
413 IOMGR_FreeFDSet(rfds);
414 IOMGR_FreeFDSet(wfds);
415 IOMGR_FreeFDSet(efds);