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