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