rxperf: Move into the tools directory
[openafs.git] / src / tools / rxperf / 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 #include <roken.h>
45
46 #ifdef HAVE_SYS_FILE_H
47 #include <sys/file.h>
48 #endif
49
50 #include <assert.h>
51
52 #include <rx/rx.h>
53 #include <rx/rx_null.h>
54 #include <rx/rx_globals.h>
55 #include <rx/rx_packet.h>
56
57 #ifdef AFS_PTHREAD_ENV
58 #include <pthread.h>
59 #define MAX_THREADS 128
60 #endif
61
62 #define DEFAULT_PORT 7009       /* To match tcpdump */
63 #define DEFAULT_HOST "127.0.0.1"
64 #define DEFAULT_BYTES 1024 * 1024
65 #define RXPERF_BUFSIZE 512 * 1024
66
67 enum { RX_PERF_VERSION = 3 };
68 enum { RX_SERVER_ID = 147 };
69 enum { RX_PERF_UNKNOWN = -1,
70        RX_PERF_SEND = 0,
71        RX_PERF_RECV = 1,
72        RX_PERF_RPC = 3,
73        RX_PERF_FILE = 4
74 };
75
76 enum { RXPERF_MAGIC_COOKIE = 0x4711 };
77
78 /*
79  *
80  */
81
82 #if RXPERF_DEBUG
83 #define DBFPRINT(x) do { printf x ; } while(0)
84 #else
85 #define DBFPRINT(x)
86 #endif
87
88 static void
89 sigusr1(int foo)
90 {
91     exit(2);                    /* XXX profiler */
92 }
93
94 static void
95 sigint(int foo)
96 {
97     rx_Finalize();
98     exit(2);                    /* XXX profiler */
99 }
100
101 /*
102  *
103  */
104
105 static struct timeval timer_start;
106 static struct timeval timer_stop;
107 static int timer_check = 0;
108
109 static void
110 start_timer(void)
111 {
112     timer_check++;
113     gettimeofday(&timer_start, NULL);
114 }
115
116 /*
117  *
118  */
119
120 static void
121 end_and_print_timer(char *str)
122 {
123     long long start_l, stop_l;
124
125     timer_check--;
126     assert(timer_check == 0);
127     gettimeofday(&timer_stop, NULL);
128     start_l = timer_start.tv_sec * 1000000 + timer_start.tv_usec;
129     stop_l = timer_stop.tv_sec * 1000000 + timer_stop.tv_usec;
130     printf("%s:\t%8llu msec\n", str, (stop_l - start_l) / 1000);
131 }
132
133 /*
134  *
135  */
136
137 static u_long
138 str2addr(const char *s)
139 {
140     struct in_addr server;
141     struct hostent *h;
142
143 #ifndef INADDR_NONE
144 #define INADDR_NONE 0xffffffff
145 #endif
146     if (inet_addr(s) != INADDR_NONE)
147         return inet_addr(s);
148     h = gethostbyname(s);
149     if (h != NULL) {
150         memcpy(&server, h->h_addr_list[0], sizeof(server));
151         return server.s_addr;
152     }
153     return 0;
154 }
155
156
157 /*
158  *
159  */
160
161 static void
162 get_sec(int serverp, struct rx_securityClass **sec, int *secureindex)
163 {
164     if (serverp) {
165         *sec = rxnull_NewServerSecurityObject();
166         *secureindex = 1;
167     } else {
168         *sec = rxnull_NewClientSecurityObject();
169         *secureindex = 0;
170     }
171 }
172
173 /*
174  * process the "RPC" and return the results
175  */
176
177 char somebuf[RXPERF_BUFSIZE];
178
179 afs_int32 rxwrite_size = sizeof(somebuf);
180 afs_int32 rxread_size = sizeof(somebuf);
181 afs_int32 use_rx_readv = 0;
182
183 static int
184 do_readbytes(struct rx_call *call, afs_int32 bytes)
185 {
186     struct iovec tiov[RX_MAXIOVECS];
187     afs_int32 size;
188     int tnio;
189     int code;
190
191     while (bytes > 0) {
192         size = rxread_size;
193
194         if (size > bytes)
195             size = bytes;
196         if (use_rx_readv) {
197             if (size > RX_MAX_PACKET_DATA_SIZE)
198                 size = RX_MAX_PACKET_DATA_SIZE;
199             code = rx_Readv(call, tiov, &tnio, RX_MAXIOVECS, size);
200         } else
201             code = rx_Read(call, somebuf, size);
202         if (code != size)
203             return 1;
204
205         bytes -= size;
206     }
207     return 0;
208 }
209
210 static int
211 do_sendbytes(struct rx_call *call, afs_int32 bytes)
212 {
213     afs_int32 size;
214
215     while (bytes > 0) {
216         size = rxwrite_size;
217         if (size > bytes)
218             size = bytes;
219         if (rx_Write(call, somebuf, size) != size)
220             return 1;
221         bytes -= size;
222     }
223     return 0;
224 }
225
226
227 static afs_int32
228 rxperf_ExecuteRequest(struct rx_call *call)
229 {
230     afs_int32 version;
231     afs_int32 command;
232     afs_int32 bytes;
233     afs_int32 recvb;
234     afs_int32 sendb;
235     afs_int32 data;
236     afs_uint32 num;
237     afs_uint32 *readwrite;
238     afs_uint32 i;
239     int readp = TRUE;
240
241     DBFPRINT(("got a request\n"));
242
243     if (rx_Read32(call, &version) != 4) {
244         warn("rx_Read failed to read version");
245         return -1;
246     }
247
248     if (htonl(RX_PERF_VERSION) != version) {
249         warnx("client has wrong version");
250         return -1;
251     }
252
253     if (rx_Read32(call, &command) != 4) {
254         warnx("rx_Read failed to read command");
255         return -1;
256     }
257     command = ntohl(command);
258
259     if (rx_Read32(call, &data) != 4) {
260         warnx("rx_Read failed to read size");
261         return -1;
262     }
263     rxread_size = ntohl(data);
264     if (rxread_size > sizeof(somebuf)) {
265         warnx("rxread_size too large %d", rxread_size);
266         return -1;
267     }
268
269     if (rx_Read32(call, &data) != 4) {
270         warnx("rx_Read failed to write size");
271         return -1;
272     }
273     rxwrite_size = ntohl(data);
274     if (rxwrite_size > sizeof(somebuf)) {
275         warnx("rxwrite_size too large %d", rxwrite_size);
276         return -1;
277     }
278
279     switch (command) {
280     case RX_PERF_SEND:
281         DBFPRINT(("got a send request\n"));
282
283         if (rx_Read32(call, &bytes) != 4) {
284             warnx("rx_Read failed to read bytes");
285             return -1;
286         }
287         bytes = ntohl(bytes);
288
289         DBFPRINT(("reading(%d) ", bytes));
290         do_readbytes(call, bytes);
291
292         data = htonl(RXPERF_MAGIC_COOKIE);
293         if (rx_Write32(call, &data) != 4) {
294             warnx("rx_Write failed when sending back result");
295             return -1;
296         }
297         DBFPRINT(("done\n"));
298
299         break;
300     case RX_PERF_RPC:
301         DBFPRINT(("got a rpc request, reading commands\n"));
302
303         if (rx_Read32(call, &recvb) != 4) {
304             warnx("rx_Read failed to read recvbytes");
305             return -1;
306         }
307         recvb = ntohl(recvb);
308         if (rx_Read32(call, &sendb) != 4) {
309             warnx("rx_Read failed to read sendbytes");
310             return -1;
311         }
312         sendb = ntohl(sendb);
313
314         DBFPRINT(("read(%d) ", recvb));
315         if (do_readbytes(call, recvb)) {
316             warnx("do_readbytes failed");
317             return -1;
318         }
319         DBFPRINT(("send(%d) ", sendb));
320         if (do_sendbytes(call, sendb)) {
321             warnx("sendbytes failed");
322             return -1;
323         }
324
325         DBFPRINT(("done\n"));
326
327         data = htonl(RXPERF_MAGIC_COOKIE);
328         if (rx_Write32(call, &data) != 4) {
329             warnx("rx_Write failed when sending back magic cookie");
330             return -1;
331         }
332
333         break;
334     case RX_PERF_FILE:
335         if (rx_Read32(call, &data) != 4)
336             errx(1, "failed to read num from client");
337         num = ntohl(data);
338
339         readwrite = malloc(num * sizeof(afs_uint32));
340         if (readwrite == NULL)
341             err(1, "malloc");
342
343         if (rx_Read(call, (char*)readwrite, num * sizeof(afs_uint32)) !=
344             num * sizeof(afs_uint32))
345             errx(1, "failed to read recvlist from client");
346
347         for (i = 0; i < num; i++) {
348             if (readwrite[i] == 0) {
349                 DBFPRINT(("readp %d", readwrite[i]));
350                 readp = !readp;
351             }
352
353             bytes = ntohl(readwrite[i]) * sizeof(afs_uint32);
354
355             if (readp) {
356                 DBFPRINT(("read\n"));
357                 do_readbytes(call, bytes);
358             } else {
359                 do_sendbytes(call, bytes);
360                 DBFPRINT(("send\n"));
361             }
362         }
363
364         break;
365     case RX_PERF_RECV:
366         DBFPRINT(("got a recv request\n"));
367
368         if (rx_Read32(call, &bytes) != 4) {
369             warnx("rx_Read failed to read bytes");
370             return -1;
371         }
372         bytes = ntohl(bytes);
373
374         DBFPRINT(("sending(%d) ", bytes));
375         do_sendbytes(call, bytes);
376
377         data = htonl(RXPERF_MAGIC_COOKIE);
378         if (rx_Write32(call, &data) != 4) {
379             warnx("rx_Write failed when sending back result");
380             return -1;
381         }
382         DBFPRINT(("done\n"));
383
384         break;
385     default:
386         warnx("client sent a unsupported command");
387         return -1;
388     }
389     DBFPRINT(("done with command\n"));
390
391     return 0;
392 }
393
394 /*
395  *
396  */
397
398 static void
399 do_server(short port, int nojumbo, int maxmtu, int maxwsize, int minpeertimeout,
400           int udpbufsz, int nostats, int hotthread,
401           int minprocs, int maxprocs)
402 {
403     struct rx_service *service;
404     struct rx_securityClass *secureobj;
405     int secureindex;
406     int ret;
407
408 #ifdef AFS_NT40_ENV
409     if (afs_winsockInit() < 0) {
410         printf("Can't initialize winsock.\n");
411         exit(1);
412     }
413 #endif
414
415     if (hotthread)
416         rx_EnableHotThread();
417
418     if (nostats)
419         rx_enable_stats = 0;
420
421     rx_SetUdpBufSize(udpbufsz);
422
423     ret = rx_Init(htons(port));
424     if (ret)
425         errx(1, "rx_Init failed");
426
427     if (nojumbo)
428       rx_SetNoJumbo();
429
430     if (maxmtu)
431       rx_SetMaxMTU(maxmtu);
432
433     if (maxwsize) {
434         rx_SetMaxReceiveWindow(maxwsize);
435         rx_SetMaxSendWindow(maxwsize);
436     }
437
438     if (minpeertimeout)
439         rx_SetMinPeerTimeout(minpeertimeout);
440
441
442     get_sec(1, &secureobj, &secureindex);
443
444     service =
445         rx_NewService(0, RX_SERVER_ID, "rxperf", &secureobj, secureindex,
446                       rxperf_ExecuteRequest);
447     if (service == NULL)
448         errx(1, "Cant create server");
449
450     rx_SetMinProcs(service, minprocs);
451     rx_SetMaxProcs(service, maxprocs);
452
453     rx_SetCheckReach(service, 1);
454
455     rx_StartServer(1);
456
457     abort();
458 }
459
460 /*
461  *
462  */
463
464 static void
465 readfile(const char *filename, afs_uint32 ** readwrite, afs_uint32 * size)
466 {
467     FILE *f;
468     afs_uint32 len = 16;
469     afs_uint32 num = 0;
470     afs_uint32 data;
471     char *ptr;
472     char *buf;
473
474     *readwrite = malloc(sizeof(afs_uint32) * len);
475     buf = malloc(RXPERF_BUFSIZE);
476
477     if (*readwrite == NULL)
478         err(1, "malloc");
479
480     f = fopen(filename, "r");
481     if (f == NULL)
482         err(1, "fopen");
483
484     while (fgets(buf, sizeof(buf), f) != NULL) {
485         if (num >= len) {
486             len = len * 2;
487             *readwrite = realloc(*readwrite, len * sizeof(afs_uint32));
488             if (*readwrite == NULL)
489                 err(1, "realloc");
490         }
491
492         if (*buf != '\n') {
493             data = htonl(strtol(buf, &ptr, 0));
494             if (ptr && ptr == buf)
495                 errx(1, "can't resolve number of bytes to transfer");
496         } else {
497             data = 0;
498         }
499
500         (*readwrite)[num] = data;
501         num++;
502     }
503
504     *size = num;
505
506
507     if (fclose(f) == -1)
508         err(1, "fclose");
509     free(buf);
510 }
511
512 struct client_data {
513     struct rx_connection *conn;
514     char *filename;
515     int command;
516     afs_int32 times;
517     afs_int32 bytes;
518     afs_int32 sendbytes;
519     afs_int32 readbytes;
520 };
521
522 static void *
523 client_thread( void *vparams)
524 {
525     struct client_data *params = (struct client_data *)vparams;
526     struct rx_call *call;
527     afs_int32 data;
528     int i, j;
529     afs_uint32 *readwrite;
530     int readp = FALSE;
531     afs_uint32 size;
532     afs_uint32 num;
533
534     for (i = 0; i < params->times; i++) {
535
536         DBFPRINT(("starting command "));
537
538         call = rx_NewCall(params->conn);
539         if (call == NULL)
540             errx(1, "rx_NewCall failed");
541
542         data = htonl(RX_PERF_VERSION);
543         if (rx_Write32(call, &data) != 4)
544             errx(1, "rx_Write failed to send version (err %d)", rx_Error(call));
545
546         data = htonl(params->command);
547         if (rx_Write32(call, &data) != 4)
548             errx(1, "rx_Write failed to send command (err %d)", rx_Error(call));
549
550         data = htonl(rxread_size);
551         if (rx_Write32(call, &data) != 4)
552             errx(1, "rx_Write failed to send read size (err %d)", rx_Error(call));
553         data = htonl(rxwrite_size);
554         if (rx_Write32(call, &data) != 4)
555             errx(1, "rx_Write failed to send write read (err %d)", rx_Error(call));
556
557
558         switch (params->command) {
559         case RX_PERF_RECV:
560             DBFPRINT(("command "));
561
562             data = htonl(params->bytes);
563             if (rx_Write32(call, &data) != 4)
564                 errx(1, "rx_Write failed to send size (err %d)", rx_Error(call));
565
566             DBFPRINT(("sending(%d) ", params->bytes));
567             if (do_readbytes(call, params->bytes))
568                 errx(1, "sendbytes (err %d)", rx_Error(call));
569
570             if (rx_Read32(call, &data) != 4)
571                 errx(1, "failed to read result from server (err %d)", rx_Error(call));
572
573             if (data != htonl(RXPERF_MAGIC_COOKIE))
574                 warn("server send wrong magic cookie in responce");
575
576             DBFPRINT(("done\n"));
577
578             break;
579         case RX_PERF_SEND:
580             DBFPRINT(("command "));
581
582             data = htonl(params->bytes);
583             if (rx_Write32(call, &data) != 4)
584                 errx(1, "rx_Write failed to send size (err %d)", rx_Error(call));
585
586             DBFPRINT(("sending(%d) ", params->bytes));
587             if (do_sendbytes(call, params->bytes))
588                 errx(1, "sendbytes (err %d)", rx_Error(call));
589
590             if (rx_Read32(call, &data) != 4)
591                 errx(1, "failed to read result from server (err %d)", rx_Error(call));
592
593             if (data != htonl(RXPERF_MAGIC_COOKIE))
594                 warn("server send wrong magic cookie in responce");
595
596             DBFPRINT(("done\n"));
597
598             break;
599         case RX_PERF_RPC:
600             DBFPRINT(("commands "));
601
602             data = htonl(params->sendbytes);
603             if (rx_Write32(call, &data) != 4)
604                 errx(1, "rx_Write failed to send command (err %d)", rx_Error(call));
605
606             data = htonl(params->readbytes);
607             if (rx_Write32(call, &data) != 4)
608                 errx(1, "rx_Write failed to send command (err %d)", rx_Error(call));
609
610             DBFPRINT(("send(%d) ", params->sendbytes));
611             if (do_sendbytes(call, params->sendbytes))
612                 errx(1, "sendbytes (err %d)", rx_Error(call));
613
614             DBFPRINT(("recv(%d) ", params->readbytes));
615             if (do_readbytes(call, params->readbytes))
616                 errx(1, "sendbytes (err %d)", rx_Error(call));
617
618             if (rx_Read32(call, &data) != 4)
619                 errx(1, "failed to read result from server (err %d)", rx_Error(call));
620
621             if (data != htonl(RXPERF_MAGIC_COOKIE))
622                 warn("server send wrong magic cookie in responce");
623
624             DBFPRINT(("done\n"));
625
626             break;
627
628         case RX_PERF_FILE:
629             readfile(params->filename, &readwrite, &num);
630
631             data = htonl(num);
632             if (rx_Write32(call, &data) != 4)
633                 errx(1, "rx_Write failed to send size (err %d)", rx_Error(call));
634
635             if (rx_Write(call, (char *)readwrite, num * sizeof(afs_uint32))
636                 != num * sizeof(afs_uint32))
637                 errx(1, "rx_Write failed to send list (err %d)", rx_Error(call));
638
639             for (j = 0; j < num; j++) {
640                 if (readwrite[j] == 0)
641                     readp = !readp;
642
643                 size = ntohl(readwrite[j]) * sizeof(afs_uint32);
644
645                 if (readp) {
646                     if (do_readbytes(call, size))
647                         errx(1, "sendbytes (err %d)", rx_Error(call));
648                     DBFPRINT(("read\n"));
649                 } else {
650                     if (do_sendbytes(call, size))
651                         errx(1, "sendbytes (err %d)", rx_Error(call));
652                     DBFPRINT(("send\n"));
653                 }
654             }
655             break;
656         default:
657             abort();
658         }
659
660         rx_EndCall(call, 0);
661     }
662
663 #ifdef AFS_PTHREAD_ENV
664     pthread_exit(NULL);
665 #endif
666
667     return NULL;
668 }
669
670 /*
671  *
672  */
673
674 static void
675 do_client(const char *server, short port, char *filename, afs_int32 command,
676           afs_int32 times, afs_int32 bytes, afs_int32 sendbytes, afs_int32 readbytes,
677           int dumpstats, int nojumbo, int maxmtu, int maxwsize, int minpeertimeout,
678           int udpbufsz, int nostats, int hotthread, int threads)
679 {
680     struct rx_connection *conn;
681     afs_uint32 addr;
682     struct rx_securityClass *secureobj;
683     int secureindex;
684     int ret;
685     char stamp[2048];
686     struct client_data *params;
687
688 #ifdef AFS_PTHREAD_ENV
689     int i;
690     pthread_t thread[MAX_THREADS];
691     pthread_attr_t tattr;
692     void *status;
693 #endif
694
695     params = malloc(sizeof(struct client_data));
696     memset(params, 0, sizeof(struct client_data));
697
698 #ifdef AFS_NT40_ENV
699     if (afs_winsockInit() < 0) {
700         printf("Can't initialize winsock.\n");
701         exit(1);
702     }
703 #endif
704
705     if (hotthread)
706         rx_EnableHotThread();
707
708     if (nostats)
709         rx_enable_stats = 0;
710
711     addr = str2addr(server);
712
713     rx_SetUdpBufSize(udpbufsz);
714
715     ret = rx_Init(0);
716     if (ret)
717         errx(1, "rx_Init failed");
718
719     if (nojumbo)
720       rx_SetNoJumbo();
721
722     if (maxmtu)
723       rx_SetMaxMTU(maxmtu);
724
725     if (maxwsize) {
726         rx_SetMaxReceiveWindow(maxwsize);
727         rx_SetMaxSendWindow(maxwsize);
728     }
729
730     if (minpeertimeout)
731         rx_SetMinPeerTimeout(minpeertimeout);
732
733
734     get_sec(0, &secureobj, &secureindex);
735
736     switch (command) {
737     case RX_PERF_RPC:
738         sprintf(stamp, "RPC: threads\t%d, times\t%d, write bytes\t%d, read bytes\t%d",
739                  threads, times, sendbytes, readbytes);
740         break;
741     case RX_PERF_RECV:
742         sprintf(stamp, "RECV: threads\t%d, times\t%d, bytes\t%d",
743                  threads, times, bytes);
744         break;
745     case RX_PERF_SEND:
746         sprintf(stamp, "SEND: threads\t%d, times\t%d, bytes\t%d",
747                  threads, times, bytes);
748         break;
749     case RX_PERF_FILE:
750         sprintf(stamp, "FILE %s: threads\t%d, times\t%d, bytes\t%d",
751                  filename, threads, times, bytes);
752         break;
753     }
754
755     conn = rx_NewConnection(addr, htons(port), RX_SERVER_ID, secureobj, secureindex);
756     if (conn == NULL)
757         errx(1, "failed to contact server");
758
759 #ifdef AFS_PTHREAD_ENV
760     pthread_attr_init(&tattr);
761     pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_JOINABLE);
762 #endif
763
764     params->conn = conn;
765     params->filename = filename;
766     params->command = command;
767     params->times = times;
768     params->bytes = bytes;
769     params->sendbytes = sendbytes;
770     params->readbytes = readbytes;
771
772     start_timer();
773
774 #ifdef AFS_PTHREAD_ENV
775     for ( i=0; i<threads; i++) {
776         pthread_create(&thread[i], &tattr, client_thread, params);
777         if ( (i + 1) % RX_MAXCALLS == 0 ) {
778             conn = rx_NewConnection(addr, htons(port), RX_SERVER_ID, secureobj, secureindex);
779             if (conn != NULL) {
780                 struct client_data *new_params = malloc(sizeof(struct client_data));
781                 memcpy(new_params, params, sizeof(struct client_data));
782                 new_params->conn = conn;
783                 params = new_params;
784             }
785         }
786     }
787 #else
788         client_thread(params);
789 #endif
790
791 #ifdef AFS_PTHREAD_ENV
792     for ( i=0; i<threads; i++)
793         pthread_join(thread[i], &status);
794 #endif
795
796     end_and_print_timer(stamp);
797     DBFPRINT(("done for good\n"));
798
799     if (dumpstats) {
800         rx_PrintStats(stdout);
801         rx_PrintPeerStats(stdout, rx_PeerOf(conn));
802     }
803     rx_Finalize();
804
805 #ifdef AFS_PTHREAD_ENV
806     pthread_attr_destroy(&tattr);
807 #endif
808
809     free(params);
810 }
811
812 static void
813 usage(void)
814 {
815 #define COMMON ""
816
817     fprintf(stderr, "usage: %s client -c send -b <bytes>\n", getprogname());
818     fprintf(stderr, "usage: %s client -c recv -b <bytes>\n", getprogname());
819     fprintf(stderr,
820             "usage: %s client -c rpc  -S <sendbytes> -R <recvbytes>\n",
821             getprogname());
822     fprintf(stderr, "usage: %s client -c file -f filename\n", getprogname());
823     fprintf(stderr,
824             "%s: usage: common option to the client "
825             "-w <write-bytes> -r <read-bytes> -T times -p port -s server -D\n",
826             getprogname());
827     fprintf(stderr, "usage: %s server -p port\n", getprogname());
828 #undef COMMMON
829     exit(1);
830 }
831
832
833
834 /*
835  * do argument processing and call networking functions
836  */
837
838 static int
839 rxperf_server(int argc, char **argv)
840 {
841     short port = DEFAULT_PORT;
842     int nojumbo = 0;
843     int maxmtu = 0;
844     int nostats = 0;
845     int udpbufsz = 64 * 1024;
846     int hotthreads = 0;
847     int minprocs = 2;
848     int maxprocs = 20;
849     int maxwsize = 0;
850     int minpeertimeout = 0;
851     char *ptr;
852     int ch;
853
854     while ((ch = getopt(argc, argv, "r:d:p:P:w:W:HNjm:u:4:s:S:V")) != -1) {
855         switch (ch) {
856         case 'd':
857 #ifdef RXDEBUG
858             rx_debugFile = fopen(optarg, "w");
859             if (rx_debugFile == NULL)
860                 err(1, "fopen %s", optarg);
861 #else
862             errx(1, "compiled without RXDEBUG");
863 #endif
864             break;
865         case 'r':
866             rxread_size = strtol(optarg, &ptr, 0);
867             if (ptr != 0 && ptr[0] != '\0')
868                 errx(1, "can't resolve readsize");
869             if (rxread_size > sizeof(somebuf))
870                 errx(1, "%d > sizeof(somebuf) (%"AFS_SIZET_FMT")", rxread_size,
871                      sizeof(somebuf));
872             break;
873         case 's':
874             minprocs = strtol(optarg, &ptr, 0);
875             if (ptr != 0 && ptr[0] != '\0')
876                 errx(1, "can't resolve minprocs");
877             break;
878         case 'S':
879             maxprocs = strtol(optarg, &ptr, 0);
880             if (ptr != 0 && ptr[0] != '\0')
881                 errx(1, "can't resolve maxprocs");
882             break;
883         case 'P':
884             minpeertimeout = strtol(optarg, &ptr, 0);
885             if (ptr != 0 && ptr[0] != '\0')
886                 errx(1, "can't resolve min peer timeout");
887             break;
888         case 'p':
889             port = (short) strtol(optarg, &ptr, 0);
890             if (ptr != 0 && ptr[0] != '\0')
891                 errx(1, "can't resolve portname");
892             break;
893         case 'w':
894             rxwrite_size = strtol(optarg, &ptr, 0);
895             if (ptr != 0 && ptr[0] != '\0')
896                 errx(1, "can't resolve writesize");
897             if (rxwrite_size > sizeof(somebuf))
898                 errx(1, "%d > sizeof(somebuf) (%"AFS_SIZET_FMT")", rxwrite_size,
899                      sizeof(somebuf));
900             break;
901         case 'j':
902           nojumbo=1;
903           break;
904         case 'N':
905           nostats=1;
906           break;
907         case 'H':
908             hotthreads = 1;
909             break;
910         case 'm':
911           maxmtu = strtol(optarg, &ptr, 0);
912           if (ptr && *ptr != '\0')
913             errx(1, "can't resolve rx maxmtu to use");
914             break;
915         case 'u':
916             udpbufsz = strtol(optarg, &ptr, 0) * 1024;
917             if (ptr && *ptr != '\0')
918                 errx(1, "can't resolve upd buffer size (Kbytes)");
919             break;
920         case 'V':
921             use_rx_readv = 1;
922             break;
923         case 'W':
924             maxwsize = strtol(optarg, &ptr, 0);
925             if (ptr && *ptr != '\0')
926                 errx(1, "can't resolve max send/recv window size (packets)");
927             break;
928         case '4':
929           RX_IPUDP_SIZE = 28;
930           break;
931         default:
932             usage();
933         }
934     }
935
936     if (optind != argc)
937         usage();
938
939     do_server(port, nojumbo, maxmtu, maxwsize, minpeertimeout, udpbufsz,
940               nostats, hotthreads, minprocs, maxprocs);
941
942     return 0;
943 }
944
945 /*
946  * do argument processing and call networking functions
947  */
948
949 static int
950 rxperf_client(int argc, char **argv)
951 {
952     char *host = DEFAULT_HOST;
953     int bytes = DEFAULT_BYTES;
954     short port = DEFAULT_PORT;
955     char *filename = NULL;
956     afs_int32 cmd;
957     int sendbytes = 3;
958     int readbytes = 30;
959     int times = 100;
960     int dumpstats = 0;
961     int nojumbo = 0;
962     int nostats = 0;
963     int maxmtu = 0;
964     int hotthreads = 0;
965     int threads = 1;
966     int udpbufsz = 64 * 1024;
967     int maxwsize = 0;
968     int minpeertimeout = 0;
969     char *ptr;
970     int ch;
971
972     cmd = RX_PERF_UNKNOWN;
973
974     while ((ch = getopt(argc, argv, "T:S:R:b:c:d:p:P:r:s:w:W:f:HDNjm:u:4:t:V")) != -1) {
975         switch (ch) {
976         case 'b':
977             bytes = strtol(optarg, &ptr, 0);
978             if (ptr && *ptr != '\0')
979                 errx(1, "can't resolve number of bytes to transfer");
980             break;
981         case 'c':
982             if (strcasecmp(optarg, "send") == 0)
983                 cmd = RX_PERF_SEND;
984             else if (strcasecmp(optarg, "recv") == 0)
985                 cmd = RX_PERF_RECV;
986             else if (strcasecmp(optarg, "rpc") == 0)
987                 cmd = RX_PERF_RPC;
988             else if (strcasecmp(optarg, "file") == 0)
989                 cmd = RX_PERF_FILE;
990             else
991                 errx(1, "unknown command %s", optarg);
992             break;
993         case 'd':
994 #ifdef RXDEBUG
995             rx_debugFile = fopen(optarg, "w");
996             if (rx_debugFile == NULL)
997                 err(1, "fopen %s", optarg);
998 #else
999             errx(1, "compiled without RXDEBUG");
1000 #endif
1001             break;
1002         case 'P':
1003             minpeertimeout = strtol(optarg, &ptr, 0);
1004             if (ptr != 0 && ptr[0] != '\0')
1005                 errx(1, "can't resolve min peer timeout");
1006             break;
1007         case 'p':
1008             port = (short) strtol(optarg, &ptr, 0);
1009             if (ptr != 0 && ptr[0] != '\0')
1010                 errx(1, "can't resolve portname");
1011             break;
1012         case 'r':
1013             rxread_size = strtol(optarg, &ptr, 0);
1014             if (ptr != 0 && ptr[0] != '\0')
1015                 errx(1, "can't resolve readsize");
1016             if (rxread_size > sizeof(somebuf))
1017                 errx(1, "%d > sizeof(somebuf) (%"AFS_SIZET_FMT")", rxread_size,
1018                      sizeof(somebuf));
1019             break;
1020         case 's':
1021             host = strdup(optarg);
1022             if (host == NULL)
1023                 err(1, "strdup");
1024             break;
1025         case 'V':
1026             use_rx_readv = 1;
1027             break;
1028         case 'w':
1029             rxwrite_size = strtol(optarg, &ptr, 0);
1030             if (ptr != 0 && ptr[0] != '\0')
1031                 errx(1, "can't resolve writesize");
1032             if (rxwrite_size > sizeof(somebuf))
1033                 errx(1, "%d > sizeof(somebuf) (%"AFS_SIZET_FMT")", rxwrite_size,
1034                      sizeof(somebuf));
1035             break;
1036         case 'W':
1037             maxwsize = strtol(optarg, &ptr, 0);
1038             if (ptr && *ptr != '\0')
1039                 errx(1, "can't resolve max send/recv window size (packets)");
1040             break;
1041         case 'T':
1042             times = strtol(optarg, &ptr, 0);
1043             if (ptr && *ptr != '\0')
1044                 errx(1, "can't resolve number of times to execute rpc");
1045             break;
1046         case 'S':
1047             sendbytes = strtol(optarg, &ptr, 0);
1048             if (ptr && *ptr != '\0')
1049                 errx(1, "can't resolve number of bytes to send");
1050             break;
1051         case 'R':
1052             readbytes = strtol(optarg, &ptr, 0);
1053             if (ptr && *ptr != '\0')
1054                 errx(1, "can't resolve number of bytes to receive");
1055             break;
1056         case 't':
1057 #ifdef AFS_PTHREAD_ENV
1058             threads = strtol(optarg, &ptr, 0);
1059             if (ptr && *ptr != '\0')
1060                 errx(1, "can't resolve number of threads to execute");
1061             if (threads > MAX_THREADS)
1062                 errx(1, "too many threads");
1063 #else
1064             errx(1, "Not built for pthreads");
1065 #endif
1066             break;
1067         case 'f':
1068             filename = optarg;
1069             break;
1070         case 'D':
1071             dumpstats = 1;
1072             break;
1073         case 'N':
1074             nostats = 1;
1075             break;
1076         case 'H':
1077             hotthreads = 1;
1078             break;
1079         case 'j':
1080           nojumbo=1;
1081           break;
1082         case 'm':
1083           maxmtu = strtol(optarg, &ptr, 0);
1084           if (ptr && *ptr != '\0')
1085             errx(1, "can't resolve rx maxmtu to use");
1086             break;
1087         case 'u':
1088             udpbufsz = strtol(optarg, &ptr, 0) * 1024;
1089             if (ptr && *ptr != '\0')
1090                 errx(1, "can't resolve upd buffer size (Kbytes)");
1091             break;
1092         case '4':
1093           RX_IPUDP_SIZE = 28;
1094           break;
1095         default:
1096             usage();
1097         }
1098     }
1099
1100     if (nostats && dumpstats)
1101         errx(1, "cannot set both -N and -D");
1102
1103     if (threads > 1 && cmd == RX_PERF_FILE)
1104         errx(1, "cannot use multiple threads with file command");
1105
1106     if (optind != argc)
1107         usage();
1108
1109     if (cmd == RX_PERF_UNKNOWN)
1110         errx(1, "no command given to the client");
1111
1112     do_client(host, port, filename, cmd, times, bytes, sendbytes,
1113               readbytes, dumpstats, nojumbo, maxmtu, maxwsize, minpeertimeout,
1114               udpbufsz, nostats, hotthreads, threads);
1115
1116     return 0;
1117 }
1118
1119 /*
1120  * setup world and call cmd
1121  */
1122
1123 int
1124 main(int argc, char **argv)
1125 {
1126 #ifndef AFS_PTHREAD_ENV
1127     PROCESS pid;
1128 #endif
1129
1130     setprogname(argv[0]);
1131
1132 #ifndef AFS_NT40_ENV
1133     signal(SIGUSR1, sigusr1);
1134     signal(SIGINT, sigint);
1135 #endif
1136
1137 #ifndef AFS_PTHREAD_ENV
1138     LWP_InitializeProcessSupport(LWP_NORMAL_PRIORITY, &pid);
1139 #endif
1140
1141     memset(somebuf, 0, sizeof(somebuf));
1142
1143     if (argc >= 2 && strcmp(argv[1], "server") == 0)
1144         rxperf_server(argc - 1, argv + 1);
1145     else if (argc >= 2 && strcmp(argv[1], "client") == 0)
1146         rxperf_client(argc - 1, argv + 1);
1147     else
1148         usage();
1149     return 0;
1150 }