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