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