reindent-20030715
[openafs.git] / src / rxdebug / rxdebug.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 #include <afsconfig.h>
11 #include <afs/param.h>
12
13 RCSID
14     ("$Header$");
15
16 #include <sys/types.h>
17 #include <errno.h>
18 #ifdef AFS_NT40_ENV
19 #include <winsock2.h>
20 #else
21 #include <sys/socket.h>
22 #include <sys/file.h>
23 #include <netdb.h>
24 #endif
25 #ifdef HAVE_NETINET_IN_H
26 #include <netinet/in.h>
27 #endif
28 #ifdef HAVE_SYS_TIME_H
29 #include <sys/time.h>
30 #endif
31 #ifdef HAVE_UNISTD_H
32 #include <unistd.h>
33 #endif
34 #ifdef HAVE_STRING_H
35 #include <string.h>
36 #else
37 #ifdef HAVE_STRINGS_H
38 #include <strings.h>
39 #endif
40 #endif
41 #include <sys/stat.h>
42 #include <afs/stds.h>
43 #include <afs/cmd.h>
44
45 #include <stdio.h>
46
47 #include "rx_user.h"
48 #include "rx_clock.h"
49 #include "rx_queue.h"
50 #include "rx.h"
51 #include "rx_globals.h"
52
53
54 #define TIMEOUT     20
55
56 extern struct hostent *hostutil_GetHostByName();
57
58 static short
59 PortNumber(aport)
60      register char *aport;
61 {
62     register int tc;
63     register short total;
64
65     total = 0;
66     while (tc = *aport++) {
67         if (tc < '0' || tc > '9')
68             return -1;          /* bad port number */
69         total *= 10;
70         total += tc - (int)'0';
71     }
72     return htons(total);
73 }
74
75 static short
76 PortName(aname)
77      register char *aname;
78 {
79     register struct servent *ts;
80     ts = getservbyname(aname, NULL);
81     if (!ts)
82         return -1;
83     return ts->s_port;          /* returns it in network byte order */
84 }
85
86 int
87 MainCommand(as, arock)
88      char *arock;
89      struct cmd_syndesc *as;
90 {
91     register int i;
92     int s;
93     int j;
94     struct sockaddr_in taddr;
95     afs_int32 host;
96     struct in_addr hostAddr;
97     short port;
98     struct hostent *th;
99     register afs_int32 code;
100     int nodally;
101     int allconns;
102     int rxstats;
103     int onlyClient, onlyServer;
104     afs_int32 onlyHost;
105     short onlyPort;
106     int onlyAuth;
107     int flag;
108     int dallyCounter;
109     int withSecStats;
110     int withAllConn;
111     int withRxStats;
112     int withWaiters;
113     int withIdleThreads;
114     int withPeers;
115     struct rx_debugStats tstats;
116     char *portName, *hostName;
117     struct rx_debugConn tconn;
118     short noConns;
119     short showPeers;
120     short showLong;
121     int version_flag;
122     char version[64];
123     afs_int32 length = 64;
124
125     afs_uint32 supportedDebugValues = 0;
126     afs_uint32 supportedStatValues = 0;
127     afs_uint32 supportedConnValues = 0;
128     afs_uint32 supportedPeerValues = 0;
129     afs_int32 nextconn = 0;
130     afs_int32 nextpeer = 0;
131
132     nodally = (as->parms[2].items ? 1 : 0);
133     allconns = (as->parms[3].items ? 1 : 0);
134     rxstats = (as->parms[4].items ? 1 : 0);
135     onlyServer = (as->parms[5].items ? 1 : 0);
136     onlyClient = (as->parms[6].items ? 1 : 0);
137     version_flag = (as->parms[10].items ? 1 : 0);
138     noConns = (as->parms[11].items ? 1 : 0);
139     showPeers = (as->parms[12].items ? 1 : 0);
140     showLong = (as->parms[13].items ? 1 : 0);
141
142     if (as->parms[0].items)
143         hostName = as->parms[0].items->data;
144     else
145         hostName = NULL;
146
147     if (as->parms[1].items)
148         portName = as->parms[1].items->data;
149     else
150         portName = NULL;
151
152     if (as->parms[7].items) {
153         char *name = as->parms[7].items->data;
154         if ((onlyPort = PortNumber(name)) == -1)
155             onlyPort = PortName(name);
156         if (onlyPort == -1) {
157             printf("rxdebug: can't resolve port name %s\n", name);
158             exit(1);
159         }
160     } else
161         onlyPort = -1;
162
163     if (as->parms[8].items) {
164         char *name = as->parms[8].items->data;
165         struct hostent *th;
166         th = hostutil_GetHostByName(name);
167         if (!th) {
168             printf("rxdebug: host %s not found in host table\n", name);
169             exit(1);
170         }
171         memcpy(&onlyHost, th->h_addr, sizeof(afs_int32));
172     } else
173         onlyHost = -1;
174
175     if (as->parms[9].items) {
176         char *name = as->parms[9].items->data;
177         if (strcmp(name, "clear") == 0)
178             onlyAuth = 0;
179         else if (strcmp(name, "auth") == 0)
180             onlyAuth = 1;
181         else if (strcmp(name, "crypt") == 0)
182             onlyAuth = 2;
183         else if ((strcmp(name, "null") == 0) || (strcmp(name, "none") == 0)
184                  || (strncmp(name, "noauth", 6) == 0)
185                  || (strncmp(name, "unauth", 6) == 0))
186             onlyAuth = -1;
187         else {
188             fprintf(stderr, "Unknown authentication level: %s\n", name);
189             exit(1);
190         }
191     } else
192         onlyAuth = 999;
193
194     /* lookup host */
195     if (hostName) {
196         th = hostutil_GetHostByName(hostName);
197         if (!th) {
198             printf("rxdebug: host %s not found in host table\n", hostName);
199             exit(1);
200         }
201         memcpy(&host, th->h_addr, sizeof(afs_int32));
202     } else
203         host = htonl(0x7f000001);       /* IP localhost */
204
205     if (!portName)
206         port = htons(7000);     /* default is fileserver */
207     else {
208         if ((port = PortNumber(portName)) == -1)
209             port = PortName(portName);
210         if (port == -1) {
211             printf("rxdebug: can't resolve port name %s\n", portName);
212             exit(1);
213         }
214     }
215
216     dallyCounter = 0;
217
218     hostAddr.s_addr = host;
219     printf("Trying %s (port %d):\n", inet_ntoa(hostAddr), ntohs(port));
220     s = socket(AF_INET, SOCK_DGRAM, 0);
221     taddr.sin_family = AF_INET;
222     taddr.sin_port = 0;
223     taddr.sin_addr.s_addr = 0;
224 #ifdef STRUCT_SOCKADDR_HAS_SA_LEN
225     taddr.sin_len = sizeof(struct sockaddr_in);
226 #endif
227     code = bind(s, (struct sockaddr *)&taddr, sizeof(struct sockaddr_in));
228     if (code) {
229         perror("bind");
230         exit(1);
231     }
232
233     if (version_flag) {
234
235         code = rx_GetServerVersion(s, host, port, length, version);
236         if (code < 0) {
237             printf("get version call failed with code %d, errno %d\n", code,
238                    errno);
239             exit(1);
240         }
241         printf("AFS version: %s\n", version);
242         fflush(stdout);
243
244         exit(0);
245
246     }
247
248
249     code = rx_GetServerDebug(s, host, port, &tstats, &supportedDebugValues);
250     if (code < 0) {
251         printf("getstats call failed with code %d\n", code);
252         exit(1);
253     }
254
255     withSecStats = (supportedDebugValues & RX_SERVER_DEBUG_SEC_STATS);
256     withAllConn = (supportedDebugValues & RX_SERVER_DEBUG_ALL_CONN);
257     withRxStats = (supportedDebugValues & RX_SERVER_DEBUG_RX_STATS);
258     withWaiters = (supportedDebugValues & RX_SERVER_DEBUG_WAITER_CNT);
259     withIdleThreads = (supportedDebugValues & RX_SERVER_DEBUG_IDLE_THREADS);
260     withPeers = (supportedDebugValues & RX_SERVER_DEBUG_ALL_PEER);
261
262     printf("Free packets: %d, packet reclaims: %d, calls: %d, used FDs: %d\n",
263            tstats.nFreePackets, tstats.packetReclaims, tstats.callsExecuted,
264            tstats.usedFDs);
265     if (!tstats.waitingForPackets)
266         printf("not ");
267     printf("waiting for packets.\n");
268     if (withWaiters)
269         printf("%d calls waiting for a thread\n", tstats.nWaiting);
270     if (withIdleThreads)
271         printf("%d threads are idle\n", tstats.idleThreads);
272
273     if (rxstats) {
274         if (!withRxStats) {
275           noRxStats:
276             withRxStats = 0;
277             fprintf(stderr,
278                     "WARNING: Server doesn't support retrieval of Rx statistics\n");
279         } else {
280             struct rx_stats rxstats;
281
282             /* should gracefully handle the case where rx_stats grows */
283             code =
284                 rx_GetServerStats(s, host, port, &rxstats,
285                                   &supportedStatValues);
286             if (code < 0) {
287                 printf("rxstats call failed with code %d\n", code);
288                 exit(1);
289             }
290             if (code != sizeof(rxstats)) {
291                 if ((((struct rx_debugIn *)(&rxstats))->type ==
292                      RX_DEBUGI_BADTYPE))
293                     goto noRxStats;
294                 printf
295                     ("WARNING: returned Rx statistics of unexpected size (got %d)\n",
296                      code);
297                 /* handle other versions?... */
298             }
299
300             rx_PrintTheseStats(stdout, &rxstats, sizeof(rxstats),
301                                tstats.nFreePackets, tstats.version);
302         }
303     }
304
305     if (!noConns) {
306         if (allconns) {
307             if (!withAllConn)
308                 fprintf(stderr,
309                         "WARNING: Server doesn't support retrieval of all connections,\n         getting only interesting instead.\n");
310         }
311
312         if (onlyServer)
313             printf("Showing only server connections\n");
314         if (onlyClient)
315             printf("Showing only client connections\n");
316         if (onlyAuth != 999) {
317             static char *name[] =
318                 { "unauthenticated", "rxkad_clear", "rxkad_auth",
319                 "rxkad_crypt"
320             };
321             printf("Showing only %s connections\n", name[onlyAuth + 1]);
322         }
323         if (onlyHost != -1) {
324             hostAddr.s_addr = onlyHost;
325             printf("Showing only connections from host %s\n",
326                    inet_ntoa(hostAddr));
327         }
328         if (onlyPort != -1)
329             printf("Showing only connections on port %u\n", ntohs(onlyPort));
330
331         for (i = 0;; i++) {
332             code =
333                 rx_GetServerConnections(s, host, port, &nextconn, allconns,
334                                         supportedDebugValues, &tconn,
335                                         &supportedConnValues);
336             if (code < 0) {
337                 printf("getconn call failed with code %d\n", code);
338                 break;
339             }
340             if (tconn.cid == 0xffffffff) {
341                 printf("Done.\n");
342                 break;
343             }
344
345             /* see if we're in nodally mode and all calls are dallying */
346             if (nodally) {
347                 flag = 0;
348                 for (j = 0; j < RX_MAXCALLS; j++) {
349                     if (tconn.callState[j] != RX_STATE_NOTINIT
350                         && tconn.callState[j] != RX_STATE_DALLY) {
351                         flag = 1;
352                         break;
353                     }
354                 }
355                 if (flag == 0) {
356                     /* this call looks too ordinary, bump skipped count and go
357                      * around again */
358                     dallyCounter++;
359                     continue;
360                 }
361             }
362             if ((onlyHost != -1) && (onlyHost != tconn.host))
363                 continue;
364             if ((onlyPort != -1) && (onlyPort != tconn.port))
365                 continue;
366             if (onlyServer && (tconn.type != RX_SERVER_CONNECTION))
367                 continue;
368             if (onlyClient && (tconn.type != RX_CLIENT_CONNECTION))
369                 continue;
370             if (onlyAuth != 999) {
371                 if (onlyAuth == -1) {
372                     if (tconn.securityIndex != 0)
373                         continue;
374                 } else {
375                     if (tconn.securityIndex != 2)
376                         continue;
377                     if (withSecStats && (tconn.secStats.type == 3)
378                         && (tconn.secStats.level != onlyAuth))
379                         continue;
380                 }
381             }
382
383             /* now display the connection */
384             hostAddr.s_addr = tconn.host;
385             printf("Connection from host %s, port %hu, ", inet_ntoa(hostAddr),
386                    ntohs(tconn.port));
387             if (tconn.epoch)
388                 printf("Cuid %x/%x", tconn.epoch, tconn.cid);
389             else
390                 printf("cid %x", tconn.cid);
391             if (tconn.error)
392                 printf(", error %d", tconn.error);
393             printf("\n  serial %d, ", tconn.serial);
394             printf(" natMTU %d, ", tconn.natMTU);
395
396             if (tconn.flags) {
397                 printf("flags");
398                 if (tconn.flags & RX_CONN_MAKECALL_WAITING)
399                     printf(" MAKECALL_WAITING");
400                 if (tconn.flags & RX_CONN_DESTROY_ME)
401                     printf(" DESTROYED");
402                 if (tconn.flags & RX_CONN_USING_PACKET_CKSUM)
403                     printf(" pktCksum");
404                 printf(", ");
405             }
406             printf("security index %d, ", tconn.securityIndex);
407             if (tconn.type == RX_CLIENT_CONNECTION)
408                 printf("client conn\n");
409             else
410                 printf("server conn\n");
411
412             if (withSecStats) {
413                 switch ((int)tconn.secStats.type) {
414                 case 0:
415                     if (tconn.securityIndex == 2)
416                         printf
417                             ("  no GetStats procedure for security object\n");
418                     break;
419                 case 1:
420                     printf("  rxnull level=%d, flags=%d\n",
421                            tconn.secStats.level, tconn.secStats.flags);
422                     break;
423                 case 2:
424                     printf("  rxvab level=%d, flags=%d\n",
425                            tconn.secStats.level, tconn.secStats.flags);
426                     break;
427                 case 3:{
428                         char *level;
429                         char flags = tconn.secStats.flags;
430                         if (tconn.secStats.level == 0)
431                             level = "clear";
432                         else if (tconn.secStats.level == 1)
433                             level = "auth";
434                         else if (tconn.secStats.level == 2)
435                             level = "crypt";
436                         else
437                             level = "unknown";
438                         printf("  rxkad: level %s", level);
439                         if (flags)
440                             printf(", flags");
441                         if (flags & 1)
442                             printf(" unalloc");
443                         if (flags & 2)
444                             printf(" authenticated");
445                         if (flags & 4)
446                             printf(" expired");
447                         if (flags & 8)
448                             printf(" pktCksum");
449                         if (tconn.secStats.expires)
450                             /* Apparently due to a bug in the RT compiler that
451                              * prevents (afs_uint32)0xffffffff => (double) from working,
452                              * this code produces negative lifetimes when run on the
453                              * RT. */
454                             printf(", expires in %.1f hours",
455                                    ((afs_uint32) tconn.secStats.expires -
456                                     time(0)) / 3600.0);
457                         if (!(flags & 1)) {
458                             printf("\n  Received %d bytes in %d packets\n",
459                                    tconn.secStats.bytesReceived,
460                                    tconn.secStats.packetsReceived);
461                             printf("  Sent %d bytes in %d packets\n",
462                                    tconn.secStats.bytesSent,
463                                    tconn.secStats.packetsSent);
464                         } else
465                             printf("\n");
466                         break;
467                     }
468
469                 default:
470                     printf("  unknown\n");
471                 }
472             }
473
474             for (j = 0; j < RX_MAXCALLS; j++) {
475                 printf("    call %d: # %d, state ", j, tconn.callNumber[j]);
476                 if (tconn.callState[j] == RX_STATE_NOTINIT) {
477                     printf("not initialized\n");
478                     continue;
479                 } else if (tconn.callState[j] == RX_STATE_PRECALL)
480                     printf("precall, ");
481                 else if (tconn.callState[j] == RX_STATE_ACTIVE)
482                     printf("active, ");
483                 else if (tconn.callState[j] == RX_STATE_DALLY)
484                     printf("dally, ");
485                 else if (tconn.callState[j] == RX_STATE_HOLD)
486                     printf("hold, ");
487                 printf("mode: ");
488                 if (tconn.callMode[j] == RX_MODE_SENDING)
489                     printf("sending");
490                 else if (tconn.callMode[j] == RX_MODE_RECEIVING)
491                     printf("receiving");
492                 else if (tconn.callMode[j] == RX_MODE_ERROR)
493                     printf("error");
494                 else if (tconn.callMode[j] == RX_MODE_EOF)
495                     printf("eof");
496                 else
497                     printf("unknown");
498                 if (tconn.callFlags[j]) {
499                     printf(", flags:");
500                     if (tconn.callFlags[j] & RX_CALL_READER_WAIT)
501                         printf(" reader_wait");
502                     if (tconn.callFlags[j] & RX_CALL_WAIT_WINDOW_ALLOC)
503                         printf(" window_alloc");
504                     if (tconn.callFlags[j] & RX_CALL_WAIT_WINDOW_SEND)
505                         printf(" window_send");
506                     if (tconn.callFlags[j] & RX_CALL_WAIT_PACKETS)
507                         printf(" wait_packets");
508                     if (tconn.callFlags[j] & RX_CALL_WAIT_PROC)
509                         printf(" waiting_for_process");
510                     if (tconn.callFlags[j] & RX_CALL_RECEIVE_DONE)
511                         printf(" receive_done");
512                     if (tconn.callFlags[j] & RX_CALL_CLEARED)
513                         printf(" call_cleared");
514                 }
515                 if (tconn.callOther[j] & RX_OTHER_IN)
516                     printf(", has_input_packets");
517                 if (tconn.callOther[j] & RX_OTHER_OUT)
518                     printf(", has_output_packets");
519                 printf("\n");
520             }
521         }
522         if (nodally)
523             printf("Skipped %d dallying connections.\n", dallyCounter);
524     }
525     if (showPeers && withPeers) {
526         for (i = 0;; i++) {
527             struct rx_debugPeer tpeer;
528             code =
529                 rx_GetServerPeers(s, host, port, &nextpeer, allconns, &tpeer,
530                                   &supportedPeerValues);
531             if (code < 0) {
532                 printf("getpeer call failed with code %d\n", code);
533                 break;
534             }
535             if (tpeer.host == 0xffffffff) {
536                 printf("Done.\n");
537                 break;
538             }
539
540             if ((onlyHost != -1) && (onlyHost != tpeer.host))
541                 continue;
542             if ((onlyPort != -1) && (onlyPort != tpeer.port))
543                 continue;
544
545             /* now display the peer */
546             hostAddr.s_addr = tpeer.host;
547             printf("Peer at host %s, port %hu\n", inet_ntoa(hostAddr),
548                    ntohs(tpeer.port));
549             printf("\tifMTU %hu\tnatMTU %hu\tmaxMTU %hu\n", tpeer.ifMTU,
550                    tpeer.natMTU, tpeer.maxMTU);
551             printf("\tpackets sent %d\tpacket resends %d\n", tpeer.nSent,
552                    tpeer.reSends);
553             printf("\tbytes sent high %d low %d\n", tpeer.bytesSent.high,
554                    tpeer.bytesSent.low);
555             printf("\tbytes received high %d low %d\n",
556                    tpeer.bytesReceived.high, tpeer.bytesReceived.low);
557             printf("\trtt %d msec, rtt_dev %d msec\n", tpeer.rtt >> 3,
558                    tpeer.rtt_dev >> 2);
559             printf("\ttimeout %d.%03d sec\n", tpeer.timeout.sec,
560                    tpeer.timeout.usec / 1000);
561             if (!showLong)
562                 continue;
563
564             printf("\tin/out packet skew: %d/%d\n", tpeer.inPacketSkew,
565                    tpeer.outPacketSkew);
566             printf("\tcongestion window %d, MTU %d\n", tpeer.cwind,
567                    tpeer.MTU);
568             printf("\tcurrent/if/max jumbogram size: %d/%d/%d\n",
569                    tpeer.nDgramPackets, tpeer.ifDgramPackets,
570                    tpeer.maxDgramPackets);
571         }
572     }
573     exit(0);
574 }
575
576 /* simple main program */
577 #ifndef AFS_NT40_ENV
578 #include "AFS_component_version_number.c"
579 #endif
580 int
581 main(argc, argv)
582      int argc;
583      char **argv;
584 {
585     struct cmd_syndesc *ts;
586
587 #ifdef AFS_NT40_ENV
588     if (afs_winsockInit() < 0) {
589         printf("%s: Couldn't initialize winsock. Exiting...\n", argv[0]);
590         return 1;
591     }
592 #endif
593
594     ts = cmd_CreateSyntax(NULL, MainCommand, 0, "probe RX server");
595     cmd_AddParm(ts, "-servers", CMD_SINGLE, CMD_REQUIRED, "server machine");
596     cmd_AddParm(ts, "-port", CMD_SINGLE, CMD_OPTIONAL, "IP port");
597     cmd_AddParm(ts, "-nodally", CMD_FLAG, CMD_OPTIONAL,
598                 "don't show dallying conns");
599     cmd_AddParm(ts, "-allconnections", CMD_FLAG, CMD_OPTIONAL,
600                 "don't filter out uninteresting connections on server");
601     cmd_AddParm(ts, "-rxstats", CMD_FLAG, CMD_OPTIONAL, "show Rx statistics");
602     cmd_AddParm(ts, "-onlyserver", CMD_FLAG, CMD_OPTIONAL,
603                 "only show server conns");
604     cmd_AddParm(ts, "-onlyclient", CMD_FLAG, CMD_OPTIONAL,
605                 "only show client conns");
606     cmd_AddParm(ts, "-onlyport", CMD_SINGLE, CMD_OPTIONAL,
607                 "show only <port>");
608     cmd_AddParm(ts, "-onlyhost", CMD_SINGLE, CMD_OPTIONAL,
609                 "show only <host>");
610     cmd_AddParm(ts, "-onlyauth", CMD_SINGLE, CMD_OPTIONAL,
611                 "show only <auth level>");
612
613     cmd_AddParm(ts, "-version", CMD_FLAG, CMD_OPTIONAL,
614                 "show AFS version id");
615     cmd_AddParm(ts, "-noconns", CMD_FLAG, CMD_OPTIONAL,
616                 "show no connections");
617     cmd_AddParm(ts, "-peers", CMD_FLAG, CMD_OPTIONAL, "show peers");
618     cmd_AddParm(ts, "-long", CMD_FLAG, CMD_OPTIONAL, "detailed output");
619
620     cmd_Dispatch(argc, argv);
621     exit(0);
622 }