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