venus: Remove dedebug
[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(FILE *output, 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     fprintf(output, "%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         fprintf(output, "\t[%.4g Gbit/s]\n", kbps/1000000.0);
136     else if (kbps > 1000.0)
137         fprintf(output, "\t[%.4g Mbit/s]\n", kbps/1000.0);
138     else
139         fprintf(output, "\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     AFS_UNREACHED(return NULL);
675 #else
676     return NULL;
677 #endif
678 }
679
680 /*
681  *
682  */
683
684 static void
685 do_client(const char *server, short port, char *filename, afs_int32 command,
686           afs_int32 times, afs_int32 bytes, afs_int32 sendbytes, afs_int32 readbytes,
687           int dumpstats, int nojumbo, int maxmtu, int maxwsize, int minpeertimeout,
688           int udpbufsz, int nostats, int hotthread, int threads, FILE *output)
689 {
690     struct rx_connection *conn;
691     afs_uint32 addr;
692     struct rx_securityClass *secureobj;
693     int secureindex;
694     int ret;
695     char stamp[2048];
696     struct client_data *params;
697
698 #ifdef AFS_PTHREAD_ENV
699     int i;
700     pthread_t thread[MAX_THREADS];
701     pthread_attr_t tattr;
702     void *status;
703 #endif
704
705     params = calloc(1, sizeof(struct client_data));
706
707 #ifdef AFS_NT40_ENV
708     if (afs_winsockInit() < 0) {
709         printf("Can't initialize winsock.\n");
710         exit(1);
711     }
712 #endif
713
714     if (hotthread)
715         rx_EnableHotThread();
716
717     if (nostats)
718         rx_enable_stats = 0;
719
720     addr = str2addr(server);
721
722     rx_SetUdpBufSize(udpbufsz);
723
724     ret = rx_Init(0);
725     if (ret)
726         errx(1, "rx_Init failed");
727
728     if (nojumbo)
729       rx_SetNoJumbo();
730
731     if (maxmtu)
732       rx_SetMaxMTU(maxmtu);
733
734     if (maxwsize) {
735         rx_SetMaxReceiveWindow(maxwsize);
736         rx_SetMaxSendWindow(maxwsize);
737     }
738
739     if (minpeertimeout)
740         rx_SetMinPeerTimeout(minpeertimeout);
741
742
743     get_sec(0, &secureobj, &secureindex);
744
745     switch (command) {
746     case RX_PERF_RPC:
747         sprintf(stamp, "RPC: threads\t%d, times\t%d, write bytes\t%d, read bytes\t%d",
748                  threads, times, sendbytes, readbytes);
749         break;
750     case RX_PERF_RECV:
751         sprintf(stamp, "RECV: threads\t%d, times\t%d, bytes\t%d",
752                  threads, times, bytes);
753         break;
754     case RX_PERF_SEND:
755         sprintf(stamp, "SEND: threads\t%d, times\t%d, bytes\t%d",
756                  threads, times, bytes);
757         break;
758     case RX_PERF_FILE:
759         sprintf(stamp, "FILE %s: threads\t%d, times\t%d, bytes\t%d",
760                  filename, threads, times, bytes);
761         break;
762     }
763
764     conn = rx_NewConnection(addr, htons(port), RX_SERVER_ID, secureobj, secureindex);
765     if (conn == NULL)
766         errx(1, "failed to contact server");
767
768 #ifdef AFS_PTHREAD_ENV
769     pthread_attr_init(&tattr);
770     pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_JOINABLE);
771 #endif
772
773     params->conn = conn;
774     params->filename = filename;
775     params->command = command;
776     params->times = times;
777     params->bytes = bytes;
778     params->sendbytes = sendbytes;
779     params->readbytes = readbytes;
780
781     start_timer();
782
783 #ifdef AFS_PTHREAD_ENV
784     for ( i=0; i<threads; i++) {
785         pthread_create(&thread[i], &tattr, client_thread, params);
786         if ( (i + 1) % RX_MAXCALLS == 0 ) {
787             conn = rx_NewConnection(addr, htons(port), RX_SERVER_ID, secureobj, secureindex);
788             if (conn != NULL) {
789                 struct client_data *new_params = malloc(sizeof(struct client_data));
790                 memcpy(new_params, params, sizeof(struct client_data));
791                 new_params->conn = conn;
792                 params = new_params;
793             }
794         }
795     }
796 #else
797         client_thread(params);
798 #endif
799
800 #ifdef AFS_PTHREAD_ENV
801     for ( i=0; i<threads; i++)
802         pthread_join(thread[i], &status);
803 #endif
804
805     switch (command) {
806     case RX_PERF_RPC:
807         end_and_print_timer(output, stamp, (long long)threads*times*(sendbytes+readbytes));
808         break;
809     case RX_PERF_RECV:
810     case RX_PERF_SEND:
811     case RX_PERF_FILE:
812         end_and_print_timer(output, stamp, (long long)threads*times*bytes);
813         break;
814     }
815
816     DBFPRINT(("done for good\n"));
817
818
819     if (dumpstats) {
820         rx_PrintStats(output);
821         rx_PrintPeerStats(output, rx_PeerOf(conn));
822     }
823     rx_Finalize();
824
825 #ifdef AFS_PTHREAD_ENV
826     pthread_attr_destroy(&tattr);
827 #endif
828
829     free(params);
830 }
831
832 static void
833 usage(void)
834 {
835 #define COMMON ""
836
837     fprintf(stderr, "usage: %s client -c send -b <bytes>\n", getprogname());
838     fprintf(stderr, "usage: %s client -c recv -b <bytes>\n", getprogname());
839     fprintf(stderr,
840             "usage: %s client -c rpc  -S <sendbytes> -R <recvbytes>\n",
841             getprogname());
842     fprintf(stderr, "usage: %s client -c file -f filename\n", getprogname());
843     fprintf(stderr,
844             "%s: usage: common option to the client "
845             "-w <write-bytes> -r <read-bytes> -T times -p port -s server -D\n",
846             getprogname());
847     fprintf(stderr, "usage: %s server -p port\n", getprogname());
848 #undef COMMMON
849     exit(1);
850 }
851
852
853
854 /*
855  * do argument processing and call networking functions
856  */
857
858 static int
859 rxperf_server(int argc, char **argv)
860 {
861     short port = DEFAULT_PORT;
862     int nojumbo = 0;
863     int maxmtu = 0;
864     int nostats = 0;
865     int udpbufsz = 64 * 1024;
866     int hotthreads = 0;
867     int minprocs = 2;
868     int maxprocs = 20;
869     int maxwsize = 0;
870     int minpeertimeout = 0;
871     char *ptr;
872     int ch;
873
874     while ((ch = getopt(argc, argv, "r:d:p:P:w:W:HNjm:u:4:s:S:V")) != -1) {
875         switch (ch) {
876         case 'd':
877 #ifdef RXDEBUG
878             rx_debugFile = fopen(optarg, "w");
879             if (rx_debugFile == NULL)
880                 err(1, "fopen %s", optarg);
881 #else
882             errx(1, "compiled without RXDEBUG");
883 #endif
884             break;
885         case 'r':
886             rxread_size = strtol(optarg, &ptr, 0);
887             if (ptr != 0 && ptr[0] != '\0')
888                 errx(1, "can't resolve readsize");
889             if (rxread_size > sizeof(somebuf))
890                 errx(1, "%d > sizeof(somebuf) (%"AFS_SIZET_FMT")", rxread_size,
891                      sizeof(somebuf));
892             break;
893         case 's':
894             minprocs = strtol(optarg, &ptr, 0);
895             if (ptr != 0 && ptr[0] != '\0')
896                 errx(1, "can't resolve minprocs");
897             break;
898         case 'S':
899             maxprocs = strtol(optarg, &ptr, 0);
900             if (ptr != 0 && ptr[0] != '\0')
901                 errx(1, "can't resolve maxprocs");
902             break;
903         case 'P':
904             minpeertimeout = strtol(optarg, &ptr, 0);
905             if (ptr != 0 && ptr[0] != '\0')
906                 errx(1, "can't resolve min peer timeout");
907             break;
908         case 'p':
909             port = (short) strtol(optarg, &ptr, 0);
910             if (ptr != 0 && ptr[0] != '\0')
911                 errx(1, "can't resolve portname");
912             break;
913         case 'w':
914             rxwrite_size = strtol(optarg, &ptr, 0);
915             if (ptr != 0 && ptr[0] != '\0')
916                 errx(1, "can't resolve writesize");
917             if (rxwrite_size > sizeof(somebuf))
918                 errx(1, "%d > sizeof(somebuf) (%"AFS_SIZET_FMT")", rxwrite_size,
919                      sizeof(somebuf));
920             break;
921         case 'j':
922           nojumbo=1;
923           break;
924         case 'N':
925           nostats=1;
926           break;
927         case 'H':
928             hotthreads = 1;
929             break;
930         case 'm':
931             maxmtu = strtol(optarg, &ptr, 0);
932             if (ptr && *ptr != '\0')
933                 errx(1, "can't resolve rx maxmtu to use");
934             break;
935         case 'u':
936             udpbufsz = strtol(optarg, &ptr, 0) * 1024;
937             if (ptr && *ptr != '\0')
938                 errx(1, "can't resolve upd buffer size (Kbytes)");
939             break;
940         case 'V':
941             use_rx_readv = 1;
942             break;
943         case 'W':
944             maxwsize = strtol(optarg, &ptr, 0);
945             if (ptr && *ptr != '\0')
946                 errx(1, "can't resolve max send/recv window size (packets)");
947             break;
948         case '4':
949           RX_IPUDP_SIZE = 28;
950           break;
951         default:
952             usage();
953         }
954     }
955
956     if (optind != argc)
957         usage();
958
959     do_server(port, nojumbo, maxmtu, maxwsize, minpeertimeout, udpbufsz,
960               nostats, hotthreads, minprocs, maxprocs);
961
962     return 0;
963 }
964
965 /*
966  * do argument processing and call networking functions
967  */
968
969 static int
970 rxperf_client(int argc, char **argv)
971 {
972     char *host = DEFAULT_HOST;
973     int bytes = DEFAULT_BYTES;
974     short port = DEFAULT_PORT;
975     char *filename = NULL;
976     afs_int32 cmd;
977     int sendbytes = 3;
978     int readbytes = 30;
979     int times = 100;
980     int dumpstats = 0;
981     int nojumbo = 0;
982     int nostats = 0;
983     int maxmtu = 0;
984     int hotthreads = 0;
985     int threads = 1;
986     int udpbufsz = 64 * 1024;
987     int maxwsize = 0;
988     int minpeertimeout = 0;
989     char *ptr;
990     int ch;
991     FILE *output = NULL;
992
993     cmd = RX_PERF_UNKNOWN;
994
995     while ((ch = getopt(argc, argv, "T:S:R:b:c:d:o:p:P:r:s:w:W:f:HDNjm:u:4:t:V")) != -1) {
996         switch (ch) {
997         case 'b':
998             bytes = strtol(optarg, &ptr, 0);
999             if (ptr && *ptr != '\0')
1000                 errx(1, "can't resolve number of bytes to transfer");
1001             break;
1002         case 'c':
1003             if (strcasecmp(optarg, "send") == 0)
1004                 cmd = RX_PERF_SEND;
1005             else if (strcasecmp(optarg, "recv") == 0)
1006                 cmd = RX_PERF_RECV;
1007             else if (strcasecmp(optarg, "rpc") == 0)
1008                 cmd = RX_PERF_RPC;
1009             else if (strcasecmp(optarg, "file") == 0)
1010                 cmd = RX_PERF_FILE;
1011             else
1012                 errx(1, "unknown command %s", optarg);
1013             break;
1014         case 'd':
1015 #ifdef RXDEBUG
1016             rx_debugFile = fopen(optarg, "w");
1017             if (rx_debugFile == NULL)
1018                 err(1, "fopen %s", optarg);
1019 #else
1020             errx(1, "compiled without RXDEBUG");
1021 #endif
1022             break;
1023         case 'o':
1024             if (output == NULL) {
1025                 output = fopen(optarg, "w");
1026                 if (output == NULL) {
1027                     err(1, "can't open %s", optarg);
1028                 }
1029             } else {
1030                 warnx("-o option given more than once, ignoring -o %s", optarg);
1031             }
1032             break;
1033         case 'P':
1034             minpeertimeout = strtol(optarg, &ptr, 0);
1035             if (ptr != 0 && ptr[0] != '\0')
1036                 errx(1, "can't resolve min peer timeout");
1037             break;
1038         case 'p':
1039             port = (short) strtol(optarg, &ptr, 0);
1040             if (ptr != 0 && ptr[0] != '\0')
1041                 errx(1, "can't resolve portname");
1042             break;
1043         case 'r':
1044             rxread_size = strtol(optarg, &ptr, 0);
1045             if (ptr != 0 && ptr[0] != '\0')
1046                 errx(1, "can't resolve readsize");
1047             if (rxread_size > sizeof(somebuf))
1048                 errx(1, "%d > sizeof(somebuf) (%"AFS_SIZET_FMT")", rxread_size,
1049                      sizeof(somebuf));
1050             break;
1051         case 's':
1052             host = strdup(optarg);
1053             if (host == NULL)
1054                 err(1, "strdup");
1055             break;
1056         case 'V':
1057             use_rx_readv = 1;
1058             break;
1059         case 'w':
1060             rxwrite_size = strtol(optarg, &ptr, 0);
1061             if (ptr != 0 && ptr[0] != '\0')
1062                 errx(1, "can't resolve writesize");
1063             if (rxwrite_size > sizeof(somebuf))
1064                 errx(1, "%d > sizeof(somebuf) (%"AFS_SIZET_FMT")", rxwrite_size,
1065                      sizeof(somebuf));
1066             break;
1067         case 'W':
1068             maxwsize = strtol(optarg, &ptr, 0);
1069             if (ptr && *ptr != '\0')
1070                 errx(1, "can't resolve max send/recv window size (packets)");
1071             break;
1072         case 'T':
1073             times = strtol(optarg, &ptr, 0);
1074             if (ptr && *ptr != '\0')
1075                 errx(1, "can't resolve number of times to execute rpc");
1076             break;
1077         case 'S':
1078             sendbytes = strtol(optarg, &ptr, 0);
1079             if (ptr && *ptr != '\0')
1080                 errx(1, "can't resolve number of bytes to send");
1081             break;
1082         case 'R':
1083             readbytes = strtol(optarg, &ptr, 0);
1084             if (ptr && *ptr != '\0')
1085                 errx(1, "can't resolve number of bytes to receive");
1086             break;
1087         case 't':
1088 #ifdef AFS_PTHREAD_ENV
1089             threads = strtol(optarg, &ptr, 0);
1090             if (ptr && *ptr != '\0')
1091                 errx(1, "can't resolve number of threads to execute");
1092             if (threads > MAX_THREADS)
1093                 errx(1, "too many threads");
1094 #else
1095             errx(1, "Not built for pthreads");
1096 #endif
1097             break;
1098         case 'f':
1099             filename = optarg;
1100             break;
1101         case 'D':
1102             dumpstats = 1;
1103             break;
1104         case 'N':
1105             nostats = 1;
1106             break;
1107         case 'H':
1108             hotthreads = 1;
1109             break;
1110         case 'j':
1111           nojumbo=1;
1112           break;
1113         case 'm':
1114             maxmtu = strtol(optarg, &ptr, 0);
1115             if (ptr && *ptr != '\0')
1116                 errx(1, "can't resolve rx maxmtu to use");
1117             break;
1118         case 'u':
1119             udpbufsz = strtol(optarg, &ptr, 0) * 1024;
1120             if (ptr && *ptr != '\0')
1121                 errx(1, "can't resolve upd buffer size (Kbytes)");
1122             break;
1123         case '4':
1124           RX_IPUDP_SIZE = 28;
1125           break;
1126         default:
1127             usage();
1128         }
1129     }
1130
1131     if (nostats && dumpstats)
1132         errx(1, "cannot set both -N and -D");
1133
1134     if (threads > 1 && cmd == RX_PERF_FILE)
1135         errx(1, "cannot use multiple threads with file command");
1136
1137     if (optind != argc)
1138         usage();
1139
1140     if (cmd == RX_PERF_UNKNOWN)
1141         errx(1, "no command given to the client");
1142
1143     do_client(host, port, filename, cmd, times, bytes, sendbytes,
1144               readbytes, dumpstats, nojumbo, maxmtu, maxwsize, minpeertimeout,
1145               udpbufsz, nostats, hotthreads, threads,
1146               (output == NULL ? stdout : output));
1147
1148     if (output != NULL) {
1149         if (fclose(output) < 0) {
1150             err(1, "fclose");
1151         }
1152     }
1153
1154     return 0;
1155 }
1156
1157 /*
1158  * setup world and call cmd
1159  */
1160
1161 int
1162 main(int argc, char **argv)
1163 {
1164 #ifndef AFS_PTHREAD_ENV
1165     PROCESS pid;
1166 #endif
1167
1168     setprogname(argv[0]);
1169
1170 #ifndef AFS_NT40_ENV
1171     signal(SIGUSR1, sigusr1);
1172     signal(SIGINT, sigint);
1173 #endif
1174
1175 #ifndef AFS_PTHREAD_ENV
1176     LWP_InitializeProcessSupport(LWP_NORMAL_PRIORITY, &pid);
1177 #endif
1178
1179     memset(somebuf, 0, sizeof(somebuf));
1180
1181     if (argc >= 2 && strcmp(argv[1], "server") == 0)
1182         rxperf_server(argc - 1, argv + 1);
1183     else if (argc >= 2 && strcmp(argv[1], "client") == 0)
1184         rxperf_client(argc - 1, argv + 1);
1185     else
1186         usage();
1187     return 0;
1188 }