b20f91fc1e1a2d185d76a96c58b7f9e81090d097
[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 = calloc(1, sizeof(struct client_data));
696
697 #ifdef AFS_NT40_ENV
698     if (afs_winsockInit() < 0) {
699         printf("Can't initialize winsock.\n");
700         exit(1);
701     }
702 #endif
703
704     if (hotthread)
705         rx_EnableHotThread();
706
707     if (nostats)
708         rx_enable_stats = 0;
709
710     addr = str2addr(server);
711
712     rx_SetUdpBufSize(udpbufsz);
713
714     ret = rx_Init(0);
715     if (ret)
716         errx(1, "rx_Init failed");
717
718     if (nojumbo)
719       rx_SetNoJumbo();
720
721     if (maxmtu)
722       rx_SetMaxMTU(maxmtu);
723
724     if (maxwsize) {
725         rx_SetMaxReceiveWindow(maxwsize);
726         rx_SetMaxSendWindow(maxwsize);
727     }
728
729     if (minpeertimeout)
730         rx_SetMinPeerTimeout(minpeertimeout);
731
732
733     get_sec(0, &secureobj, &secureindex);
734
735     switch (command) {
736     case RX_PERF_RPC:
737         sprintf(stamp, "RPC: threads\t%d, times\t%d, write bytes\t%d, read bytes\t%d",
738                  threads, times, sendbytes, readbytes);
739         break;
740     case RX_PERF_RECV:
741         sprintf(stamp, "RECV: threads\t%d, times\t%d, bytes\t%d",
742                  threads, times, bytes);
743         break;
744     case RX_PERF_SEND:
745         sprintf(stamp, "SEND: threads\t%d, times\t%d, bytes\t%d",
746                  threads, times, bytes);
747         break;
748     case RX_PERF_FILE:
749         sprintf(stamp, "FILE %s: threads\t%d, times\t%d, bytes\t%d",
750                  filename, threads, times, bytes);
751         break;
752     }
753
754     conn = rx_NewConnection(addr, htons(port), RX_SERVER_ID, secureobj, secureindex);
755     if (conn == NULL)
756         errx(1, "failed to contact server");
757
758 #ifdef AFS_PTHREAD_ENV
759     pthread_attr_init(&tattr);
760     pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_JOINABLE);
761 #endif
762
763     params->conn = conn;
764     params->filename = filename;
765     params->command = command;
766     params->times = times;
767     params->bytes = bytes;
768     params->sendbytes = sendbytes;
769     params->readbytes = readbytes;
770
771     start_timer();
772
773 #ifdef AFS_PTHREAD_ENV
774     for ( i=0; i<threads; i++) {
775         pthread_create(&thread[i], &tattr, client_thread, params);
776         if ( (i + 1) % RX_MAXCALLS == 0 ) {
777             conn = rx_NewConnection(addr, htons(port), RX_SERVER_ID, secureobj, secureindex);
778             if (conn != NULL) {
779                 struct client_data *new_params = malloc(sizeof(struct client_data));
780                 memcpy(new_params, params, sizeof(struct client_data));
781                 new_params->conn = conn;
782                 params = new_params;
783             }
784         }
785     }
786 #else
787         client_thread(params);
788 #endif
789
790 #ifdef AFS_PTHREAD_ENV
791     for ( i=0; i<threads; i++)
792         pthread_join(thread[i], &status);
793 #endif
794
795     end_and_print_timer(stamp);
796     DBFPRINT(("done for good\n"));
797
798     if (dumpstats) {
799         rx_PrintStats(stdout);
800         rx_PrintPeerStats(stdout, rx_PeerOf(conn));
801     }
802     rx_Finalize();
803
804 #ifdef AFS_PTHREAD_ENV
805     pthread_attr_destroy(&tattr);
806 #endif
807
808     free(params);
809 }
810
811 static void
812 usage(void)
813 {
814 #define COMMON ""
815
816     fprintf(stderr, "usage: %s client -c send -b <bytes>\n", getprogname());
817     fprintf(stderr, "usage: %s client -c recv -b <bytes>\n", getprogname());
818     fprintf(stderr,
819             "usage: %s client -c rpc  -S <sendbytes> -R <recvbytes>\n",
820             getprogname());
821     fprintf(stderr, "usage: %s client -c file -f filename\n", getprogname());
822     fprintf(stderr,
823             "%s: usage: common option to the client "
824             "-w <write-bytes> -r <read-bytes> -T times -p port -s server -D\n",
825             getprogname());
826     fprintf(stderr, "usage: %s server -p port\n", getprogname());
827 #undef COMMMON
828     exit(1);
829 }
830
831
832
833 /*
834  * do argument processing and call networking functions
835  */
836
837 static int
838 rxperf_server(int argc, char **argv)
839 {
840     short port = DEFAULT_PORT;
841     int nojumbo = 0;
842     int maxmtu = 0;
843     int nostats = 0;
844     int udpbufsz = 64 * 1024;
845     int hotthreads = 0;
846     int minprocs = 2;
847     int maxprocs = 20;
848     int maxwsize = 0;
849     int minpeertimeout = 0;
850     char *ptr;
851     int ch;
852
853     while ((ch = getopt(argc, argv, "r:d:p:P:w:W:HNjm:u:4:s:S:V")) != -1) {
854         switch (ch) {
855         case 'd':
856 #ifdef RXDEBUG
857             rx_debugFile = fopen(optarg, "w");
858             if (rx_debugFile == NULL)
859                 err(1, "fopen %s", optarg);
860 #else
861             errx(1, "compiled without RXDEBUG");
862 #endif
863             break;
864         case 'r':
865             rxread_size = strtol(optarg, &ptr, 0);
866             if (ptr != 0 && ptr[0] != '\0')
867                 errx(1, "can't resolve readsize");
868             if (rxread_size > sizeof(somebuf))
869                 errx(1, "%d > sizeof(somebuf) (%"AFS_SIZET_FMT")", rxread_size,
870                      sizeof(somebuf));
871             break;
872         case 's':
873             minprocs = strtol(optarg, &ptr, 0);
874             if (ptr != 0 && ptr[0] != '\0')
875                 errx(1, "can't resolve minprocs");
876             break;
877         case 'S':
878             maxprocs = strtol(optarg, &ptr, 0);
879             if (ptr != 0 && ptr[0] != '\0')
880                 errx(1, "can't resolve maxprocs");
881             break;
882         case 'P':
883             minpeertimeout = strtol(optarg, &ptr, 0);
884             if (ptr != 0 && ptr[0] != '\0')
885                 errx(1, "can't resolve min peer timeout");
886             break;
887         case 'p':
888             port = (short) strtol(optarg, &ptr, 0);
889             if (ptr != 0 && ptr[0] != '\0')
890                 errx(1, "can't resolve portname");
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) (%"AFS_SIZET_FMT")", rxwrite_size,
898                      sizeof(somebuf));
899             break;
900         case 'j':
901           nojumbo=1;
902           break;
903         case 'N':
904           nostats=1;
905           break;
906         case 'H':
907             hotthreads = 1;
908             break;
909         case 'm':
910           maxmtu = strtol(optarg, &ptr, 0);
911           if (ptr && *ptr != '\0')
912             errx(1, "can't resolve rx maxmtu to use");
913             break;
914         case 'u':
915             udpbufsz = strtol(optarg, &ptr, 0) * 1024;
916             if (ptr && *ptr != '\0')
917                 errx(1, "can't resolve upd buffer size (Kbytes)");
918             break;
919         case 'V':
920             use_rx_readv = 1;
921             break;
922         case 'W':
923             maxwsize = strtol(optarg, &ptr, 0);
924             if (ptr && *ptr != '\0')
925                 errx(1, "can't resolve max send/recv window size (packets)");
926             break;
927         case '4':
928           RX_IPUDP_SIZE = 28;
929           break;
930         default:
931             usage();
932         }
933     }
934
935     if (optind != argc)
936         usage();
937
938     do_server(port, nojumbo, maxmtu, maxwsize, minpeertimeout, udpbufsz,
939               nostats, hotthreads, minprocs, maxprocs);
940
941     return 0;
942 }
943
944 /*
945  * do argument processing and call networking functions
946  */
947
948 static int
949 rxperf_client(int argc, char **argv)
950 {
951     char *host = DEFAULT_HOST;
952     int bytes = DEFAULT_BYTES;
953     short port = DEFAULT_PORT;
954     char *filename = NULL;
955     afs_int32 cmd;
956     int sendbytes = 3;
957     int readbytes = 30;
958     int times = 100;
959     int dumpstats = 0;
960     int nojumbo = 0;
961     int nostats = 0;
962     int maxmtu = 0;
963     int hotthreads = 0;
964     int threads = 1;
965     int udpbufsz = 64 * 1024;
966     int maxwsize = 0;
967     int minpeertimeout = 0;
968     char *ptr;
969     int ch;
970
971     cmd = RX_PERF_UNKNOWN;
972
973     while ((ch = getopt(argc, argv, "T:S:R:b:c:d:p:P:r:s:w:W:f:HDNjm:u:4:t:V")) != -1) {
974         switch (ch) {
975         case 'b':
976             bytes = strtol(optarg, &ptr, 0);
977             if (ptr && *ptr != '\0')
978                 errx(1, "can't resolve number of bytes to transfer");
979             break;
980         case 'c':
981             if (strcasecmp(optarg, "send") == 0)
982                 cmd = RX_PERF_SEND;
983             else if (strcasecmp(optarg, "recv") == 0)
984                 cmd = RX_PERF_RECV;
985             else if (strcasecmp(optarg, "rpc") == 0)
986                 cmd = RX_PERF_RPC;
987             else if (strcasecmp(optarg, "file") == 0)
988                 cmd = RX_PERF_FILE;
989             else
990                 errx(1, "unknown command %s", optarg);
991             break;
992         case 'd':
993 #ifdef RXDEBUG
994             rx_debugFile = fopen(optarg, "w");
995             if (rx_debugFile == NULL)
996                 err(1, "fopen %s", optarg);
997 #else
998             errx(1, "compiled without RXDEBUG");
999 #endif
1000             break;
1001         case 'P':
1002             minpeertimeout = strtol(optarg, &ptr, 0);
1003             if (ptr != 0 && ptr[0] != '\0')
1004                 errx(1, "can't resolve min peer timeout");
1005             break;
1006         case 'p':
1007             port = (short) strtol(optarg, &ptr, 0);
1008             if (ptr != 0 && ptr[0] != '\0')
1009                 errx(1, "can't resolve portname");
1010             break;
1011         case 'r':
1012             rxread_size = strtol(optarg, &ptr, 0);
1013             if (ptr != 0 && ptr[0] != '\0')
1014                 errx(1, "can't resolve readsize");
1015             if (rxread_size > sizeof(somebuf))
1016                 errx(1, "%d > sizeof(somebuf) (%"AFS_SIZET_FMT")", rxread_size,
1017                      sizeof(somebuf));
1018             break;
1019         case 's':
1020             host = strdup(optarg);
1021             if (host == NULL)
1022                 err(1, "strdup");
1023             break;
1024         case 'V':
1025             use_rx_readv = 1;
1026             break;
1027         case 'w':
1028             rxwrite_size = strtol(optarg, &ptr, 0);
1029             if (ptr != 0 && ptr[0] != '\0')
1030                 errx(1, "can't resolve writesize");
1031             if (rxwrite_size > sizeof(somebuf))
1032                 errx(1, "%d > sizeof(somebuf) (%"AFS_SIZET_FMT")", rxwrite_size,
1033                      sizeof(somebuf));
1034             break;
1035         case 'W':
1036             maxwsize = strtol(optarg, &ptr, 0);
1037             if (ptr && *ptr != '\0')
1038                 errx(1, "can't resolve max send/recv window size (packets)");
1039             break;
1040         case 'T':
1041             times = strtol(optarg, &ptr, 0);
1042             if (ptr && *ptr != '\0')
1043                 errx(1, "can't resolve number of times to execute rpc");
1044             break;
1045         case 'S':
1046             sendbytes = strtol(optarg, &ptr, 0);
1047             if (ptr && *ptr != '\0')
1048                 errx(1, "can't resolve number of bytes to send");
1049             break;
1050         case 'R':
1051             readbytes = strtol(optarg, &ptr, 0);
1052             if (ptr && *ptr != '\0')
1053                 errx(1, "can't resolve number of bytes to receive");
1054             break;
1055         case 't':
1056 #ifdef AFS_PTHREAD_ENV
1057             threads = strtol(optarg, &ptr, 0);
1058             if (ptr && *ptr != '\0')
1059                 errx(1, "can't resolve number of threads to execute");
1060             if (threads > MAX_THREADS)
1061                 errx(1, "too many threads");
1062 #else
1063             errx(1, "Not built for pthreads");
1064 #endif
1065             break;
1066         case 'f':
1067             filename = optarg;
1068             break;
1069         case 'D':
1070             dumpstats = 1;
1071             break;
1072         case 'N':
1073             nostats = 1;
1074             break;
1075         case 'H':
1076             hotthreads = 1;
1077             break;
1078         case 'j':
1079           nojumbo=1;
1080           break;
1081         case 'm':
1082           maxmtu = strtol(optarg, &ptr, 0);
1083           if (ptr && *ptr != '\0')
1084             errx(1, "can't resolve rx maxmtu to use");
1085             break;
1086         case 'u':
1087             udpbufsz = strtol(optarg, &ptr, 0) * 1024;
1088             if (ptr && *ptr != '\0')
1089                 errx(1, "can't resolve upd buffer size (Kbytes)");
1090             break;
1091         case '4':
1092           RX_IPUDP_SIZE = 28;
1093           break;
1094         default:
1095             usage();
1096         }
1097     }
1098
1099     if (nostats && dumpstats)
1100         errx(1, "cannot set both -N and -D");
1101
1102     if (threads > 1 && cmd == RX_PERF_FILE)
1103         errx(1, "cannot use multiple threads with file command");
1104
1105     if (optind != argc)
1106         usage();
1107
1108     if (cmd == RX_PERF_UNKNOWN)
1109         errx(1, "no command given to the client");
1110
1111     do_client(host, port, filename, cmd, times, bytes, sendbytes,
1112               readbytes, dumpstats, nojumbo, maxmtu, maxwsize, minpeertimeout,
1113               udpbufsz, nostats, hotthreads, threads);
1114
1115     return 0;
1116 }
1117
1118 /*
1119  * setup world and call cmd
1120  */
1121
1122 int
1123 main(int argc, char **argv)
1124 {
1125 #ifndef AFS_PTHREAD_ENV
1126     PROCESS pid;
1127 #endif
1128
1129     setprogname(argv[0]);
1130
1131 #ifndef AFS_NT40_ENV
1132     signal(SIGUSR1, sigusr1);
1133     signal(SIGINT, sigint);
1134 #endif
1135
1136 #ifndef AFS_PTHREAD_ENV
1137     LWP_InitializeProcessSupport(LWP_NORMAL_PRIORITY, &pid);
1138 #endif
1139
1140     memset(somebuf, 0, sizeof(somebuf));
1141
1142     if (argc >= 2 && strcmp(argv[1], "server") == 0)
1143         rxperf_server(argc - 1, argv + 1);
1144     else if (argc >= 2 && strcmp(argv[1], "client") == 0)
1145         rxperf_client(argc - 1, argv + 1);
1146     else
1147         usage();
1148     return 0;
1149 }