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