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