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