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