Rx: Build rxperf test application on Windows
[openafs.git] / src / rx / test / rxperf.c
1 /*
2  * Copyright (c) 2000 - 2001 Kungliga Tekniska Högskolan
3  * (Royal Institute of Technology, Stockholm, Sweden).
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  *
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution
16  *    at such time that OpenAFS documentation is written.
17  *
18  * 3. Neither the name of the Institute nor the names of its contributors
19  *    may be used to endorse or promote products derived from this software
20  *    without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  */
34
35 #include <afsconfig.h>
36
37 /*
38 nn * We are using getopt since we want it to be possible to link to
39  * transarc libs.
40  */
41
42 #include <afsconfig.h>
43 #include <afs/param.h>
44
45 #include <stdarg.h>
46 #include <sys/types.h>
47 #ifdef AFS_NT40_ENV
48 #include <io.h>
49 #include <winsock2.h>
50 #include <fcntl.h>
51 #include <stdlib.h>
52 #include <time.h>
53 #else
54 #include <sys/time.h>
55 #include <sys/socket.h>
56 #include <sys/file.h>
57 #include <sys/stat.h>
58 #include <netinet/in.h>
59 #include <arpa/inet.h>
60 #include <netdb.h>
61 #endif
62 #include <stdio.h>
63 #include <stdlib.h>
64 #include <errno.h>
65 #ifdef HAVE_STRING_H
66 #include <string.h>
67 #else
68 #ifdef HAVE_STRINGS_H
69 #include <strings.h>
70 #endif
71 #endif
72 #include <assert.h>
73 #ifdef HAVE_UNISTD_H
74 #include <unistd.h>
75 #endif
76 #include <signal.h>
77 #ifdef HAVE_ERRX
78 #include <err.h>                /* not stricly right, but if we have a errx() there
79                                  * is hopefully a err.h */
80 #endif
81 #include <getopt.h>
82 #include "rx.h"
83 #include "rx_null.h"
84 #include "rx_globals.h"
85
86 static const char *__progname;
87
88 #ifndef HAVE_WARNX
89 static void
90 warnx(const char *fmt, ...)
91 {
92     va_list args;
93
94     va_start(args, fmt);
95     fprintf(stderr, "%s: ", __progname);
96     vfprintf(stderr, fmt, args);
97     fprintf(stderr, "\n");
98     va_end(args);
99 }
100 #endif /* !HAVE_WARNX */
101
102 #ifndef HAVE_ERRX
103 static void
104 errx(int eval, const char *fmt, ...)
105 {
106     va_list args;
107
108     va_start(args, fmt);
109     fprintf(stderr, "%s: ", __progname);
110     vfprintf(stderr, fmt, args);
111     fprintf(stderr, "\n");
112     va_end(args);
113
114     exit(eval);
115 }
116 #endif /* !HAVE_ERRX */
117
118 #ifndef HAVE_WARN
119 static void
120 warn(const char *fmt, ...)
121 {
122     va_list args;
123     char *errstr;
124
125     va_start(args, fmt);
126     fprintf(stderr, "%s: ", __progname);
127     vfprintf(stderr, fmt, args);
128
129     errstr = strerror(errno);
130
131     fprintf(stderr, ": %s\n", errstr ? errstr : "unknown error");
132     va_end(args);
133 }
134 #endif /* !HAVE_WARN */
135
136 #ifndef HAVE_ERR
137 static void
138 err(int eval, const char *fmt, ...)
139 {
140     va_list args;
141     char *errstr;
142
143     va_start(args, fmt);
144     fprintf(stderr, "%s: ", __progname);
145     vfprintf(stderr, fmt, args);
146
147     errstr = strerror(errno);
148
149     fprintf(stderr, ": %s\n", errstr ? errstr : "unknown error");
150     va_end(args);
151
152     exit(eval);
153 }
154 #endif /* !HAVE_ERR */
155
156 #define DEFAULT_PORT 7009       /* To match tcpdump */
157 #define DEFAULT_HOST "127.0.0.1"
158 #define DEFAULT_BYTES 1000000
159 #define RXPERF_BUFSIZE 512 * 1024
160
161 enum { RX_PERF_VERSION = 3 };
162 enum { RX_SERVER_ID = 147 };
163 enum { RX_PERF_UNKNOWN = -1,
164        RX_PERF_SEND = 0,
165        RX_PERF_RECV = 1,
166        RX_PERF_RPC = 3,
167        RX_PERF_FILE = 4
168 };
169
170 enum { RXPERF_MAGIC_COOKIE = 0x4711 };
171
172 /*
173  *
174  */
175
176 #if RXPERF_DEBUG
177 #define DBFPRINT(x) do { printf x ; } while(0)
178 #else
179 #define DBFPRINT(x)
180 #endif
181
182 static void
183 sigusr1(int foo)
184 {
185     exit(2);                    /* XXX profiler */
186 }
187
188 static void
189 sigint(int foo)
190 {
191     rx_Finalize();
192     exit(2);                    /* XXX profiler */
193 }
194
195 /*
196  *
197  */
198
199 static struct timeval timer_start;
200 static struct timeval timer_stop;
201 static int timer_check = 0;
202
203 static void
204 start_timer(void)
205 {
206     timer_check++;
207     gettimeofday(&timer_start, NULL);
208 }
209
210 /*
211  *
212  */
213
214 static void
215 end_and_print_timer(char *str)
216 {
217     long long start_l, stop_l;
218
219     timer_check--;
220     assert(timer_check == 0);
221     gettimeofday(&timer_stop, NULL);
222     start_l = timer_start.tv_sec * 1000000 + timer_start.tv_usec;
223     stop_l = timer_stop.tv_sec * 1000000 + timer_stop.tv_usec;
224     printf("%s:\t%8llu msec\n", str, (stop_l - start_l) / 1000);
225 }
226
227 /*
228  *
229  */
230
231 static u_long
232 str2addr(const char *s)
233 {
234     struct in_addr server;
235     struct hostent *h;
236
237 #ifndef INADDR_NONE
238 #define INADDR_NONE 0xffffffff
239 #endif
240     if (inet_addr(s) != INADDR_NONE)
241         return inet_addr(s);
242     h = gethostbyname(s);
243     if (h != NULL) {
244         memcpy(&server, h->h_addr_list[0], sizeof(server));
245         return server.s_addr;
246     }
247     return 0;
248 }
249
250
251 /*
252  *
253  */
254
255 static void
256 get_sec(int serverp, struct rx_securityClass **sec, int *secureindex)
257 {
258     if (serverp) {
259         *sec = rxnull_NewServerSecurityObject();
260         *secureindex = 1;
261     } else {
262         *sec = rxnull_NewClientSecurityObject();
263         *secureindex = 0;
264     }
265 }
266
267 /*
268  * process the "RPC" and return the results
269  */
270
271 char somebuf[RXPERF_BUFSIZE];
272
273 afs_int32 rxwrite_size = sizeof(somebuf);
274 afs_int32 rxread_size = sizeof(somebuf);
275
276 static int
277 readbytes(struct rx_call *call, afs_int32 bytes)
278 {
279     afs_int32 size;
280
281     while (bytes > 0) {
282         size = rxread_size;
283         if (size > bytes)
284             size = bytes;
285         if (rx_Read(call, somebuf, size) != size)
286             return 1;
287         bytes -= size;
288     }
289     return 0;
290 }
291
292 static int
293 sendbytes(struct rx_call *call, afs_int32 bytes)
294 {
295     afs_int32 size;
296
297     while (bytes > 0) {
298         size = rxwrite_size;
299         if (size > bytes)
300             size = bytes;
301         if (rx_Write(call, somebuf, size) != size)
302             return 1;
303         bytes -= size;
304     }
305     return 0;
306 }
307
308
309 static afs_int32
310 rxperf_ExecuteRequest(struct rx_call *call)
311 {
312     afs_int32 version;
313     afs_int32 command;
314     afs_uint32 bytes;
315     afs_uint32 recvb;
316     afs_uint32 sendb;
317     afs_uint32 data;
318     afs_uint32 num;
319     afs_uint32 *readwrite;
320     afs_uint32 i;
321     int readp = TRUE;
322
323     DBFPRINT(("got a request\n"));
324
325     if (rx_Read32(call, &version) != 4) {
326         warn("rx_Read failed to read version");
327         return -1;
328     }
329
330     if (htonl(RX_PERF_VERSION) != version) {
331         warnx("client has wrong version");
332         return -1;
333     }
334
335     if (rx_Read32(call, &command) != 4) {
336         warnx("rx_Read failed to read command");
337         return -1;
338     }
339     command = ntohl(command);
340
341     if (rx_Read32(call, &data) != 4) {
342         warnx("rx_Read failed to read size");
343         return -1;
344     }
345     rxread_size = ntohl(data);
346     if (rxread_size > sizeof(somebuf)) {
347         warnx("rxread_size too large %d", rxread_size);
348         return -1;
349     }
350
351     if (rx_Read32(call, &data) != 4) {
352         warnx("rx_Read failed to write size");
353         return -1;
354     }
355     rxwrite_size = ntohl(data);
356     if (rxwrite_size > sizeof(somebuf)) {
357         warnx("rxwrite_size too large %d", rxwrite_size);
358         return -1;
359     }
360
361     switch (command) {
362     case RX_PERF_SEND:
363         DBFPRINT(("got a send request\n"));
364
365         if (rx_Read32(call, &bytes) != 4) {
366             warnx("rx_Read failed to read bytes");
367             return -1;
368         }
369         bytes = ntohl(bytes);
370
371         DBFPRINT(("reading(%d) ", bytes));
372         readbytes(call, bytes);
373
374         data = htonl(RXPERF_MAGIC_COOKIE);
375         if (rx_Write32(call, &data) != 4) {
376             warnx("rx_Write failed when sending back result");
377             return -1;
378         }
379         DBFPRINT(("done\n"));
380
381         break;
382     case RX_PERF_RPC:
383         DBFPRINT(("got a rpc request, reading commands\n"));
384
385         if (rx_Read32(call, &recvb) != 4) {
386             warnx("rx_Read failed to read recvbytes");
387             return -1;
388         }
389         recvb = ntohl(recvb);
390         if (rx_Read32(call, &sendb) != 4) {
391             warnx("rx_Read failed to read sendbytes");
392             return -1;
393         }
394         sendb = ntohl(sendb);
395
396         DBFPRINT(("read(%d) ", recvb));
397         if (readbytes(call, recvb)) {
398             warnx("readbytes failed");
399             return -1;
400         }
401         DBFPRINT(("send(%d) ", sendb));
402         if (sendbytes(call, sendb)) {
403             warnx("sendbytes failed");
404             return -1;
405         }
406
407         DBFPRINT(("done\n"));
408
409         data = htonl(RXPERF_MAGIC_COOKIE);
410         if (rx_Write32(call, &data) != 4) {
411             warnx("rx_Write failed when sending back magic cookie");
412             return -1;
413         }
414
415         break;
416     case RX_PERF_FILE:
417         if (rx_Read32(call, &data) != 4)
418             errx(1, "failed to read num from client");
419         num = ntohl(data);
420
421         readwrite = malloc(num * sizeof(afs_uint32));
422         if (readwrite == NULL)
423             err(1, "malloc");
424
425         if (rx_Read(call, (char*)readwrite, num * sizeof(afs_uint32)) !=
426             num * sizeof(afs_uint32))
427             errx(1, "failed to read recvlist from client");
428
429         for (i = 0; i < num; i++) {
430             if (readwrite[i] == 0) {
431                 DBFPRINT(("readp %d", readwrite[i]));
432                 readp = !readp;
433             }
434
435             bytes = ntohl(readwrite[i]) * sizeof(afs_uint32);
436
437             if (readp) {
438                 DBFPRINT(("read\n"));
439                 readbytes(call, bytes);
440             } else {
441                 sendbytes(call, bytes);
442                 DBFPRINT(("send\n"));
443             }
444         }
445
446         break;
447     case RX_PERF_RECV:
448         DBFPRINT(("got a recv request\n"));
449
450         if (rx_Read32(call, &bytes) != 4) {
451             warnx("rx_Read failed to read bytes");
452             return -1;
453         }
454         bytes = ntohl(bytes);
455
456         DBFPRINT(("sending(%d) ", bytes));
457         sendbytes(call, bytes);
458
459         data = htonl(RXPERF_MAGIC_COOKIE);
460         if (rx_Write32(call, &data) != 4) {
461             warnx("rx_Write failed when sending back result");
462             return -1;
463         }
464         DBFPRINT(("done\n"));
465
466         break;
467     default:
468         warnx("client sent a unsupported command");
469         return -1;
470     }
471     DBFPRINT(("done with command\n"));
472
473     return 0;
474 }
475
476 /*
477  *
478  */
479
480 static void
481 do_server(short port, int nojumbo, int maxmtu)
482 {
483     struct rx_service *service;
484     struct rx_securityClass *secureobj;
485     int secureindex;
486     int ret;
487
488 #ifdef AFS_NT40_ENV
489     if (afs_winsockInit() < 0) {
490         printf("Can't initialize winsock.\n");
491         exit(1);
492     }
493     rx_EnableHotThread();
494 #endif
495
496     ret = rx_Init(htons(port));
497     if (ret)
498         errx(1, "rx_Init failed");
499
500     if (nojumbo)
501       rx_SetNoJumbo();
502
503     if (maxmtu)
504       rx_SetMaxMTU(maxmtu);
505
506     get_sec(1, &secureobj, &secureindex);
507
508     service =
509         rx_NewService(0, RX_SERVER_ID, "rxperf", &secureobj, secureindex,
510                       rxperf_ExecuteRequest);
511     if (service == NULL)
512         errx(1, "Cant create server");
513
514     rx_SetMinProcs(service, 2);
515     rx_SetMaxProcs(service, 100);
516     rx_SetCheckReach(service, 1);
517
518     rx_StartServer(1);
519     abort();
520 }
521
522 /*
523  *
524  */
525
526 static void
527 readfile(const char *filename, afs_uint32 ** readwrite, afs_uint32 * size)
528 {
529     FILE *f;
530     afs_uint32 len = 16;
531     afs_uint32 num = 0;
532     afs_uint32 data;
533     char *ptr;
534     char buf[RXPERF_BUFSIZE];
535
536     *readwrite = malloc(sizeof(afs_uint32) * len);
537
538     if (*readwrite == NULL)
539         err(1, "malloc");
540
541     f = fopen(filename, "r");
542     if (f == NULL)
543         err(1, "fopen");
544
545     while (fgets(buf, sizeof(buf), f) != NULL) {
546         if (num >= len) {
547             len = len * 2;
548             *readwrite = realloc(*readwrite, len * sizeof(afs_uint32));
549             if (*readwrite == NULL)
550                 err(1, "realloc");
551         }
552
553         if (*buf != '\n') {
554             data = htonl(strtol(buf, &ptr, 0));
555             if (ptr && ptr == buf)
556                 errx(1, "can't resolve number of bytes to transfer");
557         } else {
558             data = 0;
559         }
560
561         (*readwrite)[num] = data;
562         num++;
563     }
564
565     *size = num;
566
567
568     if (fclose(f) == -1)
569         err(1, "fclose");
570 }
571
572
573 /*
574  *
575  */
576
577 static void
578 do_client(const char *server, short port, char *filename, afs_int32 command,
579           afs_int32 times, afs_int32 bytes, afs_int32 sendtimes, afs_int32 recvtimes,
580           int dumpstats, int nojumbo, int maxmtu)
581 {
582     struct rx_connection *conn;
583     struct rx_call *call;
584     afs_uint32 addr;
585     struct rx_securityClass *secureobj;
586     int secureindex;
587     afs_int32 data;
588     afs_int32 num;
589     int ret;
590     int i;
591     int readp = FALSE;
592     char stamp[1024];
593     afs_uint32 size;
594
595     afs_uint32 *readwrite;
596
597 #ifdef AFS_NT40_ENV
598     if (afs_winsockInit() < 0) {
599         printf("Can't initialize winsock.\n");
600         exit(1);
601     }
602     rx_EnableHotThread();
603 #endif
604
605     addr = str2addr(server);
606
607     ret = rx_Init(0);
608     if (ret)
609         errx(1, "rx_Init failed");
610
611     if (nojumbo)
612       rx_SetNoJumbo();
613
614     if (maxmtu)
615       rx_SetMaxMTU(maxmtu);
616
617     get_sec(0, &secureobj, &secureindex);
618
619     conn = rx_NewConnection(addr, htons(port), RX_SERVER_ID, secureobj, secureindex);
620     if (conn == NULL)
621         errx(1, "failed to contact server");
622
623     sprintf(stamp, "send\t%d times\t%d writes\t%d reads", times, sendtimes,
624             recvtimes);
625     start_timer();
626
627     for (i = 0; i < times; i++) {
628
629         DBFPRINT(("starting command "));
630
631         call = rx_NewCall(conn);
632         if (call == NULL)
633             errx(1, "rx_NewCall failed");
634
635         data = htonl(RX_PERF_VERSION);
636         if (rx_Write32(call, &data) != 4)
637             errx(1, "rx_Write failed to send version (err %d)", rx_Error(call));
638
639         data = htonl(command);
640         if (rx_Write32(call, &data) != 4)
641             errx(1, "rx_Write failed to send command (err %d)", rx_Error(call));
642
643         data = htonl(rxread_size);
644         if (rx_Write32(call, &data) != 4)
645             errx(1, "rx_Write failed to send read size (err %d)", rx_Error(call));
646         data = htonl(rxwrite_size);
647         if (rx_Write32(call, &data) != 4)
648             errx(1, "rx_Write failed to send write read (err %d)", rx_Error(call));
649
650
651         switch (command) {
652         case RX_PERF_RECV:
653             DBFPRINT(("command "));
654
655             data = htonl(bytes);
656             if (rx_Write32(call, &data) != 4)
657                 errx(1, "rx_Write failed to send size (err %d)", rx_Error(call));
658
659             DBFPRINT(("sending(%d) ", bytes));
660             if (readbytes(call, bytes))
661                 errx(1, "sendbytes (err %d)", rx_Error(call));
662
663             if (rx_Read32(call, &data) != 4)
664                 errx(1, "failed to read result from server (err %d)", rx_Error(call));
665
666             if (data != htonl(RXPERF_MAGIC_COOKIE))
667                 warn("server send wrong magic cookie in responce");
668
669             DBFPRINT(("done\n"));
670
671             break;
672         case RX_PERF_SEND:
673             DBFPRINT(("command "));
674
675             data = htonl(bytes);
676             if (rx_Write32(call, &data) != 4)
677                 errx(1, "rx_Write failed to send size (err %d)", rx_Error(call));
678
679             DBFPRINT(("sending(%d) ", bytes));
680             if (sendbytes(call, bytes))
681                 errx(1, "sendbytes (err %d)", rx_Error(call));
682
683             if (rx_Read32(call, &data) != 4)
684                 errx(1, "failed to read result from server (err %d)", rx_Error(call));
685
686             if (data != htonl(RXPERF_MAGIC_COOKIE))
687                 warn("server send wrong magic cookie in responce");
688
689             DBFPRINT(("done\n"));
690
691             break;
692         case RX_PERF_RPC:
693             DBFPRINT(("commands "));
694
695             data = htonl(sendtimes);
696             if (rx_Write32(call, &data) != 4)
697                 errx(1, "rx_Write failed to send command (err %d)", rx_Error(call));
698
699             data = htonl(recvtimes);
700             if (rx_Write32(call, &data) != 4)
701                 errx(1, "rx_Write failed to send command (err %d)", rx_Error(call));
702
703             DBFPRINT(("send(%d) ", sendtimes));
704             if (sendbytes(call, sendtimes))
705                 errx(1, "sendbytes (err %d)", rx_Error(call));
706
707             DBFPRINT(("recv(%d) ", recvtimes));
708             if (readbytes(call, recvtimes))
709                 errx(1, "sendbytes (err %d)", rx_Error(call));
710
711             if (rx_Read32(call, &bytes) != 4)
712                 errx(1, "failed to read result from server (err %d)", rx_Error(call));
713
714             if (bytes != htonl(RXPERF_MAGIC_COOKIE))
715                 warn("server send wrong magic cookie in responce");
716
717             DBFPRINT(("done\n"));
718
719             break;
720         case RX_PERF_FILE:
721             readfile(filename, &readwrite, &num);
722
723             data = htonl(num);
724             if (rx_Write32(call, &data) != 4)
725                 errx(1, "rx_Write failed to send size (err %d)", rx_Error(call));
726
727             if (rx_Write(call, (char *)readwrite, num * sizeof(afs_uint32))
728                 != num * sizeof(afs_uint32))
729                 errx(1, "rx_Write failed to send list (err %d)", rx_Error(call));
730
731             for (i = 0; i < num; i++) {
732                 if (readwrite[i] == 0)
733                     readp = !readp;
734
735                 size = ntohl(readwrite[i]) * sizeof(afs_uint32);
736
737                 if (readp) {
738                     if (readbytes(call, size))
739                         errx(1, "sendbytes (err %d)", rx_Error(call));
740                     DBFPRINT(("read\n"));
741                 } else {
742                     if (sendbytes(call, size))
743                         errx(1, "sendbytes (err %d)", rx_Error(call));
744                     DBFPRINT(("send\n"));
745                 }
746             }
747             break;
748         default:
749             abort();
750         }
751
752         rx_EndCall(call, 0);
753     }
754
755     end_and_print_timer(stamp);
756     DBFPRINT(("done for good\n"));
757
758     if (dumpstats) {
759         rx_PrintStats(stdout);
760         rx_PrintPeerStats(stdout, conn->peer);
761     }
762     rx_Finalize();
763 }
764
765 static void
766 usage()
767 {
768 #define COMMON ""
769
770     fprintf(stderr, "usage: %s client -c send -b <bytes>\n", __progname);
771     fprintf(stderr, "usage: %s client -c recv -b <bytes>\n", __progname);
772     fprintf(stderr,
773             "usage: %s client -c rpc  -S <sendbytes> -R <recvbytes>\n",
774             __progname);
775     fprintf(stderr, "usage: %s client -c file -f filename\n", __progname);
776     fprintf(stderr,
777             "%s: usage: common option to the client "
778             "-w <write-bytes> -r <read-bytes> -T times -p port -s server -D\n",
779             __progname);
780     fprintf(stderr, "usage: %s server -p port\n", __progname);
781 #undef COMMMON
782     exit(1);
783 }
784
785 /*
786  * do argument processing and call networking functions
787  */
788
789 static int
790 rxperf_server(int argc, char **argv)
791 {
792     short port = DEFAULT_PORT;
793     int nojumbo = 0;
794     int maxmtu = 0;
795     char *ptr;
796     int ch;
797
798     while ((ch = getopt(argc, argv, "r:d:p:w:jm:4")) != -1) {
799         switch (ch) {
800         case 'd':
801 #ifdef RXDEBUG
802             rx_debugFile = fopen(optarg, "w");
803             if (rx_debugFile == NULL)
804                 err(1, "fopen %s", optarg);
805 #else
806             errx(1, "compiled without RXDEBUG");
807 #endif
808             break;
809         case 'r':
810             rxread_size = strtol(optarg, &ptr, 0);
811             if (ptr != 0 && ptr[0] != '\0')
812                 errx(1, "can't resolve readsize");
813             if (rxread_size > sizeof(somebuf))
814                 errx(1, "%d > sizeof(somebuf) (%d)", rxread_size,
815                      sizeof(somebuf));
816             break;
817         case 'p':
818             port = strtol(optarg, &ptr, 0);
819             if (ptr != 0 && ptr[0] != '\0')
820                 errx(1, "can't resolve portname");
821             break;
822         case 'w':
823             rxwrite_size = strtol(optarg, &ptr, 0);
824             if (ptr != 0 && ptr[0] != '\0')
825                 errx(1, "can't resolve writesize");
826             if (rxwrite_size > sizeof(somebuf))
827                 errx(1, "%d > sizeof(somebuf) (%d)", rxwrite_size,
828                      sizeof(somebuf));
829             break;
830         case 'j':
831           nojumbo=1;
832           break;
833         case 'm':
834           maxmtu = strtol(optarg, &ptr, 0);
835           if (ptr && *ptr != '\0')
836             errx(1, "can't resolve rx maxmtu to use");
837             break;
838         case '4':
839           RX_IPUDP_SIZE = 28;
840           break;
841         default:
842             usage();
843         }
844     }
845
846     if (optind != argc)
847         usage();
848
849     do_server(port, nojumbo, maxmtu);
850
851     return 0;
852 }
853
854 /*
855  * do argument processing and call networking functions
856  */
857
858 static int
859 rxperf_client(int argc, char **argv)
860 {
861     char *host = DEFAULT_HOST;
862     int bytes = DEFAULT_BYTES;
863     short port = DEFAULT_PORT;
864     char *filename = NULL;
865     afs_int32 cmd;
866     int sendtimes = 3;
867     int recvtimes = 30;
868     int times = 100;
869     int dumpstats = 0;
870     int nojumbo = 0;
871     int maxmtu = 0;
872     char *ptr;
873     int ch;
874
875     cmd = RX_PERF_UNKNOWN;
876
877     while ((ch = getopt(argc, argv, "T:S:R:b:c:d:p:r:s:w:f:Djm:4")) != -1) {
878         switch (ch) {
879         case 'b':
880             bytes = strtol(optarg, &ptr, 0);
881             if (ptr && *ptr != '\0')
882                 errx(1, "can't resolve number of bytes to transfer");
883             break;
884         case 'c':
885             if (strcasecmp(optarg, "send") == 0)
886                 cmd = RX_PERF_SEND;
887             else if (strcasecmp(optarg, "recv") == 0)
888                 cmd = RX_PERF_RECV;
889             else if (strcasecmp(optarg, "rpc") == 0)
890                 cmd = RX_PERF_RPC;
891             else if (strcasecmp(optarg, "file") == 0)
892                 cmd = RX_PERF_FILE;
893             else
894                 errx(1, "unknown command %s", optarg);
895             break;
896         case 'd':
897 #ifdef RXDEBUG
898             rx_debugFile = fopen(optarg, "w");
899             if (rx_debugFile == NULL)
900                 err(1, "fopen %s", optarg);
901 #else
902             errx(1, "compiled without RXDEBUG");
903 #endif
904             break;
905         case 'p':
906             port = strtol(optarg, &ptr, 0);
907             if (ptr != 0 && ptr[0] != '\0')
908                 errx(1, "can't resolve portname");
909             break;
910         case 'r':
911             rxread_size = strtol(optarg, &ptr, 0);
912             if (ptr != 0 && ptr[0] != '\0')
913                 errx(1, "can't resolve readsize");
914             if (rxread_size > sizeof(somebuf))
915                 errx(1, "%d > sizeof(somebuf) (%d)", rxread_size,
916                      sizeof(somebuf));
917             break;
918         case 's':
919             host = strdup(optarg);
920             if (host == NULL)
921                 err(1, "strdup");
922             break;
923         case 'w':
924             rxwrite_size = strtol(optarg, &ptr, 0);
925             if (ptr != 0 && ptr[0] != '\0')
926                 errx(1, "can't resolve writesize");
927             if (rxwrite_size > sizeof(somebuf))
928                 errx(1, "%d > sizeof(somebuf) (%d)", rxwrite_size,
929                      sizeof(somebuf));
930             break;
931         case 'T':
932             times = strtol(optarg, &ptr, 0);
933             if (ptr && *ptr != '\0')
934                 errx(1, "can't resolve number of times to execute rpc");
935             break;
936         case 'S':
937             sendtimes = strtol(optarg, &ptr, 0);
938             if (ptr && *ptr != '\0')
939                 errx(1, "can't resolve number of bytes to send");
940             break;
941         case 'R':
942             recvtimes = strtol(optarg, &ptr, 0);
943             if (ptr && *ptr != '\0')
944                 errx(1, "can't resolve number of bytes to receive");
945             break;
946         case 'f':
947             filename = optarg;
948             break;
949         case 'D':
950             dumpstats = 1;
951             break;
952         case 'j':
953           nojumbo=1;
954           break;
955         case 'm':
956           maxmtu = strtol(optarg, &ptr, 0);
957           if (ptr && *ptr != '\0')
958             errx(1, "can't resolve rx maxmtu to use");
959             break;
960         case '4':
961           RX_IPUDP_SIZE = 28;
962           break;
963         default:
964             usage();
965         }
966     }
967
968     if (optind != argc)
969         usage();
970
971     if (cmd == RX_PERF_UNKNOWN)
972         errx(1, "no command given to the client");
973
974     do_client(host, port, filename, cmd, times, bytes, sendtimes,
975               recvtimes, dumpstats, nojumbo, maxmtu);
976
977     return 0;
978 }
979
980 /*
981  * setup world and call cmd
982  */
983
984 int
985 main(int argc, char **argv)
986 {
987 #ifndef AFS_PTHREAD_ENV
988     PROCESS pid;
989 #endif
990
991     __progname = strrchr(argv[0], '/');
992     if (__progname == 0)
993         __progname = argv[0];
994
995 #ifndef AFS_NT40_ENV
996     signal(SIGUSR1, sigusr1);
997     signal(SIGINT, sigint);
998 #endif
999
1000 #ifndef AFS_PTHREAD_ENV
1001     LWP_InitializeProcessSupport(LWP_NORMAL_PRIORITY, &pid);
1002 #endif
1003
1004     memset(somebuf, 0, sizeof(somebuf));
1005
1006     if (argc >= 2 && strcmp(argv[1], "server") == 0)
1007         rxperf_server(argc - 1, argv + 1);
1008     else if (argc >= 2 && strcmp(argv[1], "client") == 0)
1009         rxperf_client(argc - 1, argv + 1);
1010     else
1011         usage();
1012     return 0;
1013 }