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