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