lwp: Don't cast returns from malloc()
[openafs.git] / src / lwp / test / selserver.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
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
8  */
9
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
16  * are also checked.
17  * 
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
23  *            write fd_sets.
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
27  *            fd_set.
28  */
29
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.
35  */
36
37 #include <afsconfig.h>
38 #include <afs/param.h>
39
40
41 #include <unistd.h>
42 #include <stdarg.h>
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <errno.h>
46 #include <sys/select.h>
47 #include <sys/types.h>
48 #include <sys/socket.h>
49 #include <string.h>
50 #include <sys/time.h>
51 #include <netinet/in.h>
52 #include <netdb.h>
53 #include <signal.h>
54 #include <sys/ioctl.h>
55 #include <assert.h>
56 #include <sys/stat.h>
57
58
59 #include "lwp.h"
60 #include "seltest.h"
61
62 extern int IOMGR_Select(int, fd_set *, fd_set *, fd_set *, struct timeval *);
63
64
65 void sendTest(int, int, int);
66 void handleRequest(char *);
67
68 /* Server Pool */
69 #define MAX_THREADS 5
70 int nThreads = 0;
71
72 typedef struct {
73 #define CH_FREE 0
74 #define CH_INUSE 1
75     int ch_state;
76     int ch_fd;
77     struct sockaddr_in ch_addr;
78     fd_set ch_read, ch_write, ch_except;
79     PROCESS ch_pid;
80 } clientHandle_t;
81
82 void handleWrite(clientHandle_t *, selcmd_t *);
83
84 clientHandle_t clientHandles[MAX_THREADS];
85
86 clientHandle_t *
87 getClientHandle()
88 {
89     int i;
90     for (i = 0; i < MAX_THREADS; i++) {
91         if (clientHandles[i].ch_state == CH_FREE) {
92             clientHandles[i].ch_state = CH_INUSE;
93             nThreads++;
94             return &clientHandles[i];
95         }
96     }
97     Die(1, "No free client handles!\n");
98
99     return (clientHandle_t *) NULL;     /* quiet compiler. */
100 }
101
102 int nSigIO = 0;
103 void
104 sigIO()
105 {
106     nSigIO++;
107 }
108
109
110 Usage()
111 {
112     printf("Usage: selserver [-fd n] [-syssel] port\n");
113     printf("\t-fd n\tUse file descriptor n for socket.\n");
114     exit(1);
115 }
116
117 char *program;
118
119 main(int ac, char **av)
120 {
121     int i;
122     int on = 1;
123     short port = -1;            /* host order. */
124     int setFD = 0;
125     struct sockaddr_in saddr;
126     int acceptFD;
127     clientHandle_t *clientHandle;
128     int code;
129     int addr_len;
130     PROCESS pid;
131     fd_set *rfds, *wfds, *efds;
132     int sockFD;
133
134     program = av[0];
135
136     if (ac < 2)
137         Usage();
138
139 /*    lwp_debug = 1; */
140
141     signal(SIGIO, sigIO);
142
143
144     for (i = 1; i < ac; i++) {
145         if (!strcmp("-fd", av[i])) {
146             if (++i >= ac) {
147                 printf("Missing number for -fd option.\n");
148                 Usage();
149             }
150             setFD = atoi(av[i]);
151             if (setFD <= 2) {
152                 printf("%d: file descriptor must be at least 3.\n", setFD);
153                 Usage();
154             }
155         } else {
156             if (port == -1) {
157                 port = atoi(av[i]);
158                 if (port <= 0) {
159                     printf("%s: port must be at least 1\n", av[i]);
160                     Usage();
161                 }
162             } else {
163                 printf("%s: Unknown argument.\n", av[i]);
164             }
165         }
166     }
167
168     if (port == -1) {
169         printf("Missing port.\n");
170         Usage();
171     }
172
173     if (!setFD) {
174         setFD = 31;
175         printf("Using default socket of %d.\n", setFD);
176     }
177
178     OpenFDs(setFD);
179
180     IOMGR_Initialize();
181
182     /* Setup server processes */
183     for (i = 0; i < MAX_THREADS; i++) {
184         if (LWP_CreateProcess
185             (handleRequest, 32768, LWP_NORMAL_PRIORITY,
186              (char *)&clientHandles[i], "HandleRequestThread", &pid) < 0) {
187             printf("%s: Failed to start all LWP's\n", program);
188             exit(1);
189         }
190         clientHandles[i].ch_pid = pid;
191     }
192
193
194     sockFD = socket(AF_INET, SOCK_STREAM, 0);
195     if (sockFD < 0) {
196         perror("socket");
197         exit(1);
198     }
199     Log("Using socket at file descriptor %d.\n", sockFD);
200
201     if (setsockopt(sockFD, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on))
202         < 0) {
203         perror("setsockopt: ");
204         exit(1);
205     }
206
207     memset((void *)&saddr, 0, sizeof(saddr));
208
209     saddr.sin_family = AF_INET;
210     saddr.sin_port = ntohs(port);
211     saddr.sin_addr.s_addr = htonl(INADDR_ANY);
212
213     if (bind(sockFD, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) {
214         perror("bind: ");
215         exit(1);
216     }
217
218
219     rfds = IOMGR_AllocFDSet();
220     wfds = IOMGR_AllocFDSet();
221     efds = IOMGR_AllocFDSet();
222     if (!rfds || !wfds || !efds) {
223         printf("main: Could not alloc fd_set's.\n");
224         exit(1);
225     }
226
227     listen(sockFD, 100);
228
229
230     while (1) {
231         FD_ZERO(rfds);
232         FD_ZERO(wfds);
233         FD_ZERO(efds);
234         FD_SET(sockFD, rfds);
235         FD_SET(sockFD, efds);
236
237         Log("Main - going to select.\n");
238         code =
239             IOMGR_Select(sockFD + 1, rfds, wfds, efds, (struct timeval *)0);
240         switch (code) {
241         case 0:         /* Timer, can't happen here. */
242         case -1:
243         case -2:
244             Log("Oops! select returns %d!\n", code);
245             abort();
246         default:
247             if (FD_ISSET(sockFD, efds)) {
248                 recvOOB(sockFD);
249                 assertNullFDSet(sockFD, rfds);
250                 assertNullFDSet(-1, wfds);
251                 assertNullFDSet(sockFD, efds);
252             }
253             if (FD_ISSET(sockFD, rfds)) {
254                 while (nThreads > MAX_THREADS) {
255                     IOMGR_Sleep(1);
256                 }
257
258                 clientHandle = getClientHandle();
259
260                 addr_len = sizeof(clientHandle->ch_addr);
261                 clientHandle->ch_fd = accept(sockFD, (struct sockaddr *)
262                                              &clientHandle->ch_addr,
263                                              &addr_len);
264                 if (clientHandle->ch_fd < 0) {
265                     perror("accept: ");
266                     exit(1);
267                 }
268
269                 Log("Main - signalling LWP 0x%x\n", &clientHandle->ch_state);
270                 LWP_NoYieldSignal(&clientHandle->ch_state);
271                 assertNullFDSet(sockFD, rfds);
272                 assertNullFDSet(-1, wfds);
273                 assertNullFDSet(-1, efds);
274                 break;
275             }
276             Die(1, "(main) No data to read.\n");
277         }
278     }
279 }
280
281 void
282 handleRequest(char *arg)
283 {
284     clientHandle_t *ch = (clientHandle_t *) arg;
285     selcmd_t sc;
286     struct stat sbuf;
287     int code = 0;
288     int c_errno = 0;
289
290     while (1) {
291         Log("(handleRequest) going to sleep on 0x%x\n", &ch->ch_state);
292         LWP_WaitProcess(&ch->ch_state);
293         assert(ch->ch_state == CH_INUSE);
294
295         FD_ZERO(&(ch->ch_read));
296         FD_ZERO(&(ch->ch_write));
297         FD_ZERO(&(ch->ch_except));
298         FD_SET(ch->ch_fd, &(ch->ch_read));
299         FD_SET(ch->ch_fd, &(ch->ch_except));
300         code =
301             IOMGR_Select(ch->ch_fd + 1, &(ch->ch_read), &(ch->ch_write),
302                          &(ch->ch_except), (struct timeval *)NULL);
303         if (FD_ISSET(ch->ch_fd, &(ch->ch_except))) {
304             Log("Received expception. Read fd_set shows %d\n",
305                 FD_ISSET(ch->ch_fd, &(ch->ch_read)));
306             assertNullFDSet(ch->ch_fd, &(ch->ch_read));
307             assertNullFDSet(-1, &(ch->ch_write));
308             assertNullFDSet(ch->ch_fd, &(ch->ch_except));
309             goto done;
310         }
311         assert(code > 0);
312
313         if (read(ch->ch_fd, (char *)&sc, sizeof(sc)) != sizeof(sc)) {
314             Die(1, "(handleRequest) read command");
315         }
316
317         Log("(handleRequest)cmd=%d\n", sc.sc_cmd);
318         fflush(stdout);
319
320         switch (sc.sc_cmd) {
321         case SC_PROBE:
322             Log("Probed from client at %s\n",
323                 inet_ntoa(ch->ch_addr.sin_addr));
324             break;
325 #ifdef notdef
326         case SC_OOB:
327             nThreads--;
328             ch->ch_fd = 0;
329             ch->ch_state = CH_FREE;
330             return;
331 #endif
332         case SC_WRITE:
333             handleWrite(ch, &sc);
334             break;
335         case SC_END:
336             Log("Ending ungracefully in server.\n");
337             exit(1);
338         default:
339             Log("%d: bad command to handleRequest.\n", sc.sc_cmd);
340             break;
341         }
342
343       done:
344         /* We're done now, so we can be re-used. */
345         nThreads--;
346         close(ch->ch_fd);
347         ch->ch_fd = 0;
348         ch->ch_state = CH_FREE;
349     }
350 }
351
352 int write_I = 0;
353 void
354 handleWrite(clientHandle_t * ch, selcmd_t * sc)
355 {
356     int i;
357     fd_set *rfds, *wfds, *efds;
358     char *buf;
359     int code;
360     int scode;
361     char c;
362     int nbytes;
363
364     rfds = IOMGR_AllocFDSet();
365     wfds = IOMGR_AllocFDSet();
366     efds = IOMGR_AllocFDSet();
367     assert(rfds && wfds && efds);
368
369     if (sc->sc_delay > 0) {
370         IOMGR_Sleep(sc->sc_delay);
371     }
372
373     Log("(handleWrite 0x%x) waking after %d second sleep.\n", ch->ch_pid,
374         sc->sc_delay);
375
376     if (sc->sc_flags & SC_WAIT_OOB)
377         sendOOB(ch->ch_fd);
378
379     buf = malloc(sc->sc_info);
380     assert(buf);
381     i = 0;
382
383     while (1) {
384         FD_ZERO(rfds);
385         FD_SET(ch->ch_fd, rfds);
386         FD_ZERO(efds);
387         FD_SET(ch->ch_fd, efds);
388         FD_ZERO(wfds);
389         scode =
390             IOMGR_Select(ch->ch_fd + 1, rfds, wfds, efds,
391                          (struct timeval *)0);
392         assert(scode > 0);
393
394         if (FD_ISSET(ch->ch_fd, rfds)) {
395
396             assert(i < sc->sc_info);
397
398             code = read(ch->ch_fd, &buf[i], 1);
399             i++;
400             write_I++;
401             if (code != 1) {
402                 Log("code =%d\n", code);
403                 assert(code == 1);
404             }
405
406             /* Test for valid fds */
407             assertNullFDSet(ch->ch_fd, rfds);
408             assertNullFDSet(-1, wfds);
409             assertNullFDSet(-1, efds);
410             if (c == END_DATA || i >= sc->sc_info) {
411                 break;
412             }
413         }
414     }
415     Log("Read %d bytes of data.\n", sc->sc_info);
416     nbytes = write(ch->ch_fd, buf, sc->sc_info);
417     assert(nbytes == sc->sc_info);
418     Log("Wrote data back to client.\n");
419     IOMGR_FreeFDSet(rfds);
420     IOMGR_FreeFDSet(wfds);
421     IOMGR_FreeFDSet(efds);
422 }