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