add option to rxperf to use rx_Readv() instead of rx_Read()
[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 afs_int32 use_rx_readv = 0;
281
282 static int
283 do_readbytes(struct rx_call *call, afs_int32 bytes)
284 {
285     struct iovec tiov[RX_MAXIOVECS];
286     afs_int32 size;
287     int tnio;
288     int code;
289
290     while (bytes > 0) {
291         size = rxread_size;
292
293         if (size > bytes)
294             size = bytes;
295         if (use_rx_readv) {
296             if (size > RX_MAX_PACKET_DATA_SIZE)
297                 size = RX_MAX_PACKET_DATA_SIZE;
298             code = rx_Readv(call, tiov, &tnio, RX_MAXIOVECS, size);
299         } else
300             code = rx_Read(call, somebuf, size);
301         if (code != size)
302             return 1;
303
304         bytes -= size;
305     }
306     return 0;
307 }
308
309 static int
310 do_sendbytes(struct rx_call *call, afs_int32 bytes)
311 {
312     afs_int32 size;
313
314     while (bytes > 0) {
315         size = rxwrite_size;
316         if (size > bytes)
317             size = bytes;
318         if (rx_Write(call, somebuf, size) != size)
319             return 1;
320         bytes -= size;
321     }
322     return 0;
323 }
324
325
326 static afs_int32
327 rxperf_ExecuteRequest(struct rx_call *call)
328 {
329     afs_int32 version;
330     afs_int32 command;
331     afs_int32 bytes;
332     afs_int32 recvb;
333     afs_int32 sendb;
334     afs_int32 data;
335     afs_uint32 num;
336     afs_uint32 *readwrite;
337     afs_uint32 i;
338     int readp = TRUE;
339
340     DBFPRINT(("got a request\n"));
341
342     if (rx_Read32(call, &version) != 4) {
343         warn("rx_Read failed to read version");
344         return -1;
345     }
346
347     if (htonl(RX_PERF_VERSION) != version) {
348         warnx("client has wrong version");
349         return -1;
350     }
351
352     if (rx_Read32(call, &command) != 4) {
353         warnx("rx_Read failed to read command");
354         return -1;
355     }
356     command = ntohl(command);
357
358     if (rx_Read32(call, &data) != 4) {
359         warnx("rx_Read failed to read size");
360         return -1;
361     }
362     rxread_size = ntohl(data);
363     if (rxread_size > sizeof(somebuf)) {
364         warnx("rxread_size too large %d", rxread_size);
365         return -1;
366     }
367
368     if (rx_Read32(call, &data) != 4) {
369         warnx("rx_Read failed to write size");
370         return -1;
371     }
372     rxwrite_size = ntohl(data);
373     if (rxwrite_size > sizeof(somebuf)) {
374         warnx("rxwrite_size too large %d", rxwrite_size);
375         return -1;
376     }
377
378     switch (command) {
379     case RX_PERF_SEND:
380         DBFPRINT(("got a send request\n"));
381
382         if (rx_Read32(call, &bytes) != 4) {
383             warnx("rx_Read failed to read bytes");
384             return -1;
385         }
386         bytes = ntohl(bytes);
387
388         DBFPRINT(("reading(%d) ", bytes));
389         do_readbytes(call, bytes);
390
391         data = htonl(RXPERF_MAGIC_COOKIE);
392         if (rx_Write32(call, &data) != 4) {
393             warnx("rx_Write failed when sending back result");
394             return -1;
395         }
396         DBFPRINT(("done\n"));
397
398         break;
399     case RX_PERF_RPC:
400         DBFPRINT(("got a rpc request, reading commands\n"));
401
402         if (rx_Read32(call, &recvb) != 4) {
403             warnx("rx_Read failed to read recvbytes");
404             return -1;
405         }
406         recvb = ntohl(recvb);
407         if (rx_Read32(call, &sendb) != 4) {
408             warnx("rx_Read failed to read sendbytes");
409             return -1;
410         }
411         sendb = ntohl(sendb);
412
413         DBFPRINT(("read(%d) ", recvb));
414         if (do_readbytes(call, recvb)) {
415             warnx("do_readbytes failed");
416             return -1;
417         }
418         DBFPRINT(("send(%d) ", sendb));
419         if (do_sendbytes(call, sendb)) {
420             warnx("sendbytes failed");
421             return -1;
422         }
423
424         DBFPRINT(("done\n"));
425
426         data = htonl(RXPERF_MAGIC_COOKIE);
427         if (rx_Write32(call, &data) != 4) {
428             warnx("rx_Write failed when sending back magic cookie");
429             return -1;
430         }
431
432         break;
433     case RX_PERF_FILE:
434         if (rx_Read32(call, &data) != 4)
435             errx(1, "failed to read num from client");
436         num = ntohl(data);
437
438         readwrite = malloc(num * sizeof(afs_uint32));
439         if (readwrite == NULL)
440             err(1, "malloc");
441
442         if (rx_Read(call, (char*)readwrite, num * sizeof(afs_uint32)) !=
443             num * sizeof(afs_uint32))
444             errx(1, "failed to read recvlist from client");
445
446         for (i = 0; i < num; i++) {
447             if (readwrite[i] == 0) {
448                 DBFPRINT(("readp %d", readwrite[i]));
449                 readp = !readp;
450             }
451
452             bytes = ntohl(readwrite[i]) * sizeof(afs_uint32);
453
454             if (readp) {
455                 DBFPRINT(("read\n"));
456                 do_readbytes(call, bytes);
457             } else {
458                 do_sendbytes(call, bytes);
459                 DBFPRINT(("send\n"));
460             }
461         }
462
463         break;
464     case RX_PERF_RECV:
465         DBFPRINT(("got a recv request\n"));
466
467         if (rx_Read32(call, &bytes) != 4) {
468             warnx("rx_Read failed to read bytes");
469             return -1;
470         }
471         bytes = ntohl(bytes);
472
473         DBFPRINT(("sending(%d) ", bytes));
474         do_sendbytes(call, bytes);
475
476         data = htonl(RXPERF_MAGIC_COOKIE);
477         if (rx_Write32(call, &data) != 4) {
478             warnx("rx_Write failed when sending back result");
479             return -1;
480         }
481         DBFPRINT(("done\n"));
482
483         break;
484     default:
485         warnx("client sent a unsupported command");
486         return -1;
487     }
488     DBFPRINT(("done with command\n"));
489
490     return 0;
491 }
492
493 /*
494  *
495  */
496
497 static void
498 do_server(short port, int nojumbo, int maxmtu, int maxwsize, int minpeertimeout,
499           int udpbufsz, int nostats, int hotthread,
500           int minprocs, int maxprocs)
501 {
502     struct rx_service *service;
503     struct rx_securityClass *secureobj;
504     int secureindex;
505     int ret;
506
507 #ifdef AFS_NT40_ENV
508     if (afs_winsockInit() < 0) {
509         printf("Can't initialize winsock.\n");
510         exit(1);
511     }
512 #endif
513
514     if (hotthread)
515         rx_EnableHotThread();
516
517     if (nostats)
518         rx_enable_stats = 0;
519
520     rx_SetUdpBufSize(udpbufsz);
521
522     ret = rx_Init(htons(port));
523     if (ret)
524         errx(1, "rx_Init failed");
525
526     if (nojumbo)
527       rx_SetNoJumbo();
528
529     if (maxmtu)
530       rx_SetMaxMTU(maxmtu);
531
532     if (maxwsize) {
533         rx_SetMaxReceiveWindow(maxwsize);
534         rx_SetMaxSendWindow(maxwsize);
535     }
536
537     if (minpeertimeout)
538         rx_SetMinPeerTimeout(minpeertimeout);
539
540
541     get_sec(1, &secureobj, &secureindex);
542
543     service =
544         rx_NewService(0, RX_SERVER_ID, "rxperf", &secureobj, secureindex,
545                       rxperf_ExecuteRequest);
546     if (service == NULL)
547         errx(1, "Cant create server");
548
549     rx_SetMinProcs(service, minprocs);
550     rx_SetMaxProcs(service, maxprocs);
551
552     rx_SetCheckReach(service, 1);
553
554     rx_StartServer(1);
555
556     abort();
557 }
558
559 /*
560  *
561  */
562
563 static void
564 readfile(const char *filename, afs_uint32 ** readwrite, afs_uint32 * size)
565 {
566     FILE *f;
567     afs_uint32 len = 16;
568     afs_uint32 num = 0;
569     afs_uint32 data;
570     char *ptr;
571     char *buf;
572
573     *readwrite = malloc(sizeof(afs_uint32) * len);
574     buf = malloc(RXPERF_BUFSIZE);
575
576     if (*readwrite == NULL)
577         err(1, "malloc");
578
579     f = fopen(filename, "r");
580     if (f == NULL)
581         err(1, "fopen");
582
583     while (fgets(buf, sizeof(buf), f) != NULL) {
584         if (num >= len) {
585             len = len * 2;
586             *readwrite = realloc(*readwrite, len * sizeof(afs_uint32));
587             if (*readwrite == NULL)
588                 err(1, "realloc");
589         }
590
591         if (*buf != '\n') {
592             data = htonl(strtol(buf, &ptr, 0));
593             if (ptr && ptr == buf)
594                 errx(1, "can't resolve number of bytes to transfer");
595         } else {
596             data = 0;
597         }
598
599         (*readwrite)[num] = data;
600         num++;
601     }
602
603     *size = num;
604
605
606     if (fclose(f) == -1)
607         err(1, "fclose");
608     free(buf);
609 }
610
611 struct client_data {
612     struct rx_connection *conn;
613     char *filename;
614     int command;
615     afs_int32 times;
616     afs_int32 bytes;
617     afs_int32 sendbytes;
618     afs_int32 readbytes;
619 };
620
621 static void *
622 client_thread( void *vparams)
623 {
624     struct client_data *params = (struct client_data *)vparams;
625     struct rx_call *call;
626     afs_int32 data;
627     int i, j;
628     afs_uint32 *readwrite;
629     int readp = FALSE;
630     afs_uint32 size;
631     afs_uint32 num;
632
633     for (i = 0; i < params->times; i++) {
634
635         DBFPRINT(("starting command "));
636
637         call = rx_NewCall(params->conn);
638         if (call == NULL)
639             errx(1, "rx_NewCall failed");
640
641         data = htonl(RX_PERF_VERSION);
642         if (rx_Write32(call, &data) != 4)
643             errx(1, "rx_Write failed to send version (err %d)", rx_Error(call));
644
645         data = htonl(params->command);
646         if (rx_Write32(call, &data) != 4)
647             errx(1, "rx_Write failed to send command (err %d)", rx_Error(call));
648
649         data = htonl(rxread_size);
650         if (rx_Write32(call, &data) != 4)
651             errx(1, "rx_Write failed to send read size (err %d)", rx_Error(call));
652         data = htonl(rxwrite_size);
653         if (rx_Write32(call, &data) != 4)
654             errx(1, "rx_Write failed to send write read (err %d)", rx_Error(call));
655
656
657         switch (params->command) {
658         case RX_PERF_RECV:
659             DBFPRINT(("command "));
660
661             data = htonl(params->bytes);
662             if (rx_Write32(call, &data) != 4)
663                 errx(1, "rx_Write failed to send size (err %d)", rx_Error(call));
664
665             DBFPRINT(("sending(%d) ", params->bytes));
666             if (do_readbytes(call, params->bytes))
667                 errx(1, "sendbytes (err %d)", rx_Error(call));
668
669             if (rx_Read32(call, &data) != 4)
670                 errx(1, "failed to read result from server (err %d)", rx_Error(call));
671
672             if (data != htonl(RXPERF_MAGIC_COOKIE))
673                 warn("server send wrong magic cookie in responce");
674
675             DBFPRINT(("done\n"));
676
677             break;
678         case RX_PERF_SEND:
679             DBFPRINT(("command "));
680
681             data = htonl(params->bytes);
682             if (rx_Write32(call, &data) != 4)
683                 errx(1, "rx_Write failed to send size (err %d)", rx_Error(call));
684
685             DBFPRINT(("sending(%d) ", params->bytes));
686             if (do_sendbytes(call, params->bytes))
687                 errx(1, "sendbytes (err %d)", rx_Error(call));
688
689             if (rx_Read32(call, &data) != 4)
690                 errx(1, "failed to read result from server (err %d)", rx_Error(call));
691
692             if (data != htonl(RXPERF_MAGIC_COOKIE))
693                 warn("server send wrong magic cookie in responce");
694
695             DBFPRINT(("done\n"));
696
697             break;
698         case RX_PERF_RPC:
699             DBFPRINT(("commands "));
700
701             data = htonl(params->sendbytes);
702             if (rx_Write32(call, &data) != 4)
703                 errx(1, "rx_Write failed to send command (err %d)", rx_Error(call));
704
705             data = htonl(params->readbytes);
706             if (rx_Write32(call, &data) != 4)
707                 errx(1, "rx_Write failed to send command (err %d)", rx_Error(call));
708
709             DBFPRINT(("send(%d) ", params->sendbytes));
710             if (do_sendbytes(call, params->sendbytes))
711                 errx(1, "sendbytes (err %d)", rx_Error(call));
712
713             DBFPRINT(("recv(%d) ", params->readbytes));
714             if (do_readbytes(call, params->readbytes))
715                 errx(1, "sendbytes (err %d)", rx_Error(call));
716
717             if (rx_Read32(call, &data) != 4)
718                 errx(1, "failed to read result from server (err %d)", rx_Error(call));
719
720             if (data != htonl(RXPERF_MAGIC_COOKIE))
721                 warn("server send wrong magic cookie in responce");
722
723             DBFPRINT(("done\n"));
724
725             break;
726
727         case RX_PERF_FILE:
728             readfile(params->filename, &readwrite, &num);
729
730             data = htonl(num);
731             if (rx_Write32(call, &data) != 4)
732                 errx(1, "rx_Write failed to send size (err %d)", rx_Error(call));
733
734             if (rx_Write(call, (char *)readwrite, num * sizeof(afs_uint32))
735                 != num * sizeof(afs_uint32))
736                 errx(1, "rx_Write failed to send list (err %d)", rx_Error(call));
737
738             for (j = 0; j < num; j++) {
739                 if (readwrite[j] == 0)
740                     readp = !readp;
741
742                 size = ntohl(readwrite[j]) * sizeof(afs_uint32);
743
744                 if (readp) {
745                     if (do_readbytes(call, size))
746                         errx(1, "sendbytes (err %d)", rx_Error(call));
747                     DBFPRINT(("read\n"));
748                 } else {
749                     if (do_sendbytes(call, size))
750                         errx(1, "sendbytes (err %d)", rx_Error(call));
751                     DBFPRINT(("send\n"));
752                 }
753             }
754             break;
755         default:
756             abort();
757         }
758
759         rx_EndCall(call, 0);
760     }
761
762 #ifdef AFS_PTHREAD_ENV
763     pthread_exit(NULL);
764 #endif
765
766     return NULL;
767 }
768
769 /*
770  *
771  */
772
773 static void
774 do_client(const char *server, short port, char *filename, afs_int32 command,
775           afs_int32 times, afs_int32 bytes, afs_int32 sendbytes, afs_int32 readbytes,
776           int dumpstats, int nojumbo, int maxmtu, int maxwsize, int minpeertimeout,
777           int udpbufsz, int nostats, int hotthread, int threads)
778 {
779     struct rx_connection *conn;
780     afs_uint32 addr;
781     struct rx_securityClass *secureobj;
782     int secureindex;
783     int ret;
784     char stamp[2048];
785     struct client_data *params;
786
787 #ifdef AFS_PTHREAD_ENV
788     int i;
789     pthread_t thread[MAX_THREADS];
790     pthread_attr_t tattr;
791     void *status;
792 #endif
793
794     params = malloc(sizeof(struct client_data));
795     memset(params, 0, sizeof(struct client_data));
796
797 #ifdef AFS_NT40_ENV
798     if (afs_winsockInit() < 0) {
799         printf("Can't initialize winsock.\n");
800         exit(1);
801     }
802 #endif
803
804     if (hotthread)
805         rx_EnableHotThread();
806
807     if (nostats)
808         rx_enable_stats = 0;
809
810     addr = str2addr(server);
811
812     rx_SetUdpBufSize(udpbufsz);
813
814     ret = rx_Init(0);
815     if (ret)
816         errx(1, "rx_Init failed");
817
818     if (nojumbo)
819       rx_SetNoJumbo();
820
821     if (maxmtu)
822       rx_SetMaxMTU(maxmtu);
823
824     if (maxwsize) {
825         rx_SetMaxReceiveWindow(maxwsize);
826         rx_SetMaxSendWindow(maxwsize);
827     }
828
829     if (minpeertimeout)
830         rx_SetMinPeerTimeout(minpeertimeout);
831
832
833     get_sec(0, &secureobj, &secureindex);
834
835     conn = rx_NewConnection(addr, htons(port), RX_SERVER_ID, secureobj, secureindex);
836     if (conn == NULL)
837         errx(1, "failed to contact server");
838
839 #ifdef AFS_PTHREAD_ENV
840     pthread_attr_init(&tattr);
841     pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_JOINABLE);
842 #endif
843
844     params->conn = conn;
845     params->filename = filename;
846     params->command = command;
847     params->times = times;
848     params->bytes = bytes;
849     params->sendbytes = sendbytes;
850     params->readbytes = readbytes;
851
852     switch (command) {
853     case RX_PERF_RPC:
854         sprintf(stamp, "RPC: threads\t%d, times\t%d, write bytes\t%d, read bytes\t%d",
855                  threads, times, sendbytes, readbytes);
856         break;
857     case RX_PERF_RECV:
858         sprintf(stamp, "RECV: threads\t%d, times\t%d, bytes\t%d",
859                  threads, times, bytes);
860         break;
861     case RX_PERF_SEND:
862         sprintf(stamp, "SEND: threads\t%d, times\t%d, bytes\t%d",
863                  threads, times, bytes);
864         break;
865     case RX_PERF_FILE:
866         sprintf(stamp, "FILE %s: threads\t%d, times\t%d, bytes\t%d",
867                  filename, threads, times, bytes);
868         break;
869     }
870
871     start_timer();
872
873 #ifdef AFS_PTHREAD_ENV
874     for ( i=0; i<threads; i++)
875         pthread_create(&thread[i], &tattr, client_thread, params);
876 #else
877         client_thread(params);
878 #endif
879
880 #ifdef AFS_PTHREAD_ENV
881     for ( i=0; i<threads; i++)
882         pthread_join(thread[i], &status);
883 #endif
884
885     end_and_print_timer(stamp);
886     DBFPRINT(("done for good\n"));
887
888     if (dumpstats) {
889         rx_PrintStats(stdout);
890         rx_PrintPeerStats(stdout, conn->peer);
891     }
892     rx_Finalize();
893
894 #ifdef AFS_PTHREAD_ENV
895     pthread_attr_destroy(&tattr);
896 #endif
897
898     free(params);
899 }
900
901 static void
902 usage(void)
903 {
904 #define COMMON ""
905
906     fprintf(stderr, "usage: %s client -c send -b <bytes>\n", __progname);
907     fprintf(stderr, "usage: %s client -c recv -b <bytes>\n", __progname);
908     fprintf(stderr,
909             "usage: %s client -c rpc  -S <sendbytes> -R <recvbytes>\n",
910             __progname);
911     fprintf(stderr, "usage: %s client -c file -f filename\n", __progname);
912     fprintf(stderr,
913             "%s: usage: common option to the client "
914             "-w <write-bytes> -r <read-bytes> -T times -p port -s server -D\n",
915             __progname);
916     fprintf(stderr, "usage: %s server -p port\n", __progname);
917 #undef COMMMON
918     exit(1);
919 }
920
921
922
923 /*
924  * do argument processing and call networking functions
925  */
926
927 static int
928 rxperf_server(int argc, char **argv)
929 {
930     short port = DEFAULT_PORT;
931     int nojumbo = 0;
932     int maxmtu = 0;
933     int nostats = 0;
934     int udpbufsz = 64 * 1024;
935     int hotthreads = 0;
936     int minprocs = 2;
937     int maxprocs = 20;
938     int maxwsize = 0;
939     int minpeertimeout = 0;
940     char *ptr;
941     int ch;
942
943     while ((ch = getopt(argc, argv, "r:d:p:P:w:W:HNjm:u:4:s:SV")) != -1) {
944         switch (ch) {
945         case 'd':
946 #ifdef RXDEBUG
947             rx_debugFile = fopen(optarg, "w");
948             if (rx_debugFile == NULL)
949                 err(1, "fopen %s", optarg);
950 #else
951             errx(1, "compiled without RXDEBUG");
952 #endif
953             break;
954         case 'r':
955             rxread_size = strtol(optarg, &ptr, 0);
956             if (ptr != 0 && ptr[0] != '\0')
957                 errx(1, "can't resolve readsize");
958             if (rxread_size > sizeof(somebuf))
959                 errx(1, "%d > sizeof(somebuf) (%d)", rxread_size,
960                      sizeof(somebuf));
961             break;
962         case 's':
963             minprocs = strtol(optarg, &ptr, 0);
964             if (ptr != 0 && ptr[0] != '\0')
965                 errx(1, "can't resolve minprocs");
966             break;
967         case 'S':
968             maxprocs = strtol(optarg, &ptr, 0);
969             if (ptr != 0 && ptr[0] != '\0')
970                 errx(1, "can't resolve maxprocs");
971             break;
972         case 'P':
973             minpeertimeout = strtol(optarg, &ptr, 0);
974             if (ptr != 0 && ptr[0] != '\0')
975                 errx(1, "can't resolve min peer timeout");
976             break;
977         case 'p':
978             port = (short) strtol(optarg, &ptr, 0);
979             if (ptr != 0 && ptr[0] != '\0')
980                 errx(1, "can't resolve portname");
981             break;
982         case 'w':
983             rxwrite_size = strtol(optarg, &ptr, 0);
984             if (ptr != 0 && ptr[0] != '\0')
985                 errx(1, "can't resolve writesize");
986             if (rxwrite_size > sizeof(somebuf))
987                 errx(1, "%d > sizeof(somebuf) (%d)", rxwrite_size,
988                      sizeof(somebuf));
989             break;
990         case 'j':
991           nojumbo=1;
992           break;
993         case 'N':
994           nostats=1;
995           break;
996         case 'H':
997             hotthreads = 1;
998             break;
999         case 'm':
1000           maxmtu = strtol(optarg, &ptr, 0);
1001           if (ptr && *ptr != '\0')
1002             errx(1, "can't resolve rx maxmtu to use");
1003             break;
1004         case 'u':
1005             udpbufsz = strtol(optarg, &ptr, 0) * 1024;
1006             if (ptr && *ptr != '\0')
1007                 errx(1, "can't resolve upd buffer size (Kbytes)");
1008             break;
1009         case 'V':
1010             use_rx_readv = 1;
1011             break;
1012         case 'W':
1013             maxwsize = strtol(optarg, &ptr, 0);
1014             if (ptr && *ptr != '\0')
1015                 errx(1, "can't resolve max send/recv window size (packets)");
1016             break;
1017         case '4':
1018           RX_IPUDP_SIZE = 28;
1019           break;
1020         default:
1021             usage();
1022         }
1023     }
1024
1025     if (optind != argc)
1026         usage();
1027
1028     do_server(port, nojumbo, maxmtu, maxwsize, minpeertimeout, udpbufsz,
1029               nostats, hotthreads, minprocs, maxprocs);
1030
1031     return 0;
1032 }
1033
1034 /*
1035  * do argument processing and call networking functions
1036  */
1037
1038 static int
1039 rxperf_client(int argc, char **argv)
1040 {
1041     char *host = DEFAULT_HOST;
1042     int bytes = DEFAULT_BYTES;
1043     short port = DEFAULT_PORT;
1044     char *filename = NULL;
1045     afs_int32 cmd;
1046     int sendbytes = 3;
1047     int readbytes = 30;
1048     int times = 100;
1049     int dumpstats = 0;
1050     int nojumbo = 0;
1051     int nostats = 0;
1052     int maxmtu = 0;
1053     int hotthreads = 0;
1054     int threads = 1;
1055     int udpbufsz = 64 * 1024;
1056     int maxwsize = 0;
1057     int minpeertimeout = 0;
1058     char *ptr;
1059     int ch;
1060
1061     cmd = RX_PERF_UNKNOWN;
1062
1063     while ((ch = getopt(argc, argv, "T:S:R:b:c:d:p:P:r:s:w:W:f:HDNjm:u:4:t:V")) != -1) {
1064         switch (ch) {
1065         case 'b':
1066             bytes = strtol(optarg, &ptr, 0);
1067             if (ptr && *ptr != '\0')
1068                 errx(1, "can't resolve number of bytes to transfer");
1069             break;
1070         case 'c':
1071             if (strcasecmp(optarg, "send") == 0)
1072                 cmd = RX_PERF_SEND;
1073             else if (strcasecmp(optarg, "recv") == 0)
1074                 cmd = RX_PERF_RECV;
1075             else if (strcasecmp(optarg, "rpc") == 0)
1076                 cmd = RX_PERF_RPC;
1077             else if (strcasecmp(optarg, "file") == 0)
1078                 cmd = RX_PERF_FILE;
1079             else
1080                 errx(1, "unknown command %s", optarg);
1081             break;
1082         case 'd':
1083 #ifdef RXDEBUG
1084             rx_debugFile = fopen(optarg, "w");
1085             if (rx_debugFile == NULL)
1086                 err(1, "fopen %s", optarg);
1087 #else
1088             errx(1, "compiled without RXDEBUG");
1089 #endif
1090             break;
1091         case 'P':
1092             minpeertimeout = strtol(optarg, &ptr, 0);
1093             if (ptr != 0 && ptr[0] != '\0')
1094                 errx(1, "can't resolve min peer timeout");
1095             break;
1096         case 'p':
1097             port = (short) strtol(optarg, &ptr, 0);
1098             if (ptr != 0 && ptr[0] != '\0')
1099                 errx(1, "can't resolve portname");
1100             break;
1101         case 'r':
1102             rxread_size = strtol(optarg, &ptr, 0);
1103             if (ptr != 0 && ptr[0] != '\0')
1104                 errx(1, "can't resolve readsize");
1105             if (rxread_size > sizeof(somebuf))
1106                 errx(1, "%d > sizeof(somebuf) (%d)", rxread_size,
1107                      sizeof(somebuf));
1108             break;
1109         case 's':
1110             host = strdup(optarg);
1111             if (host == NULL)
1112                 err(1, "strdup");
1113             break;
1114         case 'V':
1115             use_rx_readv = 1;
1116             break;
1117         case 'w':
1118             rxwrite_size = strtol(optarg, &ptr, 0);
1119             if (ptr != 0 && ptr[0] != '\0')
1120                 errx(1, "can't resolve writesize");
1121             if (rxwrite_size > sizeof(somebuf))
1122                 errx(1, "%d > sizeof(somebuf) (%d)", rxwrite_size,
1123                      sizeof(somebuf));
1124             break;
1125         case 'W':
1126             maxwsize = strtol(optarg, &ptr, 0);
1127             if (ptr && *ptr != '\0')
1128                 errx(1, "can't resolve max send/recv window size (packets)");
1129             break;
1130         case 'T':
1131             times = strtol(optarg, &ptr, 0);
1132             if (ptr && *ptr != '\0')
1133                 errx(1, "can't resolve number of times to execute rpc");
1134             break;
1135         case 'S':
1136             sendbytes = strtol(optarg, &ptr, 0);
1137             if (ptr && *ptr != '\0')
1138                 errx(1, "can't resolve number of bytes to send");
1139             break;
1140         case 'R':
1141             readbytes = strtol(optarg, &ptr, 0);
1142             if (ptr && *ptr != '\0')
1143                 errx(1, "can't resolve number of bytes to receive");
1144             break;
1145         case 't':
1146 #ifdef AFS_PTHREAD_ENV
1147             threads = strtol(optarg, &ptr, 0);
1148             if (ptr && *ptr != '\0')
1149                 errx(1, "can't resolve number of threads to execute");
1150             if (threads > MAX_THREADS)
1151                 errx(1, "too many threads");
1152 #else
1153             errx(1, "Not built for pthreads");
1154 #endif
1155             break;
1156         case 'f':
1157             filename = optarg;
1158             break;
1159         case 'D':
1160             dumpstats = 1;
1161             break;
1162         case 'N':
1163             nostats = 1;
1164             break;
1165         case 'H':
1166             hotthreads = 1;
1167             break;
1168         case 'j':
1169           nojumbo=1;
1170           break;
1171         case 'm':
1172           maxmtu = strtol(optarg, &ptr, 0);
1173           if (ptr && *ptr != '\0')
1174             errx(1, "can't resolve rx maxmtu to use");
1175             break;
1176         case 'u':
1177             udpbufsz = strtol(optarg, &ptr, 0) * 1024;
1178             if (ptr && *ptr != '\0')
1179                 errx(1, "can't resolve upd buffer size (Kbytes)");
1180             break;
1181         case '4':
1182           RX_IPUDP_SIZE = 28;
1183           break;
1184         default:
1185             usage();
1186         }
1187     }
1188
1189     if (nostats && dumpstats)
1190         errx(1, "cannot set both -N and -D");
1191
1192     if (threads > 1 && cmd == RX_PERF_FILE)
1193         errx(1, "cannot use multiple threads with file command");
1194
1195     if (optind != argc)
1196         usage();
1197
1198     if (cmd == RX_PERF_UNKNOWN)
1199         errx(1, "no command given to the client");
1200
1201     do_client(host, port, filename, cmd, times, bytes, sendbytes,
1202               readbytes, dumpstats, nojumbo, maxmtu, maxwsize, minpeertimeout,
1203               udpbufsz, nostats, hotthreads, threads);
1204
1205     return 0;
1206 }
1207
1208 /*
1209  * setup world and call cmd
1210  */
1211
1212 int
1213 main(int argc, char **argv)
1214 {
1215 #ifndef AFS_PTHREAD_ENV
1216     PROCESS pid;
1217 #endif
1218
1219     __progname = strrchr(argv[0], '/');
1220     if (__progname == 0)
1221         __progname = argv[0];
1222
1223 #ifndef AFS_NT40_ENV
1224     signal(SIGUSR1, sigusr1);
1225     signal(SIGINT, sigint);
1226 #endif
1227
1228 #ifndef AFS_PTHREAD_ENV
1229     LWP_InitializeProcessSupport(LWP_NORMAL_PRIORITY, &pid);
1230 #endif
1231
1232     memset(somebuf, 0, sizeof(somebuf));
1233
1234     if (argc >= 2 && strcmp(argv[1], "server") == 0)
1235         rxperf_server(argc - 1, argv + 1);
1236     else if (argc >= 2 && strcmp(argv[1], "client") == 0)
1237         rxperf_client(argc - 1, argv + 1);
1238     else
1239         usage();
1240     return 0;
1241 }