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