Standardize License information
[openafs.git] / src / rx / test / testclient.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 /* Client test program */
11
12 #include <afs/param.h>
13 #include <sys/types.h>
14 #include <stdio.h>
15 #ifdef AFS_NT40_ENV
16 #include <io.h>
17 #include <winsock2.h>
18 #include <fcntl.h>
19 #include <stdlib.h>
20 #else
21 #include <netinet/in.h>
22 #include <netdb.h>
23 #include <sys/file.h>
24 #endif
25 #include <sys/stat.h>
26 #include <signal.h>
27 #include "../rx_clock.h"
28 #include "../rx.h"
29 #include "../rx_globals.h"
30 #include "../rx_null.h"
31 #include <errno.h>
32 #include <afs/afsutil.h>
33
34 #ifndef osi_Alloc
35 #define osi_Alloc(n) (char *) malloc(n)
36 #endif
37
38 int timeReadvs = 0;
39 int print = 1, eventlog = 0, rxlog = 0;
40 int fillPackets;
41 int burst; struct clock burstTime;
42 struct clock retryTime;
43 extern int rx_initSendWindow, rx_initReceiveWindow;
44 extern int rxi_nSendFrags, rxi_nRecvFrags;
45 extern rx_intentionallyDroppedPacketsPer100;
46 extern int (*rxi_syscallp)();
47 FILE *debugFile;
48 int timeout;
49 struct clock waitTime, computeTime;
50
51 void OpenFD();
52
53 void intSignal(int ignore) {
54     Quit("Interrupted");
55 }
56
57 void quitSignal(int ignore) {
58     static int quitCount = 0;
59     if (++quitCount > 1) Quit("rx_ctest: second quit signal, aborting");
60     rx_debugFile = debugFile = fopen("rx_ctest.db", "w");
61     if (debugFile) rx_PrintStats(debugFile);
62 }
63
64 #if !defined(AFS_NT40_ENV) && !defined(AFS_LINUX20_ENV)
65 int test_syscall(a3, a4, a5)
66 afs_uint32 a3, a4;
67 void * a5;
68 {
69   afs_uint32 rcode;
70   void (*old)(int);
71         
72   old = signal(SIGSYS, SIG_IGN);        
73   rcode = syscall (31 /* AFS_SYSCALL */, 28 /* AFSCALL_CALL */, a3, a4, a5);
74   signal(SIGSYS, old);  
75
76 return rcode;
77 }
78 #endif
79
80 main(argc, argv)
81 char **argv;
82 {
83     char *hostname;
84     struct hostent *hostent;
85     afs_uint32 host;
86     int logstdout = 0;
87     struct rx_connection *conn;
88     struct rx_call *call;
89     int err = 0;
90     int nCalls = 1, nBytes = 1;
91     int bufferSize = 2000;
92     char *buffer;
93     char *sendFile = 0;
94     int setFD = 0;
95
96 #if !defined(AFS_NT40_ENV) && !defined(AFS_LINUX20_ENV)
97     setlinebuf(stdout);
98     rxi_syscallp = test_syscall;
99 #endif
100
101
102     argv++; argc--;
103     while (argc && **argv == '-') {
104         if (strcmp(*argv, "-silent") == 0) print = 0;
105         else if (strcmp(*argv, "-nc") == 0) nCalls = atoi(*++argv), argc--;
106         else if (strcmp(*argv, "-nb") == 0) nBytes = atoi(*++argv), argc--;
107         else if (strcmp(*argv, "-npb") == 0) rx_nPackets = atoi(*++argv), argc--;
108         else if (!strcmp(*argv, "-nsf")) 
109              rxi_nSendFrags =  atoi(*++argv), argc--;
110         else if (!strcmp(*argv, "-nrf")) 
111              rxi_nRecvFrags =  atoi(*++argv), argc--;
112         else if (strcmp(*argv, "-twind") == 0) 
113              rx_initSendWindow = atoi(*++argv), argc--;
114         else if (strcmp(*argv, "-rwind") == 0) 
115              rx_initReceiveWindow = atoi(*++argv), argc--;
116         else if (strcmp(*argv, "-rxlog") == 0) rxlog = 1;
117         else if (strcmp(*argv, "-logstdout") == 0) logstdout = 1;
118         else if (strcmp(*argv, "-eventlog") == 0) eventlog = 1;
119         else if (strcmp(*argv, "-drop") == 0) rx_intentionallyDroppedPacketsPer100 = atoi(*++argv), argc--;
120         else if (strcmp(*argv, "-burst") == 0) {
121             burst = atoi(*++argv), argc--;
122             burstTime.sec = atoi(*++argv), argc--;
123             burstTime.usec = atoi(*++argv), argc--;
124         }
125         else if (strcmp(*argv, "-retry") == 0) {
126             retryTime.sec = atoi(*++argv), argc--;
127             retryTime.usec = atoi(*++argv), argc--;
128         }
129         else if (strcmp(*argv, "-timeout") == 0) timeout = atoi(*++argv), argc--;
130         else if (strcmp(*argv, "-fill") == 0) fillPackets++;
131         else if (strcmp(*argv, "-file") == 0) sendFile = *++argv, argc--;
132         else if (strcmp(*argv, "-timereadvs") == 0) timeReadvs = 1;
133         else if (strcmp(*argv, "-wait") == 0) {
134             /* Wait time between calls--to test lastack code */
135             waitTime.sec = atoi(*++argv), argc--;
136             waitTime.usec = atoi(*++argv), argc--;
137         }
138         else if (strcmp(*argv, "-compute") == 0) {
139             /* Simulated "compute" time for each call--to test acknowledgement protocol.  This is simulated by doing an iomgr_select:  imperfect, admittedly. */
140             computeTime.sec = atoi(*++argv), argc--;
141             computeTime.usec = atoi(*++argv), argc--;
142         }
143         else if (strcmp(*argv, "-fd") == 0) {
144             /* Open at least this many fd's. */
145             setFD = atoi(*++argv), argc--;
146         }
147         else {err = 1;break;}
148         argv++, argc--;
149     }
150     if (err || argc != 1) 
151         Quit("usage: rx_ctest [-silent] [-rxlog] [-eventlog] [-nc NCALLS] [-np NPACKETS] hostname");
152     hostname = *argv++, argc--;
153
154     if (rxlog || eventlog) {
155         if (logstdout) debugFile = stdout;
156         else debugFile = fopen("rx_ctest.db", "w");
157         if (debugFile == NULL) Quit("Couldn't open rx_ctest.db");
158         if (rxlog) rx_debugFile = debugFile;
159         if (eventlog) rxevent_debugFile = debugFile;
160     }
161
162     signal(SIGINT, intSignal);/*Changed to sigquit since dbx is broken right now */
163 #ifndef AFS_NT40_ENV
164     signal(SIGQUIT, quitSignal);
165 #endif
166
167 #ifdef AFS_NT40_ENV
168     if (afs_winsockInit()<0) {
169         printf("Can't initialize winsock.\n");
170         exit(1);
171     }
172 #endif
173
174     hostent = gethostbyname(hostname);
175     if (!hostent) Abort("host %s not found", hostname);
176     if (hostent->h_length != 4)
177         Abort("host address is disagreeable length (%d)", hostent->h_length);
178     bcopy(hostent->h_addr, (char *)&host, sizeof(host));
179     if (setFD>0)
180         OpenFD(setFD);
181     if (rx_Init(0) != 0) {
182         printf("RX failed to initialize, exiting.\n");
183         exit(2);
184     }
185     if (setFD>0) {
186         printf("rx_socket=%d\n", rx_socket);
187     }
188
189     printf("Using %d packet buffers\n", rx_nPackets);
190
191     conn = rx_NewConnection(host, htons(2500), 3, rxnull_NewClientSecurityObject(), 0);
192
193     if (!conn) Abort("unable to make a new connection");
194     
195     /* Set initial parameters.  This is (currently) not the approved interface */
196     if (burst) conn->peer->burstSize = conn->peer->burst = burst;
197     if (!clock_IsZero(&burstTime)) conn->peer->burstWait = burstTime;
198     if (!clock_IsZero(&retryTime)) conn->peer->timeout = retryTime;
199
200     if (sendFile) SendFile(sendFile, conn);
201     else {
202         buffer = (char *) osi_Alloc(bufferSize);
203         while (nCalls--) {
204             struct clock startTime;
205             struct timeval t;
206             int nbytes;
207             int nSent;
208             int bytesSent = 0;
209             int bytesRead = 0;
210             call = rx_NewCall(conn);
211             if (!call) Abort("unable to make a new call");
212
213             clock_GetTime(&startTime);
214             for (bytesSent = 0; bytesSent < nBytes; bytesSent += nSent) {
215                 int tryCount;
216                 tryCount = (bufferSize > nBytes - bytesSent)? nBytes - bytesSent: bufferSize;
217                 nSent = rx_Write(call, buffer, tryCount);
218                 if (nSent == 0) break;
219
220             }
221             for (bytesRead = 0; nbytes = rx_Read(call, buffer, bufferSize); bytesRead += nbytes) {};
222             if (print) printf("Received %d characters in response\n", bytesRead);
223             err = rx_EndCall(call, 0);
224             if (err) printf("Error %d returned from rpc call\n", err);
225             else {
226                 struct clock totalTime;
227                 float elapsedTime;
228                 clock_GetTime(&totalTime);
229                 clock_Sub(&totalTime, &startTime);
230                 elapsedTime = clock_Float(&totalTime);
231                 fprintf(stderr, "Sent %d bytes in %0.3f seconds:  %0.0f bytes per second\n",
232                         bytesSent, elapsedTime, bytesSent/elapsedTime);
233             }
234             if (!clock_IsZero(&computeTime)) {
235                 t.tv_sec = computeTime.sec;
236                 t.tv_usec = computeTime.usec;
237                 if (select(0, 0, 0, 0, &t) != 0) Quit("Select didn't return 0");
238             }
239             if (!clock_IsZero(&waitTime)) {
240                 struct timeval t;
241                 t.tv_sec = waitTime.sec;
242                 t.tv_usec = waitTime.usec;
243 #ifdef AFS_PTHREAD_ENV
244                 select(0,0,0,0, &t);
245 #else
246                 IOMGR_Sleep(t.tv_sec);
247 #endif
248             }
249         }
250         if (debugFile) rx_PrintPeerStats(debugFile, rx_PeerOf(conn));
251         rx_PrintPeerStats(stdout, rx_PeerOf(conn));
252     }
253     Quit("testclient: done!\n");
254 }
255
256 SendFile(file, conn)
257 char *file;
258 struct rx_connection *conn;
259 {
260     struct rx_call *call;
261     int fd;
262     struct stat status;
263     int blockSize, bytesLeft;
264     char *buf;
265     int nbytes;
266     int err;
267     struct clock startTime;
268     int receivedStore = 0;
269     struct clock totalReadvDelay;
270     int nReadvs;
271     int code;
272 #ifdef  AFS_AIX_ENV
273 #include <sys/statfs.h>
274     struct statfs tstatfs;
275 #endif
276
277     if (timeReadvs) {
278         nReadvs = 0;
279         clock_Zero(&totalReadvDelay);
280     }
281     fd = open(file, O_RDONLY, 0);
282     if (fd < 0) Abort("Couldn't open %s\n", file);
283     fstat(fd, &status);
284 #ifdef AFS_NT40_ENV
285     blockSize = 1024;
286 #else
287 #ifdef  AFS_AIX_ENV
288 /* Unfortunately in AIX valuable fields such as st_blksize are gone from the stat structure!! */
289     fstatfs(fd, &tstatfs);
290     blockSize = tstatfs.f_bsize;
291 #else
292     blockSize = status.st_blksize;
293 #endif
294 #endif
295     buf = (char *) osi_Alloc(blockSize);
296     bytesLeft = status.st_size;
297     clock_GetTime(&startTime);
298     call = rx_NewCall(conn);
299     while (bytesLeft) {
300         if (!receivedStore && rx_GetRemoteStatus(call) == 79) {
301             receivedStore = 1;
302             fprintf(stderr, "Remote status indicates file accepted (\"received store\")\n");
303         }
304         nbytes = (bytesLeft > blockSize? blockSize: bytesLeft);
305         errno = 0;
306         code = read(fd, buf, nbytes);
307         if (code != nbytes) {
308             Abort("Only read %d bytes of %d, errno=%d\n", code, nbytes, errno);
309         }
310         code = rx_Write(call, buf, nbytes);
311         if (code != nbytes) {
312             Abort("Only wrote %d bytes of %d\n", code, nbytes);
313         }
314         bytesLeft -= nbytes;
315     }
316     while ((nbytes = rx_Read(call, buf, sizeof(buf))) > 0) {
317         char *p = buf;
318         while (nbytes--) {putchar(*p); *p++;}
319     }
320     if ((err = rx_EndCall(call, 0)) != 0) {
321         fprintf(stderr, "rx_Endcall returned error %d\n", err);
322     } else {
323         struct clock totalTime;
324         float elapsedTime;
325         clock_GetTime(&totalTime);
326         clock_Sub(&totalTime, &startTime);
327         elapsedTime = totalTime.sec + totalTime.usec/1e6;
328         fprintf(stderr, "Sent %d bytes in %0.3f seconds:  %0.0f bytes per second\n",
329                 status.st_size, elapsedTime, status.st_size/elapsedTime);
330         if (timeReadvs) {
331             float delay = clock_Float(&totalReadvDelay) / nReadvs;
332             fprintf(stderr, "%d readvs, average delay of %0.4f seconds\n", nReadvs, delay);
333         }
334     }
335     close(fd);
336 }
337     
338 Abort(msg,a,b,c,d,e) {
339     printf((char *) msg, a, b, c, d, e);
340     printf("\n");
341     if (debugFile) {
342         rx_PrintStats(debugFile);
343         fflush(debugFile);
344     }
345     afs_abort();
346     exit(1);
347 }
348
349 Quit(msg, a,b,c,d,e) {
350     printf((char *) msg, a,b,c,d,e);
351     printf("\n");
352     if (debugFile) {
353         rx_PrintStats(debugFile);
354         fflush(debugFile);
355     }
356     rx_PrintStats(stdout);
357     exit(0);
358 }
359
360 /* OpenFD
361  *
362  * Open file descriptors until file descriptor n or higher is returned.
363  */
364 #include <sys/stat.h>
365 void OpenFD(n)
366 int n;
367 {
368     int i;
369     struct stat sbuf;
370     int fd, lfd;
371
372     lfd = -1;
373     for (i=0; i<n; i++) {
374         if (fstat(i, &sbuf) == 0)
375             continue;
376         if ((fd = open("/dev/null", 0, 0)) < 0) {
377             if (lfd >=0) {
378                 close(lfd);
379                 return;
380             }
381         }
382         else {
383             if (fd >= n) {
384                 close(fd);
385                 return;
386             }
387             else {
388                 lfd = fd;
389             }
390         }
391     }
392 }