949a8bc2d05463a448648e3ea3c2da98ba32e322
[openafs.git] / src / rx / test / testclient.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 /* Client test program */
11
12 #include <afsconfig.h>
13 #include <afs/param.h>
14 #include <roken.h>
15
16 #include <sys/types.h>
17 #include <stdio.h>
18 #ifdef AFS_NT40_ENV
19 #include <io.h>
20 #include <winsock2.h>
21 #include <fcntl.h>
22 #include <stdlib.h>
23 #else
24 #include <netinet/in.h>
25 #include <netdb.h>
26 #include <sys/file.h>
27 #endif
28 #include <sys/stat.h>
29 #include <signal.h>
30
31 #include <afs/opr.h>
32 #include <rx/rx_clock.h>
33 #include <rx/rx.h>
34 #include <rx/rx_globals.h>
35 #include <rx/rx_null.h>
36 #include <errno.h>
37 #include <afs/afsutil.h>
38
39 #ifndef osi_Alloc
40 #define osi_Alloc(n) (char *) malloc(n)
41 #endif
42
43 int timeReadvs = 0;
44 int print = 1, eventlog = 0, rxlog = 0;
45 int fillPackets;
46 FILE *debugFile;
47 int timeout;
48 struct clock waitTime, computeTime;
49
50 void OpenFD(int n);
51 void Abort(const char *msg, ...);
52 void Quit(char *msg);
53 int SendFile(char *file, struct rx_connection *conn);
54
55 void
56 intSignal(int ignore)
57 {
58     Quit("Interrupted");
59 }
60
61 void
62 quitSignal(int ignore)
63 {
64     static int quitCount = 0;
65     if (++quitCount > 1)
66         Quit("rx_ctest: second quit signal, aborting");
67     rx_debugFile = debugFile = fopen("rx_ctest.db", "w");
68     if (debugFile)
69         rx_PrintStats(debugFile);
70 }
71
72 #if !defined(AFS_NT40_ENV) && !defined(AFS_LINUX20_ENV)
73 int
74 test_syscall(afs_uint32 a3, afs_uint32 a4, void *a5)
75 {
76     afs_uint32 rcode;
77     void (*old) (int);
78
79     old = signal(SIGSYS, SIG_IGN);
80     rcode =
81         syscall(31 /* AFS_SYSCALL */ , 28 /* AFSCALL_CALL */ , a3, a4, a5);
82     signal(SIGSYS, old);
83
84     return rcode;
85 }
86 #endif
87
88 int
89 main(int argc, char **argv)
90 {
91     char *hostname;
92     struct hostent *hostent;
93     afs_uint32 host;
94     int logstdout = 0;
95     struct rx_connection *conn;
96     struct rx_call *call;
97     struct rx_peer *peer;
98     int err = 0;
99     int nCalls = 1, nBytes = 1;
100     int bufferSize = 4000000;
101     char *buffer;
102     char *sendFile = 0;
103     int setFD = 0;
104     int jumbo = 0;
105
106 #if !defined(AFS_NT40_ENV) && !defined(AFS_LINUX20_ENV)
107     setlinebuf(stdout);
108     rxi_syscallp = test_syscall;
109 #endif
110
111
112     argv++;
113     argc--;
114     while (argc && **argv == '-') {
115         if (strcmp(*argv, "-silent") == 0)
116             print = 0;
117         if (strcmp(*argv, "-jumbo") == 0)
118             jumbo = 1;
119         else if (strcmp(*argv, "-nc") == 0)
120             nCalls = atoi(*++argv), argc--;
121         else if (strcmp(*argv, "-nb") == 0)
122             nBytes = atoi(*++argv), argc--;
123         else if (strcmp(*argv, "-np") == 0)
124             rx_nPackets = atoi(*++argv), argc--;
125         else if (!strcmp(*argv, "-nsf"))
126             rxi_nSendFrags = atoi(*++argv), argc--;
127         else if (!strcmp(*argv, "-nrf"))
128             rxi_nRecvFrags = atoi(*++argv), argc--;
129         else if (strcmp(*argv, "-twind") == 0)
130             rx_initSendWindow = atoi(*++argv), argc--;
131         else if (strcmp(*argv, "-rwind") == 0)
132             rx_initReceiveWindow = atoi(*++argv), argc--;
133         else if (strcmp(*argv, "-rxlog") == 0)
134             rxlog = 1;
135         else if (strcmp(*argv, "-logstdout") == 0)
136             logstdout = 1;
137         else if (strcmp(*argv, "-eventlog") == 0)
138             eventlog = 1;
139         else if (strcmp(*argv, "-drop") == 0) {
140 #ifdef RXDEBUG
141             rx_intentionallyDroppedPacketsPer100 = atoi(*++argv), argc--;
142 #else
143             fprintf(stderr, "ERROR: Compiled without RXDEBUG\n");
144 #endif
145         } else if (strcmp(*argv, "-timeout") == 0)
146             timeout = atoi(*++argv), argc--;
147         else if (strcmp(*argv, "-fill") == 0)
148             fillPackets++;
149         else if (strcmp(*argv, "-file") == 0)
150             sendFile = *++argv, argc--;
151         else if (strcmp(*argv, "-timereadvs") == 0)
152             timeReadvs = 1;
153         else if (strcmp(*argv, "-wait") == 0) {
154             /* Wait time between calls--to test lastack code */
155             waitTime.sec = atoi(*++argv), argc--;
156             waitTime.usec = atoi(*++argv), argc--;
157         } else if (strcmp(*argv, "-compute") == 0) {
158             /* Simulated "compute" time for each call--to test acknowledgement protocol.  This is simulated by doing an iomgr_select:  imperfect, admittedly. */
159             computeTime.sec = atoi(*++argv), argc--;
160             computeTime.usec = atoi(*++argv), argc--;
161         } else if (strcmp(*argv, "-fd") == 0) {
162             /* Open at least this many fd's. */
163             setFD = atoi(*++argv), argc--;
164         } else {
165             err = 1;
166             break;
167         }
168         argv++, argc--;
169     }
170     if (err || argc != 1)
171         Quit("usage: rx_ctest [-silent] [-rxlog] [-eventlog] [-nc NCALLS] [-np NPACKETS] hostname");
172     hostname = *argv++, argc--;
173
174     if (rxlog || eventlog) {
175         if (logstdout)
176             debugFile = stdout;
177         else
178             debugFile = fopen("rx_ctest.db", "w");
179         if (debugFile == NULL)
180             Quit("Couldn't open rx_ctest.db");
181         if (rxlog)
182             rx_debugFile = debugFile;
183         if (eventlog)
184             rxevent_debugFile = debugFile;
185     }
186
187     signal(SIGINT, intSignal);  /*Changed to sigquit since dbx is broken right now */
188 #ifndef AFS_NT40_ENV
189     signal(SIGQUIT, quitSignal);
190 #endif
191
192 #ifdef AFS_NT40_ENV
193     if (afs_winsockInit() < 0) {
194         printf("Can't initialize winsock.\n");
195         exit(1);
196     }
197     rx_EnableHotThread();
198 #endif
199
200     rx_SetUdpBufSize(256 * 1024);
201
202     if (!jumbo)
203         rx_SetNoJumbo();
204
205     hostent = gethostbyname(hostname);
206     if (!hostent)
207         Abort("host %s not found", hostname);
208     if (hostent->h_length != 4)
209         Abort("host address is disagreeable length (%d)", hostent->h_length);
210     memcpy((char *)&host, hostent->h_addr, sizeof(host));
211     if (setFD > 0)
212         OpenFD(setFD);
213     if (rx_Init(0) != 0) {
214         printf("RX failed to initialize, exiting.\n");
215         exit(2);
216     }
217     if (setFD > 0) {
218         printf("rx_socket=%d\n", rx_socket);
219     }
220
221     printf("Using %d packet buffers\n", rx_nPackets);
222
223     conn =
224         rx_NewConnection(host, htons(2500), 3,
225                          rxnull_NewClientSecurityObject(), 0);
226
227     if (!conn)
228         Abort("unable to make a new connection");
229
230     if (sendFile)
231         SendFile(sendFile, conn);
232     else {
233         buffer = (char *)osi_Alloc(bufferSize);
234         while (nCalls--) {
235             struct clock startTime;
236             struct timeval t;
237             int nbytes;
238             int nSent;
239             int bytesSent = 0;
240             int bytesRead = 0;
241             call = rx_NewCall(conn);
242             if (!call)
243                 Abort("unable to make a new call");
244
245             clock_GetTime(&startTime);
246             for (bytesSent = 0; bytesSent < nBytes; bytesSent += nSent) {
247                 int tryCount;
248                 tryCount =
249                     (bufferSize >
250                      nBytes - bytesSent) ? nBytes - bytesSent : bufferSize;
251                 nSent = rx_Write(call, buffer, tryCount);
252                 if (nSent == 0)
253                     break;
254
255             }
256             for (bytesRead = 0; (nbytes = rx_Read(call, buffer, bufferSize));
257                  bytesRead += nbytes) {
258             };
259             if (print)
260                 printf("Received %d characters in response\n", bytesRead);
261             err = rx_EndCall(call, 0);
262             if (err)
263                 printf("Error %d returned from rpc call\n", err);
264             else {
265                 struct clock totalTime;
266                 float elapsedTime;
267                 clock_GetTime(&totalTime);
268                 clock_Sub(&totalTime, &startTime);
269                 elapsedTime = clock_Float(&totalTime);
270                 fprintf(stderr,
271                         "Sent %d bytes in %0.3f seconds:  %0.0f bytes per second\n",
272                         bytesSent, elapsedTime, bytesSent / elapsedTime);
273             }
274             if (!clock_IsZero(&computeTime)) {
275                 t.tv_sec = computeTime.sec;
276                 t.tv_usec = computeTime.usec;
277                 if (select(0, 0, 0, 0, &t) != 0)
278                     Quit("Select didn't return 0");
279             }
280             if (!clock_IsZero(&waitTime)) {
281                 struct timeval t;
282                 t.tv_sec = waitTime.sec;
283                 t.tv_usec = waitTime.usec;
284 #ifdef AFS_PTHREAD_ENV
285                 select(0, 0, 0, 0, &t);
286 #else
287                 IOMGR_Sleep(t.tv_sec);
288 #endif
289             }
290             if (debugFile)
291                 rx_PrintPeerStats(debugFile, rx_PeerOf(conn));
292             rx_PrintPeerStats(stdout, rx_PeerOf(conn));
293         }
294     }
295     Quit("testclient: done!\n");
296     return 0;
297 }
298
299 int
300 SendFile(char *file, struct rx_connection *conn)
301 {
302     struct rx_call *call;
303     int fd;
304     struct stat status;
305     int blockSize, bytesLeft;
306     char *buf;
307     int nbytes;
308     int err;
309     struct clock startTime;
310     int receivedStore = 0;
311     struct clock totalReadvDelay;
312     int nReadvs;
313     int code;
314 #ifdef  AFS_AIX_ENV
315 #include <sys/statfs.h>
316     struct statfs tstatfs;
317 #endif
318
319     if (timeReadvs) {
320         nReadvs = 0;
321         clock_Zero(&totalReadvDelay);
322     }
323     fd = open(file, O_RDONLY, 0);
324     if (fd < 0)
325         Abort("Couldn't open %s\n", file);
326     fstat(fd, &status);
327 #ifdef AFS_NT40_ENV
328     blockSize = 1024;
329 #else
330 #ifdef  AFS_AIX_ENV
331 /* Unfortunately in AIX valuable fields such as st_blksize are gone from the stat structure!! */
332     fstatfs(fd, &tstatfs);
333     blockSize = tstatfs.f_bsize;
334 #else
335     blockSize = status.st_blksize;
336 #endif
337 #endif
338     buf = (char *)osi_Alloc(blockSize);
339     bytesLeft = status.st_size;
340     clock_GetTime(&startTime);
341     call = rx_NewCall(conn);
342     while (bytesLeft) {
343         if (!receivedStore && rx_GetRemoteStatus(call) == 79) {
344             receivedStore = 1;
345             fprintf(stderr,
346                     "Remote status indicates file accepted (\"received store\")\n");
347         }
348         nbytes = (bytesLeft > blockSize ? blockSize : bytesLeft);
349         errno = 0;
350         code = read(fd, buf, nbytes);
351         if (code != nbytes) {
352             Abort("Only read %d bytes of %d, errno=%d\n", code, nbytes,
353                   errno);
354         }
355         code = rx_Write(call, buf, nbytes);
356         if (code != nbytes) {
357             Abort("Only wrote %d bytes of %d\n", code, nbytes);
358         }
359         bytesLeft -= nbytes;
360     }
361     while ((nbytes = rx_Read(call, buf, sizeof(buf))) > 0) {
362         char *p = buf;
363         while (nbytes--) {
364             putchar(*p);
365             p++;
366         }
367     }
368     if ((err = rx_EndCall(call, 0)) != 0) {
369         fprintf(stderr, "rx_Endcall returned error %d\n", err);
370     } else {
371         struct clock totalTime;
372         float elapsedTime;
373         clock_GetTime(&totalTime);
374         clock_Sub(&totalTime, &startTime);
375         elapsedTime = totalTime.sec + totalTime.usec / 1e6;
376         fprintf(stderr,
377                 "Sent %d bytes in %0.3f seconds:  %0.0f bytes per second\n",
378                 (int) status.st_size, elapsedTime, status.st_size / elapsedTime);
379         if (timeReadvs) {
380             float delay = clock_Float(&totalReadvDelay) / nReadvs;
381             fprintf(stderr, "%d readvs, average delay of %0.4f seconds\n",
382                     nReadvs, delay);
383         }
384     }
385     close(fd);
386
387     return(0);
388 }
389
390 void
391 Abort(const char *msg, ...)
392 {
393     va_list args;
394
395     va_start(args, msg);
396     printf(msg, args);
397     va_end(args);
398
399     printf("\n");
400     if (debugFile) {
401         rx_PrintStats(debugFile);
402         fflush(debugFile);
403     }
404     opr_abort();
405     exit(1);
406 }
407
408 void
409 Quit(char *msg)
410 {
411     printf("%s\n", msg);
412     if (debugFile) {
413         rx_PrintStats(debugFile);
414         fflush(debugFile);
415     }
416     rx_PrintStats(stdout);
417     exit(0);
418 }
419
420 /* OpenFD
421  *
422  * Open file descriptors until file descriptor n or higher is returned.
423  */
424 #include <sys/stat.h>
425 void
426 OpenFD(int n)
427 {
428     int i;
429     struct stat sbuf;
430     int fd, lfd;
431
432     lfd = -1;
433     for (i = 0; i < n; i++) {
434         if (fstat(i, &sbuf) == 0)
435             continue;
436         if ((fd = open("/dev/null", 0, 0)) < 0) {
437             if (lfd >= 0) {
438                 close(lfd);
439                 return;
440             }
441         } else {
442             if (fd >= n) {
443                 close(fd);
444                 return;
445             } else {
446                 lfd = fd;
447             }
448         }
449     }
450 }