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