no-copy-libafs-builds-20021015
[openafs.git] / src / lwp / test / selclient.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 /* selclient.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 <unistd.h>
38 #include <stdio.h>
39 #include <stdarg.h>
40 #include <errno.h>
41 #include <sys/select.h>
42 #include <sys/types.h>
43 #include <sys/socket.h>
44 #include <bstring.h>
45 #include <sys/time.h>
46 #include <netinet/in.h>
47 #include <netdb.h>
48 #include <signal.h>
49 #include <sys/ioctl.h>
50 #include <assert.h>
51 #include <time.h>
52
53 #include <afsconfig.h>
54 #include <afs/param.h>
55
56 RCSID("$Header$");
57
58
59 #include "lwp.h"
60 #include "seltest.h"
61
62 /* Put this in lwp.h? */
63 extern int IOMGR_Select(int, fd_set *, fd_set *, fd_set *, struct timeval *);
64
65
66 void sendTest(int, int, int, int);
67 void sendEnd(int);
68
69 int nSigIO = 0;
70 void sigIO()
71 {
72     nSigIO++;
73 }
74
75 char *program;
76
77
78 Usage()
79 {
80     printf("Usage: selclient [-fd n] [-oob] [-soob] [-delay n] [-end] [-write n] host port\n");
81     printf("\t-fd n\tUse file descriptor n for socket.\n");
82     printf("\t-oob\tRequest a MSG_OOB from server.\n");
83     printf("\t-soob\tSend a MSG_OOB to server.\n");
84     printf("\t-delay n\tAsk server to delay n seconds for my writes.\n");
85     printf("\t-end\tAsk server to terminate.\n");
86     printf("\t-write\tWrite n bytes to server, verify reply.\n");
87     exit(1);
88 }
89
90 main(int ac, char **av)
91 {
92     int i;
93     int on = 1;
94     char *hostname = 0;
95     struct hostent *hostent;
96     int host; /* net order. */
97     short port = -1; /* host order. */
98     int setFD = 0;
99     int sockFD;
100     struct sockaddr_in saddr;
101     int reqOOB = 0;
102     int putOOB = 0;
103     int delay = 5;
104     int doEnd = 0;
105     int doWrite = 0;
106     int writeSize = 0;
107
108     program = av[0];
109
110     signal(SIGIO, sigIO);
111
112
113     for (i=1; i<ac; i++) {
114         if (!strcmp("-fd", av[i])) {
115             if (++i>=ac) {
116                 printf("Missing number for -fd option.\n");
117                 Usage();
118             }
119             setFD = atoi(av[i]);
120             if (setFD<=2) {
121                 printf("%s: %d: file descriptor must be at least 3.\n",
122                        program, setFD);
123                 Usage();
124             }
125         }
126         else if (!strcmp("-end", av[i])) {
127             doEnd = 1;
128         }
129         else if (!strcmp("-delay", av[i])) {
130             if (++i>=ac) {
131                 printf("%s: Missing time for -delay option.\n", program);
132                 Usage();
133             }
134             delay = atoi(av[i]);
135             if (delay<0) {
136                 printf("%s: %s: delay must be at least 0 seconds.\n",
137                        program, av[i]);
138                 Usage();
139             }
140         }
141         else if (!strcmp("-write", av[i])) {
142             doWrite = 1;
143             if (++i>=ac) {
144                 printf("%s: Missing size for -write option.\n", program);
145                 Usage();
146             }
147             writeSize = atoi(av[i]);
148             if (writeSize<1) {
149                 printf("%s: %s: Write size must be at least 1 byte.\n",
150                        program, av[i]);
151                 Usage();
152             }
153         }
154         else if (!strcmp("-oob", av[i])) {
155             reqOOB = 1;
156         }
157         else if (!strcmp("-soob", av[i])) {
158             putOOB = 1;
159         }
160         else {
161             if (!hostname) {
162                 hostname = av[i];
163             }
164             else if (port == -1) {
165                 port = atoi(av[i]);
166                 if (port<=0) {
167                     printf("%s: %s: port must be at least 1\n",
168                            program, av[i]);
169                     Usage();
170                 }
171             }
172             else {
173                 printf("%s: %s: Unknown argument.\n", program, av[i]);
174             }
175         }
176     }
177
178     if (!hostname) {
179         printf("%s: Missing hostname and port.\n", program);
180         Usage();
181     }
182     if (port == -1) {
183         printf("%s: Missing port.\n", program);
184         Usage();
185     }
186
187     if (!setFD) {
188         setFD = 31;
189         printf("%s: Using default socket of %d.\n", program, setFD);
190     }
191
192     if (!(hostent = gethostbyname(hostname))) {
193         printf("%s: Failed to find host entry for %s.\n",
194                program, hostname);
195         exit(1);
196     }
197
198     memcpy((void*)&host, (const void*)hostent->h_addr, sizeof(host));
199     
200     OpenFDs(setFD);
201
202     /* Connect to server. */
203     sockFD = socket(AF_INET, SOCK_STREAM, 0);
204     if (sockFD<0) {
205         Die(0, "socket");
206     }
207     printf("%s: Using socket at file descriptor %d.\n", program, sockFD);
208
209     memset((void*)&saddr, 0, sizeof(saddr));
210     saddr.sin_family = AF_INET;
211     saddr.sin_addr.s_addr = host; /* already in network byte order. */
212     saddr.sin_port = htons(port);
213     
214     if (connect(sockFD, (struct sockaddr*)&saddr, sizeof(saddr))<0) {
215         assert(0);
216     }
217
218
219     if (doEnd) {
220         sendEnd(sockFD);
221     }
222     else if (putOOB) {
223         Log("Will send OOB in 2 seconds.\n");
224         sleep(2);
225         sendOOB(sockFD);
226         Log("Sent OOB, sleeping for 5 seconds.\n");
227         sleep(5);
228         Log("Sent OOB, exiting.\n");
229     }
230     else {
231         IOMGR_Initialize();
232         sendTest(sockFD, delay, reqOOB, writeSize);
233     }
234     close(sockFD);
235 }
236
237 /* sendTest
238  */
239 int writeIndex;
240 void
241 sendTest(int sockFD, int delay, int reqOOB, int size)
242 {
243     char *buf, *bufTest;
244     fd_set *rfds, *wfds, *efds;
245     int i, j;
246     int nbytes, code;
247     selcmd_t selCmd;
248     time_t stime, etime;
249
250     buf = (char*)malloc(size);
251     assert(buf);
252     bufTest = (char*)malloc(size);
253     assert(bufTest);
254
255     for (j=i=0; i<size; i++, j++) {
256         if (j==END_DATA) j++;
257         if (j>255) j=0;
258         buf[i] = (char)j;
259     }
260     
261     selCmd.sc_cmd = SC_WRITE;
262     selCmd.sc_info = size;
263     selCmd.sc_delay = delay;
264     selCmd.sc_flags = SC_WAIT_ONLY;
265
266     nbytes = write(sockFD, (char*)&selCmd, sizeof(selCmd));
267     assert(nbytes == sizeof(selCmd));
268
269     Log("Starting to write %d bytes.\n", size);
270    if (!delay) {
271         nbytes = write(sockFD, buf, size);
272         assert(nbytes == size);
273     }
274     else {
275         rfds = IOMGR_AllocFDSet();
276         wfds = IOMGR_AllocFDSet();
277         efds = IOMGR_AllocFDSet();
278         if (!rfds || !wfds || !efds) {
279             printf("%s: Could not allocate all fd_sets.\n", program);
280             exit(1);
281         }
282
283         for (writeIndex = i=0; i<size; writeIndex++, i++) {
284             FD_ZERO(rfds); FD_ZERO(wfds); FD_ZERO(efds);
285             FD_SET(sockFD, wfds);
286             FD_SET(sockFD, efds);
287             (void) time(&stime);
288             code = IOMGR_Select(sockFD+1, rfds, wfds, efds,
289                                 (struct timeval*)NULL);
290             assert(code>0);
291
292             if (FD_ISSET(sockFD, wfds)) {
293                 (void) time(&etime);
294                 if (etime - stime > 1 ) {
295                     Log("Waited %d seconds to write at offset %d.\n",
296                         etime - stime, i);
297                 }
298                 stime = etime;
299                 nbytes = write(sockFD, &buf[i], 1);
300                 (void) time(&etime);
301                 if (etime - stime > 1 ) {
302                     Log("Waited %d seconds IN write.\n", etime - stime);
303                 }
304                 assert(nbytes == 1);
305                 FD_CLR(sockFD, wfds);
306             }
307             assertNullFDSet(0, rfds);
308             assertNullFDSet(0, wfds);
309             assertNullFDSet(0, efds);
310         }
311     }
312
313     Log("Wrote %d bytes.\n", size);
314     i = 0;
315     while (i<size) {
316         nbytes = read(sockFD, &bufTest[i], size);
317         i += nbytes;
318     }
319     Log("Read %d bytes.\n", size);
320
321     assert(memcmp(buf, bufTest, size) == 0);
322     Log("Compared %d bytes.\n", size);
323 }
324
325 void sendEnd(int fd)
326 {
327     selcmd_t sc;
328
329     sc.sc_cmd = SC_END;
330     
331     if (write(fd, (char*)&sc, sizeof(sc)) != sizeof(sc)) {
332         Die(1, "(sendEnd) write failed: ");
333     }
334 }